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 b85cd5da0..5d4e8f351 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -1285,7 +1285,7 @@ class MailboxDashBoardController extends ReloadableController { void _handleRefreshActionWhenBackToApp(RefreshActionViewEvent viewEvent) { log('MailboxDashBoardController::_handleRefreshActionWhenBackToApp():'); try { - _getEmailStateToRefreshInteractor = Get.find(); + _getEmailStateToRefreshInteractor = getBinding(); } catch (e) { logError('MailboxDashBoardController::_handleRefreshActionWhenBackToApp(): $e'); } @@ -1297,7 +1297,7 @@ class MailboxDashBoardController extends ReloadableController { void _deleteEmailStateToRefreshAction() { log('MailboxDashBoardController::_deleteEmailStateToRefreshAction():'); try { - _deleteEmailStateToRefreshInteractor = Get.find(); + _deleteEmailStateToRefreshInteractor = getBinding(); } catch (e) { logError('MailboxDashBoardController::_deleteEmailStateToRefreshAction(): $e'); } diff --git a/lib/features/push_notification/data/datasource/fcm_datasource.dart b/lib/features/push_notification/data/datasource/fcm_datasource.dart index 92b3f0e50..75ce9e909 100644 --- a/lib/features/push_notification/data/datasource/fcm_datasource.dart +++ b/lib/features/push_notification/data/datasource/fcm_datasource.dart @@ -23,4 +23,6 @@ abstract class FCMDatasource { Future getFirebaseSubscriptionByDeviceId(String deviceId); Future registerNewToken(RegisterNewTokenRequest newTokenRequest); + + Future getDeviceId(); } \ No newline at end of file diff --git a/lib/features/push_notification/data/datasource_impl/fcm_datasource_impl.dart b/lib/features/push_notification/data/datasource_impl/fcm_datasource_impl.dart index d1d0ffec0..b79b462d2 100644 --- a/lib/features/push_notification/data/datasource_impl/fcm_datasource_impl.dart +++ b/lib/features/push_notification/data/datasource_impl/fcm_datasource_impl.dart @@ -66,4 +66,9 @@ class FcmDatasourceImpl extends FCMDatasource { _exceptionThrower.throwException(error); }); } + + @override + Future getDeviceId() { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/push_notification/data/datasource_impl/hive_fcm_datasource_impl.dart b/lib/features/push_notification/data/datasource_impl/hive_fcm_datasource_impl.dart index 5339fa5ee..dc2e03a94 100644 --- a/lib/features/push_notification/data/datasource_impl/hive_fcm_datasource_impl.dart +++ b/lib/features/push_notification/data/datasource_impl/hive_fcm_datasource_impl.dart @@ -83,7 +83,16 @@ class HiveFCMDatasourceImpl extends FCMDatasource { } @override - Future registerNewToken(RegisterNewTokenRequest registerNewTokenRequest) { + Future registerNewToken(RegisterNewTokenRequest newTokenRequest) { throw UnimplementedError(); } + + @override + Future getDeviceId() { + return Future.sync(() async { + return await _firebaseCacheManager.getDeviceId(); + }).catchError((error) { + _exceptionThrower.throwException(error); + }); + } } \ No newline at end of file diff --git a/lib/features/push_notification/data/local/fcm_cache_manager.dart b/lib/features/push_notification/data/local/fcm_cache_manager.dart index 5eb3eecc6..681407f7e 100644 --- a/lib/features/push_notification/data/local/fcm_cache_manager.dart +++ b/lib/features/push_notification/data/local/fcm_cache_manager.dart @@ -75,4 +75,14 @@ class FCMCacheManager { Future storeDeviceId(String deviceId) { return _sharedPreferences.setString(fcmDeviceIdKey, deviceId); } + + Future getDeviceId() async { + await _sharedPreferences.reload(); + final deviceId = _sharedPreferences.getString(fcmDeviceIdKey); + if (deviceId != null) { + return deviceId; + } else { + throw NotFoundDeviceIdException(); + } + } } \ No newline at end of file diff --git a/lib/features/push_notification/data/repository/fcm_repository_impl.dart b/lib/features/push_notification/data/repository/fcm_repository_impl.dart index 2b568dd0d..a871450f7 100644 --- a/lib/features/push_notification/data/repository/fcm_repository_impl.dart +++ b/lib/features/push_notification/data/repository/fcm_repository_impl.dart @@ -104,4 +104,9 @@ class FCMRepositoryImpl extends FCMRepository { Future registerNewToken(RegisterNewTokenRequest newTokenRequest) { return _fcmDatasource[DataSourceType.network]!.registerNewToken(newTokenRequest); } + + @override + Future getDeviceId() { + return _fcmDatasource[DataSourceType.local]!.getDeviceId(); + } } \ No newline at end of file diff --git a/lib/features/push_notification/domain/exceptions/fcm_exception.dart b/lib/features/push_notification/domain/exceptions/fcm_exception.dart index e141f5ca6..756aa19c1 100644 --- a/lib/features/push_notification/domain/exceptions/fcm_exception.dart +++ b/lib/features/push_notification/domain/exceptions/fcm_exception.dart @@ -6,4 +6,6 @@ class NotFoundStateToRefreshException implements Exception {} class NotFoundEmailDeliveryStateException implements Exception {} -class NotFoundFirebaseSubscriptionException implements Exception {} \ No newline at end of file +class NotFoundFirebaseSubscriptionException implements Exception {} + +class NotFoundDeviceIdException implements Exception {} \ No newline at end of file diff --git a/lib/features/push_notification/domain/repository/fcm_repository.dart b/lib/features/push_notification/domain/repository/fcm_repository.dart index db6cea9d8..b1b019074 100644 --- a/lib/features/push_notification/domain/repository/fcm_repository.dart +++ b/lib/features/push_notification/domain/repository/fcm_repository.dart @@ -34,4 +34,6 @@ abstract class FCMRepository { Future getFirebaseSubscriptionByDeviceId(String deviceId); Future registerNewToken(RegisterNewTokenRequest newTokenRequest); + + Future getDeviceId(); } \ No newline at end of file diff --git a/lib/features/push_notification/domain/state/get_device_id_state.dart b/lib/features/push_notification/domain/state/get_device_id_state.dart new file mode 100644 index 000000000..45b694ce4 --- /dev/null +++ b/lib/features/push_notification/domain/state/get_device_id_state.dart @@ -0,0 +1,24 @@ + +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; + +class GetDeviceIdLoading extends UIState {} + +class GetDeviceIdSuccess extends UIState { + + final String deviceId; + + GetDeviceIdSuccess(this.deviceId); + + @override + List get props => [deviceId]; +} + +class GetDeviceIdFailure extends FeatureFailure { + final dynamic exception; + + GetDeviceIdFailure(this.exception); + + @override + List get props => [exception]; +} \ No newline at end of file diff --git a/lib/features/push_notification/domain/usecases/get_device_id_interactor.dart b/lib/features/push_notification/domain/usecases/get_device_id_interactor.dart new file mode 100644 index 000000000..5c3603136 --- /dev/null +++ b/lib/features/push_notification/domain/usecases/get_device_id_interactor.dart @@ -0,0 +1,21 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/state/get_device_id_state.dart'; + +class GetDeviceIdInteractor { + final FCMRepository _fcmRepository; + + GetDeviceIdInteractor(this._fcmRepository); + + Stream> execute() async* { + try { + yield Right(GetDeviceIdLoading()); + final deviceId = await _fcmRepository.getDeviceId(); + yield Right(GetDeviceIdSuccess(deviceId)); + } catch (e) { + yield Left(GetDeviceIdFailure(e)); + } + } +} \ No newline at end of file diff --git a/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart b/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart index 2278223f5..48f56bdba 100644 --- a/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart +++ b/lib/features/push_notification/presentation/bindings/fcm_interactor_bindings.dart @@ -10,6 +10,7 @@ import 'package:tmail_ui_user/features/push_notification/data/repository/fcm_rep import 'package:tmail_ui_user/features/push_notification/domain/repository/fcm_repository.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_email_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/delete_fcm_token_cache_interactor.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_device_id_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_changes_to_push_notification_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_email_state_to_refresh_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_fcm_token_cache_interactor.dart'; @@ -66,6 +67,7 @@ class FcmInteractorBindings extends InteractorsBindings { Get.lazyPut(() => StoreDeviceIdInteractor(Get.find())); Get.lazyPut(() => GetFirebaseSubscriptionInteractor(Get.find())); Get.lazyPut(() => RegisterNewTokenInteractor(Get.find())); + Get.lazyPut(() => GetDeviceIdInteractor(Get.find())); } @override diff --git a/lib/features/push_notification/presentation/controller/fcm_token_handler.dart b/lib/features/push_notification/presentation/controller/fcm_token_handler.dart index 7f55103f6..eff0073f9 100644 --- a/lib/features/push_notification/presentation/controller/fcm_token_handler.dart +++ b/lib/features/push_notification/presentation/controller/fcm_token_handler.dart @@ -12,7 +12,10 @@ import 'package:fcm/model/type_name.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart'; import 'package:tmail_ui_user/features/push_notification/domain/model/register_new_token_request.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/state/get_device_id_state.dart'; import 'package:tmail_ui_user/features/push_notification/domain/state/get_firebase_subscription_state.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/state/register_new_token_state.dart'; +import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_device_id_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/get_firebase_subscription_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/register_new_token_interactor.dart'; import 'package:tmail_ui_user/features/push_notification/domain/usecases/store_device_id_interactor.dart'; @@ -28,9 +31,13 @@ class FcmTokenHandler { static FcmTokenHandler get instance => _instance; + static const int limitedTimeToExpire = 3; + static const int extensionTimeExpire = 7; + StoreDeviceIdInteractor? _storeDeviceIdInteractor; GetFirebaseSubscriptionInteractor? _getFirebaseSubscriptionInteractor; RegisterNewTokenInteractor? _registerNewTokenInteractor; + GetDeviceIdInteractor? _getDeviceIdInteractor; FirebaseToken? _fcmToken; DeviceClientId? _deviceClientId; @@ -40,6 +47,7 @@ class FcmTokenHandler { _storeDeviceIdInteractor = getBinding(); _getFirebaseSubscriptionInteractor = getBinding(); _registerNewTokenInteractor = getBinding(); + _getDeviceIdInteractor = getBinding(); } catch (e) { logError('FcmTokenHandler::initialize(): ${e.toString()}'); } @@ -54,6 +62,8 @@ class FcmTokenHandler { log('FcmTokenHandler::handle(): fcmToken: $_fcmToken'); log('FcmTokenHandler::handle(): deviceId: $deviceId'); _getFcmTokenFromBackend(deviceId); + } else { + _getDeviceIdAction(); } } @@ -69,6 +79,12 @@ class FcmTokenHandler { } } + void _getDeviceIdAction() { + if (_getDeviceIdInteractor != null) { + _consumeState(_getDeviceIdInteractor!.execute()); + } + } + void _consumeState(Stream> newStateStream) { newStateStream.listen( _handleStateStream, @@ -95,13 +111,20 @@ class FcmTokenHandler { void _handleSuccessViewState(Success success) { log('FcmTokenHandler::_handleSuccessViewState(): $success'); if (success is GetFirebaseSubscriptionSuccess) { - _fcmToken = success.firebaseSubscription.token; _deviceClientId = success.firebaseSubscription.deviceClientId; final expireTime = success.firebaseSubscription.expires; log('FcmTokenHandler::_handleSuccessViewState():_fcmToken: $_fcmToken'); if (_isTokenExpired(expireTime)) { - _handleWhenTokenExpired(_fcmToken!, _deviceClientId!); + log('FcmTokenHandler::_handleSuccessViewState(): _isTokenExpired true'); + _handleWhenTokenExpired(); } + } else if (success is RegisterNewTokenSuccess) { + final deviceId = success.firebaseSubscription.deviceClientId?.value; + if (deviceId != null) { + _storeDeviceIdAction(deviceId); + } + } else if (success is GetDeviceIdSuccess) { + _getFcmTokenFromBackend(success.deviceId); } } @@ -115,21 +138,26 @@ class FcmTokenHandler { log('FcmTokenHandler::_isTokenExpired():currentTime: $currentTime'); return currentTime.isBefore(expireTimeLocal) && - expireTimeLocal.daysBetween(currentTime) == 3; + expireTimeLocal.daysBetween(currentTime) <= limitedTimeToExpire; } else { return true; } } - void _handleWhenTokenExpired(FirebaseToken fcmToken, DeviceClientId deviceClientId) { + void _handleWhenTokenExpired() { + if (_fcmToken == null || _deviceClientId == null) { + log('FcmTokenHandler::_handleSuccessViewState():_fcmToken or _deviceClientId is null'); + return; + } + final generateCreationId = Id(const Uuid().v4()); - final newExpireTime = DateTime.now().add(const Duration(days: 7)); + final newExpireTime = DateTime.now().add(const Duration(days: extensionTimeExpire)); log('FcmTokenHandler::_handleSuccessViewState():newExpireTime: $newExpireTime'); final firebaseSubscription = FirebaseSubscription( - token: fcmToken, + token: _fcmToken!, expires: FirebaseExpiredTime(newExpireTime.toUTCDate()!), - deviceClientId: deviceClientId, + deviceClientId: _deviceClientId!, types: [TypeName.emailType, TypeName.mailboxType, TypeName.emailDelivery] );