TF-1317 Show push notification on background or terminated app

This commit is contained in:
dab246
2023-01-09 17:01:34 +07:00
committed by Dat H. Pham
parent 97583820fa
commit 7367d7e1d2
12 changed files with 292 additions and 96 deletions
@@ -15,10 +15,12 @@ class UpdateAuthenticationAccountInteractor {
try{
yield Right(UpdateAuthenticationAccountLoading());
final currentAccount = await _accountRepository.getCurrentAccount();
await _accountRepository.setCurrentAccount(currentAccount.fromAccountId(
accountId: accountId,
apiUrl: apiUrl
));
await _accountRepository.setCurrentAccount(
currentAccount.fromAccountId(
accountId: accountId,
apiUrl: apiUrl
)
);
yield Right(UpdateAuthenticationAccountSuccess());
} catch(e) {
yield Left(UpdateAuthenticationAccountFailure(e));
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:core/core.dart';
import 'package:dartz/dartz.dart';
@@ -10,7 +11,6 @@ import 'package:get/get.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
import 'package:jmap_dart_client/jmap/core/capability/mail_capability.dart';
import 'package:jmap_dart_client/jmap/core/id.dart';
import 'package:jmap_dart_client/jmap/core/session/session.dart';
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
@@ -101,6 +101,7 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/routes/route_utils.dart';
import 'package:tmail_ui_user/main/routes/router_arguments.dart';
import 'package:tmail_ui_user/main/utils/email_receive_manager.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
class MailboxDashBoardController extends ReloadableController {
@@ -387,16 +388,7 @@ class MailboxDashBoardController extends ReloadableController {
_notificationManager.activatedNotificationClickedOnTerminate = true;
final notificationResponse = await _notificationManager.getCurrentNotificationResponse();
log('MailboxDashBoardController::_handleClickLocalNotificationOnTerminated():payload: ${notificationResponse?.payload}');
final emailIdFromPayload = notificationResponse?.payload;
final currentAccountId = accountId.value;
if (emailIdFromPayload?.isNotEmpty == true && currentAccountId != null) {
_getPresentationEmailFromEmailIdAction(
EmailId(Id(emailIdFromPayload!)),
currentAccountId
);
} else {
dispatchRoute(DashboardRoutes.thread);
}
_handleMessageFromNotification(notificationResponse?.payload, onForeground: false);
}
void _getUserProfile() async {
@@ -1428,21 +1420,62 @@ class MailboxDashBoardController extends ReloadableController {
void _handleClickLocalNotificationOnForeground(NotificationResponse? response) {
_notificationManager.activatedNotificationClickedOnTerminate = true;
log('MailboxDashBoardController::_handleClickLocalNotificationOnForeground():payload: ${response?.payload}');
final emailIdFromPayload = response?.payload;
final currentAccountId = accountId.value;
if (emailIdFromPayload?.isNotEmpty == true && currentAccountId != null) {
popAllRouteIfHave();
dispatchRoute(DashboardRoutes.waiting);
_handleMessageFromNotification(response?.payload);
}
_getPresentationEmailFromEmailIdAction(
EmailId(Id(emailIdFromPayload!)),
currentAccountId
);
void _handleMessageFromNotification(String? payload, {bool onForeground = true}) {
log('MailboxDashBoardController::_handleMessageFromNotification():payload: $payload');
if (payload == null) {
dispatchRoute(DashboardRoutes.thread);
return;
}
final payloadDecoded = jsonDecode(payload);
if (payloadDecoded is Map<String, dynamic>) {
final notificationPayload = NotificationPayload.fromJson(payloadDecoded);
log('MailboxDashBoardController::_handleMessageFromNotification():notificationPayload: $notificationPayload');
if (notificationPayload.emailId != null) {
_handleNotificationMessageFromEmailId(notificationPayload.emailId!, onForeground: onForeground);
} else if (notificationPayload.newState != null) {
_handleNotificationMessageFromNewState(notificationPayload.newState!, onForeground: onForeground);
} else {
dispatchRoute(DashboardRoutes.thread);
}
} else {
dispatchRoute(DashboardRoutes.thread);
}
}
void _handleNotificationMessageFromNewState(jmap.State newState, {bool onForeground = true}) {
if (onForeground) {
_openInboxMailbox();
}
}
void _handleNotificationMessageFromEmailId(EmailId emailId, {bool onForeground = true}) {
final currentAccountId = accountId.value;
if (currentAccountId != null) {
if (onForeground) {
_showWaitingView();
}
_getPresentationEmailFromEmailIdAction(emailId, currentAccountId);
} else {
dispatchRoute(DashboardRoutes.thread);
}
}
void _showWaitingView() {
popAllRouteIfHave();
dispatchRoute( DashboardRoutes.waiting);
}
void _openInboxMailbox() {
popAllRouteIfHave();
dispatchMailboxUIAction(SelectMailboxDefaultAction());
dispatchRoute(DashboardRoutes.thread);
}
void _getPresentationEmailFromEmailIdAction(EmailId emailId, AccountId accountId) {
log('MailboxDashBoardController:_getPresentationEmailFromEmailIdAction:emailId: $emailId');
consumeState(_getEmailByIdInteractor.execute(
@@ -1482,6 +1515,10 @@ class MailboxDashBoardController extends ReloadableController {
}
}
void updateEmailList(List<PresentationEmail> newEmailList) {
emailsInCurrentMailbox.value = newEmailList;
}
@override
void onClose() {
_emailReceiveManager.closeEmailReceiveManagerStream();
@@ -1,4 +1,6 @@
import 'dart:io';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart';
@@ -6,6 +8,7 @@ import 'package:core/utils/build_utils.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:model/email/presentation_email.dart';
import 'package:model/notification/notification_payload.dart';
import 'package:tmail_ui_user/features/base/action/ui_action.dart';
import 'package:tmail_ui_user/features/email/domain/state/get_stored_state_email_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_stored_email_state_interactor.dart';
@@ -20,8 +23,11 @@ import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_e
import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_email_state_to_refresh_interactor.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/action/fcm_action.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/listener/change_listener.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_config.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_manager.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/utils/fcm_utils.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class EmailChangeListener extends ChangeListener {
@@ -78,9 +84,23 @@ class EmailChangeListener extends ChangeListener {
_newState = newState;
_accountId = accountId;
log('EmailChangeListener::_pushNotificationAction():newState: $newState');
_getStoredEmailDeliveryState();
if (BuildUtils.isWeb) {
_storeEmailDeliveryStateAction(_newState!);
} else {
if (Platform.isAndroid) {
_getStoredEmailDeliveryState();
} else if (Platform.isIOS) {
_storeEmailDeliveryStateAction(_newState!);
_showLocalNotificationForIOS(_newState!, _accountId!);
} else {
logError('EmailChangeListener::_pushNotificationAction(): NOT SUPPORTED PLATFORM');
}
}
}
void _getStoredEmailDeliveryState() {
if (_getStoredEmailDeliveryStateInteractor != null) {
consumeState(_getStoredEmailDeliveryStateInteractor!.execute());
@@ -112,13 +132,30 @@ class EmailChangeListener extends ChangeListener {
}
}
void _showLocalNotification(PresentationEmail presentationEmail, jmap.State newState) {
void _showLocalNotification(PresentationEmail presentationEmail) {
final notificationPayload = NotificationPayload(emailId: presentationEmail.id);
log('EmailChangeListener::_showLocalNotification():notificationPayload: $notificationPayload');
LocalNotificationManager.instance.showPushNotification(
id: presentationEmail.id.id.value,
title: presentationEmail.subject ?? '',
message: presentationEmail.preview,
emailAddress: presentationEmail.from?.first,
payload: presentationEmail.id.id.value,
payload: notificationPayload.encodeToString,
);
}
void _showLocalNotificationForIOS(jmap.State newState, AccountId accountId) {
final notificationPayload = NotificationPayload(newState: newState);
log('EmailChangeListener::_showLocalNotificationForIOS():notificationPayload: $notificationPayload');
LocalNotificationManager.instance.showPushNotification(
id: '${FcmUtils.instance.platformOS}-${accountId.id.value}',
title: currentContext != null
? AppLocalizations.of(currentContext!).appTitlePushNotification
: LocalNotificationConfig.notificationTitle,
message: currentContext != null
? AppLocalizations.of(currentContext!).youHaveNewMessages
: LocalNotificationConfig.notificationMessage,
payload: notificationPayload.encodeToString,
);
}
@@ -144,19 +181,21 @@ class EmailChangeListener extends ChangeListener {
if (_newState != null) {
_storeEmailDeliveryStateAction(_newState!);
if (!BuildUtils.isWeb) {
for (var presentationEmail in success.emailList) {
_showLocalNotification(presentationEmail, _newState!);
}
if (!BuildUtils.isWeb && Platform.isAndroid) {
_handleLocalPushNotification(success.emailList);
}
}
if (!BuildUtils.isWeb) {
LocalNotificationManager.instance.groupPushNotification();
}
}
}
void _handleLocalPushNotification(List<PresentationEmail> emailList) {
for (var presentationEmail in emailList) {
_showLocalNotification(presentationEmail);
}
LocalNotificationManager.instance.groupPushNotification();
}
void _handleStoreEmailStateToRefreshAction(jmap.State newState) {
log('EmailChangeListener::_handleStoreEmailStateToRefreshAction():newState: $newState');
if (_storeEmailStateToRefreshInteractor != null) {
@@ -7,6 +7,8 @@ class LocalNotificationConfig {
static const _channelId = 'team_mail_notification_channel_id';
static const _channelName = 'Team Mail notifications';
static const _channelDescription = 'Team Mail notifications';
static const notificationTitle = 'Team Mail';
static const notificationMessage = 'You have new messages';
static const iosInitializationSettings = DarwinInitializationSettings();
@@ -53,6 +55,7 @@ class LocalNotificationConfig {
presentSound: true,
presentAlert: true,
presentBadge: true,
threadIdentifier: _channelId
),
);
}
@@ -8,6 +8,8 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_config.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class LocalNotificationManager {
@@ -159,7 +161,9 @@ class LocalNotificationManager {
if (activeNotifications != null && activeNotifications.isNotEmpty) {
final inboxStyleInformation = InboxStyleInformation(
[''],
summaryText: '${activeNotifications.length - 1} new emails'.addBlockTag('b'),
summaryText: currentContext != null
? AppLocalizations.of(currentContext!).totalNewMessagePushNotification(activeNotifications.length - 1).addBlockTag('b')
: '${activeNotifications.length - 1} new emails'.addBlockTag('b'),
htmlFormatSummaryText: true,
);
@@ -82,20 +82,20 @@ class FcmUtils {
String get platformOS {
var platformName = '';
if (BuildUtils.isWeb) {
platformName = "Web";
platformName = 'Web';
} else {
if (Platform.isAndroid) {
platformName = "Android";
platformName = 'Android';
} else if (Platform.isIOS) {
platformName = "IOS";
platformName = 'IOS';
} else if (Platform.isFuchsia) {
platformName = "Fuchsia";
platformName = 'Fuchsia';
} else if (Platform.isLinux) {
platformName = "Linux";
platformName = 'Linux';
} else if (Platform.isMacOS) {
platformName = "MacOS";
platformName = 'MacOS';
} else if (Platform.isWindows) {
platformName = "Windows";
platformName = 'Windows';
}
}
log('FcmUtils::platformOS():$platformName');
@@ -117,8 +117,6 @@ class ThreadController extends BaseController with EmailActionController {
SearchQuery? get searchQuery => searchController.searchEmailFilter.value.text;
RxList<PresentationEmail> get emailList => mailboxDashBoardController.emailsInCurrentMailbox;
ThreadController(
this._getEmailsInMailboxInteractor,
this._refreshChangesEmailsInMailboxInteractor,
@@ -154,7 +152,7 @@ class ThreadController extends BaseController with EmailActionController {
newState.fold(
(failure) {
if (failure is SearchEmailFailure) {
emailList.clear();
mailboxDashBoardController.emailsInCurrentMailbox.clear();
} else if (failure is SearchMoreEmailFailure || failure is LoadMoreEmailsFailure) {
_isLoadingMore = false;
} else if (failure is GetEmailByIdFailure) {
@@ -356,7 +354,7 @@ class ThreadController extends BaseController with EmailActionController {
void _resetToOriginalValue() {
dispatchState(Right(LoadingState()));
emailList.clear();
mailboxDashBoardController.emailsInCurrentMailbox.clear();
canLoadMore = true;
_isLoadingMore = false;
cancelSelectEmail();
@@ -365,13 +363,13 @@ class ThreadController extends BaseController with EmailActionController {
void _getAllEmailSuccess(GetAllEmailSuccess success) {
_currentEmailState = success.currentEmailState;
log('ThreadController::_getAllEmailSuccess():_currentEmailState: $_currentEmailState');
emailList.value = success.emailList.syncPresentationEmail(
final newListEmail = success.emailList.syncPresentationEmail(
mapMailboxById: mailboxDashBoardController.mapMailboxById,
selectedMailbox: currentMailbox,
searchQuery: searchController.searchQuery,
isSearchEmailRunning: searchController.isSearchEmailRunning
);
mailboxDashBoardController.updateEmailList(newListEmail);
if (listEmailController.hasClients) {
listEmailController.animateTo(0, duration: const Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
}
@@ -380,17 +378,18 @@ class ThreadController extends BaseController with EmailActionController {
void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) {
_currentEmailState = success.currentEmailState;
final emailsBeforeChanges = emailList;
final emailsBeforeChanges = mailboxDashBoardController.emailsInCurrentMailbox;
final emailsAfterChanges = success.emailList;
final newListEmail = emailsAfterChanges.combine(emailsBeforeChanges);
emailList.value = newListEmail.syncPresentationEmail(
final emailListSynced = newListEmail.syncPresentationEmail(
mapMailboxById: mailboxDashBoardController.mapMailboxById,
selectedMailbox: currentMailbox,
searchQuery: searchController.searchQuery,
isSearchEmailRunning: searchController.isSearchEmailRunning
);
mailboxDashBoardController.updateEmailList(emailListSynced);
if (emailList.isEmpty) {
if (mailboxDashBoardController.emailsInCurrentMailbox.isEmpty) {
refreshAllEmail();
}
}
@@ -410,29 +409,33 @@ class ThreadController extends BaseController with EmailActionController {
}
EmailFilterCondition _getFilterCondition({bool isLoadMore = false}) {
final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
? mailboxDashBoardController.emailsInCurrentMailbox.last
: null;
final mailboxIdSelected = mailboxDashBoardController.selectedMailbox.value?.id;
switch(mailboxDashBoardController.filterMessageOption.value) {
case FilterMessageOption.all:
return EmailFilterCondition(
inMailbox: mailboxDashBoardController.selectedMailbox.value?.id,
before: isLoadMore ? emailList.last.receivedAt : null
inMailbox: mailboxIdSelected,
before: isLoadMore ? lastEmail?.receivedAt : null
);
case FilterMessageOption.unread:
return EmailFilterCondition(
inMailbox: mailboxDashBoardController.selectedMailbox.value?.id,
notKeyword: KeyWordIdentifier.emailSeen.value,
before: isLoadMore ? emailList.last.receivedAt : null
inMailbox: mailboxIdSelected,
notKeyword: KeyWordIdentifier.emailSeen.value,
before: isLoadMore ? lastEmail?.receivedAt : null
);
case FilterMessageOption.attachments:
return EmailFilterCondition(
inMailbox: mailboxDashBoardController.selectedMailbox.value?.id,
hasAttachment: true,
before: isLoadMore ? emailList.last.receivedAt : null
inMailbox: mailboxIdSelected,
hasAttachment: true,
before: isLoadMore ? lastEmail?.receivedAt : null
);
case FilterMessageOption.starred:
return EmailFilterCondition(
inMailbox: mailboxDashBoardController.selectedMailbox.value?.id,
hasKeyword: KeyWordIdentifier.emailFlagged.value,
before: isLoadMore ? emailList.last.receivedAt : null
inMailbox: mailboxIdSelected,
hasKeyword: KeyWordIdentifier.emailFlagged.value,
before: isLoadMore ? lastEmail?.receivedAt : null
);
}
}
@@ -443,20 +446,26 @@ class ThreadController extends BaseController with EmailActionController {
cancelSelectEmail();
if (searchController.isSearchEmailRunning) {
final limit = emailList.isNotEmpty ? UnsignedInt(emailList.length) : ThreadConstants.defaultLimit;
searchController.searchEmailFilter.value = _searchEmailFilter.clearBeforeDate();
_searchEmail(limit: limit);
_searchEmail(limit: limitEmailFetched);
} else {
_getAllEmail();
}
}
UnsignedInt get limitEmailFetched {
final emailsInCurrentMailbox = mailboxDashBoardController.emailsInCurrentMailbox;
final limit = emailsInCurrentMailbox.isNotEmpty
? UnsignedInt(emailsInCurrentMailbox.length)
: ThreadConstants.defaultLimit;
return limit;
}
void _refreshEmailChanges({jmap.State? currentEmailState}) {
log('ThreadController::_refreshEmailChanges(): currentEmailState: $currentEmailState');
if (searchController.isSearchEmailRunning) {
final limit = emailList.isNotEmpty ? UnsignedInt(emailList.length) : ThreadConstants.defaultLimit;
searchController.searchEmailFilter.value = _searchEmailFilter.clearBeforeDate();
_searchEmail(limit: limit);
_searchEmail(limit: limitEmailFetched);
} else {
final newEmailState = currentEmailState ?? _currentEmailState;
log('ThreadController::_refreshEmailChanges(): newEmailState: $newEmailState');
@@ -487,7 +496,7 @@ class ThreadController extends BaseController with EmailActionController {
filterOption: mailboxDashBoardController.filterMessageOption.value,
filter: _getFilterCondition(isLoadMore: true),
properties: ThreadConstants.propertiesDefault,
lastEmailId: emailList.last.id)
lastEmailId: mailboxDashBoardController.emailsInCurrentMailbox.last.id)
));
}
}
@@ -497,7 +506,9 @@ class ThreadController extends BaseController with EmailActionController {
}
bool _notDuplicatedInCurrentList(PresentationEmail email) {
return emailList.isEmpty || !emailList.map((element) => element.id).contains(email.id);
final emailsInCurrentMailbox = mailboxDashBoardController.emailsInCurrentMailbox;
return emailsInCurrentMailbox.isEmpty ||
!emailsInCurrentMailbox.map((element) => element.id).contains(email.id);
}
void _loadMoreEmailsSuccess(LoadMoreEmailsSuccess success) {
@@ -513,7 +524,7 @@ class ThreadController extends BaseController with EmailActionController {
isSearchEmailRunning: searchController.isSearchEmailRunning
);
emailList.addAll(appendableList);
mailboxDashBoardController.emailsInCurrentMailbox.addAll(appendableList);
} else {
canLoadMore = false;
}
@@ -527,8 +538,11 @@ class ThreadController extends BaseController with EmailActionController {
}
Tuple2<StartRangeSelection,EndRangeSelection> _getSelectionEmailsRange(PresentationEmail presentationEmailSelected) {
final emailSelectedIndex = emailList.indexWhere((e) => e.id == presentationEmailSelected.id);
final latestEmailSelectedOrUnselectedIndex = emailList.indexWhere((e) => e.id == latestEmailSelectedOrUnselected.value?.id);
final emailsInCurrentMailbox = mailboxDashBoardController.emailsInCurrentMailbox;
final emailSelectedIndex = emailsInCurrentMailbox
.indexWhere((e) => e.id == presentationEmailSelected.id);
final latestEmailSelectedOrUnselectedIndex = emailsInCurrentMailbox
.indexWhere((e) => e.id == latestEmailSelectedOrUnselected.value?.id);
if (emailSelectedIndex > latestEmailSelectedOrUnselectedIndex) {
return Tuple2(latestEmailSelectedOrUnselectedIndex, emailSelectedIndex);
} else {
@@ -537,16 +551,22 @@ class ThreadController extends BaseController with EmailActionController {
}
bool _checkAllowMakeRangeEmailsSelected(Tuple2<StartRangeSelection,EndRangeSelection> selectionEmailsRange) {
final emailsInCurrentMailbox = mailboxDashBoardController.emailsInCurrentMailbox;
return latestEmailSelectedOrUnselected.value?.selectMode == SelectMode.ACTIVE &&
!emailList.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.ACTIVE) ||
!emailsInCurrentMailbox.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.ACTIVE) ||
latestEmailSelectedOrUnselected.value?.selectMode == SelectMode.INACTIVE &&
emailList.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.INACTIVE);
emailsInCurrentMailbox.sublist(selectionEmailsRange.value1, selectionEmailsRange.value2).every((e) => e.selectMode == SelectMode.INACTIVE);
}
void _applySelectModeToRangeEmails(Tuple2<StartRangeSelection,EndRangeSelection> 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();
final newEmailList = mailboxDashBoardController.emailsInCurrentMailbox
.asMap()
.map((index, email) {
return MapEntry(index, index >= selectionEmailsRange.value1 && index <= selectionEmailsRange.value2 ? email.toSelectedEmail(selectMode: selectMode) : email);
})
.values
.toList();
mailboxDashBoardController.updateEmailList(newEmailList);
}
void _rangeSelectionEmailsAction(PresentationEmail presentationEmailSelected) {
@@ -560,14 +580,19 @@ class ThreadController extends BaseController with EmailActionController {
}
void selectEmail(BuildContext context, PresentationEmail presentationEmailSelected) {
final emailsInCurrentMailbox = mailboxDashBoardController.emailsInCurrentMailbox;
if (_rangeSelectionMode && latestEmailSelectedOrUnselected.value != null && latestEmailSelectedOrUnselected.value?.id != presentationEmailSelected.id) {
_rangeSelectionEmailsAction(presentationEmailSelected);
} else {
emailList.value = emailList
final newEmailList = emailsInCurrentMailbox
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.toList();
mailboxDashBoardController.updateEmailList(newEmailList);
}
latestEmailSelectedOrUnselected.value = emailList.firstWhereOrNull((e) => e.id == presentationEmailSelected.id);
latestEmailSelectedOrUnselected.value = emailsInCurrentMailbox
.firstWhereOrNull((e) => e.id == presentationEmailSelected.id);
focusNodeKeyBoard.requestFocus();
if (_isUnSelectedAll()) {
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
@@ -585,19 +610,27 @@ class ThreadController extends BaseController with EmailActionController {
}
void setSelectAllEmailAction() {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.ACTIVE)).toList();
final newEmailList = mailboxDashBoardController.emailsInCurrentMailbox
.map((email) => email.toSelectedEmail(selectMode: SelectMode.ACTIVE))
.toList();
mailboxDashBoardController.updateEmailList(newEmailList);
mailboxDashBoardController.currentSelectMode.value = SelectMode.ACTIVE;
mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
}
List<PresentationEmail> get listEmailSelected => emailList.listEmailSelected;
List<PresentationEmail> get listEmailSelected =>
mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected;
bool _isUnSelectedAll() {
return emailList.every((email) => email.selectMode == SelectMode.INACTIVE);
return mailboxDashBoardController.emailsInCurrentMailbox
.every((email) => email.selectMode == SelectMode.INACTIVE);
}
void cancelSelectEmail() {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
final newEmailList = mailboxDashBoardController.emailsInCurrentMailbox
.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE))
.toList();
mailboxDashBoardController.updateEmailList(newEmailList);
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
mailboxDashBoardController.listEmailSelected.clear();
}
@@ -673,28 +706,30 @@ class ThreadController extends BaseController with EmailActionController {
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
.toList();
final emailsSearchBeforeChanges = emailList;
final emailsSearchBeforeChanges = mailboxDashBoardController.emailsInCurrentMailbox;
final emailsSearchAfterChanges = resultEmailSearchList;
final newListEmailSearch = emailsSearchAfterChanges.combine(emailsSearchBeforeChanges);
emailList.value = newListEmailSearch.syncPresentationEmail(
final newEmailListSynced = newListEmailSearch.syncPresentationEmail(
mapMailboxById: mailboxDashBoardController.mapMailboxById,
selectedMailbox: currentMailbox,
searchQuery: searchController.searchQuery,
isSearchEmailRunning: searchController.isSearchEmailRunning
);
mailboxDashBoardController.updateEmailList(newEmailListSynced);
searchController.autoFocus.value = true;
}
void searchMoreEmails() {
if (canSearchMore && _accountId != null) {
searchController.updateFilterEmail(before: emailList.last.receivedAt);
final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.last;
searchController.updateFilterEmail(before: lastEmail.receivedAt);
consumeState(_searchMoreEmailInteractor.execute(
_accountId!,
limit: ThreadConstants.defaultLimit,
sort: _sortOrder,
filter: searchController.searchEmailFilter.value.mappingToEmailFilterCondition(),
properties: ThreadConstants.propertiesDefault,
lastEmailId: emailList.last.id
lastEmailId: lastEmail.id
));
}
}
@@ -703,7 +738,7 @@ class ThreadController extends BaseController with EmailActionController {
if (success.emailList.isNotEmpty) {
final resultEmailSearchList = success.emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
.where((email) => !emailList.contains(email))
.where((email) => !mailboxDashBoardController.emailsInCurrentMailbox.contains(email))
.toList()
.syncPresentationEmail(
mapMailboxById: mailboxDashBoardController.mapMailboxById,
@@ -711,7 +746,7 @@ class ThreadController extends BaseController with EmailActionController {
searchQuery: searchController.searchQuery,
isSearchEmailRunning: searchController.isSearchEmailRunning
);
emailList.addAll(resultEmailSearchList);
mailboxDashBoardController.emailsInCurrentMailbox.addAll(resultEmailSearchList);
} else {
canSearchMore = false;
}
@@ -122,7 +122,7 @@ class ThreadView extends GetWidget<ThreadController>
return Obx(() {
if ((!BuildUtils.isWeb || (BuildUtils.isWeb && controller.isSelectionEnabled()
&& controller.isSearchActive() && !_responsiveUtils.isDesktop(context)))
&& controller.emailList.listEmailSelected.isNotEmpty) {
&& controller.mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected.isNotEmpty) {
return Column(children: [
const Divider(color: AppColor.lineItemListColor, height: 1, thickness: 0.2),
Padding(
@@ -131,7 +131,7 @@ class ThreadView extends GetWidget<ThreadController>
context,
_imagePaths,
_responsiveUtils,
controller.emailList.listEmailSelected,
controller.mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected,
controller.mailboxDashBoardController.selectedMailbox.value)
..addOnPressEmailSelectionActionClick((actionType, selectionEmail) =>
controller.pressEmailSelectionAction(context, actionType, selectionEmail)))
@@ -147,7 +147,7 @@ class ThreadView extends GetWidget<ThreadController>
return Obx(() {
return AppBarThreadWidgetBuilder(
controller.currentMailbox,
controller.emailList.listEmailSelected,
controller.mailboxDashBoardController.emailsInCurrentMailbox.listEmailSelected,
controller.mailboxDashBoardController.currentSelectMode.value,
controller.mailboxDashBoardController.filterMessageOption.value,
onOpenMailboxMenuActionClick: controller.openMailboxLeftMenu,
@@ -287,9 +287,10 @@ class ThreadView extends GetWidget<ThreadController>
padding: EdgeInsets.zero,
color: Colors.white,
child: Obx(() {
log('ThreadView::_buildListEmail():');
return Visibility(
visible: controller.openingEmail.isFalse,
child: _buildResultListEmail(context, controller.emailList));
child: _buildResultListEmail(context, controller.mailboxDashBoardController.emailsInCurrentMailbox));
})
);
}
@@ -439,7 +440,7 @@ class ThreadView extends GetWidget<ThreadController>
bool supportEmptyTrash(BuildContext context) {
return controller.isMailboxTrash
&& controller.emailList.isNotEmpty
&& controller.mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
&& !controller.isSearchActive()
&& !_responsiveUtils.isWebDesktop(context);
}
+23 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2022-12-28T14:09:51.971658",
"@@last_modified": "2023-01-09T16:48:24.908944",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -2551,5 +2551,27 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"youHaveNewMessages": "You have new messages",
"@youHaveNewMessages": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"appTitlePushNotification": "Team Mail",
"@appTitlePushNotification": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"totalNewMessagePushNotification": "{count} new emails",
"@totalNewMessagePushNotification": {
"type": "text",
"placeholders_order": [
"count"
],
"placeholders": {
"count": {}
}
}
}
@@ -2620,4 +2620,24 @@ class AppLocalizations {
name: 'regards',
);
}
String get youHaveNewMessages {
return Intl.message(
'You have new messages',
name: 'youHaveNewMessages',
);
}
String get appTitlePushNotification {
return Intl.message(
'Team Mail',
name: 'appTitlePushNotification');
}
String totalNewMessagePushNotification(int count) {
return Intl.message(
'$count new emails',
name: 'totalNewMessagePushNotification',
args: [count]);
}
}
+3 -1
View File
@@ -74,4 +74,6 @@ export 'upload/file_info.dart';
export 'upload/upload_response.dart';
// User
export 'user/user_profile.dart';
export 'user/user_profile_response.dart';
export 'user/user_profile_response.dart';
// Notification
export 'notification/notification_payload.dart';
@@ -0,0 +1,31 @@
import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/http/converter/email_id_nullable_converter.dart';
import 'package:jmap_dart_client/http/converter/state_nullable_converter.dart';
import 'package:jmap_dart_client/jmap/core/state.dart' as jmap;
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:json_annotation/json_annotation.dart';
part 'notification_payload.g.dart';
@EmailIdNullableConverter()
@StateNullableConverter()
@JsonSerializable(explicitToJson: true, includeIfNull: false)
class NotificationPayload with EquatableMixin {
final EmailId? emailId;
final jmap.State? newState;
NotificationPayload({this.emailId, this.newState});
factory NotificationPayload.fromJson(Map<String, dynamic> json) => _$NotificationPayloadFromJson(json);
Map<String, dynamic> toJson() => _$NotificationPayloadToJson(this);
String get encodeToString => jsonEncode(toJson());
@override
List<Object?> get props => [emailId, newState];
}