diff --git a/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart b/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart index 0bdf165ce..35b9b3e8d 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart @@ -55,8 +55,8 @@ class TopBarThreadSelection { buildIconWeb( icon: SvgPicture.asset( listEmail.isAllEmailRead - ? imagePaths.icUnread - : imagePaths.icRead, + ? imagePaths.icRead + : imagePaths.icUnread, fit: BoxFit.fill), tooltip: listEmail.isAllEmailRead ? AppLocalizations.of(context).mark_as_unread diff --git a/lib/features/search/presentation/widgets/app_bar_selection_mode.dart b/lib/features/search/presentation/widgets/app_bar_selection_mode.dart index 83960862a..cadce9f7e 100644 --- a/lib/features/search/presentation/widgets/app_bar_selection_mode.dart +++ b/lib/features/search/presentation/widgets/app_bar_selection_mode.dart @@ -60,8 +60,8 @@ class AppBarSelectionMode extends StatelessWidget { splashRadius: 15, icon: SvgPicture.asset( listEmail.isAllEmailRead - ? _imagePaths.icUnread - : _imagePaths.icRead, + ? _imagePaths.icRead + : _imagePaths.icUnread, fit: BoxFit.fill), tooltip: listEmail.isAllEmailRead ? AppLocalizations.of(context).unread diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 7a21547f1..12f6d3b2f 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -101,7 +101,7 @@ class ThreadController extends BaseController { final CachingManager _cachingManager; final listEmailDrag = [].obs; - bool shiftSelectedMode = false; + bool _rangeSelectionMode = false; bool canLoadMore = true; bool canSearchMore = true; bool _isLoadingMore = false; @@ -110,7 +110,7 @@ class ThreadController extends BaseController { jmap.State? _currentEmailState; final ScrollController listEmailController = ScrollController(); final FocusNode focusNodeKeyBoard = FocusNode(); - final latestEmailAction = Rxn(); + final latestEmailInteracted = Rxn(); late Worker mailboxWorker, searchWorker, dashboardActionWorker, viewStateWorker, advancedSearchFilterWorker; Set? get _sortOrder => {} @@ -520,44 +520,48 @@ class ThreadController extends BaseController { mailboxDashBoardController.dispatchRoute(DashboardRoutes.emailDetailed); } - void _shiftSelectEmail(PresentationEmail presentationEmailSelected) { - int startIndexAction = 0; - int endIndexAction = 0; - final indexOfPresentationEmailSelected = emailList.indexWhere((e) => e.id == presentationEmailSelected.id); - final indexOfLatestEmailAction = emailList.indexWhere((e) => e.id == latestEmailAction.value?.id); - if (indexOfPresentationEmailSelected > indexOfLatestEmailAction) { - startIndexAction = indexOfLatestEmailAction; - endIndexAction = indexOfPresentationEmailSelected; + Tuple2 _getSelectionEmailsRange(PresentationEmail presentationEmailSelected) { + final emailSelectedIndex = emailList.indexWhere((e) => e.id == presentationEmailSelected.id); + final latestEmailInteractedIndex = emailList.indexWhere((e) => e.id == latestEmailInteracted.value?.id); + if (emailSelectedIndex > latestEmailInteractedIndex) { + return Tuple2(latestEmailInteractedIndex, emailSelectedIndex); } else { - startIndexAction = indexOfPresentationEmailSelected; - endIndexAction = indexOfLatestEmailAction; + return Tuple2(emailSelectedIndex, latestEmailInteractedIndex); } + } - final enableChangeSelectModeOfEmailsToActive = latestEmailAction.value?.selectMode == SelectMode.ACTIVE && - !emailList.sublist(startIndexAction, endIndexAction).every((e) => e.selectMode == SelectMode.ACTIVE) || - latestEmailAction.value?.selectMode == SelectMode.INACTIVE && - emailList.sublist(startIndexAction, endIndexAction).every((e) => e.selectMode == SelectMode.INACTIVE); + bool _checkAllowMakeRangeEmailsSelected(Tuple2 selectionEmailsRange) { + return latestEmailInteracted.value?.selectMode == SelectMode.ACTIVE && + !emailList.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.ACTIVE) || + latestEmailInteracted.value?.selectMode == SelectMode.INACTIVE && + emailList.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.INACTIVE); + } - if (enableChangeSelectModeOfEmailsToActive) { - emailList.value = emailList.asMap().map((index, email) { - return MapEntry(index, index >= startIndexAction && index <= endIndexAction ? email.toSelectedEmail(selectMode: SelectMode.ACTIVE) : email); - }).values.toList(); + void _applySelectModeToRangeEmails(Tuple2 selectionEmailsRange, SelectMode selectMode) { + emailList.value = emailList.asMap().map((index, email) { + return MapEntry(index, index >= selectionEmailsRange.value1 && index <= selectionEmailsRange.value2 ? email.toSelectedEmail(selectMode: selectMode) : email); + }).values.toList(); + } + + void _rangeSelectionEmailsAction(PresentationEmail presentationEmailSelected) { + final selectionEmailsRange = _getSelectionEmailsRange(presentationEmailSelected); + + if (_checkAllowMakeRangeEmailsSelected(selectionEmailsRange)) { + _applySelectModeToRangeEmails(selectionEmailsRange, SelectMode.ACTIVE); } else { - emailList.value = emailList.asMap().map((index, email) { - return MapEntry(index, index >= startIndexAction && index <= endIndexAction ? email.toSelectedEmail(selectMode: SelectMode.INACTIVE) : email); - }).values.toList(); + _applySelectModeToRangeEmails(selectionEmailsRange, SelectMode.INACTIVE); } } void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) { - if (shiftSelectedMode && latestEmailAction.value != null && latestEmailAction.value?.id != presentationEmailSelected.id) { - _shiftSelectEmail(presentationEmailSelected); + if (_rangeSelectionMode && latestEmailInteracted.value != null && latestEmailInteracted.value?.id != presentationEmailSelected.id) { + _rangeSelectionEmailsAction(presentationEmailSelected); } else { emailList.value = emailList .map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email) .toList(); } - latestEmailAction.value = emailList.firstWhere((e) => e.id == presentationEmailSelected.id); + latestEmailInteracted.value = emailList.firstWhere((e) => e.id == presentationEmailSelected.id); focusNodeKeyBoard.requestFocus(); if (_isUnSelectedAll()) { mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE; @@ -1512,11 +1516,11 @@ class ThreadController extends BaseController { KeyEventResult handleKeyEvent(FocusNode node, RawKeyEvent event) { final shiftEvent = event.logicalKey == LogicalKeyboardKey.shiftLeft || event.logicalKey == LogicalKeyboardKey.shiftRight; if (event is RawKeyDownEvent && shiftEvent) { - shiftSelectedMode = true; + _rangeSelectionMode = true; } if (event is RawKeyUpEvent && shiftEvent) { - shiftSelectedMode = false; + _rangeSelectionMode = false; } return shiftEvent ? KeyEventResult.handled diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 40c7e3911..b858171e5 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -319,59 +319,64 @@ class ThreadView extends GetWidget with AppLoaderMixin, } return false; }, - child: ListView.builder( - controller: controller.listEmailController, - physics: const AlwaysScrollableScrollPhysics(), - padding: EdgeInsets.zero, - key: const PageStorageKey('list_presentation_email_in_threads'), - itemExtent: _getItemExtent(context), - itemCount: listPresentationEmail.length, - itemBuilder: (context, index) { - return Obx(() => Draggable>( - maxSimultaneousDrags: kIsWeb ? null : 0, - data: controller.listEmailDrag, - child: (EmailTileBuilder( - context, - listPresentationEmail[index], - controller.mailboxDashBoardController.currentSelectMode.value, - controller.searchQuery, - controller.mailboxDashBoardController.selectedEmail.value?.id == listPresentationEmail[index].id, - mailboxCurrent: controller.searchController.isSearchEmailRunning - ? listPresentationEmail[index].findMailboxContain(controller.mailboxDashBoardController.mapMailboxById) - : controller.currentMailbox, - isSearchEmailRunning: controller.searchController.isSearchEmailRunning) - ..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(), - feedback: _buildFeedBackWidget(context), - childWhenDragging: (EmailTileBuilder( + child: Focus( + focusNode: controller.focusNodeKeyBoard, + autofocus: kIsWeb, + onKey: kIsWeb ? controller.handleKeyEvent : null, + child: ListView.builder( + controller: controller.listEmailController, + physics: const AlwaysScrollableScrollPhysics(), + padding: EdgeInsets.zero, + key: const PageStorageKey('list_presentation_email_in_threads'), + itemExtent: _getItemExtent(context), + itemCount: listPresentationEmail.length, + itemBuilder: (context, index) { + return Obx(() => Draggable>( + maxSimultaneousDrags: kIsWeb ? null : 0, + data: controller.listEmailDrag, + child: (EmailTileBuilder( context, listPresentationEmail[index], controller.mailboxDashBoardController.currentSelectMode.value, controller.searchQuery, controller.mailboxDashBoardController.selectedEmail.value?.id == listPresentationEmail[index].id, mailboxCurrent: controller.searchController.isSearchEmailRunning - ? listPresentationEmail[index].findMailboxContain( - controller.mailboxDashBoardController.mapMailboxById) + ? listPresentationEmail[index].findMailboxContain(controller.mailboxDashBoardController.mapMailboxById) : controller.currentMailbox, - isSearchEmailRunning: controller.searchController.isSearchEmailRunning, - isDrag: true) - ).build(), - dragAnchorStrategy: pointerDragAnchorStrategy, - onDragStarted: () { - controller.calculateDragValue(listPresentationEmail[index]); - }, - )); - }) + isSearchEmailRunning: controller.searchController.isSearchEmailRunning) + ..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(), + feedback: _buildFeedBackWidget(context), + childWhenDragging: (EmailTileBuilder( + context, + listPresentationEmail[index], + controller.mailboxDashBoardController.currentSelectMode.value, + controller.searchQuery, + controller.mailboxDashBoardController.selectedEmail.value?.id == listPresentationEmail[index].id, + mailboxCurrent: controller.searchController.isSearchEmailRunning + ? listPresentationEmail[index].findMailboxContain( + controller.mailboxDashBoardController.mapMailboxById) + : controller.currentMailbox, + isSearchEmailRunning: controller.searchController.isSearchEmailRunning, + isDrag: true) + ).build(), + dragAnchorStrategy: pointerDragAnchorStrategy, + onDragStarted: () { + controller.calculateDragValue(listPresentationEmail[index]); + }, + )); + }), + ) ); } diff --git a/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart b/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart index 959d42490..5fd57946e 100644 --- a/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart +++ b/lib/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart @@ -112,8 +112,8 @@ class AppBarThreadWidgetBuilder extends StatelessWidget { splashRadius: 15, icon: SvgPicture.asset( _listSelectionEmail.isAllEmailRead - ? _imagePaths.icUnread - : _imagePaths.icRead, + ? _imagePaths.icRead + : _imagePaths.icUnread, fit: BoxFit.fill), tooltip: _listSelectionEmail.isAllEmailRead ? AppLocalizations.of(context).unread 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 b27ebeaf0..05a55d720 100644 --- a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart @@ -393,8 +393,8 @@ class EmailTileBuilder with BaseEmailItemTile { splashRadius: 10, icon: SvgPicture.asset( _presentationEmail.hasRead - ? imagePaths.icUnread - : imagePaths.icRead, + ? imagePaths.icRead + : imagePaths.icUnread, color: AppColor.colorActionButtonHover, width: 16, height: 16,