diff --git a/lib/features/caching/caching_manager.dart b/lib/features/caching/caching_manager.dart index 34d30c89f..71e84671c 100644 --- a/lib/features/caching/caching_manager.dart +++ b/lib/features/caching/caching_manager.dart @@ -21,7 +21,6 @@ import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox/data/local/state_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox/data/model/state_type.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/sending_email_cache_manager.dart'; @@ -45,7 +44,6 @@ class CachingManager { final FileUtils _fileUtils; final SendingEmailCacheManager _sendingEmailCacheManager; final SessionCacheManager _sessionCacheManager; - final LocalSpamReportManager _localSpamReportManager; final KeychainSharingManager _keychainSharingManager; final TokenOidcCacheManager _tokenOidcCacheManager; final OidcConfigurationCacheManager _oidcConfigurationCacheManager; @@ -67,7 +65,6 @@ class CachingManager { this._fileUtils, this._sendingEmailCacheManager, this._sessionCacheManager, - this._localSpamReportManager, this._keychainSharingManager, this._tokenOidcCacheManager, this._oidcConfigurationCacheManager, @@ -82,7 +79,6 @@ class CachingManager { _emailCacheManager.clear(), _fcmCacheManager.clear(), _accountCacheManager.clear(), - _localSpamReportManager.clear(), if (PlatformInfo.isMobile) ...[ _sessionCacheManager.clear(), diff --git a/lib/features/mailbox_dashboard/data/datasource/spam_report_datasource.dart b/lib/features/mailbox_dashboard/data/datasource/spam_report_datasource.dart index a570ccb96..bb443a74a 100644 --- a/lib/features/mailbox_dashboard/data/datasource/spam_report_datasource.dart +++ b/lib/features/mailbox_dashboard/data/datasource/spam_report_datasource.dart @@ -8,11 +8,11 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_repor import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/unread_spam_emails_response.dart'; abstract class SpamReportDataSource { - Future storeLastTimeDismissedSpamReported(DateTime lastTimeDismissedSpamReported); + Future storeLastTimeDismissedSpamReported(DateTime lastTimeDismissedSpamReported); Future getLastTimeDismissedSpamReported(); - Future deleteLastTimeDismissedSpamReported(); + Future deleteLastTimeDismissedSpamReported(); Future findNumberOfUnreadSpamEmails( Session session, @@ -27,7 +27,5 @@ abstract class SpamReportDataSource { Future storeSpamReportState(SpamReportState spamReportState); - Future deleteSpamReportState(); - Future getSpamMailboxCached(AccountId accountId, UserName userName); } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/hive_spam_report_datasource_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/hive_spam_report_datasource_impl.dart index 5af2c4e1a..cd6ad724c 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/hive_spam_report_datasource_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/hive_spam_report_datasource_impl.dart @@ -22,11 +22,6 @@ class HiveSpamReportDataSourceImpl extends SpamReportDataSource { throw UnimplementedError(); } - @override - Future deleteSpamReportState() { - throw UnimplementedError(); - } - @override Future findNumberOfUnreadSpamEmails(Session session, AccountId accountId, {MailboxFilterCondition? mailboxFilterCondition, UnsignedInt? limit}) { throw UnimplementedError(); diff --git a/lib/features/mailbox_dashboard/data/datasource_impl/local_spam_report_datasource_impl.dart b/lib/features/mailbox_dashboard/data/datasource_impl/local_spam_report_datasource_impl.dart index 9f064d518..6324d5866 100644 --- a/lib/features/mailbox_dashboard/data/datasource_impl/local_spam_report_datasource_impl.dart +++ b/lib/features/mailbox_dashboard/data/datasource_impl/local_spam_report_datasource_impl.dart @@ -5,35 +5,50 @@ import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_filter_condition.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/spam_report_datasource.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/unread_spam_emails_response.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/spam_report_config.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class LocalSpamReportDataSourceImpl extends SpamReportDataSource { - final LocalSpamReportManager _localSpamReportManager; + final PreferencesSettingManager _preferencesSettingManager; final ExceptionThrower _exceptionThrower; - LocalSpamReportDataSourceImpl(this._localSpamReportManager, this._exceptionThrower); + LocalSpamReportDataSourceImpl( + this._preferencesSettingManager, + this._exceptionThrower, + ); @override Future getLastTimeDismissedSpamReported() async { return Future.sync(() async { - return await _localSpamReportManager.getLastTimeDismissedSpamReported(); + final spamReportConfig = + await _preferencesSettingManager.getSpamReportConfig(); + return DateTime.fromMillisecondsSinceEpoch( + spamReportConfig.lastTimeDismissedMilliseconds, + ); }).catchError(_exceptionThrower.throwException); } @override - Future storeLastTimeDismissedSpamReported(DateTime lastTimeDismissedSpamReported) async { + Future storeLastTimeDismissedSpamReported( + DateTime lastTimeDismissedSpamReported, + ) async { return Future.sync(() async { - return await _localSpamReportManager.storeLastTimeDismissedSpamReported(lastTimeDismissedSpamReported); + return await _preferencesSettingManager.updateSpamReport( + lastTimeDismissedMilliseconds: + lastTimeDismissedSpamReported.millisecondsSinceEpoch, + ); }).catchError(_exceptionThrower.throwException); } - + @override - Future deleteLastTimeDismissedSpamReported() { + Future deleteLastTimeDismissedSpamReported() { return Future.sync(() async { - return await _localSpamReportManager.deleteLastTimeDismissedSpamReported(); + return await _preferencesSettingManager.updateSpamReport( + lastTimeDismissedMilliseconds: 0, + ); }).catchError(_exceptionThrower.throwException); } @@ -49,24 +64,21 @@ class LocalSpamReportDataSourceImpl extends SpamReportDataSource { throw UnimplementedError(); } - @override - Future deleteSpamReportState() { - return Future.sync(() async { - return await _localSpamReportManager.deleteLastTimeDismissedSpamReported(); - }).catchError(_exceptionThrower.throwException); - } - @override Future getSpamReportState() { return Future.sync(() async { - return await _localSpamReportManager.getSpamReportState(); + final spamReportConfig = + await _preferencesSettingManager.getSpamReportConfig(); + return spamReportConfig.spamReportState; }).catchError(_exceptionThrower.throwException); } @override Future storeSpamReportState(SpamReportState spamReportState) { return Future.sync(() async { - return await _localSpamReportManager.storeSpamReportState(spamReportState); + return await _preferencesSettingManager.updateSpamReport( + isEnabled: spamReportState == SpamReportState.enabled, + ); }).catchError(_exceptionThrower.throwException); } diff --git a/lib/features/mailbox_dashboard/data/local/local_spam_report_manager.dart b/lib/features/mailbox_dashboard/data/local/local_spam_report_manager.dart deleted file mode 100644 index 97ac04d6c..000000000 --- a/lib/features/mailbox_dashboard/data/local/local_spam_report_manager.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:core/utils/app_logger.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; - -class LocalSpamReportManager { - static const String _keyLastTimeDismissedSpamReported = 'KEY_LAST_TIME_DISMISSED_SPAM_REPORTED'; - static const String _keySpamReportState = 'KEY_SPAM_REPORT_STATE'; - - final SharedPreferences _sharedPreferences; - - LocalSpamReportManager(this._sharedPreferences); - - Future getLastTimeDismissedSpamReported() async { - final timeStamp = _sharedPreferences.getInt(_keyLastTimeDismissedSpamReported) ?? 0; - log('LocalSpamReportManager::getLastTimeDismissedSpamReported:timeStamp: $timeStamp'); - final lastTimeDismissedSpamReported = DateTime.fromMillisecondsSinceEpoch(timeStamp); - return lastTimeDismissedSpamReported; - } - - Future storeLastTimeDismissedSpamReported(DateTime lastTimeDismissedSpamReported) async { - final timeStamp = lastTimeDismissedSpamReported.millisecondsSinceEpoch; - log('LocalSpamReportManager::storeLastTimeDismissedSpamReported:timeStamp: $timeStamp'); - return await _sharedPreferences.setInt(_keyLastTimeDismissedSpamReported, timeStamp); - } - - Future deleteLastTimeDismissedSpamReported() async { - return await _sharedPreferences.remove(_keyLastTimeDismissedSpamReported); - } - - Future deleteSpamReportState() async { - return await _sharedPreferences.remove(_keySpamReportState); - } - - Future getSpamReportState() async { - final spamReportState = _sharedPreferences.getString(_keySpamReportState) ?? ''; - return spamReportState == SpamReportState.disabled.keyValue ? SpamReportState.disabled : SpamReportState.enabled; - } - - Future storeSpamReportState(SpamReportState spamReportState) async { - final spamReportState0 = spamReportState.keyValue; - return await _sharedPreferences.setString(_keySpamReportState, spamReportState0); - } - - Future clear() async { - await deleteLastTimeDismissedSpamReported(); - await deleteSpamReportState(); - } -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart b/lib/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart index fe13707c0..aad9696f0 100644 --- a/lib/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart +++ b/lib/features/mailbox_dashboard/data/repository/spam_report_repository_impl.dart @@ -36,11 +36,6 @@ class SpamReportRepositoryImpl extends SpamReportRepository { return mapDataSource[DataSourceType.local]!.storeSpamReportState(spamReportState); } - @override - Future deleteSpamReportState() { - return mapDataSource[DataSourceType.local]!.deleteSpamReportState(); - } - @override Future getSpamMailboxCached(AccountId accountId, UserName userName) { return mapDataSource[DataSourceType.hiveCache]!.getSpamMailboxCached(accountId, userName); diff --git a/lib/features/mailbox_dashboard/domain/repository/spam_report_repository.dart b/lib/features/mailbox_dashboard/domain/repository/spam_report_repository.dart index edabee51e..39e37628c 100644 --- a/lib/features/mailbox_dashboard/domain/repository/spam_report_repository.dart +++ b/lib/features/mailbox_dashboard/domain/repository/spam_report_repository.dart @@ -14,7 +14,5 @@ abstract class SpamReportRepository { Future storeSpamReportState(SpamReportState spamReportState); - Future deleteSpamReportState(); - Future getSpamMailboxCached(AccountId accountId, UserName userName); } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/domain/usecases/delete_spam_report_state_interactor.dart b/lib/features/mailbox_dashboard/domain/usecases/delete_spam_report_state_interactor.dart deleted file mode 100644 index 74e5d9a57..000000000 --- a/lib/features/mailbox_dashboard/domain/usecases/delete_spam_report_state_interactor.dart +++ /dev/null @@ -1,21 +0,0 @@ -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/mailbox_dashboard/domain/repository/spam_report_repository.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/delete_spam_report_state.dart'; - -class DeleteSpamReportStateInteractor { - final SpamReportRepository _spamReportRepository; - - DeleteSpamReportStateInteractor(this._spamReportRepository); - - Stream> execute() async* { - try { - yield Right(DeleteSpamReportStateLoading()); - await _spamReportRepository.deleteSpamReportState(); - yield Right(DeleteSpamReportStateSuccess()); - } catch (e) { - yield Left(DeleteSpamReportStateFailure(e)); - } - } -} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart index 60f0d0fda..3a6f8c8d2 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -69,7 +69,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/lo import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/search_datasource_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource_impl/session_storage_composer_datasoure_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_sort_order_manager.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/network/linagora_ecosystem_api.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/app_grid_repository_impl.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/repository/composer_cache_repository_impl.dart'; @@ -100,6 +99,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/identity_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_interactors_bindings.dart'; @@ -278,7 +278,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find())); Get.lazyPut(() => LocalSpamReportDataSourceImpl( - Get.find(), + Get.find(), Get.find(), )); Get.lazyPut(() => HiveSpamReportDataSourceImpl( 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 eef703486..660240fd4 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -2004,6 +2004,7 @@ class MailboxDashBoardController extends ReloadableController _getAllIdentities(); notifyThreadDetailSettingUpdated(); getServerSetting(); + spamReportController.getSpamReportStateAction(); } Future> quickSearchEmails(String query) async { @@ -2074,6 +2075,7 @@ class MailboxDashBoardController extends ReloadableController _getAllIdentities(); notifyThreadDetailSettingUpdated(); getServerSetting(); + spamReportController.getSpamReportStateAction(); } void _handleUpdateVacationSuccess(UpdateVacationSuccess success) { diff --git a/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart index 7f8283cc8..7b8aa9bc2 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart @@ -19,6 +19,8 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_spa import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_last_time_dismissed_spam_reported_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_spam_report_state_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/spam_report_loader_status.dart'; +import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class SpamReportController extends BaseController { final StoreSpamReportInteractor _storeSpamReportInteractor; @@ -29,6 +31,9 @@ class SpamReportController extends BaseController { final presentationSpamMailbox = Rxn(); final spamReportState = Rx(SpamReportState.enabled); + AppLifecycleListener? _appLifecycleListener; + SpamReportLoaderStatus _spamReportLoaderStatus = SpamReportLoaderStatus.idle; + SpamReportController( this._storeSpamReportInteractor, this._storeSpamReportStateInteractor, @@ -36,28 +41,60 @@ class SpamReportController extends BaseController { this._getSpamMailboxCachedInteractor ); + @override + void onInit() { + super.onInit(); + _appLifecycleListener ??= AppLifecycleListener( + onResume: () { + if (_spamReportLoaderStatus == SpamReportLoaderStatus.loading) { + return; + } + getSpamReportStateAction(); + }, + ); + } + @override void handleSuccessViewState(Success success) { - super.handleSuccessViewState(success); if (success is StoreLastTimeDismissedSpamReportSuccess) { presentationSpamMailbox.value = null; + } else if (success is GetSpamReportStateLoading) { + _spamReportLoaderStatus = SpamReportLoaderStatus.loading; } else if (success is GetSpamReportStateSuccess) { - spamReportState.value = success.spamReportState; + _loadSpamReportConfigSuccess(success.spamReportState); } else if (success is StoreSpamReportStateSuccess) { spamReportState.value = success.spamReportState; + getBinding()?.refreshSpamReportBanner(); } else if (success is GetSpamMailboxCachedSuccess) { presentationSpamMailbox.value = success.spamMailbox.toPresentationMailbox(); + } else { + super.handleSuccessViewState(success); } } @override void handleFailureViewState(Failure failure) { - super.handleFailureViewState(failure); if (failure is GetSpamMailboxCachedFailure) { presentationSpamMailbox.value = null; + } else if (failure is GetSpamReportStateFailure) { + _spamReportLoaderStatus = SpamReportLoaderStatus.completed; + } else { + super.handleFailureViewState(failure); } } + @override + void handleErrorViewState(Object error, StackTrace stackTrace) { + super.handleErrorViewState(error, stackTrace); + _spamReportLoaderStatus = SpamReportLoaderStatus.completed; + } + + void _loadSpamReportConfigSuccess(SpamReportState newState) { + spamReportState.value = newState; + _spamReportLoaderStatus = SpamReportLoaderStatus.completed; + getBinding()?.refreshSpamReportBanner(); + } + void dismissSpamReportAction(BuildContext context) { if (Get.isRegistered()) { final mailboxDashBoardController = Get.find(); @@ -109,4 +146,10 @@ class SpamReportController extends BaseController { void setSpamPresentationMailbox(PresentationMailbox? spamMailbox) { presentationSpamMailbox.value = spamMailbox; } + + @override + void onClose() { + _appLifecycleListener?.dispose(); + super.onClose(); + } } diff --git a/lib/features/mailbox_dashboard/presentation/model/spam_report_loader_status.dart b/lib/features/mailbox_dashboard/presentation/model/spam_report_loader_status.dart new file mode 100644 index 000000000..5099dda84 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/model/spam_report_loader_status.dart @@ -0,0 +1 @@ +enum SpamReportLoaderStatus { idle, loading, completed } diff --git a/lib/features/manage_account/data/datasource/manage_account_datasource.dart b/lib/features/manage_account/data/datasource/manage_account_datasource.dart index 146c6671e..f7e6f0d9d 100644 --- a/lib/features/manage_account/data/datasource/manage_account_datasource.dart +++ b/lib/features/manage_account/data/datasource/manage_account_datasource.dart @@ -1,15 +1,11 @@ import 'dart:ui'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; abstract class ManageAccountDataSource { Future persistLanguage(Locale localeCurrent); - Future updateLocalSettings( - Map localSettings, - ); + Future updateLocalSettings(PreferencesRoot preferencesRoot); - Future> getLocalSettings( - List supportedLocalSettings, - ); + Future getLocalSettings(); } \ No newline at end of file diff --git a/lib/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart b/lib/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart index 303123468..3a4b1296d 100644 --- a/lib/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart +++ b/lib/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart @@ -2,19 +2,19 @@ import 'dart:ui'; import 'package:tmail_ui_user/features/manage_account/data/datasource/manage_account_datasource.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class ManageAccountDataSourceImpl extends ManageAccountDataSource { final LanguageCacheManager _languageCacheManager; - final LocalSettingCacheManager _localSettingCacheManager; + final PreferencesSettingManager _preferencesSettingManager; final ExceptionThrower _exceptionThrower; ManageAccountDataSourceImpl( this._languageCacheManager, - this._localSettingCacheManager, + this._preferencesSettingManager, this._exceptionThrower ); @@ -26,20 +26,16 @@ class ManageAccountDataSourceImpl extends ManageAccountDataSource { } @override - Future updateLocalSettings( - Map localSettings, - ) { + Future updateLocalSettings(PreferencesRoot preferencesRoot) { return Future.sync(() async { - return await _localSettingCacheManager.update(localSettings); + return await _preferencesSettingManager.savePreferences(preferencesRoot); }).catchError(_exceptionThrower.throwException); } @override - Future> getLocalSettings( - List supportedLocalSettings, - ) { + Future getLocalSettings() { return Future.sync(() async { - return await _localSettingCacheManager.get(supportedLocalSettings); + return await _preferencesSettingManager.loadPreferences(); }).catchError(_exceptionThrower.throwException); } } \ No newline at end of file diff --git a/lib/features/manage_account/data/local/local_setting_cache_manager.dart b/lib/features/manage_account/data/local/local_setting_cache_manager.dart deleted file mode 100644 index a241edcbe..000000000 --- a/lib/features/manage_account/data/local/local_setting_cache_manager.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'dart:convert'; - -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; - -class LocalSettingCacheManager { - const LocalSettingCacheManager(this._sharedPreferences); - - final SharedPreferences _sharedPreferences; - - Future update( - Map localSettings, - ) async { - await Future.wait(localSettings.entries.map((entry) async { - if (entry.value == null) { - await _sharedPreferences.remove(entry.key.name); - return; - } - - await _sharedPreferences.setString( - entry.key.name, - jsonEncode(entry.value!.toJson()), - ); - })); - } - - Future> get( - List supportedLocalSettings, - ) async { - await _sharedPreferences.reload(); - - return Map.fromEntries(supportedLocalSettings.map((supportedLocalSetting) { - final data = _sharedPreferences.getString(supportedLocalSetting.name); - - return MapEntry( - supportedLocalSetting, - data == null ? null : LocalSettingOptions.fromJson(jsonDecode(data)), - ); - })); - } -} \ No newline at end of file diff --git a/lib/features/manage_account/data/local/preferences_setting_manager.dart b/lib/features/manage_account/data/local/preferences_setting_manager.dart new file mode 100644 index 000000000..2c2b7ef35 --- /dev/null +++ b/lib/features/manage_account/data/local/preferences_setting_manager.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; + +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/spam_report_config.dart'; + +class PreferencesSettingManager { + static const String _preferencesSettingKey = 'PREFERENCES_SETTING'; + + const PreferencesSettingManager(this._sharedPreferences); + + final SharedPreferences _sharedPreferences; + + Future loadPreferences() async { + await _sharedPreferences.reload(); + + final jsonString = _sharedPreferences.getString(_preferencesSettingKey); + + if (jsonString != null) { + return PreferencesRoot.fromJson(jsonDecode(jsonString)); + } + + return PreferencesRoot.initial(); + } + + Future savePreferences(PreferencesRoot root) async { + await _sharedPreferences.setString( + _preferencesSettingKey, + jsonEncode(root.toJson()), + ); + } + + Future updateThread(bool enabled) async { + final current = await loadPreferences(); + final updated = current.updateThreadDetail(enabled); + await savePreferences(updated); + } + + Future updateSpamReport({ + bool? isEnabled, + int? lastTimeDismissedMilliseconds, + }) async { + final current = await loadPreferences(); + final updated = current.updateSpamReport( + isEnabled: isEnabled, + lastTimeDismissedMilliseconds: lastTimeDismissedMilliseconds, + ); + await savePreferences(updated); + } + + Future getSpamReportConfig() async { + final preferences = await loadPreferences(); + return preferences.setting.spamReport; + } +} diff --git a/lib/features/manage_account/data/repository/manage_account_repository_impl.dart b/lib/features/manage_account/data/repository/manage_account_repository_impl.dart index bccc521f9..d52bce62c 100644 --- a/lib/features/manage_account/data/repository/manage_account_repository_impl.dart +++ b/lib/features/manage_account/data/repository/manage_account_repository_impl.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:tmail_ui_user/features/manage_account/data/datasource/manage_account_datasource.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; class ManageAccountRepositoryImpl extends ManageAccountRepository { @@ -16,16 +16,12 @@ class ManageAccountRepositoryImpl extends ManageAccountRepository { } @override - Future updateLocalSettings( - Map localSettings, - ) { - return dataSource.updateLocalSettings(localSettings); + Future updateLocalSettings(PreferencesRoot preferencesRoot) { + return dataSource.updateLocalSettings(preferencesRoot); } @override - Future> getLocalSettings( - List supportedLocalSettings, - ) { - return dataSource.getLocalSettings(supportedLocalSettings); + Future getLocalSettings() { + return dataSource.getLocalSettings(); } } \ No newline at end of file diff --git a/lib/features/manage_account/domain/repository/manage_account_repository.dart b/lib/features/manage_account/domain/repository/manage_account_repository.dart index c5d88c247..341f5923a 100644 --- a/lib/features/manage_account/domain/repository/manage_account_repository.dart +++ b/lib/features/manage_account/domain/repository/manage_account_repository.dart @@ -1,15 +1,11 @@ import 'dart:ui'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; abstract class ManageAccountRepository { Future persistLanguage(Locale localeCurrent); - Future updateLocalSettings( - Map localSettings, - ); + Future updateLocalSettings(PreferencesRoot preferencesRoot); - Future> getLocalSettings( - List supportedLocalSettings, - ); -} \ No newline at end of file + Future getLocalSettings(); +} diff --git a/lib/features/manage_account/domain/state/get_local_settings_state.dart b/lib/features/manage_account/domain/state/get_local_settings_state.dart index 7dded8a8f..5c6c572ad 100644 --- a/lib/features/manage_account/domain/state/get_local_settings_state.dart +++ b/lib/features/manage_account/domain/state/get_local_settings_state.dart @@ -1,16 +1,16 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; class GettingLocalSettingsState extends LoadingState {} class GetLocalSettingsSuccess extends UIState { - GetLocalSettingsSuccess(this.localSettings); + GetLocalSettingsSuccess(this.preferencesRoot); - final Map localSettings; + final PreferencesRoot preferencesRoot; @override - List get props => [localSettings]; + List get props => [preferencesRoot]; } class GetLocalSettingsFailure extends FeatureFailure { diff --git a/lib/features/manage_account/domain/state/update_local_settings_state.dart b/lib/features/manage_account/domain/state/update_local_settings_state.dart index 13d1cf8f5..0c33ed1ee 100644 --- a/lib/features/manage_account/domain/state/update_local_settings_state.dart +++ b/lib/features/manage_account/domain/state/update_local_settings_state.dart @@ -1,16 +1,16 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; class UpdatingLocalSettingsState extends LoadingState {} class UpdateLocalSettingsSuccess extends UIState { - final Map localSettings; + final PreferencesRoot preferencesRoot; - UpdateLocalSettingsSuccess(this.localSettings); + UpdateLocalSettingsSuccess(this.preferencesRoot); @override - List get props => [localSettings]; + List get props => [preferencesRoot]; } class UpdateLocalSettingsFailure extends FeatureFailure { diff --git a/lib/features/manage_account/domain/usecases/get_local_settings_interactor.dart b/lib/features/manage_account/domain/usecases/get_local_settings_interactor.dart index 66f1d8869..8a534cbfe 100644 --- a/lib/features/manage_account/domain/usecases/get_local_settings_interactor.dart +++ b/lib/features/manage_account/domain/usecases/get_local_settings_interactor.dart @@ -4,19 +4,16 @@ import 'package:core/utils/app_logger.dart'; import 'package:dartz/dartz.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/get_local_settings_state.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; class GetLocalSettingsInteractor { const GetLocalSettingsInteractor(this._manageAccountRepository); final ManageAccountRepository _manageAccountRepository; - Stream> execute( - List supportedLocalSettings, - ) async* { + Stream> execute() async* { try { yield Right(GettingLocalSettingsState()); - final result = await _manageAccountRepository.getLocalSettings(supportedLocalSettings); + final result = await _manageAccountRepository.getLocalSettings(); yield Right(GetLocalSettingsSuccess(result)); } catch (e) { logError('$runtimeType::execute(): exception: $e'); diff --git a/lib/features/manage_account/domain/usecases/update_local_settings_interactor.dart b/lib/features/manage_account/domain/usecases/update_local_settings_interactor.dart index c9f82a259..e479344d7 100644 --- a/lib/features/manage_account/domain/usecases/update_local_settings_interactor.dart +++ b/lib/features/manage_account/domain/usecases/update_local_settings_interactor.dart @@ -4,7 +4,7 @@ import 'package:core/utils/app_logger.dart'; import 'package:dartz/dartz.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/update_local_settings_state.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; class UpdateLocalSettingsInteractor { const UpdateLocalSettingsInteractor(this._manageAccountRepository); @@ -12,12 +12,12 @@ class UpdateLocalSettingsInteractor { final ManageAccountRepository _manageAccountRepository; Stream> execute( - Map localSettings, + PreferencesRoot preferencesRoot, ) async* { try { yield Right(UpdatingLocalSettingsState()); - await _manageAccountRepository.updateLocalSettings(localSettings); - yield Right(UpdateLocalSettingsSuccess(localSettings)); + await _manageAccountRepository.updateLocalSettings(preferencesRoot); + yield Right(UpdateLocalSettingsSuccess(preferencesRoot)); } catch (e) { logError('$runtimeType::execute(): exception: $e'); yield Left(UpdateLocalSettingsFailure(exception: e)); diff --git a/lib/features/manage_account/presentation/extensions/local_settings_map_extension.dart b/lib/features/manage_account/presentation/extensions/local_settings_map_extension.dart deleted file mode 100644 index ae348fea3..000000000 --- a/lib/features/manage_account/presentation/extensions/local_settings_map_extension.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; - -extension LocalSettingsMapExtension on Map { - bool? get threadDetailEnabled => (this[SupportedLocalSetting.threadDetail]?.setting as ThreadDetailLocalSettingDetail?)?.value; -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart index 020d066e3..d5a8ff439 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart @@ -3,7 +3,7 @@ import 'package:tmail_ui_user/features/base/base_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/data/datasource/manage_account_datasource.dart'; import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/manage_account/data/repository/manage_account_repository_impl.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/identities/identity_bindings.dart'; @@ -36,7 +36,7 @@ class ManageAccountDashBoardBindings extends BaseBindings { void bindingsDataSourceImpl() { Get.lazyPut(() => ManageAccountDataSourceImpl( Get.find(), - Get.find(), + Get.find(), Get.find())); } diff --git a/lib/features/manage_account/presentation/model/local_setting_detail/local_setting_detail.dart b/lib/features/manage_account/presentation/model/local_setting_detail/local_setting_detail.dart deleted file mode 100644 index c39b334e0..000000000 --- a/lib/features/manage_account/presentation/model/local_setting_detail/local_setting_detail.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; - -abstract class LocalSettingDetail extends Equatable { - const LocalSettingDetail(this.value); - - final T value; - - Map toJson(); -} - -class LocalSettingDetailConverter extends JsonConverter> { - const LocalSettingDetailConverter(); - - @override - LocalSettingDetail fromJson(Map json) { - final type = json['type'] as String?; - - if (type == SupportedLocalSetting.threadDetail.name) { - return ThreadDetailLocalSettingDetail.fromJson(json); - } - - throw UnimplementedError(); - } - - @override - Map toJson(LocalSettingDetail object) { - return object.toJson(); - } -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart b/lib/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart deleted file mode 100644 index 8b45d3dae..000000000 --- a/lib/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_detail/local_setting_detail.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; - -part 'thread_detail_local_setting_detail.g.dart'; - -@JsonSerializable() -class ThreadDetailLocalSettingDetail extends LocalSettingDetail { - const ThreadDetailLocalSettingDetail( - super.value, [ - this.type = SupportedLocalSetting.threadDetail, - ]); - - @JsonKey(defaultValue: SupportedLocalSetting.threadDetail) - final SupportedLocalSetting type; - - factory ThreadDetailLocalSettingDetail.fromJson(Map json) => - _$ThreadDetailLocalSettingDetailFromJson(json); - @override - Map toJson() => _$ThreadDetailLocalSettingDetailToJson(this); - - @override - List get props => [value, type]; -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/local_setting_options.dart b/lib/features/manage_account/presentation/model/local_setting_options.dart deleted file mode 100644 index 32fe58414..000000000 --- a/lib/features/manage_account/presentation/model/local_setting_options.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_detail/local_setting_detail.dart'; - -part 'local_setting_options.g.dart'; - -enum SupportedLocalSetting { - threadDetail, -} - -@JsonSerializable(converters: [LocalSettingDetailConverter()]) -class LocalSettingOptions with EquatableMixin { - const LocalSettingOptions({ - required this.setting, - }); - - final LocalSettingDetail? setting; - - factory LocalSettingOptions.fromJson(Map json) => - _$LocalSettingOptionsFromJson(json); - - Map toJson() => _$LocalSettingOptionsToJson(this); - - @override - List get props => [setting]; -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/model/preferences/preferences_root.dart b/lib/features/manage_account/presentation/model/preferences/preferences_root.dart new file mode 100644 index 000000000..58fb9d23f --- /dev/null +++ b/lib/features/manage_account/presentation/model/preferences/preferences_root.dart @@ -0,0 +1,50 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_setting.dart'; + +part 'preferences_root.g.dart'; + +@JsonSerializable(explicitToJson: true) +class PreferencesRoot with EquatableMixin { + final PreferencesSetting setting; + + PreferencesRoot({required this.setting}); + + factory PreferencesRoot.initial() { + return PreferencesRoot( + setting: PreferencesSetting.initial(), + ); + } + + factory PreferencesRoot.fromJson(Map json) => + _$PreferencesRootFromJson(json); + + Map toJson() => _$PreferencesRootToJson(this); + + @override + List get props => [setting]; +} + +extension PreferencesRootExtension on PreferencesRoot { + PreferencesRoot copyWith({PreferencesSetting? setting}) { + return PreferencesRoot( + setting: setting ?? this.setting, + ); + } + + PreferencesRoot updateThreadDetail(bool enabled) { + return copyWith(setting: setting.updateThreadDetail(enabled)); + } + + PreferencesRoot updateSpamReport({ + bool? isEnabled, + int? lastTimeDismissedMilliseconds, + }) { + return copyWith( + setting: setting.updateSpamReport( + isEnabled: isEnabled, + lastTimeDismissedMilliseconds: lastTimeDismissedMilliseconds, + ), + ); + } +} diff --git a/lib/features/manage_account/presentation/model/preferences/preferences_setting.dart b/lib/features/manage_account/presentation/model/preferences/preferences_setting.dart new file mode 100644 index 000000000..eef33f8b9 --- /dev/null +++ b/lib/features/manage_account/presentation/model/preferences/preferences_setting.dart @@ -0,0 +1,61 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/spam_report_config.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/thread_detail_config.dart'; + +part 'preferences_setting.g.dart'; + +@JsonSerializable(explicitToJson: true) +class PreferencesSetting with EquatableMixin { + final ThreadDetailConfig threadDetail; + final SpamReportConfig spamReport; + + PreferencesSetting({ + required this.threadDetail, + required this.spamReport, + }); + + factory PreferencesSetting.initial() { + return PreferencesSetting( + threadDetail: ThreadDetailConfig.initial(), + spamReport: SpamReportConfig.initial(), + ); + } + + factory PreferencesSetting.fromJson(Map json) => + _$PreferencesSettingFromJson(json); + + Map toJson() => _$PreferencesSettingToJson(this); + + @override + List get props => [threadDetail, spamReport]; +} + +extension PreferencesSettingExtension on PreferencesSetting { + PreferencesSetting copyWith({ + ThreadDetailConfig? threadDetail, + SpamReportConfig? spamReport, + }) { + return PreferencesSetting( + threadDetail: threadDetail ?? this.threadDetail, + spamReport: spamReport ?? this.spamReport, + ); + } + + PreferencesSetting updateThreadDetail(bool enabled) { + return copyWith(threadDetail: threadDetail.copyWith(isEnabled: enabled)); + } + + PreferencesSetting updateSpamReport({ + bool? isEnabled, + int? lastTimeDismissedMilliseconds, + }) { + return copyWith( + spamReport: spamReport.copyWith( + isEnabled: isEnabled ?? spamReport.isEnabled, + lastTimeDismissedMilliseconds: lastTimeDismissedMilliseconds ?? + spamReport.lastTimeDismissedMilliseconds, + ), + ); + } +} diff --git a/lib/features/manage_account/presentation/model/preferences/spam_report_config.dart b/lib/features/manage_account/presentation/model/preferences/spam_report_config.dart new file mode 100644 index 000000000..5dcc49e17 --- /dev/null +++ b/lib/features/manage_account/presentation/model/preferences/spam_report_config.dart @@ -0,0 +1,47 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; + +part 'spam_report_config.g.dart'; + +@JsonSerializable() +class SpamReportConfig with EquatableMixin { + final bool isEnabled; + final int lastTimeDismissedMilliseconds; + + SpamReportConfig({ + this.isEnabled = true, + this.lastTimeDismissedMilliseconds = 0, + }); + + factory SpamReportConfig.initial() { + return SpamReportConfig( + isEnabled: true, + lastTimeDismissedMilliseconds: 0, + ); + } + + factory SpamReportConfig.fromJson(Map json) => + _$SpamReportConfigFromJson(json); + + Map toJson() => _$SpamReportConfigToJson(this); + + @override + List get props => [isEnabled, lastTimeDismissedMilliseconds]; +} + +extension SpamReportConfigExtension on SpamReportConfig { + SpamReportConfig copyWith({ + bool? isEnabled, + int? lastTimeDismissedMilliseconds, + }) { + return SpamReportConfig( + isEnabled: isEnabled ?? this.isEnabled, + lastTimeDismissedMilliseconds: + lastTimeDismissedMilliseconds ?? this.lastTimeDismissedMilliseconds, + ); + } + + SpamReportState get spamReportState => + isEnabled ? SpamReportState.enabled : SpamReportState.disabled; +} diff --git a/lib/features/manage_account/presentation/model/preferences/thread_detail_config.dart b/lib/features/manage_account/presentation/model/preferences/thread_detail_config.dart new file mode 100644 index 000000000..db8c63c17 --- /dev/null +++ b/lib/features/manage_account/presentation/model/preferences/thread_detail_config.dart @@ -0,0 +1,33 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'thread_detail_config.g.dart'; + +@JsonSerializable() +class ThreadDetailConfig with EquatableMixin { + final bool isEnabled; + + ThreadDetailConfig({this.isEnabled = false}); + + factory ThreadDetailConfig.initial() { + return ThreadDetailConfig( + isEnabled: false, + ); + } + + factory ThreadDetailConfig.fromJson(Map json) => + _$ThreadDetailConfigFromJson(json); + + Map toJson() => _$ThreadDetailConfigToJson(this); + + @override + List get props => [isEnabled]; +} + +extension ThreadDetailConfigExtension on ThreadDetailConfig { + ThreadDetailConfig copyWith({bool? isEnabled}) { + return ThreadDetailConfig( + isEnabled: isEnabled ?? this.isEnabled, + ); + } +} diff --git a/lib/features/manage_account/presentation/model/setting_option_type.dart b/lib/features/manage_account/presentation/model/preferences_option_type.dart similarity index 50% rename from lib/features/manage_account/presentation/model/setting_option_type.dart rename to lib/features/manage_account/presentation/model/preferences_option_type.dart index e7c44e801..24b9d2197 100644 --- a/lib/features/manage_account/presentation/model/setting_option_type.dart +++ b/lib/features/manage_account/presentation/model/preferences_option_type.dart @@ -1,66 +1,71 @@ import 'package:server_settings/server_settings/tmail_server_settings.dart'; import 'package:server_settings/server_settings/tmail_server_settings_extension.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/extensions/local_settings_map_extension.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_setting.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -enum SettingOptionType { - readReceipt, - senderPriority, - thread; +enum PreferencesOptionType { + readReceipt(isLocal: false), + senderPriority(isLocal: false), + thread(isLocal: true), + spamReport(isLocal: true); + + final bool isLocal; + + const PreferencesOptionType({required this.isLocal}); String getTitle(AppLocalizations appLocalizations) { switch(this) { - case SettingOptionType.readReceipt: + case PreferencesOptionType.readReceipt: return appLocalizations.emailReadReceipts; - case SettingOptionType.senderPriority: + case PreferencesOptionType.senderPriority: return appLocalizations.senderSetImportantFlag; - case SettingOptionType.thread: + case PreferencesOptionType.thread: return appLocalizations.thread; + case PreferencesOptionType.spamReport: + return appLocalizations.spamReports; } } String getExplanation(AppLocalizations appLocalizations) { switch(this) { - case SettingOptionType.readReceipt: + case PreferencesOptionType.readReceipt: return appLocalizations.emailReadReceiptsSettingExplanation; - case SettingOptionType.senderPriority: + case PreferencesOptionType.senderPriority: return appLocalizations.senderImportantSettingExplanation; - case SettingOptionType.thread: + case PreferencesOptionType.thread: return appLocalizations.threadSettingExplanation; + case PreferencesOptionType.spamReport: + return appLocalizations.spamReportsSettingExplanation; } } String getToggleDescription(AppLocalizations appLocalizations) { switch(this) { - case SettingOptionType.readReceipt: + case PreferencesOptionType.readReceipt: return appLocalizations.emailReadReceiptsToggleDescription; - case SettingOptionType.senderPriority: + case PreferencesOptionType.senderPriority: return appLocalizations.senderImportantSettingToggleDescription; - case SettingOptionType.thread: + case PreferencesOptionType.thread: return appLocalizations.threadToggleDescription; + case PreferencesOptionType.spamReport: + return appLocalizations.spamReportToggleDescription; } } bool isEnabled( TMailServerSettingOptions? settingOption, - Map localSettings, + PreferencesSetting preferencesSetting, ) { switch(this) { - case SettingOptionType.readReceipt: + case PreferencesOptionType.readReceipt: return settingOption?.isAlwaysReadReceipts ?? false; - case SettingOptionType.senderPriority: + case PreferencesOptionType.senderPriority: return settingOption?.isDisplaySenderPriority ?? false; - case SettingOptionType.thread: - return localSettings.threadDetailEnabled ?? false; + case PreferencesOptionType.thread: + return preferencesSetting.threadDetail.isEnabled; + case PreferencesOptionType.spamReport: + return preferencesSetting.spamReport.isEnabled; } } - - bool get isLocal { - return switch (this) { - thread => true, - _ => false, - }; - } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/preferences/bindings/preferences_interactors_bindings.dart b/lib/features/manage_account/presentation/preferences/bindings/preferences_interactors_bindings.dart index 2fa2a8b43..09dd63546 100644 --- a/lib/features/manage_account/presentation/preferences/bindings/preferences_interactors_bindings.dart +++ b/lib/features/manage_account/presentation/preferences/bindings/preferences_interactors_bindings.dart @@ -3,7 +3,7 @@ import 'package:tmail_ui_user/features/base/interactors_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/data/datasource/manage_account_datasource.dart'; import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/manage_account/data/repository/manage_account_repository_impl.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/save_language_interactor.dart'; @@ -43,7 +43,7 @@ class PreferencesInteractorsBindings extends InteractorsBindings { ), tag: composerId); Get.lazyPut(() => ManageAccountDataSourceImpl( Get.find(), - Get.find(), + Get.find(), Get.find(), ), tag: composerId); } diff --git a/lib/features/manage_account/presentation/preferences/preferences_controller.dart b/lib/features/manage_account/presentation/preferences/preferences_controller.dart index ae76147e9..dd8af8e1a 100644 --- a/lib/features/manage_account/presentation/preferences/preferences_controller.dart +++ b/lib/features/manage_account/presentation/preferences/preferences_controller.dart @@ -10,9 +10,8 @@ import 'package:tmail_ui_user/features/manage_account/domain/state/update_local_ import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_local_settings_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/update_local_settings_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/manage_account_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/setting_option_type.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences_option_type.dart'; import 'package:tmail_ui_user/features/server_settings/domain/state/get_server_setting_state.dart'; import 'package:tmail_ui_user/features/server_settings/domain/state/update_server_setting_state.dart'; import 'package:tmail_ui_user/features/server_settings/domain/usecases/get_server_setting_interactor.dart'; @@ -34,7 +33,7 @@ class PreferencesController extends BaseController { final UpdateLocalSettingsInteractor _updateLocalSettingsInteractor; final settingOption = Rxn(); - final localSettings = Rxn({}); + final localSettings = Rxn(); bool get isLoading => viewState.value.fold( (failure) => false, @@ -55,13 +54,9 @@ class PreferencesController extends BaseController { } else if (success is UpdateServerSettingSuccess) { _updateSettingOptionValue(newSettingOption: success.settingOption); } else if (success is GetLocalSettingsSuccess) { - _updateLocalSettingOptionValue( - newLocalSettings: success.localSettings, - ); + _updateLocalSettingOptionValue(success.preferencesRoot); } else if (success is UpdateLocalSettingsSuccess) { - _updateLocalSettingOptionValue( - newLocalSettings: success.localSettings, - ); + _updateLocalSettingOptionValue(success.preferencesRoot); } else { super.handleSuccessViewState(success); } @@ -90,49 +85,68 @@ class PreferencesController extends BaseController { settingOption.value = newSettingOption; } - void _updateLocalSettingOptionValue({ - required Map newLocalSettings - }) { - localSettings.value = newLocalSettings; + void _updateLocalSettingOptionValue(PreferencesRoot preferencesRoot) { + localSettings.value = preferencesRoot; } void _getSettingOption() { - consumeState(_getLocalSettingInteractor.execute(SupportedLocalSetting.values)); + consumeState(_getLocalSettingInteractor.execute()); final accountId = _manageAccountDashBoardController.accountId.value; if (accountId != null) { consumeState(_getServerSettingInteractor.execute(accountId)); } else { consumeState(Stream.value(Left(GetServerSettingFailure(NotFoundAccountIdException())))); - consumeState(Stream.value(Left(GetLocalSettingsFailure( - exception: NotFoundAccountIdException(), - )))); } } - void updateStateSettingOption(SettingOptionType optionType, bool isEnabled) { + void updateStateSettingOption( + PreferencesOptionType optionType, + bool isEnabled, + ) { if (optionType.isLocal) { - Map newLocalSettings = {}; - switch(optionType) { - case SettingOptionType.thread: - var currentLocalSettings = Map.from(localSettings.value ?? {}); - currentLocalSettings[SupportedLocalSetting.threadDetail] = LocalSettingOptions(setting: ThreadDetailLocalSettingDetail(!isEnabled)); - newLocalSettings = currentLocalSettings; - break; - default: - break; - } - consumeState(_updateLocalSettingsInteractor.execute(newLocalSettings)); - return; + _updateLocalPreferencesSetting(optionType, isEnabled); + } else { + _updateServerPreferencesSetting(optionType, isEnabled); + } + } + + void _updateLocalPreferencesSetting( + PreferencesOptionType optionType, + bool isEnabled, + ) { + PreferencesRoot? preferencesRoot; + switch(optionType) { + case PreferencesOptionType.thread: + preferencesRoot = localSettings.value?.updateThreadDetail( + !isEnabled, + ); + break; + case PreferencesOptionType.spamReport: + preferencesRoot = localSettings.value?.updateSpamReport( + isEnabled: !isEnabled, + ); + break; + default: + break; } + if (preferencesRoot != null) { + consumeState(_updateLocalSettingsInteractor.execute(preferencesRoot)); + } + } + + void _updateServerPreferencesSetting( + PreferencesOptionType optionType, + bool isEnabled, + ) { TMailServerSettingOptions? newSettingOption; switch(optionType) { - case SettingOptionType.readReceipt: + case PreferencesOptionType.readReceipt: newSettingOption = settingOption.value?.copyWith( alwaysReadReceipts: !isEnabled, ); break; - case SettingOptionType.senderPriority: + case PreferencesOptionType.senderPriority: newSettingOption = settingOption.value?.copyWith( displaySenderPriority: !isEnabled, ); @@ -143,12 +157,18 @@ class PreferencesController extends BaseController { final accountId = _manageAccountDashBoardController.accountId.value; if (accountId != null && newSettingOption != null) { - consumeState(_updateServerSettingInteractor.execute( - accountId, - newSettingOption, - )); + consumeState( + _updateServerSettingInteractor.execute( + accountId, + newSettingOption, + ), + ); } else { - consumeState(Stream.value(Left(UpdateServerSettingFailure(NotFoundAccountIdException())))); + consumeState( + Stream.value( + Left(UpdateServerSettingFailure(NotFoundAccountIdException())), + ), + ); } } } \ No newline at end of file diff --git a/lib/features/manage_account/presentation/preferences/preferences_view.dart b/lib/features/manage_account/presentation/preferences/preferences_view.dart index b205026fb..948fbf1d9 100644 --- a/lib/features/manage_account/presentation/preferences/preferences_view.dart +++ b/lib/features/manage_account/presentation/preferences/preferences_view.dart @@ -4,9 +4,9 @@ import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/base/setting_detail_view_builder.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/setting_option_type.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences_option_type.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/preferences/preferences_controller.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/preferences/widgets/setting_option_item.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/preferences/widgets/preferences_option_item.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/widgets/setting_header_widget.dart'; class PreferencesView extends GetWidget with AppLoaderMixin { @@ -57,31 +57,33 @@ class PreferencesView extends GetWidget with AppLoaderMix ), Obx(() { final settingOption = controller.settingOption.value; - final localSettingOption = controller.localSettings; + final localSettingOption = controller.localSettings.value; - if (settingOption == null && (localSettingOption.value?.isEmpty ?? true)) { + if (settingOption == null && localSettingOption == null) { return const SizedBox.shrink(); } final availableSettingOptions = [ - if (settingOption != null) ...SettingOptionType.values.where( - (optionType) => !optionType.isLocal, - ), - ...SettingOptionType.values.where( - (optionType) => optionType.isLocal, - ), + if (settingOption != null) + ...PreferencesOptionType.values.where( + (optionType) => !optionType.isLocal, + ), + if (localSettingOption != null) + ...PreferencesOptionType.values.where( + (optionType) => optionType.isLocal, + ), ]; return Expanded( child: ListView.separated( itemCount: availableSettingOptions.length, itemBuilder: (context, index) { - return SettingOptionItem( + return PreferencesOptionItem( imagePaths: controller.imagePaths, settingOption: settingOption, - localSettings: localSettingOption.value ?? {}, + preferencesSetting: localSettingOption!.setting, optionType: availableSettingOptions[index], - onTapSettingOptionAction: controller.updateStateSettingOption, + onTapPreferencesOptionAction: controller.updateStateSettingOption, ); }, separatorBuilder: (_, __) => const SizedBox(height: 49), diff --git a/lib/features/manage_account/presentation/preferences/widgets/setting_option_item.dart b/lib/features/manage_account/presentation/preferences/widgets/preferences_option_item.dart similarity index 73% rename from lib/features/manage_account/presentation/preferences/widgets/setting_option_item.dart rename to lib/features/manage_account/presentation/preferences/widgets/preferences_option_item.dart index 4d8faa380..ec3dc9f62 100644 --- a/lib/features/manage_account/presentation/preferences/widgets/setting_option_item.dart +++ b/lib/features/manage_account/presentation/preferences/widgets/preferences_option_item.dart @@ -6,25 +6,27 @@ import 'package:server_settings/server_settings/tmail_server_settings.dart'; import 'package:tmail_ui_user/features/base/widget/default_switch_icon_widget.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/setting_option_type.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_setting.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences_option_type.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -typedef OnTapSettingOptionAction = Function(SettingOptionType optionType, bool isEnabled); +typedef OnTapPreferencesOptionAction = Function(PreferencesOptionType optionType, bool isEnabled); -class SettingOptionItem extends StatelessWidget { +class PreferencesOptionItem extends StatelessWidget { final ImagePaths imagePaths; final TMailServerSettingOptions? settingOption; - final Map localSettings; - final SettingOptionType optionType; - final OnTapSettingOptionAction onTapSettingOptionAction; + final PreferencesSetting preferencesSetting; + final PreferencesOptionType optionType; + final OnTapPreferencesOptionAction onTapPreferencesOptionAction; - const SettingOptionItem({ + const PreferencesOptionItem({ super.key, required this.imagePaths, required this.settingOption, - required this.localSettings, + required this.preferencesSetting, required this.optionType, - required this.onTapSettingOptionAction, + required this.onTapPreferencesOptionAction, }); @override @@ -60,18 +62,18 @@ class SettingOptionItem extends StatelessWidget { children: [ InkWell( key: ValueKey(optionType.getTitle(appLocalizations)), - onTap: () => onTapSettingOptionAction( + onTap: () => onTapPreferencesOptionAction( optionType, - optionType.isEnabled(settingOption, localSettings), + optionType.isEnabled(settingOption, preferencesSetting), ), child: DefaultSwitchIconWidget( key: ValueKey( - optionType.isEnabled(settingOption, localSettings) + optionType.isEnabled(settingOption, preferencesSetting) ? 'setting_option_switch_on' : 'setting_option_switch_off', ), imagePaths: imagePaths, - isEnabled: optionType.isEnabled(settingOption, localSettings), + isEnabled: optionType.isEnabled(settingOption, preferencesSetting), ), ), const SizedBox(width: 12), diff --git a/lib/features/thread_detail/data/data_source/thread_detail_local_data_source_impl.dart b/lib/features/thread_detail/data/data_source/thread_detail_local_data_source_impl.dart index 657985587..fee379265 100644 --- a/lib/features/thread_detail/data/data_source/thread_detail_local_data_source_impl.dart +++ b/lib/features/thread_detail/data/data_source/thread_detail_local_data_source_impl.dart @@ -2,19 +2,17 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_detail/thread_detail_local_setting_detail.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/model/local_setting_options.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/thread_detail/data/data_source/thread_detail_data_source.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; class ThreadDetailLocalDataSourceImpl implements ThreadDetailDataSource { const ThreadDetailLocalDataSourceImpl( - this._localSettingCacheManager, + this._preferencesSettingManager, this._exceptionThrower, ); - final LocalSettingCacheManager _localSettingCacheManager; + final PreferencesSettingManager _preferencesSettingManager; final ExceptionThrower _exceptionThrower; @override @@ -30,10 +28,8 @@ class ThreadDetailLocalDataSourceImpl implements ThreadDetailDataSource { @override Future getThreadDetailStatus() { return Future.sync(() async { - final localSetting = await _localSettingCacheManager.get([ - SupportedLocalSetting.threadDetail, - ]); - return (localSetting[SupportedLocalSetting.threadDetail]?.setting as ThreadDetailLocalSettingDetail?)?.value ?? false; + final preferencesRoot = await _preferencesSettingManager.loadPreferences(); + return preferencesRoot.setting.spamReport.isEnabled; }).catchError(_exceptionThrower.throwException); } } \ No newline at end of file diff --git a/lib/features/thread_detail/presentation/thread_detail_bindings.dart b/lib/features/thread_detail/presentation/thread_detail_bindings.dart index 06474cddf..3a3884a0a 100644 --- a/lib/features/thread_detail/presentation/thread_detail_bindings.dart +++ b/lib/features/thread_detail/presentation/thread_detail_bindings.dart @@ -7,7 +7,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_i import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; import 'package:tmail_ui_user/features/thread_detail/data/data_source/thread_detail_data_source.dart'; @@ -57,7 +57,7 @@ class ThreadDetailBindings extends BaseBindings { Get.find(), )); Get.lazyPut(() => ThreadDetailLocalDataSourceImpl( - Get.find(), + Get.find(), Get.find(), )); } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 03f8e9f34..823827c72 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4851,5 +4851,23 @@ "placeholders": { "keyword": {} } + }, + "spamReports": "Spam reports", + "@spamReports": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "spamReportsSettingExplanation": "Reminds you that you need to moderate your spam emails recurringly", + "@spamReportsSettingExplanation": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "spamReportToggleDescription": "Enable spam report", + "@spamReportToggleDescription": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/bindings/local/local_bindings.dart b/lib/main/bindings/local/local_bindings.dart index 96fb5decc..5d9fd1ea1 100644 --- a/lib/main/bindings/local/local_bindings.dart +++ b/lib/main/bindings/local/local_bindings.dart @@ -34,9 +34,8 @@ import 'package:tmail_ui_user/features/login/data/local/token_oidc_cache_manager import 'package:tmail_ui_user/features/mailbox/data/local/mailbox_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox/data/local/state_cache_manager.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_sort_order_manager.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/data/local/local_spam_report_manager.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/data/local/local_setting_cache_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/preferences_setting_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_manager.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/new_email_cache_worker_queue.dart'; import 'package:tmail_ui_user/features/offline_mode/manager/opened_email_cache_manager.dart'; @@ -77,7 +76,7 @@ class LocalBindings extends Bindings { Get.put(OidcConfigurationCacheClient()); Get.put(OidcConfigurationCacheManager(Get.find(), Get.find())); Get.put(LanguageCacheManager(Get.find())); - Get.put(LocalSettingCacheManager(Get.find())); + Get.put(PreferencesSettingManager(Get.find())); Get.put(RecentLoginUrlCacheClient()); Get.put(RecentLoginUrlCacheManager((Get.find()))); Get.put(RecentLoginUsernameCacheClient()); @@ -94,7 +93,6 @@ class LocalBindings extends Bindings { Get.put(SendingEmailCacheManager(Get.find())); Get.put(SessionHiveCacheClient()); Get.put(SessionCacheManager(Get.find())); - Get.put(LocalSpamReportManager(Get.find())); Get.put(LocalSortOrderManager(Get.find())); Get.put(CachingManager( Get.find(), @@ -111,7 +109,6 @@ class LocalBindings extends Bindings { Get.find(), Get.find(), Get.find(), - Get.find(), Get.find(), Get.find(), Get.find(), diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index d06012b68..d805d397a 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -5124,4 +5124,25 @@ class AppLocalizations { args: [keyword], ); } + + String get spamReports { + return Intl.message( + 'Spam reports', + name: 'spamReports', + ); + } + + String get spamReportsSettingExplanation { + return Intl.message( + 'Reminds you that you need to moderate your spam emails recurringly', + name: 'spamReportsSettingExplanation', + ); + } + + String get spamReportToggleDescription { + return Intl.message( + 'Enable spam report', + name: 'spamReportToggleDescription', + ); + } }