diff --git a/lib/features/mailbox/presentation/mailbox_view_web.dart b/lib/features/mailbox/presentation/mailbox_view_web.dart index 53eafc0fd..6183863c3 100644 --- a/lib/features/mailbox/presentation/mailbox_view_web.dart +++ b/lib/features/mailbox/presentation/mailbox_view_web.dart @@ -281,10 +281,11 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu controller.openMailbox(context, mailboxNode.item)) ..addOnExpandFolderActionClick((mailboxNode) => controller.toggleMailboxFolder(mailboxNode)) - ..adOnMenuActionClick((position, mailboxNode) => + ..addOnMenuActionClick((position, mailboxNode) => _openMailboxMenuAction(context, position, mailboxNode.item)) ..addOnSelectMailboxFolderClick((mailboxNode) => - controller.selectMailboxNode(mailboxNode))) + controller.selectMailboxNode(mailboxNode)) + ..addOnDragItemAccepted(controller.mailboxDashBoardController.dragSelectedMultipleEmailToMailbox)) .build()), children: _buildListChildTileWidget(context, mailboxNode) ).build() @@ -292,10 +293,11 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu mailboxNodeSelected: controller.mailboxDashBoardController.selectedMailbox.value) ..addOnOpenMailboxFolderClick((mailboxNode) => controller.openMailbox(context, mailboxNode.item)) - ..adOnMenuActionClick((position, mailboxNode) => + ..addOnMenuActionClick((position, mailboxNode) => _openMailboxMenuAction(context, position, mailboxNode.item)) ..addOnSelectMailboxFolderClick((mailboxNode) => - controller.selectMailboxNode(mailboxNode))) + controller.selectMailboxNode(mailboxNode)) + ..addOnDragItemAccepted(controller.mailboxDashBoardController.dragSelectedMultipleEmailToMailbox)) .build()) ).toList() ?? []; } @@ -361,6 +363,7 @@ class MailboxView extends GetWidget with AppLoaderMixin, Popu _responsiveUtils, listMailbox[index], lastMailbox: controller.listMailboxSearched.last) + ..addOnDragItemAccepted(controller.mailboxDashBoardController.dragSelectedMultipleEmailToMailbox) ..addOnOpenMailboxAction((mailbox) => controller.openMailbox(context, mailbox)) ..addOnMenuActionClick((position, mailbox) => _openMailboxMenuAction(context, position, mailbox)) ..addOnSelectMailboxActionClick((mailbox) => controller.selectMailboxSearched(context, mailbox))) diff --git a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart index 1cf31c080..f4b1ac2a5 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_folder_tile_builder.dart @@ -14,6 +14,7 @@ typedef OnExpandFolderActionClick = void Function(MailboxNode); typedef OnOpenMailboxFolderClick = void Function(MailboxNode); typedef OnSelectMailboxFolderClick = void Function(MailboxNode); typedef OnMenuActionClick = void Function(RelativeRect, MailboxNode); +typedef OnDragItemAccepted = void Function(List, PresentationMailbox); class MailBoxFolderTileBuilder { @@ -33,6 +34,7 @@ class MailBoxFolderTileBuilder { OnOpenMailboxFolderClick? _onOpenMailboxFolderClick; OnSelectMailboxFolderClick? _onSelectMailboxFolderClick; OnMenuActionClick? _onMenuActionClick; + OnDragItemAccepted? _onDragItemAccepted; bool isHoverItem = false; @@ -62,11 +64,23 @@ class MailBoxFolderTileBuilder { _onSelectMailboxFolderClick = onSelectMailboxFolderClick; } - void adOnMenuActionClick(OnMenuActionClick onMenuActionClick) { + void addOnMenuActionClick(OnMenuActionClick onMenuActionClick) { _onMenuActionClick = onMenuActionClick; } - Widget build() => _buildMailboxItem(); + void addOnDragItemAccepted(OnDragItemAccepted onDragItemAccepted) { + _onDragItemAccepted = onDragItemAccepted; + } + + Widget build() => DragTarget>( + builder: (context, _, __,) { + return _buildMailboxItem(); + }, + onAccept: (emails) { + _onDragItemAccepted?.call(emails, _mailboxNode.item); + print(emails); + }, + ); Widget _buildMailboxItem() { if (mailboxDisplayed == MailboxDisplayed.mailbox) { diff --git a/lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart b/lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart index 6debb9aa8..8fee6c0de 100644 --- a/lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart +++ b/lib/features/mailbox/presentation/widgets/mailbox_search_tile_builder.dart @@ -10,6 +10,7 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_displa typedef OnOpenMailboxActionClick = void Function(PresentationMailbox); typedef OnSelectMailboxActionClick = void Function(PresentationMailbox); typedef OnOpenMenuActionClick = void Function(RelativeRect, PresentationMailbox); +typedef OnDragItemAccepted = void Function(List, PresentationMailbox); class MailboxSearchTileBuilder { @@ -28,6 +29,7 @@ class MailboxSearchTileBuilder { OnOpenMailboxActionClick? _onOpenMailboxActionClick; OnSelectMailboxActionClick? _onSelectMailboxActionClick; OnOpenMenuActionClick? _onMenuActionClick; + OnDragItemAccepted? _onDragItemAccepted; MailboxSearchTileBuilder( this._context, @@ -55,12 +57,24 @@ class MailboxSearchTileBuilder { _onMenuActionClick = onOpenMenuActionClick; } + void addOnDragItemAccepted(OnDragItemAccepted onDragItemAccepted) { + _onDragItemAccepted = onDragItemAccepted; + } + Widget build() { return Theme( data: ThemeData( splashColor: Colors.transparent, highlightColor: Colors.transparent), - child: _buildMailboxItem() + child: DragTarget>( + builder: (context, _, __,) { + return _buildMailboxItem(); + }, + onAccept: (emails) { + _onDragItemAccepted?.call(emails, _presentationMailbox); + print(emails.first.preview); + }, + ), ); } @@ -73,21 +87,21 @@ class MailboxSearchTileBuilder { child: Opacity( opacity: _presentationMailbox.isActivated ? 1.0 : 0.3, child: InkWell( - onTap: () {}, - onHover: (value) => setState(() => isHoverItem = value), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: backgroundColorItem), - child: ListTile( - contentPadding: const EdgeInsets.only(left: 8), - onTap: () => _onOpenMailboxActionClick?.call(_presentationMailbox), - leading: _buildLeadingIcon(), - title: _buildTitleItem(), - subtitle: _buildSubtitleItem(), - trailing: _buildMenuIcon(), - ), - ) + onTap: () {}, + onHover: (value) => setState(() => isHoverItem = value), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: backgroundColorItem), + child: ListTile( + contentPadding: const EdgeInsets.only(left: 8), + onTap: () => _onOpenMailboxActionClick?.call(_presentationMailbox), + leading: _buildLeadingIcon(), + title: _buildTitleItem(), + subtitle: _buildSubtitleItem(), + trailing: _buildMenuIcon(), + ), + ) ), ), ); diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index e62b42e7d..026536696 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -74,6 +74,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_e import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/move_multiple_email_to_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; +import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; @@ -650,6 +651,37 @@ class MailboxDashBoardController extends ReloadableController { } } + void dragSelectedMultipleEmailToMailbox( + List listEmails, + PresentationMailbox destinationMailbox + ) async { + if (accountId.value != null && selectedMailbox.value != null) { + if (destinationMailbox.isTrash) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + selectedMailbox.value!.id, + destinationMailbox.id, + MoveAction.moving, + EmailActionType.moveToTrash)); + } else if (destinationMailbox.isSpam) { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + selectedMailbox.value!.id, + destinationMailbox.id, + MoveAction.moving, + EmailActionType.moveToSpam)); + } else { + _moveSelectedEmailMultipleToMailboxAction(accountId.value!, MoveToMailboxRequest( + listEmails.listEmailIds, + selectedMailbox.value!.id, + destinationMailbox.id, + MoveAction.moving, + EmailActionType.moveToMailbox, + destinationPath: destinationMailbox.mailboxPath)); + } + } + } + void _moveSelectedEmailMultipleToMailboxAction( AccountId accountId, MoveToMailboxRequest moveRequest @@ -672,6 +704,9 @@ class MailboxDashBoardController extends ReloadableController { destinationMailboxId = success.destinationMailboxId; moveAction = success.moveAction; emailActionType = success.emailActionType; + if (Get.isRegistered()){ + Get.find().refreshEmailChanges(currentEmailState: success.currentEmailState); + } } else if (success is MoveMultipleEmailToMailboxHasSomeEmailFailure) { destinationPath = success.destinationPath; movedEmailIds = success.movedListEmailId; diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 323beaaa9..6f1d14dea 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -303,25 +303,25 @@ class ThreadController extends BaseController { if (viewState is Either) { viewState.map((success) { if (success is MarkAsEmailReadSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is MoveToMailboxSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is MarkAsStarEmailSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is DeleteEmailPermanentlySuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is SaveEmailAsDraftsSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is RemoveEmailDraftsSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is SendEmailSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is UpdateEmailDraftsSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is MarkAsMailboxReadAllSuccess) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is MarkAsMailboxReadHasSomeEmailFailure) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } }); } @@ -424,8 +424,8 @@ class ThreadController extends BaseController { } } - void _refreshEmailChanges({jmap.State? currentEmailState}) { - log('ThreadController::_refreshEmailChanges(): currentEmailState: $currentEmailState'); + void refreshEmailChanges({jmap.State? currentEmailState}) { + log('ThreadController::refreshEmailChanges(): currentEmailState: $currentEmailState'); if (isSearchActive()) { if (_accountId != null && searchQuery != null) { final limit = emailList.isNotEmpty @@ -436,7 +436,7 @@ class ThreadController extends BaseController { } } else { final newEmailState = currentEmailState ?? _currentEmailState; - log('ThreadController::_refreshEmailChanges(): newEmailState: $newEmailState'); + log('ThreadController::refreshEmailChanges(): newEmailState: $newEmailState'); if (_accountId != null && newEmailState != null) { consumeState(_refreshChangesEmailsInMailboxInteractor.execute( _accountId!, @@ -575,7 +575,7 @@ class ThreadController extends BaseController { message: message, icon: readActions == ReadActions.markAsUnread ? _imagePaths.icUnreadToast : _imagePaths.icReadToast); } - _refreshEmailChanges(currentEmailState: currentEmailState); + refreshEmailChanges(currentEmailState: currentEmailState); } void _markAsReadSelectedMultipleEmailFailure(Failure failure) { @@ -732,7 +732,7 @@ class ThreadController extends BaseController { ); } - _refreshEmailChanges(currentEmailState: currentEmailState); + refreshEmailChanges(currentEmailState: currentEmailState); } void moveSelectedMultipleEmailToTrash( @@ -820,7 +820,7 @@ class ThreadController extends BaseController { } void _markAsStarEmailSuccess(MarkAsStarEmailSuccess success) { - _refreshEmailChanges(currentEmailState: success.currentEmailState); + refreshEmailChanges(currentEmailState: success.currentEmailState); } void markAsStarSelectedMultipleEmail( @@ -861,7 +861,7 @@ class ThreadController extends BaseController { icon: markStarAction == MarkStarAction.unMarkStar ? _imagePaths.icUnStar : _imagePaths.icStar); } - _refreshEmailChanges(currentEmailState: currentEmailState); + refreshEmailChanges(currentEmailState: currentEmailState); } void _markAsStarMultipleEmailFailure(Failure failure) { @@ -1316,7 +1316,7 @@ class ThreadController extends BaseController { icon: _imagePaths.icDeleteToast); } - _refreshEmailChanges(currentEmailState: currentEmailState); + refreshEmailChanges(currentEmailState: currentEmailState); } void _emptyTrashFolderAction() { diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index faa69caf7..68546561e 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -332,7 +332,10 @@ class ThreadView extends GetWidget with AppLoaderMixin, key: const PageStorageKey('list_presentation_email_in_threads'), itemExtent: _getItemExtent(context), itemCount: listPresentationEmail.length, - itemBuilder: (context, index) => Obx(() => (EmailTileBuilder( + itemBuilder: (context, index) => + Draggable>( + data: [listPresentationEmail[index]], + child: Obx(() => (EmailTileBuilder( context, listPresentationEmail[index], controller.mailboxDashBoardController.currentSelectMode.value, @@ -340,21 +343,71 @@ class ThreadView extends GetWidget with AppLoaderMixin, controller.searchQuery, mailboxCurrent: controller.searchController.isSearchEmailRunning ? listPresentationEmail[index].findMailboxContain( - controller.mailboxDashBoardController.mapMailboxById) + controller.mailboxDashBoardController.mapMailboxById) : controller.currentMailbox, advancedSearchActivated: controller.searchController.isAdvancedSearchHasApply.isTrue) - ..addOnPressEmailActionClick((action, email) => - controller.pressEmailAction( + ..addOnPressEmailActionClick((action, email) => + controller.pressEmailAction( context, action, email, mailboxContain: controller.searchController.isSearchEmailRunning ? email.findMailboxContain(controller.mailboxDashBoardController.mapMailboxById) : controller.currentMailbox)) - ..addOnMoreActionClick((email, position) => _responsiveUtils.isMobile(context) - ? controller.openContextMenuAction(context, _contextMenuActionTile(context, email)) - : controller.openPopupMenuAction(context, position, _popupMenuActionTile(context, email)))) - .build())) + ..addOnMoreActionClick((email, position) => _responsiveUtils.isMobile(context) + ? controller.openContextMenuAction(context, _contextMenuActionTile(context, email)) + : controller.openPopupMenuAction(context, position, _popupMenuActionTile(context, email)))) + .build()), + feedback: _buildFeedBackWidget(), + childWhenDragging: (EmailTileBuilder( + context, + listPresentationEmail[index], + controller.mailboxDashBoardController.currentSelectMode.value, + controller.searchController.searchState.value.searchStatus, + controller.searchQuery, + mailboxCurrent: controller.searchController.isSearchEmailRunning + ? listPresentationEmail[index].findMailboxContain( + controller.mailboxDashBoardController.mapMailboxById) + : controller.currentMailbox, + advancedSearchActivated: controller.searchController.isAdvancedSearchHasApply.isTrue, + isDrag: true)) + .build(), + dragAnchorStrategy: pointerDragAnchorStrategy, + )) + ); + } + + Widget _buildFeedBackWidget() { + return SizedBox( + height: 60, + child: Material( + borderRadius: BorderRadius.circular(10), + color: AppColor.colorTextButton, + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + SvgPicture.asset( + _imagePaths.icFilterMessageAll, + width: 24, + height: 24, + fit: BoxFit.fill, + color: Colors.white, + ), + const SizedBox(width: 10), + const Text( + 'Move 1 conversation', + overflow: TextOverflow.clip, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + ), + ], + ), + ), + ), ); } diff --git a/lib/features/thread/presentation/widgets/email_tile_builder.dart b/lib/features/thread/presentation/widgets/email_tile_builder.dart index af44e0df2..5aa028148 100644 --- a/lib/features/thread/presentation/widgets/email_tile_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_builder.dart @@ -17,6 +17,7 @@ class EmailTileBuilder with BaseEmailItemTile { final bool advancedSearchActivated; final EdgeInsets? padding; final EdgeInsets? paddingDivider; + final bool isDrag; OnPressEmailActionClick? _emailActionClick; @@ -31,6 +32,7 @@ class EmailTileBuilder with BaseEmailItemTile { this.mailboxCurrent, this.padding, this.paddingDivider, + this.isDrag = false, } ); diff --git a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart index 1ee1ef3c9..c643af354 100644 --- a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart @@ -19,6 +19,7 @@ class EmailTileBuilder with BaseEmailItemTile { final bool advancedSearchActivated; final EdgeInsets? padding; final EdgeInsets? paddingDivider; + final bool isDrag; OnPressEmailActionClick? _emailActionClick; OnMoreActionClick? _onMoreActionClick; @@ -37,6 +38,7 @@ class EmailTileBuilder with BaseEmailItemTile { this.mailboxCurrent, this.padding, this.paddingDivider, + this.isDrag = false, } ); @@ -74,8 +76,8 @@ class EmailTileBuilder with BaseEmailItemTile { return Container( margin: const EdgeInsets.only(top: 3), padding: const EdgeInsets.symmetric(vertical: 8), - decoration: _selectModeAll == SelectMode.ACTIVE && - _presentationEmail.selectMode == SelectMode.ACTIVE + decoration: (_selectModeAll == SelectMode.ACTIVE && + _presentationEmail.selectMode == SelectMode.ACTIVE) || isDrag ? BoxDecoration( borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop) @@ -86,8 +88,8 @@ class EmailTileBuilder with BaseEmailItemTile { return Container( margin: const EdgeInsets.only(top: 3, left: 16, right: 16), padding: const EdgeInsets.only(bottom: 8, right: 8, top: 8), - decoration: _selectModeAll == SelectMode.ACTIVE && - _presentationEmail.selectMode == SelectMode.ACTIVE + decoration: (_selectModeAll == SelectMode.ACTIVE && + _presentationEmail.selectMode == SelectMode.ACTIVE) || isDrag ? BoxDecoration( borderRadius: BorderRadius.circular(14), color: AppColor.colorItemEmailSelectedDesktop)