diff --git a/lib/features/caching/caching_manager.dart b/lib/features/caching/caching_manager.dart index 414684f03..63918b100 100644 --- a/lib/features/caching/caching_manager.dart +++ b/lib/features/caching/caching_manager.dart @@ -17,7 +17,7 @@ import 'package:tmail_ui_user/features/caching/clients/state_cache_client.dart'; import 'package:tmail_ui_user/features/caching/clients/subscription_cache_client.dart'; import 'package:tmail_ui_user/features/caching/utils/caching_constants.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; -import 'package:tmail_ui_user/features/offline_mode/controller/work_scheduler_controller.dart'; +import 'package:tmail_ui_user/features/offline_mode/controller/work_manager_controller.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart'; class CachingManager { @@ -133,7 +133,7 @@ class CachingManager { final sendingIds = listSendingEmails.map((sendingEmail) => sendingEmail.sendingId).toSet().toList(); if (sendingIds.isNotEmpty) { await Future.wait( - sendingIds.map(WorkSchedulerController().cancelByUniqueId), + sendingIds.map(WorkManagerController().cancelByUniqueId), eagerError: true ); await _sendingEmailCacheManager.clearAllSendingEmails(); diff --git a/lib/features/caching/utils/cache_utils.dart b/lib/features/caching/utils/cache_utils.dart index b63140aeb..954395754 100644 --- a/lib/features/caching/utils/cache_utils.dart +++ b/lib/features/caching/utils/cache_utils.dart @@ -14,12 +14,14 @@ class TupleKey { String key1, [ String? key2, - String? key3 + String? key3, + String? key4, ] ) : parts = [ key1, if (key2 != null) key2, if (key3 != null) key3, + if (key4 != null) key4, ]; const TupleKey.byParts(this.parts); diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 3085ac339..40038f4cb 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -84,9 +84,9 @@ import 'package:tmail_ui_user/features/manage_account/presentation/model/account import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart'; import 'package:tmail_ui_user/features/network_status_handle/presentation/network_connnection_controller.dart'; import 'package:tmail_ui_user/features/offline_mode/config/work_manager_constants.dart'; -import 'package:tmail_ui_user/features/offline_mode/controller/work_scheduler_controller.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/one_time_work_request.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker_type.dart'; +import 'package:tmail_ui_user/features/offline_mode/controller/work_manager_controller.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/one_time_work_request.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/worker_type.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/get_email_state_to_refresh_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/get_mailbox_state_to_refresh_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_email_state_to_refresh_interactor.dart'; @@ -126,7 +126,6 @@ import 'package:tmail_ui_user/main/routes/route_utils.dart'; import 'package:tmail_ui_user/main/utils/email_receive_manager.dart'; import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; import 'package:uuid/uuid.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker.dart' as worker_scheduler; import 'package:workmanager/workmanager.dart' as work_manager; class MailboxDashBoardController extends ReloadableController { @@ -1904,34 +1903,34 @@ class MailboxDashBoardController extends ReloadableController { } void _handleUpdateSendingEmailSuccess(UpdateSendingEmailSuccess success) async { - await WorkSchedulerController().cancelByUniqueId(success.newSendingEmail.sendingId); + await WorkManagerController().cancelByUniqueId(success.newSendingEmail.sendingId); addSendingEmailToSendingQueue(success.newSendingEmail); getAllSendingEmails(); } void addSendingEmailToSendingQueue(SendingEmail sendingEmail) async { log('MailboxDashBoardController::addSendingEmailToSendingQueue():sendingEmail: $sendingEmail'); - final worker = worker_scheduler.Worker( - sendingEmail.sendingId, - WorkerType.sendingEmail, - sendingEmail.toJson() - ); - final workRequest = OneTimeWorkRequest( - worker, - initialDelay: const Duration(milliseconds: WorkManagerConstants.initialDelayTime), + final work = OneTimeWorkRequest( + uniqueId: PlatformInfo.isAndroid + ? sendingEmail.sendingId + : WorkerType.sendingEmail.iOSUniqueId, + taskId: sendingEmail.sendingId, + tag: WorkerType.sendingEmail.name, + inputData: sendingEmail.toJson() + ..addAll({ + WorkManagerConstants.workerTypeKey: WorkerType.sendingEmail.name + }), + initialDelay: const Duration(milliseconds: WorkManagerConstants.delayTime), + backoffPolicy: work_manager.BackoffPolicy.linear, + backoffPolicyDelay: const Duration(milliseconds: WorkManagerConstants.delayTime), constraints: work_manager.Constraints(networkType: work_manager.NetworkType.connected) ); - try { - await WorkSchedulerController().enqueue(workRequest); - } catch (e) { - logError('MailboxDashBoardController::addSendingEmailToSendingQueue(): EXCEPTION: $e'); - } + await WorkManagerController().enqueue(work); } void getAllSendingEmails() { if (accountId.value != null && sessionCurrent != null) { - log('MailboxDashBoardController::getAllSendingEmails():accountId: ${accountId.value} | userName: ${sessionCurrent?.username}'); consumeState(_getAllSendingEmailInteractor.execute( accountId.value!, sessionCurrent!.username @@ -1939,11 +1938,10 @@ class MailboxDashBoardController extends ReloadableController { } } - void _handleGetAllSendingEmailsSuccess(GetAllSendingEmailSuccess success) { - log('MailboxDashBoardController::_handleGetAllSendingEmailsSuccess():LIST_SENDING_EMAIL: $success'); + void _handleGetAllSendingEmailsSuccess(GetAllSendingEmailSuccess success) async { listSendingEmails.value = success.sendingEmails; - if (success.sendingEmails.isEmpty && dashboardRoute.value == DashboardRoutes.sendingQueue) { + if (listSendingEmails.isEmpty && dashboardRoute.value == DashboardRoutes.sendingQueue) { _openDefaultMailbox(); } } diff --git a/lib/features/offline_mode/config/work_manager_config.dart b/lib/features/offline_mode/config/work_manager_config.dart index 81ae7c828..77ec26f9d 100644 --- a/lib/features/offline_mode/config/work_manager_config.dart +++ b/lib/features/offline_mode/config/work_manager_config.dart @@ -1,6 +1,6 @@ import 'package:core/core.dart'; -import 'package:tmail_ui_user/features/offline_mode/manager/work_dispatcher.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/work_dispatcher.dart'; import 'package:workmanager/workmanager.dart'; class WorkManagerConfig { diff --git a/lib/features/offline_mode/config/work_manager_constants.dart b/lib/features/offline_mode/config/work_manager_constants.dart index d00ec2db7..6da0fc126 100644 --- a/lib/features/offline_mode/config/work_manager_constants.dart +++ b/lib/features/offline_mode/config/work_manager_constants.dart @@ -2,5 +2,5 @@ class WorkManagerConstants { static const String sendingEmailUniqueId = 'com.linagora.ios.teammail.sendingQueue'; static const String workerTypeKey = 'worker_type'; - static const int initialDelayTime = 2000; + static const int delayTime = 2000; } \ No newline at end of file diff --git a/lib/features/offline_mode/controller/work_scheduler_controller.dart b/lib/features/offline_mode/controller/work_manager_controller.dart similarity index 62% rename from lib/features/offline_mode/controller/work_scheduler_controller.dart rename to lib/features/offline_mode/controller/work_manager_controller.dart index 3bb84a0d1..1b8865693 100644 --- a/lib/features/offline_mode/controller/work_scheduler_controller.dart +++ b/lib/features/offline_mode/controller/work_manager_controller.dart @@ -2,59 +2,56 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:core/utils/app_logger.dart'; import 'package:tmail_ui_user/features/offline_mode/config/work_manager_constants.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/one_time_work_request.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/periodic_work_request.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/work_request.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker_type.dart'; +import 'package:tmail_ui_user/features/offline_mode/exceptions/workmanager_exception.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/one_time_work_request.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/periodic_work_request.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/work_request.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/worker_type.dart'; import 'package:workmanager/workmanager.dart'; -class WorkSchedulerController { +class WorkManagerController { - static WorkSchedulerController? _instance; + static WorkManagerController? _instance; - WorkSchedulerController._(); + WorkManagerController._(); - factory WorkSchedulerController() => _instance ??= WorkSchedulerController._(); + factory WorkManagerController() => _instance ??= WorkManagerController._(); - Future enqueue(WorkRequest workRequest) { + Future enqueue(WorkRequest workRequest) async { try { log('WorkSchedulerController::enqueue():workRequest: $workRequest'); if (workRequest is OneTimeWorkRequest) { - return Workmanager().registerOneOffTask( - workRequest.worker.uniqueId, - workRequest.worker.id, - tag: workRequest.worker.type.name, + await Workmanager().registerOneOffTask( + workRequest.uniqueId, + workRequest.taskId, + tag: workRequest.tag, initialDelay: workRequest.initialDelay, constraints: workRequest.constraints, backoffPolicy: workRequest.backoffPolicy, backoffPolicyDelay: workRequest.backoffPolicyDelay, outOfQuotaPolicy: workRequest.outOfQuotaPolicy, - inputData: workRequest.worker.inputData + inputData: workRequest.inputData ); } if (workRequest is PeriodicWorkRequest) { - return Workmanager().registerPeriodicTask( - workRequest.worker.uniqueId, - workRequest.worker.id, + await Workmanager().registerPeriodicTask( + workRequest.uniqueId, + workRequest.taskId, + tag: workRequest.tag, frequency: workRequest.frequency, - tag: workRequest.worker.type.name, initialDelay: workRequest.initialDelay, constraints: workRequest.constraints, backoffPolicy: workRequest.backoffPolicy, backoffPolicyDelay: workRequest.backoffPolicyDelay, outOfQuotaPolicy: workRequest.outOfQuotaPolicy, - inputData: workRequest.worker.inputData + inputData: workRequest.inputData ); - } else { - return Future.value(); } } catch (e) { logError('WorkSchedulerController::enqueue(): EXCEPTION: $e'); - return Future.value(); } } Future handleBackgroundTask(String taskName, Map? inputData) async { - final completer = Completer(); log('WorkSchedulerController::handleBackgroundTask():taskName: $taskName | inputData: $inputData'); try { if (inputData != null && inputData.isNotEmpty) { @@ -64,15 +61,20 @@ class WorkSchedulerController { final matchedType = WorkerType.values.firstWhereOrNull((type) => type.name == workerType); if (matchedType != null) { - await matchedType.usingObserver().bindDI(); - await matchedType.usingObserver().observe(taskName, dataObject, completer); + final worker = matchedType.getWorker(); + await worker.bindDI(); + final result = await worker.doWork(taskName, dataObject); + return result; + } else { + return Future.error(CanNotFoundWorkerType()); } + } else { + return Future.error(CanNotFoundInputData()); } } catch (e) { - completer.completeError(e); logError('WorkSchedulerController::handleBackgroundTask():EXCEPTION: $e'); + return Future.error(e); } - return completer.future; } Future cancelByWorkType(WorkerType type) => Workmanager().cancelByTag(type.name); diff --git a/lib/features/offline_mode/exceptions/workmanager_exception.dart b/lib/features/offline_mode/exceptions/workmanager_exception.dart index 1b5d0dd1a..a1204f091 100644 --- a/lib/features/offline_mode/exceptions/workmanager_exception.dart +++ b/lib/features/offline_mode/exceptions/workmanager_exception.dart @@ -1 +1,3 @@ -class CannotCompleteTaskInWorkManagerException implements Exception {} \ No newline at end of file +class CanNotFoundInputData implements Exception {} + +class CanNotFoundWorkerType implements Exception {} \ No newline at end of file diff --git a/lib/features/offline_mode/model/sending_state.dart b/lib/features/offline_mode/model/sending_state.dart index 7a2485b13..ba951f814 100644 --- a/lib/features/offline_mode/model/sending_state.dart +++ b/lib/features/offline_mode/model/sending_state.dart @@ -14,11 +14,10 @@ enum SendingState { switch(this) { case SendingState.waiting: case SendingState.running: + case SendingState.success: return AppLocalizations.of(context).delivering; case SendingState.error: return AppLocalizations.of(context).error; - case SendingState.success: - return ''; } } @@ -26,11 +25,10 @@ enum SendingState { switch(this) { case SendingState.waiting: case SendingState.running: + case SendingState.success: return imagePaths.icDelivering; case SendingState.error: return imagePaths.icError; - case SendingState.success: - return ''; } } diff --git a/lib/features/offline_mode/scheduler/worker.dart b/lib/features/offline_mode/scheduler/worker.dart deleted file mode 100644 index 6e280b4d1..000000000 --- a/lib/features/offline_mode/scheduler/worker.dart +++ /dev/null @@ -1,30 +0,0 @@ - -import 'package:core/utils/platform_info.dart'; -import 'package:equatable/equatable.dart'; -import 'package:tmail_ui_user/features/offline_mode/config/work_manager_constants.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker_type.dart'; - -/// Equivalent to the task or work that needs to be done in the background -class Worker with EquatableMixin { - - final String id; - final WorkerType type; - final Map data; - - Worker(this.id, this.type, this.data); - - String get uniqueId { - if (PlatformInfo.isIOS) { - return type.iOSUniqueId; - } - return id; - } - - Map get inputData { - data.addAll({WorkManagerConstants.workerTypeKey: type.name}); - return data; - } - - @override - List get props => [id, type, data]; -} \ No newline at end of file diff --git a/lib/features/offline_mode/scheduler/one_time_work_request.dart b/lib/features/offline_mode/work_manager/one_time_work_request.dart similarity index 67% rename from lib/features/offline_mode/scheduler/one_time_work_request.dart rename to lib/features/offline_mode/work_manager/one_time_work_request.dart index ba54888f9..f5aaf9c92 100644 --- a/lib/features/offline_mode/scheduler/one_time_work_request.dart +++ b/lib/features/offline_mode/work_manager/one_time_work_request.dart @@ -1,12 +1,14 @@ -import 'package:tmail_ui_user/features/offline_mode/scheduler/work_request.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/work_request.dart'; import 'package:workmanager/workmanager.dart'; /// A WorkRequest for non-repeating work. class OneTimeWorkRequest extends WorkRequest { - OneTimeWorkRequest( - Worker worker, { + OneTimeWorkRequest({ + required String uniqueId, + required String taskId, + String? tag, + Map? inputData, Duration initialDelay = Duration.zero, Duration backoffPolicyDelay = Duration.zero, ExistingWorkPolicy? existingWorkPolicy, @@ -14,7 +16,10 @@ class OneTimeWorkRequest extends WorkRequest { OutOfQuotaPolicy? outOfQuotaPolicy, Constraints? constraints }) : super( - worker, + uniqueId: uniqueId, + taskId: taskId, + tag: tag, + inputData: inputData, initialDelay: initialDelay, backoffPolicyDelay: backoffPolicyDelay, existingWorkPolicy: existingWorkPolicy, diff --git a/lib/features/offline_mode/scheduler/periodic_work_request.dart b/lib/features/offline_mode/work_manager/periodic_work_request.dart similarity index 70% rename from lib/features/offline_mode/scheduler/periodic_work_request.dart rename to lib/features/offline_mode/work_manager/periodic_work_request.dart index 093fc1fea..a051a600e 100644 --- a/lib/features/offline_mode/scheduler/periodic_work_request.dart +++ b/lib/features/offline_mode/work_manager/periodic_work_request.dart @@ -1,14 +1,16 @@ -import 'package:tmail_ui_user/features/offline_mode/scheduler/work_request.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/work_request.dart'; import 'package:workmanager/workmanager.dart'; /// A WorkRequest for repeating work. class PeriodicWorkRequest extends WorkRequest { final Duration? frequency; - PeriodicWorkRequest( - Worker worker, { + PeriodicWorkRequest({ + required String uniqueId, + required String taskId, + String? tag, + Map? inputData, Duration initialDelay = Duration.zero, Duration backoffPolicyDelay = Duration.zero, ExistingWorkPolicy? existingWorkPolicy, @@ -17,7 +19,10 @@ class PeriodicWorkRequest extends WorkRequest { Constraints? constraints, this.frequency }) : super( - worker, + uniqueId: uniqueId, + taskId: taskId, + tag: tag, + inputData: inputData, initialDelay: initialDelay, backoffPolicyDelay: backoffPolicyDelay, existingWorkPolicy: existingWorkPolicy, diff --git a/lib/features/offline_mode/observer/sending_email_observer.dart b/lib/features/offline_mode/work_manager/sending_email_worker.dart similarity index 58% rename from lib/features/offline_mode/observer/sending_email_observer.dart rename to lib/features/offline_mode/work_manager/sending_email_worker.dart index 6cf2a1289..fef80ffbe 100644 --- a/lib/features/offline_mode/observer/sending_email_observer.dart +++ b/lib/features/offline_mode/work_manager/sending_email_worker.dart @@ -5,31 +5,28 @@ import 'package:core/presentation/state/success.dart'; import 'package:core/utils/app_logger.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:model/extensions/account_id_extensions.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:model/oidc/token_oidc.dart'; import 'package:tmail_ui_user/features/caching/config/hive_cache_config.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; import 'package:tmail_ui_user/features/composer/domain/state/send_email_state.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; -import 'package:tmail_ui_user/features/email/domain/state/delete_sending_email_state.dart'; -import 'package:tmail_ui_user/features/home/presentation/home_bindings.dart'; import 'package:tmail_ui_user/features/login/data/network/config/authorization_interceptors.dart'; import 'package:tmail_ui_user/features/login/domain/state/get_authenticated_account_state.dart'; import 'package:tmail_ui_user/features/login/domain/state/get_credential_state.dart'; import 'package:tmail_ui_user/features/login/domain/state/get_stored_token_oidc_state.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; -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/offline_mode/work_manager/worker.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_sending_email_state.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/update_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/sending_queue/presentation/bindings/sending_queue_bindings.dart'; +import 'package:tmail_ui_user/features/sending_queue/presentation/bindings/sending_queue_interactor_bindings.dart'; import 'package:tmail_ui_user/features/sending_queue/presentation/utils/sending_queue_isolate_manager.dart'; import 'package:tmail_ui_user/features/session/domain/extensions/session_extensions.dart'; import 'package:tmail_ui_user/features/session/domain/state/get_session_state.dart'; @@ -37,37 +34,39 @@ import 'package:tmail_ui_user/features/session/domain/usecases/get_session_inter import 'package:tmail_ui_user/main/bindings/main_bindings.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; -class SendingEmailObserver extends WorkObserver { - - AccountId? _currentAccountId; - Session? _currentSession; - SendingEmail? _sendingEmail; +class SendingEmailWorker extends Worker { SendEmailInteractor? _sendEmailInteractor; GetAuthenticatedAccountInteractor? _getAuthenticatedAccountInteractor; DynamicUrlInterceptors? _dynamicUrlInterceptors; AuthorizationInterceptors? _authorizationInterceptors; GetSessionInteractor? _getSessionInteractor; - DeleteSendingEmailInteractor? _deleteSendingEmailInteractor; SendingQueueIsolateManager? _sendingQueueIsolateManager; - UpdateSendingEmailInteractor? _updateSendingEmailInteractor; SendingEmailCacheManager? _sendingEmailCacheManager; - Completer? _completer; + late Completer _completer; + late SendingEmail _sendingEmail; - static SendingEmailObserver? _instance; + AccountId? _currentAccountId; + Session? _currentSession; - SendingEmailObserver._(); + static SendingEmailWorker? _instance; - factory SendingEmailObserver() => _instance ??= SendingEmailObserver._(); + SendingEmailWorker._(); + + factory SendingEmailWorker() => _instance ??= SendingEmailWorker._(); @override - Future observe(String taskId, Map inputData, Completer completer) async { - _completer = completer; + Future doWork(String taskId, Map inputData) { + _completer = Completer(); _sendingEmail = SendingEmail.fromJson(inputData); log('SendingEmailObserver::observe():_sendingEmail: $_sendingEmail'); - _updatingSendingStateToMainUI(); + _updatingSendingStateToMainUI( + sendingId: _sendingEmail.sendingId, + sendingState: SendingState.running + ); _getAuthenticatedAccount(); + return _completer.future; } @override @@ -77,17 +76,13 @@ class SendingEmailObserver extends WorkObserver { HiveCacheConfig().setUp() ]); - await Future.sync(() { - HomeBindings().dependencies(); - MailboxDashBoardBindings().dependencies(); - SendEmailInteractorBindings().dependencies(); - }); + SendingQueueInteractorBindings().dependencies(); + SendEmailInteractorBindings().dependencies(); + SendingQueueBindings().dependencies(); - await _getInteractorBindings(); + _getInteractorBindings(); await _sendingEmailCacheManager?.closeSendingEmailHiveCacheBox(); - - return Future.value(); } @override @@ -95,14 +90,11 @@ class SendingEmailObserver extends WorkObserver { log('SendingEmailObserver::_handleFailureViewState(): $failure'); if (failure is SendEmailFailure) { _handleSendEmailFailure(failure); - } else if (failure is DeleteSendingEmailFailure) { - _handleDeleteSendingEmailFailure(failure); } else if (failure is GetAuthenticatedAccountFailure || failure is NoAuthenticatedAccountFailure || failure is GetSessionFailure || failure is GetStoredTokenOidcFailure || - failure is GetCredentialFailure || - failure is UpdateSendingEmailFailure) { + failure is GetCredentialFailure) { _handleTaskFailureInWorkManager(); } } @@ -118,10 +110,6 @@ class SendingEmailObserver extends WorkObserver { _handleGetAccountByBasicAuthSuccess(success); } else if (success is SendEmailSuccess) { _handleSendEmailSuccess(success); - } else if (success is DeleteSendingEmailSuccess) { - _handleDeleteSendingEmailSuccess(success); - } else if (success is UpdateSendingEmailSuccess) { - _handleUpdateStoredSendingEmailSuccess(success); } } @@ -131,27 +119,22 @@ class SendingEmailObserver extends WorkObserver { _handleTaskFailureInWorkManager(); } - Future _getInteractorBindings() async { - try { - _getAuthenticatedAccountInteractor = getBinding(); - _dynamicUrlInterceptors = getBinding(); - _authorizationInterceptors = getBinding(); - _getSessionInteractor = getBinding(); - _sendEmailInteractor = getBinding(); - _deleteSendingEmailInteractor = getBinding(); - _sendingQueueIsolateManager = getBinding(); - _updateSendingEmailInteractor = getBinding(); - _sendingEmailCacheManager = getBinding(); - } catch (e) { - logError('SendingEmailObserver::_getInteractorBindings(): ${e.toString()}'); - _handleTaskFailureInWorkManager(); - } + void _getInteractorBindings() { + _getAuthenticatedAccountInteractor = getBinding(); + _dynamicUrlInterceptors = getBinding(); + _authorizationInterceptors = getBinding(); + _getSessionInteractor = getBinding(); + _sendEmailInteractor = getBinding(); + _sendingQueueIsolateManager = getBinding(); + _sendingEmailCacheManager = getBinding(); } void _updatingSendingStateToMainUI({String? sendingId, SendingState? sendingState}) { final eventAction = _generateEventAction( - sendingId ?? _sendingEmail!.sendingId, - sendingState ?? _sendingEmail!.sendingState + sendingId ?? _sendingEmail.sendingId, + sendingState ?? _sendingEmail.sendingState, + accountId: _currentAccountId, + userName: _currentSession?.username ); log('SendingEmailObserver::_updatingSendingStateToMainUI():eventAction: $eventAction'); _sendingQueueIsolateManager?.addEvent(eventAction); @@ -169,9 +152,9 @@ class SendingEmailObserver extends WorkObserver { _currentSession = success.session; _currentAccountId = success.session.personalAccount.accountId; final apiUrl = success.session.getQualifiedApiUrl(baseUrl: _dynamicUrlInterceptors?.jmapUrl); - if (apiUrl.isNotEmpty) { + if (apiUrl.isNotEmpty && _currentSession != null && _currentAccountId != null) { _dynamicUrlInterceptors?.changeBaseUrl(apiUrl); - _sendEmailAction(); + _sendEmailAction(_currentAccountId!, _currentSession!); } else { _handleTaskFailureInWorkManager(); } @@ -187,23 +170,23 @@ class SendingEmailObserver extends WorkObserver { _getSessionAction(); } - void _sendEmailAction() { + void _sendEmailAction(AccountId accountId, Session session) { consumeState( _sendEmailInteractor!.execute( - _currentSession!, - _currentAccountId!, - _sendingEmail!.toEmailRequest(), + session, + accountId, + _sendingEmail.toEmailRequest(), mailboxRequest: _getMailboxRequest() ) ); } CreateNewMailboxRequest? _getMailboxRequest() { - if (_sendingEmail!.mailboxNameRequest != null && - _sendingEmail!.creationIdRequest != null) { + if (_sendingEmail.mailboxNameRequest != null && + _sendingEmail.creationIdRequest != null) { return CreateNewMailboxRequest( - _sendingEmail!.creationIdRequest!, - _sendingEmail!.mailboxNameRequest!); + _sendingEmail.creationIdRequest!, + _sendingEmail.mailboxNameRequest!); } else { return null; } @@ -220,80 +203,45 @@ class SendingEmailObserver extends WorkObserver { } void _handleSendEmailSuccess(SendEmailSuccess success) { - _updateStoredSendingEmail(SendingState.success); - } - - void _handleSendEmailFailure(SendEmailFailure failure) { - _updateStoredSendingEmail(SendingState.error); - } - - void _deleteSendingEmailAction() { - consumeState( - _deleteSendingEmailInteractor!.execute( - _currentAccountId!, - _currentSession!.username, - _sendingEmail!.sendingId - ) - ); - } - - void _handleDeleteSendingEmailSuccess(DeleteSendingEmailSuccess success) { + _updatingSendingStateToMainUI(sendingState: SendingState.success); _handleTaskSuccessInWorkManager(); } - void _handleDeleteSendingEmailFailure(DeleteSendingEmailFailure failure) { - _handleTaskFailureInWorkManager(); - } - - void _updateStoredSendingEmail(SendingState newState) { - log('SendingEmailObserver::_updateStoredSendingEmail():newState: $newState'); - consumeState( - _updateSendingEmailInteractor!.execute( - _currentAccountId!, - _currentSession!.username, - _sendingEmail!.updatingSendingState(newState) - ) - ); - } - - void _handleUpdateStoredSendingEmailSuccess(UpdateSendingEmailSuccess success) { - log('SendingEmailObserver::_handleUpdateStoredSendingEmailSuccess(): $success'); - if (success.newSendingEmail.isSuccess) { - _deleteSendingEmailAction(); - } else { - _updatingSendingStateToMainUI( - sendingState: success.newSendingEmail.sendingState, - sendingId: success.newSendingEmail.sendingId); - } + void _handleSendEmailFailure(SendEmailFailure failure) { + _updatingSendingStateToMainUI(sendingState: SendingState.error); + _handleTaskErrorInWorkManager(failure.exception); } void _handleTaskFailureInWorkManager() async { log('SendingEmailObserver::_handleTaskFailureInWorkManager():'); - _updatingSendingStateToMainUI(sendingState: SendingState.error); - await Future.delayed( const Duration(milliseconds: 1000), - () { - _completer?.completeError(CannotCompleteTaskInWorkManagerException()); - _sendingEmail = null; - _completer = null; - } + () => _completer.complete(false) + ); + } + + void _handleTaskErrorInWorkManager(dynamic error) async { + log('SendingEmailObserver::_handleTaskErrorInWorkManager():'); + await Future.delayed( + const Duration(milliseconds: 1000), + () => _completer.completeError(error) ); } void _handleTaskSuccessInWorkManager() async { log('SendingEmailObserver::_handleTaskSuccessInWorkManager():'); - _updatingSendingStateToMainUI(sendingState: SendingState.success); - await Future.delayed( const Duration(milliseconds: 1000), - () { - _completer?.complete(true); - _sendingEmail = null; - _completer = null; - } + () => _completer.complete(true) ); } - String _generateEventAction(String sendingId, SendingState sendingState) => TupleKey(sendingId, sendingState.name).toString(); + String _generateEventAction( + String sendingId, + SendingState sendingState, + { + AccountId? accountId, + UserName? userName + } + ) => TupleKey(sendingId, sendingState.name, accountId?.asString, userName?.value).toString(); } \ No newline at end of file diff --git a/lib/features/offline_mode/manager/work_dispatcher.dart b/lib/features/offline_mode/work_manager/work_dispatcher.dart similarity index 60% rename from lib/features/offline_mode/manager/work_dispatcher.dart rename to lib/features/offline_mode/work_manager/work_dispatcher.dart index 3ae7cc84c..82a33b532 100644 --- a/lib/features/offline_mode/manager/work_dispatcher.dart +++ b/lib/features/offline_mode/work_manager/work_dispatcher.dart @@ -1,8 +1,8 @@ -import 'package:tmail_ui_user/features/offline_mode/controller/work_scheduler_controller.dart'; +import 'package:tmail_ui_user/features/offline_mode/controller/work_manager_controller.dart'; import 'package:workmanager/workmanager.dart'; @pragma('vm:entry-point') void callbackDispatcher() { - Workmanager().executeTask(WorkSchedulerController().handleBackgroundTask); + Workmanager().executeTask(WorkManagerController().handleBackgroundTask); } diff --git a/lib/features/offline_mode/scheduler/work_request.dart b/lib/features/offline_mode/work_manager/work_request.dart similarity index 56% rename from lib/features/offline_mode/scheduler/work_request.dart rename to lib/features/offline_mode/work_manager/work_request.dart index 424da2355..e6be56113 100644 --- a/lib/features/offline_mode/scheduler/work_request.dart +++ b/lib/features/offline_mode/work_manager/work_request.dart @@ -1,11 +1,13 @@ import 'package:equatable/equatable.dart'; -import 'package:tmail_ui_user/features/offline_mode/scheduler/worker.dart'; import 'package:workmanager/workmanager.dart'; /// Represents the scheduling of requests abstract class WorkRequest with EquatableMixin { - final Worker worker; + final String uniqueId; + final String taskId; + final String? tag; + final Map? inputData; final Duration initialDelay; final Duration backoffPolicyDelay; final ExistingWorkPolicy? existingWorkPolicy; @@ -13,21 +15,25 @@ abstract class WorkRequest with EquatableMixin { final OutOfQuotaPolicy? outOfQuotaPolicy; final Constraints? constraints; - WorkRequest( - this.worker, - { - this.initialDelay = Duration.zero, - this.backoffPolicyDelay = Duration.zero, - this.existingWorkPolicy, - this.backoffPolicy, - this.outOfQuotaPolicy, - this.constraints - } - ); + WorkRequest( { + required this.uniqueId, + required this.taskId, + this.tag, + this.inputData, + this.initialDelay = Duration.zero, + this.backoffPolicyDelay = Duration.zero, + this.existingWorkPolicy, + this.backoffPolicy, + this.outOfQuotaPolicy, + this.constraints + }); @override List get props => [ - worker, + uniqueId, + taskId, + tag, + inputData, initialDelay, backoffPolicyDelay, existingWorkPolicy, diff --git a/lib/features/offline_mode/observer/work_observer.dart b/lib/features/offline_mode/work_manager/worker.dart similarity index 86% rename from lib/features/offline_mode/observer/work_observer.dart rename to lib/features/offline_mode/work_manager/worker.dart index f08469a43..e74755b5d 100644 --- a/lib/features/offline_mode/observer/work_observer.dart +++ b/lib/features/offline_mode/work_manager/worker.dart @@ -4,10 +4,10 @@ import 'package:core/presentation/state/success.dart'; import 'package:core/utils/app_logger.dart'; import 'package:dartz/dartz.dart'; -abstract class WorkObserver { +abstract class Worker { Future bindDI(); - Future observe(String taskId, Map inputData, Completer completer); + Future doWork(String taskId, Map inputData); void consumeState(Stream> newStateStream) { newStateStream.listen( diff --git a/lib/features/offline_mode/scheduler/worker_type.dart b/lib/features/offline_mode/work_manager/worker_type.dart similarity index 58% rename from lib/features/offline_mode/scheduler/worker_type.dart rename to lib/features/offline_mode/work_manager/worker_type.dart index 4ab093789..c9647792a 100644 --- a/lib/features/offline_mode/scheduler/worker_type.dart +++ b/lib/features/offline_mode/work_manager/worker_type.dart @@ -1,15 +1,15 @@ import 'package:tmail_ui_user/features/offline_mode/config/work_manager_constants.dart'; -import 'package:tmail_ui_user/features/offline_mode/observer/sending_email_observer.dart'; -import 'package:tmail_ui_user/features/offline_mode/observer/work_observer.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/sending_email_worker.dart'; +import 'package:tmail_ui_user/features/offline_mode/work_manager/worker.dart'; enum WorkerType { sendingEmail; - WorkObserver usingObserver() { + Worker getWorker() { switch(this) { case WorkerType.sendingEmail: - return SendingEmailObserver(); + return SendingEmailWorker(); } } diff --git a/lib/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart b/lib/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart index ad2e1bf9b..44daca729 100644 --- a/lib/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart +++ b/lib/features/sending_queue/domain/usecases/get_all_sending_email_interactor.dart @@ -1,5 +1,6 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; +import 'package:core/utils/app_logger.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'; @@ -15,6 +16,7 @@ class GetAllSendingEmailInteractor { try { yield Right(GetAllSendingEmailLoading()); final sendingEmails = await _sendingQueueRepository.getAllSendingEmails(accountId, userName); + log('GetAllSendingEmailInteractor::execute():sendingEmails: ${sendingEmails.map((e) => '${e.email.subject} | ${e.sendingState}')}'); yield Right(GetAllSendingEmailSuccess(sendingEmails)); } catch (e) { yield Left(GetAllSendingEmailFailure(e)); diff --git a/lib/features/sending_queue/presentation/bindings/sending_queue_bindings.dart b/lib/features/sending_queue/presentation/bindings/sending_queue_bindings.dart index 37d8bb028..b5fc2e957 100644 --- a/lib/features/sending_queue/presentation/bindings/sending_queue_bindings.dart +++ b/lib/features/sending_queue/presentation/bindings/sending_queue_bindings.dart @@ -1,6 +1,8 @@ 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/delete_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/sending_queue/domain/usecases/get_stored_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,8 +17,10 @@ class SendingQueueBindings extends Bindings { void _bindingsController() { Get.put(SendingQueueController( Get.find(), - Get.find(), Get.find(), + Get.find(), + Get.find(), + Get.find(), )); } } \ No newline at end of file diff --git a/lib/features/sending_queue/presentation/bindings/sending_queue_interactor_bindings.dart b/lib/features/sending_queue/presentation/bindings/sending_queue_interactor_bindings.dart index ad6043930..3a24df36b 100644 --- a/lib/features/sending_queue/presentation/bindings/sending_queue_interactor_bindings.dart +++ b/lib/features/sending_queue/presentation/bindings/sending_queue_interactor_bindings.dart @@ -13,6 +13,7 @@ import 'package:tmail_ui_user/features/sending_queue/domain/usecases/get_all_sen import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart'; 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/get_stored_sending_email_interactor.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'; @@ -45,6 +46,7 @@ class SendingQueueInteractorBindings extends InteractorsBindings { Get.lazyPut(() => DeleteSendingEmailInteractor(Get.find())); Get.lazyPut(() => UpdateSendingEmailInteractor(Get.find())); Get.lazyPut(() => UpdateMultipleSendingEmailInteractor(Get.find())); + Get.lazyPut(() => GetStoredSendingEmailInteractor(Get.find())); } @override diff --git a/lib/features/sending_queue/presentation/sending_queue_controller.dart b/lib/features/sending_queue/presentation/sending_queue_controller.dart index 413adb8c7..fa9230245 100644 --- a/lib/features/sending_queue/presentation/sending_queue_controller.dart +++ b/lib/features/sending_queue/presentation/sending_queue_controller.dart @@ -1,5 +1,4 @@ -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'; @@ -8,26 +7,32 @@ import 'package:core/presentation/utils/app_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/extensions/list_email_content_extension.dart'; import 'package:model/mailbox/select_mode.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; import 'package:tmail_ui_user/features/caching/utils/cache_utils.dart'; +import 'package:tmail_ui_user/features/email/domain/state/delete_sending_email_state.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/controller/work_manager_controller.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/get_stored_sending_email_state.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/delete_sending_email_interactor.dart'; +import 'package:tmail_ui_user/features/sending_queue/domain/usecases/get_stored_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/utils/sending_queue_isolate_manager.dart'; -import 'package:tmail_ui_user/features/offline_mode/controller/work_scheduler_controller.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/state/delete_multiple_sending_email_state.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/presentation/extensions/list_sending_email_extension.dart'; @@ -38,13 +43,14 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class SendingQueueController extends BaseController with MessageDialogActionMixin { final DeleteMultipleSendingEmailInteractor _deleteMultipleSendingEmailInteractor; - final UpdateSendingEmailInteractor _updateSendingEmailInteractor; final UpdateMultipleSendingEmailInteractor _updateMultipleSendingEmailInteractor; + final UpdateSendingEmailInteractor _updateSendingEmailInteractor; + final DeleteSendingEmailInteractor _deleteSendingEmailInteractor; + final GetStoredSendingEmailInteractor _getStoredSendingEmailInteractor; final dashboardController = getBinding(); final _networkConnectionController = getBinding(); final _sendingQueueIsolateManager = getBinding(); - final _sendingEmailCacheManager = getBinding(); final _imagePaths = getBinding(); final _appToast = getBinding(); @@ -54,8 +60,10 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi SendingQueueController( this._deleteMultipleSendingEmailInteractor, - this._updateSendingEmailInteractor, this._updateMultipleSendingEmailInteractor, + this._updateSendingEmailInteractor, + this._deleteSendingEmailInteractor, + this._getStoredSendingEmailInteractor, ); @override @@ -74,24 +82,21 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi try { if (event is String) { final tupleKey = TupleKey.fromString(event); - 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: - _updatingSendingStateToRunningAction(sendingId); - break; - case SendingState.running: - case SendingState.success: - refreshSendingQueue(); - break; - case SendingState.error: - await WorkSchedulerController().cancelByUniqueId(sendingId); - _updatingSendingStateToErrorAction(sendingId); - break; + log('SendingQueueController::_handleSendingQueueEvent():tupleKey: $tupleKey'); + if (tupleKey.parts.length >= 2) { + final sendingId = tupleKey.parts[0]; + final sendingState = SendingState.values.firstWhere((state) => state.name == tupleKey.parts[1]); + if (tupleKey.parts.length >= 4) { + final accountId = AccountId(Id(tupleKey.parts[2])); + final userName = UserName(tupleKey.parts[3]); + _updatingSendingStateAction( + sendingId: sendingId, + newState: sendingState, + accountId: accountId, + userName: userName + ); + } else { + _updatingSendingStateAction(sendingId: sendingId, newState: sendingState); } } } @@ -100,21 +105,45 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi } } - void _updatingSendingStateToRunningAction(String sendingId) { - log('SendingQueueController::_updatingSendingStateToRunningAction():sendingId: $sendingId'); - final matchedSendingEmail = dashboardController!.listSendingEmails.firstWhereOrNull((sendingEmail) => sendingEmail.sendingId == sendingId); - if (matchedSendingEmail != null) { - final newSendingEmail = matchedSendingEmail.updatingSendingState(SendingState.running); - _updateSendingEmailAction(newSendingEmail); - } - } + void _updatingSendingStateAction({ + required String sendingId, + required SendingState newState, + AccountId? accountId, + UserName? userName + }) async { + log('SendingQueueController::_updatingSendingStateAction():sendingId: $sendingId | newState: $newState'); + switch(newState) { + case SendingState.waiting: + case SendingState.running: + if (dashboardController != null) { + final listSendingEmails = dashboardController!.listSendingEmails + .map((sendingEmail) => sendingEmail.sendingId == sendingId + ? sendingEmail.updatingSendingState(newState) + : sendingEmail) + .toList(); - 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); + dashboardController!.listSendingEmails.value = listSendingEmails; + } + break; + case SendingState.error: + if (accountId != null && userName != null) { + final matchedSendingEmail = dashboardController?.listSendingEmails.firstWhereOrNull((sendingEmail) => sendingEmail.sendingId == sendingId); + if (matchedSendingEmail != null) { + _updateSendingEmailAction( + newSendingEmail: matchedSendingEmail.updatingSendingState(SendingState.error), + accountId: accountId, + userName: userName + ); + } else { + _getStoredSendingEmailAction(sendingId, accountId, userName, SendingState.error); + } + } + break; + case SendingState.success: + if (accountId != null && userName != null) { + _deleteSendingEmailAction(sendingId, accountId, userName); + } + break; } } @@ -141,7 +170,9 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi bool get isConnectedNetwork => _networkConnectionController?.isNetworkConnectionAvailable() == true; void refreshSendingQueue() { - dashboardController!.getAllSendingEmails(); + if (dashboardController != null) { + dashboardController!.getAllSendingEmails(); + } } void openMailboxMenu() { @@ -161,7 +192,7 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi ) { switch(actionType) { case SendingEmailActionType.delete: - _deleteSendingEmailAction(context, listSendingEmails); + _deleteListSendingEmailAction(context, listSendingEmails); break; case SendingEmailActionType.edit: if (!isConnectedNetwork) { @@ -176,7 +207,7 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi } } - void _deleteSendingEmailAction(BuildContext context, List listSendingEmails) { + void _deleteListSendingEmailAction(BuildContext context, List listSendingEmails) { showConfirmDialogAction( context, AppLocalizations.of(context).messageDialogDeleteSendingEmail, @@ -205,11 +236,11 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi fontSize: 17, fontWeight: FontWeight.w500 ), - onConfirmAction: () => _handleDeleteSendingEmail(listSendingEmails), + onConfirmAction: () => _handleDeleteListSendingEmail(listSendingEmails), ); } - void _handleDeleteSendingEmail(List listSendingEmails) async { + void _handleDeleteListSendingEmail(List listSendingEmails) async { disableSelectionMode(); final accountId = dashboardController!.accountId.value; @@ -225,8 +256,8 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi } } - void _handleDeleteSendingEmailSuccess(DeleteMultipleSendingEmailSuccess success) async { - await Future.wait(success.sendingIds.map(WorkSchedulerController().cancelByUniqueId)); + void _handleDeleteListSendingEmailSuccess(DeleteMultipleSendingEmailSuccess success) async { + await Future.wait(success.sendingIds.map(WorkManagerController().cancelByUniqueId)); if (currentContext != null && currentOverlayContext != null) { _appToast!.showToastSuccessMessage( @@ -251,18 +282,6 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi dashboardController?.goToComposer(arguments); } - void _updateSendingEmailAction(SendingEmail newSendingEmail) { - final accountId = dashboardController!.accountId.value; - final session = dashboardController!.sessionCurrent; - if (accountId != null && session != null) { - consumeState(_updateSendingEmailInteractor.execute( - accountId, - session.username, - newSendingEmail - )); - } - } - void _resendSendingEmailAction(List listSendingEmails) async { disableSelectionMode(); @@ -282,7 +301,7 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi void _handleResendSendingEmailSuccess(List newListSendingEmails) async { await Future.forEach(newListSendingEmails, (sendingEmail) async { - await WorkSchedulerController().cancelByUniqueId(sendingEmail.sendingId); + await WorkManagerController().cancelByUniqueId(sendingEmail.sendingId); dashboardController!.addSendingEmailToSendingQueue(sendingEmail); }); @@ -294,26 +313,58 @@ class SendingQueueController extends BaseController with MessageDialogActionMixi refreshSendingQueue(); } + void _updateSendingEmailAction({ + required SendingEmail newSendingEmail, + required AccountId accountId, + required UserName userName + }) { + consumeState(_updateSendingEmailInteractor.execute(accountId, userName, newSendingEmail)); + } + + void _deleteSendingEmailAction(String sendingId, AccountId accountId, UserName userName) { + consumeState(_deleteSendingEmailInteractor.execute(accountId, userName, sendingId)); + } + + void _handleUpdateSendingEmailSuccess(UpdateSendingEmailSuccess success) async { + await WorkManagerController().cancelByUniqueId(success.newSendingEmail.sendingId); + refreshSendingQueue(); + } + + void _getStoredSendingEmailAction( + String sendingId, + AccountId accountId, + UserName userName, + SendingState sendingState + ) { + consumeState( + _getStoredSendingEmailInteractor.execute( + accountId, + userName, + sendingId, + sendingState + ) + ); + } @override void handleSuccessViewState(Success success) { super.handleSuccessViewState(success); if (success is DeleteMultipleSendingEmailSuccess) { - _handleDeleteSendingEmailSuccess(success); - } else if (success is UpdateSendingEmailSuccess) { - refreshSendingQueue(); + _handleDeleteListSendingEmailSuccess(success); } 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 UpdateSendingEmailFailure) { + } else if (success is UpdateSendingEmailSuccess) { + _handleUpdateSendingEmailSuccess(success); + } else if (success is DeleteSendingEmailSuccess) { refreshSendingQueue(); + } else if (success is GetStoredSendingEmailSuccess) { + _updateSendingEmailAction( + newSendingEmail: success.sendingEmail.updatingSendingState(success.sendingState), + accountId: success.accountId, + userName: success.userName + ); } } diff --git a/lib/main/bindings/credential/credential_bindings.dart b/lib/main/bindings/credential/credential_bindings.dart index 2b8cf2061..488824ab0 100644 --- a/lib/main/bindings/credential/credential_bindings.dart +++ b/lib/main/bindings/credential/credential_bindings.dart @@ -19,7 +19,9 @@ import 'package:tmail_ui_user/features/login/domain/repository/authentication_oi import 'package:tmail_ui_user/features/login/domain/repository/credential_repository.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/get_authenticated_account_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_credential_interactor.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/get_stored_token_oidc_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; @@ -37,6 +39,15 @@ class CredentialBindings extends BaseBindings { Get.find(), Get.find()) ); + Get.lazyPut(() => GetStoredTokenOidcInteractor( + Get.find(), + Get.find(), + )); + Get.lazyPut(() => GetAuthenticatedAccountInteractor( + Get.find(), + Get.find(), + Get.find(), + )); } @override