TF-987: make email range selection function simple
This commit is contained in:
@@ -55,8 +55,8 @@ class TopBarThreadSelection {
|
|||||||
buildIconWeb(
|
buildIconWeb(
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
listEmail.isAllEmailRead
|
listEmail.isAllEmailRead
|
||||||
? imagePaths.icUnread
|
? imagePaths.icRead
|
||||||
: imagePaths.icRead,
|
: imagePaths.icUnread,
|
||||||
fit: BoxFit.fill),
|
fit: BoxFit.fill),
|
||||||
tooltip: listEmail.isAllEmailRead
|
tooltip: listEmail.isAllEmailRead
|
||||||
? AppLocalizations.of(context).mark_as_unread
|
? AppLocalizations.of(context).mark_as_unread
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ class AppBarSelectionMode extends StatelessWidget {
|
|||||||
splashRadius: 15,
|
splashRadius: 15,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
listEmail.isAllEmailRead
|
listEmail.isAllEmailRead
|
||||||
? _imagePaths.icUnread
|
? _imagePaths.icRead
|
||||||
: _imagePaths.icRead,
|
: _imagePaths.icUnread,
|
||||||
fit: BoxFit.fill),
|
fit: BoxFit.fill),
|
||||||
tooltip: listEmail.isAllEmailRead
|
tooltip: listEmail.isAllEmailRead
|
||||||
? AppLocalizations.of(context).unread
|
? AppLocalizations.of(context).unread
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class ThreadController extends BaseController {
|
|||||||
final CachingManager _cachingManager;
|
final CachingManager _cachingManager;
|
||||||
|
|
||||||
final listEmailDrag = <PresentationEmail>[].obs;
|
final listEmailDrag = <PresentationEmail>[].obs;
|
||||||
bool shiftSelectedMode = false;
|
bool _rangeSelectionMode = false;
|
||||||
bool canLoadMore = true;
|
bool canLoadMore = true;
|
||||||
bool canSearchMore = true;
|
bool canSearchMore = true;
|
||||||
bool _isLoadingMore = false;
|
bool _isLoadingMore = false;
|
||||||
@@ -110,7 +110,7 @@ class ThreadController extends BaseController {
|
|||||||
jmap.State? _currentEmailState;
|
jmap.State? _currentEmailState;
|
||||||
final ScrollController listEmailController = ScrollController();
|
final ScrollController listEmailController = ScrollController();
|
||||||
final FocusNode focusNodeKeyBoard = FocusNode();
|
final FocusNode focusNodeKeyBoard = FocusNode();
|
||||||
final latestEmailAction = Rxn<PresentationEmail>();
|
final latestEmailInteracted = Rxn<PresentationEmail>();
|
||||||
late Worker mailboxWorker, searchWorker, dashboardActionWorker, viewStateWorker, advancedSearchFilterWorker;
|
late Worker mailboxWorker, searchWorker, dashboardActionWorker, viewStateWorker, advancedSearchFilterWorker;
|
||||||
|
|
||||||
Set<Comparator>? get _sortOrder => <Comparator>{}
|
Set<Comparator>? get _sortOrder => <Comparator>{}
|
||||||
@@ -520,44 +520,48 @@ class ThreadController extends BaseController {
|
|||||||
mailboxDashBoardController.dispatchRoute(DashboardRoutes.emailDetailed);
|
mailboxDashBoardController.dispatchRoute(DashboardRoutes.emailDetailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _shiftSelectEmail(PresentationEmail presentationEmailSelected) {
|
Tuple2<int,int> _getSelectionEmailsRange(PresentationEmail presentationEmailSelected) {
|
||||||
int startIndexAction = 0;
|
final emailSelectedIndex = emailList.indexWhere((e) => e.id == presentationEmailSelected.id);
|
||||||
int endIndexAction = 0;
|
final latestEmailInteractedIndex = emailList.indexWhere((e) => e.id == latestEmailInteracted.value?.id);
|
||||||
final indexOfPresentationEmailSelected = emailList.indexWhere((e) => e.id == presentationEmailSelected.id);
|
if (emailSelectedIndex > latestEmailInteractedIndex) {
|
||||||
final indexOfLatestEmailAction = emailList.indexWhere((e) => e.id == latestEmailAction.value?.id);
|
return Tuple2(latestEmailInteractedIndex, emailSelectedIndex);
|
||||||
if (indexOfPresentationEmailSelected > indexOfLatestEmailAction) {
|
|
||||||
startIndexAction = indexOfLatestEmailAction;
|
|
||||||
endIndexAction = indexOfPresentationEmailSelected;
|
|
||||||
} else {
|
} else {
|
||||||
startIndexAction = indexOfPresentationEmailSelected;
|
return Tuple2(emailSelectedIndex, latestEmailInteractedIndex);
|
||||||
endIndexAction = indexOfLatestEmailAction;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final enableChangeSelectModeOfEmailsToActive = latestEmailAction.value?.selectMode == SelectMode.ACTIVE &&
|
bool _checkAllowMakeRangeEmailsSelected(Tuple2<int,int> selectionEmailsRange) {
|
||||||
!emailList.sublist(startIndexAction, endIndexAction).every((e) => e.selectMode == SelectMode.ACTIVE) ||
|
return latestEmailInteracted.value?.selectMode == SelectMode.ACTIVE &&
|
||||||
latestEmailAction.value?.selectMode == SelectMode.INACTIVE &&
|
!emailList.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.ACTIVE) ||
|
||||||
emailList.sublist(startIndexAction, endIndexAction).every((e) => e.selectMode == SelectMode.INACTIVE);
|
latestEmailInteracted.value?.selectMode == SelectMode.INACTIVE &&
|
||||||
|
emailList.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.INACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
if (enableChangeSelectModeOfEmailsToActive) {
|
void _applySelectModeToRangeEmails(Tuple2<int,int> selectionEmailsRange, SelectMode selectMode) {
|
||||||
emailList.value = emailList.asMap().map((index, email) {
|
emailList.value = emailList.asMap().map((index, email) {
|
||||||
return MapEntry(index, index >= startIndexAction && index <= endIndexAction ? email.toSelectedEmail(selectMode: SelectMode.ACTIVE) : email);
|
return MapEntry(index, index >= selectionEmailsRange.value1 && index <= selectionEmailsRange.value2 ? email.toSelectedEmail(selectMode: selectMode) : email);
|
||||||
}).values.toList();
|
}).values.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _rangeSelectionEmailsAction(PresentationEmail presentationEmailSelected) {
|
||||||
|
final selectionEmailsRange = _getSelectionEmailsRange(presentationEmailSelected);
|
||||||
|
|
||||||
|
if (_checkAllowMakeRangeEmailsSelected(selectionEmailsRange)) {
|
||||||
|
_applySelectModeToRangeEmails(selectionEmailsRange, SelectMode.ACTIVE);
|
||||||
} else {
|
} else {
|
||||||
emailList.value = emailList.asMap().map((index, email) {
|
_applySelectModeToRangeEmails(selectionEmailsRange, SelectMode.INACTIVE);
|
||||||
return MapEntry(index, index >= startIndexAction && index <= endIndexAction ? email.toSelectedEmail(selectMode: SelectMode.INACTIVE) : email);
|
|
||||||
}).values.toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) {
|
void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) {
|
||||||
if (shiftSelectedMode && latestEmailAction.value != null && latestEmailAction.value?.id != presentationEmailSelected.id) {
|
if (_rangeSelectionMode && latestEmailInteracted.value != null && latestEmailInteracted.value?.id != presentationEmailSelected.id) {
|
||||||
_shiftSelectEmail(presentationEmailSelected);
|
_rangeSelectionEmailsAction(presentationEmailSelected);
|
||||||
} else {
|
} else {
|
||||||
emailList.value = emailList
|
emailList.value = emailList
|
||||||
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
|
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
latestEmailAction.value = emailList.firstWhere((e) => e.id == presentationEmailSelected.id);
|
latestEmailInteracted.value = emailList.firstWhere((e) => e.id == presentationEmailSelected.id);
|
||||||
focusNodeKeyBoard.requestFocus();
|
focusNodeKeyBoard.requestFocus();
|
||||||
if (_isUnSelectedAll()) {
|
if (_isUnSelectedAll()) {
|
||||||
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
|
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
|
||||||
@@ -1512,11 +1516,11 @@ class ThreadController extends BaseController {
|
|||||||
KeyEventResult handleKeyEvent(FocusNode node, RawKeyEvent event) {
|
KeyEventResult handleKeyEvent(FocusNode node, RawKeyEvent event) {
|
||||||
final shiftEvent = event.logicalKey == LogicalKeyboardKey.shiftLeft || event.logicalKey == LogicalKeyboardKey.shiftRight;
|
final shiftEvent = event.logicalKey == LogicalKeyboardKey.shiftLeft || event.logicalKey == LogicalKeyboardKey.shiftRight;
|
||||||
if (event is RawKeyDownEvent && shiftEvent) {
|
if (event is RawKeyDownEvent && shiftEvent) {
|
||||||
shiftSelectedMode = true;
|
_rangeSelectionMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event is RawKeyUpEvent && shiftEvent) {
|
if (event is RawKeyUpEvent && shiftEvent) {
|
||||||
shiftSelectedMode = false;
|
_rangeSelectionMode = false;
|
||||||
}
|
}
|
||||||
return shiftEvent
|
return shiftEvent
|
||||||
? KeyEventResult.handled
|
? KeyEventResult.handled
|
||||||
|
|||||||
@@ -319,59 +319,64 @@ class ThreadView extends GetWidget<ThreadController> with AppLoaderMixin,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
child: ListView.builder(
|
child: Focus(
|
||||||
controller: controller.listEmailController,
|
focusNode: controller.focusNodeKeyBoard,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
autofocus: kIsWeb,
|
||||||
padding: EdgeInsets.zero,
|
onKey: kIsWeb ? controller.handleKeyEvent : null,
|
||||||
key: const PageStorageKey('list_presentation_email_in_threads'),
|
child: ListView.builder(
|
||||||
itemExtent: _getItemExtent(context),
|
controller: controller.listEmailController,
|
||||||
itemCount: listPresentationEmail.length,
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) {
|
padding: EdgeInsets.zero,
|
||||||
return Obx(() => Draggable<List<PresentationEmail>>(
|
key: const PageStorageKey('list_presentation_email_in_threads'),
|
||||||
maxSimultaneousDrags: kIsWeb ? null : 0,
|
itemExtent: _getItemExtent(context),
|
||||||
data: controller.listEmailDrag,
|
itemCount: listPresentationEmail.length,
|
||||||
child: (EmailTileBuilder(
|
itemBuilder: (context, index) {
|
||||||
context,
|
return Obx(() => Draggable<List<PresentationEmail>>(
|
||||||
listPresentationEmail[index],
|
maxSimultaneousDrags: kIsWeb ? null : 0,
|
||||||
controller.mailboxDashBoardController.currentSelectMode.value,
|
data: controller.listEmailDrag,
|
||||||
controller.searchQuery,
|
child: (EmailTileBuilder(
|
||||||
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(
|
|
||||||
context,
|
context,
|
||||||
listPresentationEmail[index],
|
listPresentationEmail[index],
|
||||||
controller.mailboxDashBoardController.currentSelectMode.value,
|
controller.mailboxDashBoardController.currentSelectMode.value,
|
||||||
controller.searchQuery,
|
controller.searchQuery,
|
||||||
controller.mailboxDashBoardController.selectedEmail.value?.id == listPresentationEmail[index].id,
|
controller.mailboxDashBoardController.selectedEmail.value?.id == listPresentationEmail[index].id,
|
||||||
mailboxCurrent: controller.searchController.isSearchEmailRunning
|
mailboxCurrent: controller.searchController.isSearchEmailRunning
|
||||||
? listPresentationEmail[index].findMailboxContain(
|
? listPresentationEmail[index].findMailboxContain(controller.mailboxDashBoardController.mapMailboxById)
|
||||||
controller.mailboxDashBoardController.mapMailboxById)
|
|
||||||
: controller.currentMailbox,
|
: controller.currentMailbox,
|
||||||
isSearchEmailRunning: controller.searchController.isSearchEmailRunning,
|
isSearchEmailRunning: controller.searchController.isSearchEmailRunning)
|
||||||
isDrag: true)
|
..addOnPressEmailActionClick((action, email) =>
|
||||||
).build(),
|
controller.pressEmailAction(
|
||||||
dragAnchorStrategy: pointerDragAnchorStrategy,
|
context,
|
||||||
onDragStarted: () {
|
action,
|
||||||
controller.calculateDragValue(listPresentationEmail[index]);
|
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]);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ class AppBarThreadWidgetBuilder extends StatelessWidget {
|
|||||||
splashRadius: 15,
|
splashRadius: 15,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
_listSelectionEmail.isAllEmailRead
|
_listSelectionEmail.isAllEmailRead
|
||||||
? _imagePaths.icUnread
|
? _imagePaths.icRead
|
||||||
: _imagePaths.icRead,
|
: _imagePaths.icUnread,
|
||||||
fit: BoxFit.fill),
|
fit: BoxFit.fill),
|
||||||
tooltip: _listSelectionEmail.isAllEmailRead
|
tooltip: _listSelectionEmail.isAllEmailRead
|
||||||
? AppLocalizations.of(context).unread
|
? AppLocalizations.of(context).unread
|
||||||
|
|||||||
@@ -393,8 +393,8 @@ class EmailTileBuilder with BaseEmailItemTile {
|
|||||||
splashRadius: 10,
|
splashRadius: 10,
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
_presentationEmail.hasRead
|
_presentationEmail.hasRead
|
||||||
? imagePaths.icUnread
|
? imagePaths.icRead
|
||||||
: imagePaths.icRead,
|
: imagePaths.icUnread,
|
||||||
color: AppColor.colorActionButtonHover,
|
color: AppColor.colorActionButtonHover,
|
||||||
width: 16,
|
width: 16,
|
||||||
height: 16,
|
height: 16,
|
||||||
|
|||||||
Reference in New Issue
Block a user