From 5b8c45586b67111cb107a9802c0f82a6b61ba18b Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 2 Oct 2023 15:07:33 +0700 Subject: [PATCH] TF-2172 Add DropZone widget (cherry picked from commit 72f5f04800c1bb56118676b44cf0102ba14ef034) --- assets/images/ic_drop_zone_icon.svg | 4 + .../extensions/color_extension.dart | 2 + .../presentation/resources/image_paths.dart | 1 + .../styles/web/drop_zone_widget_style.dart | 22 +++++ .../widgets/web/drop_zone_widget.dart | 87 +++++++++++++++++++ lib/l10n/intl_messages.arb | 8 +- lib/main/localizations/app_localizations.dart | 7 ++ pubspec.lock | 16 ++++ pubspec.yaml | 2 + 9 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 assets/images/ic_drop_zone_icon.svg create mode 100644 lib/features/composer/presentation/styles/web/drop_zone_widget_style.dart create mode 100644 lib/features/composer/presentation/widgets/web/drop_zone_widget.dart diff --git a/assets/images/ic_drop_zone_icon.svg b/assets/images/ic_drop_zone_icon.svg new file mode 100644 index 000000000..37ec0f09e --- /dev/null +++ b/assets/images/ic_drop_zone_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index b1116ad13..3143ae773 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -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)], diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index d4ffc99ee..d8b866c66 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -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; diff --git a/lib/features/composer/presentation/styles/web/drop_zone_widget_style.dart b/lib/features/composer/presentation/styles/web/drop_zone_widget_style.dart new file mode 100644 index 000000000..033c224f6 --- /dev/null +++ b/lib/features/composer/presentation/styles/web/drop_zone_widget_style.dart @@ -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 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 + ); +} \ No newline at end of file diff --git a/lib/features/composer/presentation/widgets/web/drop_zone_widget.dart b/lib/features/composer/presentation/widgets/web/drop_zone_widget.dart new file mode 100644 index 000000000..58b908323 --- /dev/null +++ b/lib/features/composer/presentation/widgets/web/drop_zone_widget.dart @@ -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 createState() => _DropZoneWidgetState(); +} + +class _DropZoneWidgetState extends State { + + final _imagePaths = Get.find(); + + bool _isDragging = false; + + @override + Widget build(BuildContext context) { + return DragTarget( + 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); + } + }, + ); + } +} diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 53bafb7d3..e355d56a4 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -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": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index f046b6217..ec118870c 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -3340,4 +3340,11 @@ class AppLocalizations { name: 'saveAsDraft', ); } + + String get dropFileHereToAttachThem { + return Intl.message( + 'Drop file here to attach them', + name: 'dropFileHereToAttachThem', + ); + } } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index e37829e50..d40ffde9a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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: diff --git a/pubspec.yaml b/pubspec.yaml index 646ecb017..8d1670ecc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -211,6 +211,8 @@ dependencies: url_strategy: 0.2.0 + dotted_border: 2.1.0 + dev_dependencies: flutter_test: sdk: flutter