TF-1897 Implement resend sending email when failed

(cherry picked from commit f508b65688503e9ae8ece5a1924e84481b98a39e)
This commit is contained in:
dab246
2023-06-10 19:20:30 +07:00
committed by Dat Vu
parent b6528b5bf5
commit c5bd77f800
16 changed files with 338 additions and 129 deletions
@@ -21,7 +21,6 @@ class SendingEmailCacheManager {
SendingEmailHiveCache sendingEmailHiveCache
) async {
final keyCache = TupleKey(sendingEmailHiveCache.sendingId, accountId.asString, userName.value).encodeKey;
log('SendingEmailCacheManager::storeSendingEmail():keyCache: $keyCache | sendingEmailHiveCache: $sendingEmailHiveCache');
await _hiveCacheClient.insertItem(keyCache, sendingEmailHiveCache);
final newSendingEmailHiveCache = await _hiveCacheClient.getItem(keyCache);
if (newSendingEmailHiveCache != null) {
@@ -32,29 +31,15 @@ class SendingEmailCacheManager {
}
}
Future<List<SendingEmailHiveCache>> getAllSendingEmailsByTupleKey(
AccountId accountId,
UserName userName,
{bool needToReopen = false}
) async {
final sendingEmailsCache = await _hiveCacheClient.getListByTupleKey(
accountId.asString,
userName.value,
needToReopen: needToReopen);
log('SendingEmailCacheManager::getAllSendingEmailsByTupleKey():COUNT: ${sendingEmailsCache.length}');
Future<List<SendingEmailHiveCache>> getAllSendingEmailsByTupleKey(AccountId accountId, UserName userName) async {
final sendingEmailsCache = await _hiveCacheClient.getListByTupleKey(accountId.asString, userName.value);
sendingEmailsCache.sortByLatestTime();
return sendingEmailsCache;
}
Future<void> deleteSendingEmail(
AccountId accountId,
UserName userName,
String sendingId,
{bool needToReopen = false}
) async {
Future<void> deleteSendingEmail(AccountId accountId, UserName userName, String sendingId) async {
final keyCache = TupleKey(sendingId, accountId.asString, userName.value).encodeKey;
log('SendingEmailCacheManager::deleteSendingEmail():keyCache: $keyCache');
await _hiveCacheClient.deleteItem(keyCache, needToReopen: needToReopen);
await _hiveCacheClient.deleteItem(keyCache);
final storedSendingEmail = await _hiveCacheClient.getItem(keyCache);
if (storedSendingEmail != null) {
log('SendingEmailCacheManager::deleteSendingEmail():sendingId: ${storedSendingEmail.sendingId}');
@@ -62,9 +47,8 @@ class SendingEmailCacheManager {
}
}
Future<List<SendingEmailHiveCache>> getAllSendingEmails({bool needToReopen = false}) async {
final sendingEmailsCache = await _hiveCacheClient.getAll(needToReopen: needToReopen);
log('SendingEmailCacheManager::getAllSendingEmails():COUNT: ${sendingEmailsCache.length}');
Future<List<SendingEmailHiveCache>> getAllSendingEmails() async {
final sendingEmailsCache = await _hiveCacheClient.getAll();
sendingEmailsCache.sortByLatestTime();
return sendingEmailsCache;
}
@@ -74,12 +58,10 @@ class SendingEmailCacheManager {
Future<SendingEmailHiveCache> updateSendingEmail(
AccountId accountId,
UserName userName,
SendingEmailHiveCache sendingEmailHiveCache,
{bool needToReopen = false}
SendingEmailHiveCache sendingEmailHiveCache
) async {
final keyCache = TupleKey(sendingEmailHiveCache.sendingId, accountId.asString, userName.value).encodeKey;
log('SendingEmailCacheManager::updateSendingEmail():keyCache: $keyCache | sendingEmailHiveCache: $sendingEmailHiveCache');
await _hiveCacheClient.updateItem(keyCache, sendingEmailHiveCache, needToReopen: needToReopen);
await _hiveCacheClient.updateItem(keyCache, sendingEmailHiveCache);
final newSendingEmailHiveCache = await _hiveCacheClient.getItem(keyCache);
if (newSendingEmailHiveCache != null) {
log('SendingEmailCacheManager::updateSendingEmail():sendingId: ${newSendingEmailHiveCache.sendingId} | sendingState: ${newSendingEmailHiveCache.sendingState}');
@@ -88,4 +70,31 @@ class SendingEmailCacheManager {
throw NotFoundSendingEmailHiveObject();
}
}
Future<List<SendingEmailHiveCache>> updateMultipleSendingEmail(
AccountId accountId,
UserName userName,
List<SendingEmailHiveCache> listSendingEmailHiveCache
) async {
final mapSendingEmailCache = {
for (var sendingEmailCache in listSendingEmailHiveCache)
TupleKey(sendingEmailCache.sendingId, accountId.asString, userName.value).encodeKey: sendingEmailCache
};
await _hiveCacheClient.updateMultipleItem(mapSendingEmailCache);
final newListSendingEmailCache = await _hiveCacheClient.getValuesByListKey(mapSendingEmailCache.keys.toList());
log('SendingEmailCacheManager::updateMultipleSendingEmail():newListSendingEmailCache: ${newListSendingEmailCache.map((sendingEmail) => '${sendingEmail.sendingId} | ${sendingEmail.sendingState}').toList()}');
return newListSendingEmailCache;
}
Future<void> deleteMultipleSendingEmail(AccountId accountId, UserName userName, List<String> sendingIds) async {
final listTupleKey = sendingIds.map((sendingId) => TupleKey(sendingId, accountId.asString, userName.value).encodeKey).toList();
await _hiveCacheClient.deleteMultipleItem(listTupleKey);
final newListSendingEmailCache = await _hiveCacheClient.getValuesByListKey(listTupleKey);
log('SendingEmailCacheManager::deleteMultipleSendingEmail():newListSendingEmailCache: ${newListSendingEmailCache.map((sendingEmail) => '${sendingEmail.sendingId} | ${sendingEmail.sendingState}').toList()}');
if (newListSendingEmailCache.isNotEmpty) {
throw ExistSendingEmailHiveObject();
}
}
Future<void> closeSendingEmailHiveCacheBox() => _hiveCacheClient.closeBox();
}
@@ -23,6 +23,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_r
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart';
import 'package:tmail_ui_user/features/offline_mode/bindings/sending_email_interactor_bindings.dart';
import 'package:tmail_ui_user/features/offline_mode/exceptions/workmanager_exception.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart';
import 'package:tmail_ui_user/features/offline_mode/model/sending_state.dart';
import 'package:tmail_ui_user/features/offline_mode/observer/work_observer.dart';
import 'package:tmail_ui_user/features/push_notification/presentation/notification/local_notification_config.dart';
@@ -53,6 +54,7 @@ class SendingEmailObserver extends WorkObserver {
DeleteSendingEmailInteractor? _deleteSendingEmailInteractor;
SendingQueueIsolateManager? _sendingQueueIsolateManager;
UpdateSendingEmailInteractor? _updateSendingEmailInteractor;
SendingEmailCacheManager? _sendingEmailCacheManager;
Completer<bool>? _completer;
@@ -64,7 +66,6 @@ class SendingEmailObserver extends WorkObserver {
@override
Future<void> observe(String taskId, Map<String, dynamic> inputData, Completer<bool> completer) async {
log('SendingEmailObserver::observe():taskId: $taskId | inputData: $inputData');
_completer = completer;
_sendingEmail = SendingEmail.fromJson(inputData);
log('SendingEmailObserver::observe():_sendingEmail: $_sendingEmail');
@@ -85,14 +86,20 @@ class SendingEmailObserver extends WorkObserver {
SendEmailInteractorBindings().dependencies();
});
return await _getInteractorBindings();
await _getInteractorBindings();
await _sendingEmailCacheManager?.closeSendingEmailHiveCacheBox();
return Future.value();
}
@override
void handleFailureViewState(Failure failure) {
log('SendingEmailObserver::_handleFailureViewState(): $failure');
if (failure is SendEmailFailure || failure is DeleteSendingEmailFailure) {
_updateStoredSendingEmail(SendingState.error);
if (failure is SendEmailFailure) {
_handleSendEmailFailure(failure);
} else if (failure is DeleteSendingEmailFailure) {
_handleDeleteSendingEmailFailure(failure);
} else if (failure is GetAuthenticatedAccountFailure ||
failure is NoAuthenticatedAccountFailure ||
failure is GetSessionFailure ||
@@ -115,7 +122,7 @@ class SendingEmailObserver extends WorkObserver {
} else if (success is SendEmailSuccess) {
_handleSendEmailSuccess(success);
} else if (success is DeleteSendingEmailSuccess) {
_handleDeleteSendingEmailSuccess();
_handleDeleteSendingEmailSuccess(success);
} else if (success is UpdateSendingEmailSuccess) {
_handleUpdateStoredSendingEmailSuccess(success);
}
@@ -137,6 +144,7 @@ class SendingEmailObserver extends WorkObserver {
_deleteSendingEmailInteractor = getBinding<DeleteSendingEmailInteractor>();
_sendingQueueIsolateManager = getBinding<SendingQueueIsolateManager>();
_updateSendingEmailInteractor = getBinding<UpdateSendingEmailInteractor>();
_sendingEmailCacheManager = getBinding<SendingEmailCacheManager>();
} catch (e) {
logError('SendingEmailObserver::_getInteractorBindings(): ${e.toString()}');
_handleTaskFailureInWorkManager();
@@ -153,19 +161,11 @@ class SendingEmailObserver extends WorkObserver {
}
void _getAuthenticatedAccount() {
if (_getAuthenticatedAccountInteractor != null) {
consumeState(_getAuthenticatedAccountInteractor!.execute());
} else {
_handleTaskFailureInWorkManager();
}
consumeState(_getAuthenticatedAccountInteractor!.execute());
}
void _getSessionAction() {
if (_getSessionInteractor != null) {
consumeState(_getSessionInteractor!.execute());
} else {
_handleTaskFailureInWorkManager();
}
consumeState(_getSessionInteractor!.execute());
}
void _handleGetSessionSuccess(GetSessionSuccess success) async {
@@ -174,13 +174,7 @@ class SendingEmailObserver extends WorkObserver {
final apiUrl = success.session.getQualifiedApiUrl(baseUrl: _dynamicUrlInterceptors?.jmapUrl);
if (apiUrl.isNotEmpty) {
_dynamicUrlInterceptors?.changeBaseUrl(apiUrl);
_updateStoredSendingEmail(SendingState.running);
await Future.delayed(
const Duration(milliseconds: 2000),
_sendEmailAction
);
_sendEmailAction();
} else {
_handleTaskFailureInWorkManager();
}
@@ -197,26 +191,32 @@ class SendingEmailObserver extends WorkObserver {
}
void _sendEmailAction() {
if (_sendEmailInteractor != null && _isDataParameterNotNull) {
final mailboxRequest = _sendingEmail!.mailboxNameRequest != null && _sendingEmail!.creationIdRequest != null
? CreateNewMailboxRequest(_sendingEmail!.creationIdRequest!, _sendingEmail!.mailboxNameRequest!)
: null;
consumeState(_sendEmailInteractor!.execute(
consumeState(
_sendEmailInteractor!.execute(
_currentSession!,
_currentAccountId!,
_sendingEmail!.toEmailRequest(),
mailboxRequest: mailboxRequest
));
mailboxRequest: _getMailboxRequest()
)
);
}
CreateNewMailboxRequest? _getMailboxRequest() {
if (_sendingEmail!.mailboxNameRequest != null &&
_sendingEmail!.creationIdRequest != null) {
return CreateNewMailboxRequest(
_sendingEmail!.creationIdRequest!,
_sendingEmail!.mailboxNameRequest!);
} else {
_updateStoredSendingEmail(SendingState.error);
return null;
}
}
void _handleGetAccountByOidcSuccess(GetStoredTokenOidcSuccess storedTokenOidcSuccess) {
_dynamicUrlInterceptors?.setJmapUrl(storedTokenOidcSuccess.baseUrl.toString());
_authorizationInterceptors?.setTokenAndAuthorityOidc(
newToken: storedTokenOidcSuccess.tokenOidc.toToken(),
newConfig: storedTokenOidcSuccess.oidcConfiguration
newToken: storedTokenOidcSuccess.tokenOidc.toToken(),
newConfig: storedTokenOidcSuccess.oidcConfiguration
);
_dynamicUrlInterceptors?.changeBaseUrl(storedTokenOidcSuccess.baseUrl.toString());
_getSessionAction();
@@ -224,28 +224,31 @@ class SendingEmailObserver extends WorkObserver {
void _handleSendEmailSuccess(SendEmailSuccess success) {
_showLocalNotification();
_deleteSendingEmailAction();
_updateStoredSendingEmail(SendingState.success);
}
void _handleSendEmailFailure(SendEmailFailure failure) {
_updateStoredSendingEmail(SendingState.error);
}
void _deleteSendingEmailAction() {
log('SendingEmailObserver::_deleteSendingEmailAction():');
if (_deleteSendingEmailInteractor != null && _isDataParameterNotNull) {
consumeState(_deleteSendingEmailInteractor!.execute(
consumeState(
_deleteSendingEmailInteractor!.execute(
_currentAccountId!,
_currentSession!.username,
_sendingEmail!.sendingId,
needToReopen: true
));
} else {
log('SendingEmailObserver::_deleteSendingEmailAction(): NOT CALLED');
_updateStoredSendingEmail(SendingState.error);
}
_sendingEmail!.sendingId
)
);
}
void _handleDeleteSendingEmailSuccess() {
void _handleDeleteSendingEmailSuccess(DeleteSendingEmailSuccess success) {
_handleTaskSuccessInWorkManager();
}
void _handleDeleteSendingEmailFailure(DeleteSendingEmailFailure failure) {
_handleTaskFailureInWorkManager();
}
void _showLocalNotification() {
LocalNotificationManager.instance.showPushNotification(
id: _sendingEmail?.sendingId ?? '',
@@ -255,26 +258,26 @@ class SendingEmailObserver extends WorkObserver {
);
}
bool get _isDataParameterNotNull => _currentSession != null && _currentAccountId != null && _sendingEmail != null;
void _updateStoredSendingEmail(SendingState newState) {
log('SendingEmailObserver::_updateStoredSendingEmail():newState: $newState');
if (_updateSendingEmailInteractor != null && _isDataParameterNotNull) {
consumeState(_updateSendingEmailInteractor!.execute(
consumeState(
_updateSendingEmailInteractor!.execute(
_currentAccountId!,
_currentSession!.username,
_sendingEmail!.updatingSendingState(newState),
needToReopen: true
));
} else {
_handleTaskFailureInWorkManager();
}
_sendingEmail!.updatingSendingState(newState)
)
);
}
void _handleUpdateStoredSendingEmailSuccess(UpdateSendingEmailSuccess success) {
_updatingSendingStateToMainUI(
sendingState: success.newSendingEmail.sendingState,
sendingId: success.newSendingEmail.sendingId);
log('SendingEmailObserver::_handleUpdateStoredSendingEmailSuccess(): $success');
if (success.newSendingEmail.isSuccess) {
_deleteSendingEmailAction();
} else {
_updatingSendingStateToMainUI(
sendingState: success.newSendingEmail.sendingState,
sendingId: success.newSendingEmail.sendingId);
}
}
void _handleTaskFailureInWorkManager() async {
@@ -0,0 +1,9 @@
import 'package:tmail_ui_user/features/offline_mode/model/sending_email_hive_cache.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/extensions/sending_email_extension.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
extension ListSendingEmailExtension on List<SendingEmail> {
List<SendingEmailHiveCache> toHiveCache() => map((sendingEmail) => sendingEmail.toHiveCache()).toList();
List<String> get sendingIds => map((sendingEmail) => sendingEmail.sendingId).toSet().toList();
}
@@ -101,6 +101,10 @@ class SendingEmail with EquatableMixin {
bool get isWaiting => sendingState == SendingState.waiting;
bool get isError => sendingState == SendingState.error;
bool get isSuccess => sendingState == SendingState.success;
@override
List<Object?> get props => [
sendingId,
@@ -0,0 +1,40 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
class UpdateMultipleSendingEmailLoading extends UIState {}
class UpdateMultipleSendingEmailAllSuccess extends UIState {
final List<SendingEmail> newSendingEmails;
UpdateMultipleSendingEmailAllSuccess(this.newSendingEmails);
@override
List<Object?> get props => [newSendingEmails];
}
class UpdateMultipleSendingEmailHasSomeSuccess extends UIState {
final List<SendingEmail> newSendingEmails;
UpdateMultipleSendingEmailHasSomeSuccess(this.newSendingEmails);
@override
List<Object?> get props => [newSendingEmails];
}
class UpdateMultipleSendingEmailAllFailure extends FeatureFailure {
UpdateMultipleSendingEmailAllFailure(dynamic exception) : super(exception: exception);
@override
List<Object?> get props => [exception];
}
class UpdateMultipleSendingEmailFailure extends FeatureFailure {
UpdateMultipleSendingEmailFailure(dynamic exception) : super(exception: exception);
@override
List<Object?> get props => [exception];
}
@@ -0,0 +1,38 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/account_id.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:tmail_ui_user/features/sending_queue/data/exceptions/sending_queue_exceptions.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/repository/sending_queue_repository.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/state/update_multiple_sending_email_state.dart';
class UpdateMultipleSendingEmailInteractor {
final SendingQueueRepository _sendingQueueRepository;
UpdateMultipleSendingEmailInteractor(this._sendingQueueRepository);
Stream<Either<Failure, Success>> execute(
AccountId accountId,
UserName userName,
List<SendingEmail> newSendingEmails
) async* {
try {
yield Right<Failure, Success>(UpdateMultipleSendingEmailLoading());
final storedSendingEmails = await _sendingQueueRepository.updateMultipleSendingEmail(
accountId,
userName,
newSendingEmails);
if (storedSendingEmails.length == newSendingEmails.length) {
yield Right<Failure, Success>(UpdateMultipleSendingEmailAllSuccess(storedSendingEmails));
} else if (storedSendingEmails.isEmpty) {
yield Left<Failure, Success>(UpdateMultipleSendingEmailAllFailure(NotFoundSendingEmailHiveObject()));
} else {
yield Right<Failure, Success>(UpdateMultipleSendingEmailHasSomeSuccess(storedSendingEmails));
}
} catch (e) {
yield Left<Failure, Success>(UpdateMultipleSendingEmailFailure(e));
}
}
}
@@ -15,12 +15,11 @@ class UpdateSendingEmailInteractor {
Stream<Either<Failure, Success>> execute(
AccountId accountId,
UserName userName,
SendingEmail newSendingEmail,
{bool needToReopen = false}
SendingEmail newSendingEmail
) async* {
try {
yield Right<Failure, Success>(UpdateSendingEmailLoading());
final storedSendingEmail = await _sendingQueueRepository.updateSendingEmail(accountId, userName, newSendingEmail, needToReopen: needToReopen);
final storedSendingEmail = await _sendingQueueRepository.updateSendingEmail(accountId, userName, newSendingEmail);
yield Right<Failure, Success>(UpdateSendingEmailSuccess(storedSendingEmail));
} catch (e) {
yield Left<Failure, Success>(UpdateSendingEmailFailure(e));
@@ -1,6 +1,7 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/sending_queue_controller.dart';
@@ -15,6 +16,7 @@ class SendingQueueBindings extends Bindings {
Get.put(SendingQueueController(
Get.find<DeleteMultipleSendingEmailInteractor>(),
Get.find<UpdateSendingEmailInteractor>(),
Get.find<UpdateMultipleSendingEmailInteractor>(),
));
}
}
@@ -7,7 +7,6 @@ import 'package:tmail_ui_user/features/sending_queue/data/repository/sending_que
import 'package:tmail_ui_user/features/sending_queue/domain/repository/sending_queue_repository.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/delete_single_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_manager.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/detailed_email_cache_worker_queue.dart';
@@ -15,6 +14,7 @@ import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_m
import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_worker_queue.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/store_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/thread/data/local/email_cache_manager.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
@@ -41,10 +41,10 @@ class SendingQueueInteractorBindings extends InteractorsBindings {
void bindingsInteractor() {
Get.lazyPut(() => StoreSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => GetAllSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => DeleteSingleSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => DeleteMultipleSendingEmailInteractor(Get.find<DeleteSingleSendingEmailInteractor>()));
Get.lazyPut(() => DeleteMultipleSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => DeleteSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => UpdateSendingEmailInteractor(Get.find<SendingQueueRepository>()));
Get.lazyPut(() => UpdateMultipleSendingEmailInteractor(Get.find<SendingQueueRepository>()));
}
@override
@@ -1,4 +1,5 @@
import 'package:tmail_ui_user/features/offline_mode/model/sending_state.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/extensions/sending_email_extension.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
@@ -16,4 +17,8 @@ extension ListSendingEmailExtension on List<SendingEmail> {
bool isAllUnSelected() => every((sendingEmail) => !sendingEmail.isSelected);
List<SendingEmail> listSelected() => where((sendingEmail) => sendingEmail.isSelected).toList();
bool isAllSendingStateError() => every((sendingEmail) => sendingEmail.isError);
List<SendingEmail> toSendingStateWaiting() => map((sendingEmail) => sendingEmail.updatingSendingState(SendingState.waiting)).toList();
}
@@ -7,6 +7,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum SendingEmailActionType {
create,
edit,
resend,
delete;
String getButtonTitle(BuildContext context) {
@@ -17,6 +18,8 @@ enum SendingEmailActionType {
return AppLocalizations.of(context).edit;
case SendingEmailActionType.create:
return '';
case SendingEmailActionType.resend:
return AppLocalizations.of(context).resend;
}
}
@@ -28,6 +31,8 @@ enum SendingEmailActionType {
return 'button_edit_sending_email';
case SendingEmailActionType.create:
return '';
case SendingEmailActionType.resend:
return 'button_resend_sending_email';
}
}
@@ -36,6 +41,7 @@ enum SendingEmailActionType {
case SendingEmailActionType.delete:
return AppColor.colorDeletePermanentlyButton.withOpacity(buttonState.opacity);
case SendingEmailActionType.edit:
case SendingEmailActionType.resend:
return AppColor.primaryColor.withOpacity(buttonState.opacity);
case SendingEmailActionType.create:
return Colors.transparent.withOpacity(buttonState.opacity);
@@ -47,6 +53,7 @@ enum SendingEmailActionType {
case SendingEmailActionType.delete:
return AppColor.colorDeletePermanentlyButton.withOpacity(buttonState.opacity);
case SendingEmailActionType.edit:
case SendingEmailActionType.resend:
return AppColor.primaryColor.withOpacity(buttonState.opacity);
case SendingEmailActionType.create:
return Colors.transparent.withOpacity(buttonState.opacity);
@@ -1,8 +1,8 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/presentation/utils/app_toast.dart';
import 'package:flutter/material.dart';
@@ -17,9 +17,14 @@ import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/network_status_handle/presentation/network_connnection_controller.dart';
import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart';
import 'package:tmail_ui_user/features/offline_mode/model/sending_state.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/extensions/list_sending_email_extension.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/extensions/sending_email_extension.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/state/update_multiple_sending_email_state.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/state/update_sending_email_state.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_multiple_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/usecases/update_sending_email_interactor.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/utils/sending_queue_isolate_manager.dart';
import 'package:tmail_ui_user/features/offline_mode/controller/work_scheduler_controller.dart';
@@ -34,10 +39,12 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
final DeleteMultipleSendingEmailInteractor _deleteMultipleSendingEmailInteractor;
final UpdateSendingEmailInteractor _updateSendingEmailInteractor;
final UpdateMultipleSendingEmailInteractor _updateMultipleSendingEmailInteractor;
final dashboardController = getBinding<MailboxDashBoardController>();
final _networkConnectionController = getBinding<NetworkConnectionController>();
final _sendingQueueIsolateManager = getBinding<SendingQueueIsolateManager>();
final _sendingEmailCacheManager = getBinding<SendingEmailCacheManager>();
final _imagePaths = getBinding<ImagePaths>();
final _appToast = getBinding<AppToast>();
@@ -48,6 +55,7 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
SendingQueueController(
this._deleteMultipleSendingEmailInteractor,
this._updateSendingEmailInteractor,
this._updateMultipleSendingEmailInteractor,
);
@override
@@ -61,7 +69,7 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
);
}
void _handleSendingQueueEvent(Object? event) {
void _handleSendingQueueEvent(Object? event) async {
log('SendingQueueController::_handleSendingQueueEvent():event: $event');
try {
if (event is String) {
@@ -69,16 +77,20 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
final sendingId = tupleKey.parts[0];
final sendingState = SendingState.values.firstWhereOrNull((state) => state.name == tupleKey.parts[1]);
log('SendingQueueController::_handleSendingQueueEvent():sendingId: $sendingId | sendingState: $sendingState');
if (sendingState != null) {
await _sendingEmailCacheManager?.closeSendingEmailHiveCacheBox();
switch(sendingState) {
case SendingState.waiting:
_handleSendingStateRunningEvent(sendingId);
_updatingSendingStateToRunningAction(sendingId);
break;
case SendingState.running:
case SendingState.success:
refreshSendingQueue();
break;
case SendingState.error:
refreshSendingQueue(needToReopen: true);
await WorkSchedulerController().cancelByUniqueId(sendingId);
_updatingSendingStateToErrorAction(sendingId);
break;
}
}
@@ -88,11 +100,21 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
}
}
void _handleSendingStateRunningEvent(String sendingId) {
log('SendingQueueController::_handleSendingStateRunningEvent():sendingId: $sendingId');
void _updatingSendingStateToRunningAction(String sendingId) {
log('SendingQueueController::_updatingSendingStateToRunningAction():sendingId: $sendingId');
final matchedSendingEmail = dashboardController!.listSendingEmails.firstWhereOrNull((sendingEmail) => sendingEmail.sendingId == sendingId);
if (matchedSendingEmail != null) {
_updateSendingEmailAction(matchedSendingEmail);
final newSendingEmail = matchedSendingEmail.updatingSendingState(SendingState.running);
_updateSendingEmailAction(newSendingEmail);
}
}
void _updatingSendingStateToErrorAction(String sendingId) {
log('SendingQueueController::_updatingSendingStateToErrorAction():sendingId: $sendingId');
final matchedSendingEmail = dashboardController!.listSendingEmails.firstWhereOrNull((sendingEmail) => sendingEmail.sendingId == sendingId);
if (matchedSendingEmail != null) {
final newSendingEmail = matchedSendingEmail.updatingSendingState(SendingState.error);
_updateSendingEmailAction(newSendingEmail);
}
}
@@ -118,8 +140,8 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
bool get isConnectedNetwork => _networkConnectionController?.isNetworkConnectionAvailable() == true;
void refreshSendingQueue({bool needToReopen = false}) {
dashboardController!.getAllSendingEmails(needToReopen: needToReopen);
void refreshSendingQueue() {
dashboardController!.getAllSendingEmails();
}
void openMailboxMenu() {
@@ -148,6 +170,9 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
break;
case SendingEmailActionType.create:
break;
case SendingEmailActionType.resend:
_resendSendingEmailAction(listSendingEmails);
break;
}
}
@@ -185,32 +210,31 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
}
void _handleDeleteSendingEmail(List<SendingEmail> listSendingEmails) async {
disableSelectionMode();
final accountId = dashboardController!.accountId.value;
final session = dashboardController!.sessionCurrent;
if (accountId != null && session != null) {
final sendingIds = listSendingEmails.map((sendingEmail) => sendingEmail.sendingId).toSet().toList();
await Future.wait(
sendingIds.map((sendingId) => WorkSchedulerController().cancelByUniqueId(sendingId)),
eagerError: true
consumeState(
_deleteMultipleSendingEmailInteractor.execute(
accountId,
session.username,
listSendingEmails.sendingIds
)
);
consumeState(_deleteMultipleSendingEmailInteractor.execute(accountId, session.username, sendingIds));
}
}
void _handleDeleteSendingEmailSuccess() {
if (currentContext != null && currentOverlayContext != null) {
selectionState.value = SelectMode.INACTIVE;
void _handleDeleteSendingEmailSuccess(DeleteMultipleSendingEmailSuccess success) async {
await Future.wait(success.sendingIds.map(WorkSchedulerController().cancelByUniqueId));
if (currentContext != null && currentOverlayContext != null) {
_appToast!.showToastSuccessMessage(
currentOverlayContext!,
AppLocalizations.of(currentContext!).messageHaveBeenDeletedSuccessfully
);
refreshSendingQueue();
AppLocalizations.of(currentContext!).messageHaveBeenDeletedSuccessfully);
}
refreshSendingQueue();
}
void _editSendingEmailAction(SendingEmail sendingEmail) {
@@ -227,10 +251,6 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
dashboardController?.goToComposer(arguments);
}
void _handleDeleteSendingEmailFailure() {
selectionState.value = SelectMode.INACTIVE;
}
void _updateSendingEmailAction(SendingEmail newSendingEmail) {
final accountId = dashboardController!.accountId.value;
final session = dashboardController!.sessionCurrent;
@@ -238,29 +258,62 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi
consumeState(_updateSendingEmailInteractor.execute(
accountId,
session.username,
newSendingEmail,
needToReopen: true
newSendingEmail
));
}
}
void _resendSendingEmailAction(List<SendingEmail> listSendingEmails) async {
disableSelectionMode();
final accountId = dashboardController!.accountId.value;
final session = dashboardController!.sessionCurrent;
if (accountId != null && session != null) {
consumeState(
_updateMultipleSendingEmailInteractor.execute(
accountId,
session.username,
listSendingEmails.toSendingStateWaiting()
)
);
}
}
void _handleResendSendingEmailSuccess(List<SendingEmail> newListSendingEmails) async {
await Future.forEach<SendingEmail>(newListSendingEmails, (sendingEmail) async {
await WorkSchedulerController().cancelByUniqueId(sendingEmail.sendingId);
dashboardController!.addSendingEmailToSendingQueue(sendingEmail);
});
if (currentContext != null && currentOverlayContext != null) {
_appToast!.showToastSuccessMessage(
currentOverlayContext!,
AppLocalizations.of(currentContext!).messagesHaveBeenResent);
}
refreshSendingQueue();
}
@override
void handleSuccessViewState(Success success) {
super.handleSuccessViewState(success);
if (success is DeleteMultipleSendingEmailAllSuccess ||
success is DeleteMultipleSendingEmailHasSomeSuccess) {
_handleDeleteSendingEmailSuccess();
if (success is DeleteMultipleSendingEmailSuccess) {
_handleDeleteSendingEmailSuccess(success);
} else if (success is UpdateSendingEmailSuccess) {
refreshSendingQueue(needToReopen: true);
refreshSendingQueue();
} else if (success is UpdateMultipleSendingEmailAllSuccess) {
_handleResendSendingEmailSuccess(success.newSendingEmails);
} else if (success is UpdateMultipleSendingEmailHasSomeSuccess) {
_handleResendSendingEmailSuccess(success.newSendingEmails);
}
}
@override
void handleFailureViewState(Failure failure) {
super.handleFailureViewState(failure);
if (failure is DeleteMultipleSendingEmailAllFailure ||
failure is DeleteMultipleSendingEmailFailure) {
_handleDeleteSendingEmailFailure();
if (failure is UpdateSendingEmailFailure) {
refreshSendingQueue();
}
}
@@ -64,7 +64,7 @@ class SendingQueueView extends GetWidget<SendingQueueController> with AppLoaderM
if (controller.selectionState.value == SelectMode.INACTIVE) {
return RefreshIndicator(
color: AppColor.primaryColor,
onRefresh: () async => controller.refreshSendingQueue(needToReopen: true),
onRefresh: () async => controller.refreshSendingQueue(),
child: _buildListViewItemSendingEmails());
} else {
return _buildListViewItemSendingEmails();
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/state/button_state.dart';
import 'package:tmail_ui_user/features/sending_queue/domain/model/sending_email.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/extensions/list_sending_email_extension.dart';
import 'package:tmail_ui_user/features/sending_queue/presentation/model/sending_email_action_type.dart';
typedef OnHandleSendingEmailActionType = void Function(SendingEmailActionType, List<SendingEmail>);
@@ -53,6 +54,19 @@ class BottomBarSendingQueueWidget extends StatelessWidget {
})
..text(SendingEmailActionType.edit.getButtonTitle(context), isVertical: responsiveUtils.isPortraitMobile(context))
).build()),
Expanded(child: (ButtonBuilder(imagePaths.icRefresh)
..key(Key(SendingEmailActionType.resend.getButtonKey()))
..iconColor(SendingEmailActionType.resend.getButtonIconColor(_isCanResend ? ButtonState.enabled : ButtonState.disabled))
..padding(const EdgeInsets.all(8))
..radiusSplash(8)
..textStyle(TextStyle(fontSize: 12, color: SendingEmailActionType.resend.getButtonTitleColor(_isCanResend ? ButtonState.enabled : ButtonState.disabled)))
..onPressActionClick(() {
if (_isCanResend) {
onHandleSendingEmailActionType?.call(SendingEmailActionType.resend, listSendingEmailSelected);
}
})
..text(SendingEmailActionType.resend.getButtonTitle(context), isVertical: responsiveUtils.isPortraitMobile(context))
).build()),
Expanded(child: (ButtonBuilder(imagePaths.icDeleteComposer)
..key(Key(SendingEmailActionType.delete.getButtonKey()))
..iconColor(SendingEmailActionType.delete.getButtonIconColor(ButtonState.enabled))
@@ -70,4 +84,6 @@ class BottomBarSendingQueueWidget extends StatelessWidget {
bool get _isEditable => !isConnectedNetwork &&
listSendingEmailSelected.length == 1 &&
listSendingEmailSelected.first.isWaiting;
bool get _isCanResend => listSendingEmailSelected.isAllSendingStateError();
}
+13 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2023-06-09T10:30:29.843203",
"@@last_modified": "2023-06-09T22:51:52.101985",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -2905,5 +2905,17 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"resend": "Resend",
"@resend": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"messagesHaveBeenResent": "Messages have been resent",
"@messagesHaveBeenResent": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
@@ -2995,4 +2995,16 @@ class AppLocalizations {
name: 'connectedToTheInternet'
);
}
String get resend {
return Intl.message(
'Resend',
name: 'resend');
}
String get messagesHaveBeenResent {
return Intl.message(
'Messages have been resent',
name: 'messagesHaveBeenResent');
}
}