TF-2172 Add DropZone widget
(cherry picked from commit 72f5f04800c1bb56118676b44cf0102ba14ef034)
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="80" height="80" rx="20" fill="#D1E9FF"/>
|
||||
<path d="M44.1339 23.4943C44.6289 23.6084 45.0669 23.7898 45.4976 24.0592C45.9282 24.3285 46.2771 24.6112 47.19 25.5241L52.8087 31.1429C53.7216 32.0558 54.0044 32.4046 54.2737 32.8353C54.543 33.266 54.7244 33.7039 54.8385 34.1989C54.9526 34.6939 54.9993 35.1405 54.9993 36.4315V48.5905C54.9993 50.8192 54.7673 51.6275 54.3315 52.4423C53.8958 53.2571 53.2563 53.8966 52.4415 54.3323C51.6266 54.7681 50.8184 55.0002 48.5896 55.0002H33.0757C30.8469 55.0002 30.0387 54.7681 29.2239 54.3323C28.4091 53.8966 27.7696 53.2571 27.3338 52.4423C26.8981 51.6275 26.666 50.8192 26.666 48.5905V29.7432C26.666 27.5144 26.8981 26.7062 27.3338 25.8914C27.7696 25.0766 28.4091 24.4371 29.2239 24.0013C30.0387 23.5656 30.8469 23.3335 33.0757 23.3335H41.9013C43.1924 23.3335 43.639 23.3802 44.1339 23.4943ZM42.9993 26.5406C42.7232 26.5406 42.4993 26.7645 42.4993 27.0406V33.3335C42.4993 33.7938 42.8724 34.1669 43.3327 34.1669H49.6256C49.7582 34.1669 49.8854 34.1142 49.9791 34.0204C50.1744 33.8252 50.1744 33.5086 49.9791 33.3133L43.3529 26.6871C43.2591 26.5933 43.132 26.5406 42.9993 26.5406Z" fill="#007AFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -218,6 +218,8 @@ extension AppColor on Color {
|
||||
static const colorSelected = Color(0xFFE3F1FF);
|
||||
static const colorAttachmentBorder = Color(0xFFE5ECF3);
|
||||
static const colorProgressLoadingBackground = Color(0xFFE3F1FF);
|
||||
static const colorDropZoneBackground = Color(0xFFF6FAFF);
|
||||
static const colorDropZoneBorder = Color(0xFF46A2FF);
|
||||
|
||||
static const mapGradientColor = [
|
||||
[Color(0xFF21D4FD), Color(0xFFB721FF)],
|
||||
|
||||
@@ -203,6 +203,7 @@ class ImagePaths {
|
||||
String get icAttachFile => _getImagePath('ic_attach_file.svg');
|
||||
String get icSend => _getImagePath('ic_send.svg');
|
||||
String get icReadReceipt => _getImagePath('ic_read_receipt.svg');
|
||||
String get icDropZoneIcon => _getImagePath('ic_drop_zone_icon.svg');
|
||||
|
||||
String _getImagePath(String imageName) {
|
||||
return AssetsPaths.images + imageName;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DropZoneWidgetStyle {
|
||||
static const double space = 20;
|
||||
static const double borderWidth = 2;
|
||||
static const double radius = 16;
|
||||
|
||||
static const List<double> dashSize = [6, 3];
|
||||
|
||||
static const Color backgroundColor = AppColor.colorDropZoneBackground;
|
||||
static const Color borderColor = AppColor.colorDropZoneBorder;
|
||||
|
||||
static const EdgeInsetsGeometry padding = EdgeInsets.all(20);
|
||||
static const EdgeInsetsGeometry margin = EdgeInsetsDirectional.symmetric(vertical: 8);
|
||||
|
||||
static const TextStyle labelTextStyle = TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w600
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:dotted_border/dotted_border.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:model/email/attachment.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/styles/web/drop_zone_widget_style.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
class DropZoneWidget extends StatefulWidget {
|
||||
|
||||
final double? width;
|
||||
final double? height;
|
||||
|
||||
const DropZoneWidget({super.key, this.width, this.height});
|
||||
|
||||
@override
|
||||
State<DropZoneWidget> createState() => _DropZoneWidgetState();
|
||||
}
|
||||
|
||||
class _DropZoneWidgetState extends State<DropZoneWidget> {
|
||||
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
bool _isDragging = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DragTarget<Attachment>(
|
||||
builder: (context, candidateData, rejectedData) {
|
||||
if (_isDragging) {
|
||||
return Padding(
|
||||
padding: DropZoneWidgetStyle.margin,
|
||||
child: DottedBorder(
|
||||
borderType: BorderType.RRect,
|
||||
radius: const Radius.circular(DropZoneWidgetStyle.radius),
|
||||
color: DropZoneWidgetStyle.borderColor,
|
||||
strokeWidth: DropZoneWidgetStyle.borderWidth,
|
||||
dashPattern: DropZoneWidgetStyle.dashSize,
|
||||
child: Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: const ShapeDecoration(
|
||||
color: DropZoneWidgetStyle.backgroundColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(DropZoneWidgetStyle.radius)),
|
||||
),
|
||||
),
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
padding: DropZoneWidgetStyle.padding,
|
||||
alignment: AlignmentDirectional.center,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SvgPicture.asset(_imagePaths.icDropZoneIcon),
|
||||
const SizedBox(height: DropZoneWidgetStyle.space),
|
||||
Text(
|
||||
AppLocalizations.of(context).dropFileHereToAttachThem,
|
||||
style: DropZoneWidgetStyle.labelTextStyle,
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return SizedBox(width: widget.width, height: widget.height);
|
||||
}
|
||||
},
|
||||
onAccept: (attachment) {
|
||||
log('_DropZoneWidgetState::build:onAccept: $attachment');
|
||||
},
|
||||
onLeave: (attachment) {
|
||||
if (_isDragging) {
|
||||
setState(() => _isDragging = false);
|
||||
}
|
||||
},
|
||||
onMove: (details) {
|
||||
if (!_isDragging) {
|
||||
setState(() => _isDragging = true);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2023-09-07T19:09:09.089986",
|
||||
"@@last_modified": "2023-10-02T15:04:12.165160",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -3239,5 +3239,11 @@
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"dropFileHereToAttachThem": "Drop file here to attach them",
|
||||
"@dropFileHereToAttachThem": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
@@ -3340,4 +3340,11 @@ class AppLocalizations {
|
||||
name: 'saveAsDraft',
|
||||
);
|
||||
}
|
||||
|
||||
String get dropFileHereToAttachThem {
|
||||
return Intl.message(
|
||||
'Drop file here to attach them',
|
||||
name: 'dropFileHereToAttachThem',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -360,6 +360,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
dotted_border:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dotted_border
|
||||
sha256: "108837e11848ca776c53b30bc870086f84b62ed6e01c503ed976e8f8c7df9c04"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
dropdown_button2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1142,6 +1150,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_drawing
|
||||
sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -211,6 +211,8 @@ dependencies:
|
||||
|
||||
url_strategy: 0.2.0
|
||||
|
||||
dotted_border: 2.1.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
Reference in New Issue
Block a user