TF-3977 Separate settings keys for easier in conflict

This commit is contained in:
dab246
2025-09-09 11:12:57 +07:00
committed by Dat H. Pham
parent 7fdfb97fc5
commit 5a88f3c36f
27 changed files with 290 additions and 206 deletions
@@ -8,7 +8,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/data/datasource/spam_re
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/features/manage_account/domain/model/preferences/spam_report_config.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
class LocalSpamReportDataSourceImpl extends SpamReportDataSource {
@@ -23,8 +23,7 @@ class LocalSpamReportDataSourceImpl extends SpamReportDataSource {
@override
Future<DateTime> getLastTimeDismissedSpamReported() async {
return Future.sync(() async {
final spamReportConfig =
await _preferencesSettingManager.getSpamReportConfig();
final spamReportConfig = await _preferencesSettingManager.getSpamReportConfig();
return DateTime.fromMillisecondsSinceEpoch(
spamReportConfig.lastTimeDismissedMilliseconds,
);
@@ -19,7 +19,7 @@ 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/features/mailbox_dashboard/presentation/model/loader_status.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
class SpamReportController extends BaseController {
@@ -32,7 +32,7 @@ class SpamReportController extends BaseController {
final spamReportState = Rx<SpamReportState>(SpamReportState.enabled);
AppLifecycleListener? _appLifecycleListener;
SpamReportLoaderStatus _spamReportLoaderStatus = SpamReportLoaderStatus.idle;
LoaderStatus _spamReportLoaderStatus = LoaderStatus.idle;
SpamReportController(
this._storeSpamReportInteractor,
@@ -46,7 +46,7 @@ class SpamReportController extends BaseController {
super.onInit();
_appLifecycleListener ??= AppLifecycleListener(
onResume: () {
if (_spamReportLoaderStatus == SpamReportLoaderStatus.loading) {
if (_spamReportLoaderStatus == LoaderStatus.loading) {
return;
}
getSpamReportStateAction();
@@ -59,7 +59,7 @@ class SpamReportController extends BaseController {
if (success is StoreLastTimeDismissedSpamReportSuccess) {
presentationSpamMailbox.value = null;
} else if (success is GetSpamReportStateLoading) {
_spamReportLoaderStatus = SpamReportLoaderStatus.loading;
_spamReportLoaderStatus = LoaderStatus.loading;
} else if (success is GetSpamReportStateSuccess) {
_loadSpamReportConfigSuccess(success.spamReportState);
} else if (success is StoreSpamReportStateSuccess) {
@@ -77,7 +77,7 @@ class SpamReportController extends BaseController {
if (failure is GetSpamMailboxCachedFailure) {
presentationSpamMailbox.value = null;
} else if (failure is GetSpamReportStateFailure) {
_spamReportLoaderStatus = SpamReportLoaderStatus.completed;
_spamReportLoaderStatus = LoaderStatus.completed;
} else {
super.handleFailureViewState(failure);
}
@@ -86,12 +86,12 @@ class SpamReportController extends BaseController {
@override
void handleErrorViewState(Object error, StackTrace stackTrace) {
super.handleErrorViewState(error, stackTrace);
_spamReportLoaderStatus = SpamReportLoaderStatus.completed;
_spamReportLoaderStatus = LoaderStatus.completed;
}
void _loadSpamReportConfigSuccess(SpamReportState newState) {
spamReportState.value = newState;
_spamReportLoaderStatus = SpamReportLoaderStatus.completed;
_spamReportLoaderStatus = LoaderStatus.completed;
getBinding<MailboxDashBoardController>()?.refreshSpamReportBanner();
}
@@ -0,0 +1 @@
enum LoaderStatus { idle, loading, completed }
@@ -1 +0,0 @@
enum SpamReportLoaderStatus { idle, loading, completed }
@@ -1,11 +1,12 @@
import 'dart:ui';
import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
abstract class ManageAccountDataSource {
Future<void> persistLanguage(Locale localeCurrent);
Future<void> updateLocalSettings(PreferencesRoot preferencesRoot);
Future<PreferencesSetting> toggleLocalSettingsState(PreferencesConfig preferencesConfig);
Future<PreferencesRoot> getLocalSettings();
}
Future<PreferencesSetting> getLocalSettings();
}
@@ -3,7 +3,10 @@ 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/preferences_setting_manager.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/spam_report_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/thread_detail_config.dart';
import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart';
class ManageAccountDataSourceImpl extends ManageAccountDataSource {
@@ -26,14 +29,27 @@ class ManageAccountDataSourceImpl extends ManageAccountDataSource {
}
@override
Future<void> updateLocalSettings(PreferencesRoot preferencesRoot) {
Future<PreferencesSetting> toggleLocalSettingsState(PreferencesConfig preferencesConfig) {
return Future.sync(() async {
return await _preferencesSettingManager.savePreferences(preferencesRoot);
if (preferencesConfig is ThreadDetailConfig) {
await _preferencesSettingManager.updateThread(
preferencesConfig.isEnabled,
);
} else if (preferencesConfig is SpamReportConfig) {
await _preferencesSettingManager.updateSpamReport(
isEnabled: preferencesConfig.isEnabled,
);
} else {
await _preferencesSettingManager.savePreferences(
preferencesConfig,
);
}
return await _preferencesSettingManager.loadPreferences();
}).catchError(_exceptionThrower.throwException);
}
@override
Future<PreferencesRoot> getLocalSettings() {
Future<PreferencesSetting> getLocalSettings() {
return Future.sync(() async {
return await _preferencesSettingManager.loadPreferences();
}).catchError(_exceptionThrower.throwException);
@@ -1,55 +1,113 @@
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';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/default_preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/empty_preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/spam_report_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/thread_detail_config.dart';
class PreferencesSettingManager {
static const String _preferencesSettingKey = 'PREFERENCES_SETTING';
static const String _preferencesSettingThreadKey =
'${_preferencesSettingKey}_THREAD';
static const String _preferencesSettingSpamReportKey =
'${_preferencesSettingKey}_SPAM_REPORT';
const PreferencesSettingManager(this._sharedPreferences);
final SharedPreferences _sharedPreferences;
Future<PreferencesRoot> loadPreferences() async {
Future<PreferencesSetting> loadPreferences() async {
await _sharedPreferences.reload();
final jsonString = _sharedPreferences.getString(_preferencesSettingKey);
final keys = _sharedPreferences.getKeys();
final preferencesKeys =
keys.where((key) => key.startsWith(_preferencesSettingKey)).toList();
if (jsonString != null) {
return PreferencesRoot.fromJson(jsonDecode(jsonString));
final listConfigs = preferencesKeys.map((key) {
final jsonString = _sharedPreferences.getString(key);
if (jsonString != null) {
final jsonDecoded = jsonDecode(jsonString);
switch (key) {
case _preferencesSettingThreadKey:
return ThreadDetailConfig.fromJson(jsonDecoded);
case _preferencesSettingSpamReportKey:
return SpamReportConfig.fromJson(jsonDecoded);
default:
return DefaultPreferencesConfig.fromJson(jsonDecoded);
}
}
return EmptyPreferencesConfig();
}).toList();
if (listConfigs.isEmpty) {
return PreferencesSetting.initial();
}
return PreferencesRoot.initial();
return PreferencesSetting(listConfigs);
}
Future<void> savePreferences(PreferencesRoot root) async {
await _sharedPreferences.setString(
_preferencesSettingKey,
jsonEncode(root.toJson()),
);
Future<void> savePreferences(PreferencesConfig config) async {
if (config is ThreadDetailConfig) {
await _sharedPreferences.setString(
_preferencesSettingThreadKey,
jsonEncode(config.toJson()),
);
} else if (config is SpamReportConfig) {
await _sharedPreferences.setString(
_preferencesSettingSpamReportKey,
jsonEncode(config.toJson()),
);
} else {
await _sharedPreferences.setString(
_preferencesSettingKey,
jsonEncode(config.toJson()),
);
}
}
Future<void> updateThread(bool enabled) async {
final current = await loadPreferences();
final updated = current.updateThreadDetail(enabled);
await savePreferences(updated);
Future<void> updateThread(bool isEnabled) async {
final currentConfig = await getThreadConfig();
final updatedConfig = currentConfig.copyWith(isEnabled: isEnabled);
await savePreferences(updatedConfig);
}
Future<void> updateSpamReport({
bool? isEnabled,
int? lastTimeDismissedMilliseconds,
}) async {
final current = await loadPreferences();
final updated = current.updateSpamReport(
final currentConfig = await getSpamReportConfig();
final updatedConfig = currentConfig.copyWith(
isEnabled: isEnabled,
lastTimeDismissedMilliseconds: lastTimeDismissedMilliseconds,
);
await savePreferences(updated);
await savePreferences(updatedConfig);
}
Future<SpamReportConfig> getSpamReportConfig() async {
final preferences = await loadPreferences();
return preferences.setting.spamReport;
await _sharedPreferences.reload();
final jsonString = _sharedPreferences.getString(
_preferencesSettingSpamReportKey,
);
return jsonString == null
? SpamReportConfig.initial()
: SpamReportConfig.fromJson(jsonDecode(jsonString));
}
Future<ThreadDetailConfig> getThreadConfig() async {
await _sharedPreferences.reload();
final jsonString = _sharedPreferences.getString(
_preferencesSettingThreadKey,
);
return jsonString == null
? ThreadDetailConfig.initial()
: ThreadDetailConfig.fromJson(jsonDecode(jsonString));
}
}
@@ -1,8 +1,9 @@
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/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.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/preferences/preferences_root.dart';
class ManageAccountRepositoryImpl extends ManageAccountRepository {
@@ -16,12 +17,12 @@ class ManageAccountRepositoryImpl extends ManageAccountRepository {
}
@override
Future<void> updateLocalSettings(PreferencesRoot preferencesRoot) {
return dataSource.updateLocalSettings(preferencesRoot);
Future<PreferencesSetting> toggleLocalSettingsState(PreferencesConfig preferencesConfig) {
return dataSource.toggleLocalSettingsState(preferencesConfig);
}
@override
Future<PreferencesRoot> getLocalSettings() {
Future<PreferencesSetting> getLocalSettings() {
return dataSource.getLocalSettings();
}
}
@@ -0,0 +1,18 @@
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/converters/default_preferences_config_converter.dart';
class DefaultPreferencesConfig extends PreferencesConfig {
final dynamic data;
DefaultPreferencesConfig(this.data);
factory DefaultPreferencesConfig.fromJson(Map<String, dynamic> json) =>
const DefaultPreferencesConfigConverter().fromJson(json);
@override
Map<String, dynamic> toJson() =>
const DefaultPreferencesConfigConverter().toJson(this);
@override
List<Object?> get props => [data];
}
@@ -0,0 +1,9 @@
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
class EmptyPreferencesConfig extends PreferencesConfig {
@override
List<Object?> get props => [];
@override
Map<String, dynamic> toJson() => {};
}
@@ -0,0 +1,9 @@
import 'package:equatable/equatable.dart';
abstract class PreferencesConfig with EquatableMixin {
Map<String, dynamic> toJson();
@override
List<Object?> get props => [];
}
@@ -0,0 +1,41 @@
import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/spam_report_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/thread_detail_config.dart';
class PreferencesSetting with EquatableMixin {
final List<PreferencesConfig> configs;
PreferencesSetting(this.configs);
factory PreferencesSetting.initial() {
return PreferencesSetting([
ThreadDetailConfig.initial(),
SpamReportConfig.initial(),
]);
}
ThreadDetailConfig get threadConfig {
final threadConfig =
configs.firstWhereOrNull((config) => config is ThreadDetailConfig);
if (threadConfig != null) {
return threadConfig as ThreadDetailConfig;
} else {
return ThreadDetailConfig.initial();
}
}
SpamReportConfig get spamReportConfig {
final spamConfig =
configs.firstWhereOrNull((config) => config is SpamReportConfig);
if (spamConfig != null) {
return spamConfig as SpamReportConfig;
} else {
return SpamReportConfig.initial();
}
}
@override
List<Object?> get props => [configs];
}
@@ -1,11 +1,11 @@
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';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
part 'spam_report_config.g.dart';
@JsonSerializable()
class SpamReportConfig with EquatableMixin {
class SpamReportConfig extends PreferencesConfig {
final bool isEnabled;
final int lastTimeDismissedMilliseconds;
@@ -24,6 +24,7 @@ class SpamReportConfig with EquatableMixin {
factory SpamReportConfig.fromJson(Map<String, dynamic> json) =>
_$SpamReportConfigFromJson(json);
@override
Map<String, dynamic> toJson() => _$SpamReportConfigToJson(this);
@override
@@ -1,10 +1,10 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
part 'thread_detail_config.g.dart';
@JsonSerializable()
class ThreadDetailConfig with EquatableMixin {
class ThreadDetailConfig extends PreferencesConfig {
final bool isEnabled;
ThreadDetailConfig({this.isEnabled = false});
@@ -18,6 +18,7 @@ class ThreadDetailConfig with EquatableMixin {
factory ThreadDetailConfig.fromJson(Map<String, dynamic> json) =>
_$ThreadDetailConfigFromJson(json);
@override
Map<String, dynamic> toJson() => _$ThreadDetailConfigToJson(this);
@override
@@ -1,11 +1,12 @@
import 'dart:ui';
import 'package:tmail_ui_user/features/manage_account/presentation/model/preferences/preferences_root.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
abstract class ManageAccountRepository {
Future<void> persistLanguage(Locale localeCurrent);
Future<void> updateLocalSettings(PreferencesRoot preferencesRoot);
Future<PreferencesSetting> toggleLocalSettingsState(PreferencesConfig preferencesConfig);
Future<PreferencesRoot> getLocalSettings();
Future<PreferencesSetting> getLocalSettings();
}
@@ -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/preferences/preferences_root.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
class GettingLocalSettingsState extends LoadingState {}
class GetLocalSettingsSuccess extends UIState {
GetLocalSettingsSuccess(this.preferencesRoot);
GetLocalSettingsSuccess(this.preferencesSetting);
final PreferencesRoot preferencesRoot;
final PreferencesSetting preferencesSetting;
@override
List<Object?> get props => [preferencesRoot];
List<Object?> get props => [preferencesSetting];
}
class GetLocalSettingsFailure extends FeatureFailure {
@@ -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/preferences/preferences_root.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
class UpdatingLocalSettingsState extends LoadingState {}
class UpdateLocalSettingsSuccess extends UIState {
final PreferencesRoot preferencesRoot;
final PreferencesSetting preferencesSetting;
UpdateLocalSettingsSuccess(this.preferencesRoot);
UpdateLocalSettingsSuccess(this.preferencesSetting);
@override
List<Object?> get props => [preferencesRoot];
List<Object?> get props => [preferencesSetting];
}
class UpdateLocalSettingsFailure extends FeatureFailure {
@@ -1,6 +1,5 @@
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: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';
@@ -16,7 +15,6 @@ class GetLocalSettingsInteractor {
final result = await _manageAccountRepository.getLocalSettings();
yield Right(GetLocalSettingsSuccess(result));
} catch (e) {
logError('$runtimeType::execute(): exception: $e');
yield Left(GetLocalSettingsFailure(exception: e));
}
}
@@ -1,25 +1,23 @@
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:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.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/preferences/preferences_root.dart';
class UpdateLocalSettingsInteractor {
const UpdateLocalSettingsInteractor(this._manageAccountRepository);
final ManageAccountRepository _manageAccountRepository;
Stream<Either<Failure, Success>> execute(
PreferencesRoot preferencesRoot,
) async* {
Stream<Either<Failure, Success>> execute(PreferencesConfig preferencesConfig) async* {
try {
yield Right(UpdatingLocalSettingsState());
await _manageAccountRepository.updateLocalSettings(preferencesRoot);
yield Right(UpdateLocalSettingsSuccess(preferencesRoot));
final preferencesSetting = await _manageAccountRepository.toggleLocalSettingsState(
preferencesConfig,
);
yield Right(UpdateLocalSettingsSuccess(preferencesSetting));
} catch (e) {
logError('$runtimeType::execute(): exception: $e');
yield Left(UpdateLocalSettingsFailure(exception: e));
}
}
@@ -0,0 +1,14 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/default_preferences_config.dart';
class DefaultPreferencesConfigConverter
implements JsonConverter<DefaultPreferencesConfig, Map<String, dynamic>> {
const DefaultPreferencesConfigConverter();
@override
DefaultPreferencesConfig fromJson(Map<String, dynamic> json) =>
DefaultPreferencesConfig(json);
@override
Map<String, dynamic> toJson(DefaultPreferencesConfig config) => config.data;
}
@@ -1,50 +0,0 @@
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<String, dynamic> json) =>
_$PreferencesRootFromJson(json);
Map<String, dynamic> toJson() => _$PreferencesRootToJson(this);
@override
List<Object?> 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,
),
);
}
}
@@ -1,61 +0,0 @@
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<String, dynamic> json) =>
_$PreferencesSettingFromJson(json);
Map<String, dynamic> toJson() => _$PreferencesSettingToJson(this);
@override
List<Object?> 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,
),
);
}
}
@@ -1,7 +1,7 @@
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/model/preferences/preferences_setting.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum PreferencesOptionType {
@@ -63,9 +63,9 @@ enum PreferencesOptionType {
case PreferencesOptionType.senderPriority:
return settingOption?.isDisplaySenderPriority ?? false;
case PreferencesOptionType.thread:
return preferencesSetting.threadDetail.isEnabled;
return preferencesSetting.threadConfig.isEnabled;
case PreferencesOptionType.spamReport:
return preferencesSetting.spamReport.isEnabled;
return preferencesSetting.spamReportConfig.isEnabled;
}
}
}
@@ -1,16 +1,21 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:server_settings/server_settings/tmail_server_settings.dart';
import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/loader_status.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/preferences_setting.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/spam_report_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/thread_detail_config.dart';
import 'package:tmail_ui_user/features/manage_account/domain/state/get_local_settings_state.dart';
import 'package:tmail_ui_user/features/manage_account/domain/state/update_local_settings_state.dart';
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/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';
@@ -33,7 +38,10 @@ class PreferencesController extends BaseController {
final UpdateLocalSettingsInteractor _updateLocalSettingsInteractor;
final settingOption = Rxn<TMailServerSettingOptions>();
final localSettings = Rxn<PreferencesRoot>();
final localSettings = Rx<PreferencesSetting>(PreferencesSetting.initial());
AppLifecycleListener? _appLifecycleListener;
LoaderStatus _localSettingLoaderStatus = LoaderStatus.idle;
bool get isLoading => viewState.value.fold(
(failure) => false,
@@ -45,6 +53,15 @@ class PreferencesController extends BaseController {
void onInit() {
super.onInit();
_getSettingOption();
_appLifecycleListener ??= AppLifecycleListener(
onResume: () {
if (_localSettingLoaderStatus == LoaderStatus.loading) {
return;
}
consumeState(_getLocalSettingInteractor.execute());
},
);
}
@override
@@ -54,9 +71,12 @@ class PreferencesController extends BaseController {
} else if (success is UpdateServerSettingSuccess) {
_updateSettingOptionValue(newSettingOption: success.settingOption);
} else if (success is GetLocalSettingsSuccess) {
_updateLocalSettingOptionValue(success.preferencesRoot);
_localSettingLoaderStatus = LoaderStatus.completed;
_updateLocalSettingOptionValue(success.preferencesSetting);
} else if (success is UpdateLocalSettingsSuccess) {
_updateLocalSettingOptionValue(success.preferencesRoot);
_updateLocalSettingOptionValue(success.preferencesSetting);
} else if (success is GettingLocalSettingsState) {
_localSettingLoaderStatus = LoaderStatus.loading;
} else {
super.handleSuccessViewState(success);
}
@@ -66,6 +86,8 @@ class PreferencesController extends BaseController {
void handleFailureViewState(Failure failure) {
if (failure is GetServerSettingFailure) {
_updateSettingOptionValue(newSettingOption: null);
} else if (failure is GetLocalSettingsFailure) {
_localSettingLoaderStatus = LoaderStatus.completed;
} else if (failure is UpdateServerSettingFailure) {
_handleUpdateServerSettingFailure();
} else {
@@ -73,6 +95,12 @@ class PreferencesController extends BaseController {
}
}
@override
void handleErrorViewState(Object error, StackTrace stackTrace) {
super.handleErrorViewState(error, stackTrace);
_localSettingLoaderStatus = LoaderStatus.completed;
}
void _handleUpdateServerSettingFailure() {
if (currentOverlayContext != null && currentContext != null) {
appToast.showToastErrorMessage(
@@ -85,8 +113,8 @@ class PreferencesController extends BaseController {
settingOption.value = newSettingOption;
}
void _updateLocalSettingOptionValue(PreferencesRoot preferencesRoot) {
localSettings.value = preferencesRoot;
void _updateLocalSettingOptionValue(PreferencesSetting preferencesSetting) {
localSettings.value = preferencesSetting;
}
void _getSettingOption() {
@@ -114,24 +142,20 @@ class PreferencesController extends BaseController {
PreferencesOptionType optionType,
bool isEnabled,
) {
PreferencesRoot? preferencesRoot;
PreferencesConfig? config;
switch(optionType) {
case PreferencesOptionType.thread:
preferencesRoot = localSettings.value?.updateThreadDetail(
!isEnabled,
);
config = ThreadDetailConfig(isEnabled: !isEnabled);
break;
case PreferencesOptionType.spamReport:
preferencesRoot = localSettings.value?.updateSpamReport(
isEnabled: !isEnabled,
);
config = SpamReportConfig(isEnabled: !isEnabled);
break;
default:
break;
}
if (preferencesRoot != null) {
consumeState(_updateLocalSettingsInteractor.execute(preferencesRoot));
if (config != null) {
consumeState(_updateLocalSettingsInteractor.execute(config));
}
}
@@ -171,4 +195,11 @@ class PreferencesController extends BaseController {
);
}
}
@override
void onClose() {
_appLifecycleListener?.dispose();
super.onClose();
}
}
@@ -59,7 +59,8 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
final settingOption = controller.settingOption.value;
final localSettingOption = controller.localSettings.value;
if (settingOption == null && localSettingOption == null) {
if (settingOption == null &&
localSettingOption.configs.isEmpty) {
return const SizedBox.shrink();
}
@@ -68,7 +69,7 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
...PreferencesOptionType.values.where(
(optionType) => !optionType.isLocal,
),
if (localSettingOption != null)
if (localSettingOption.configs.isNotEmpty)
...PreferencesOptionType.values.where(
(optionType) => optionType.isLocal,
),
@@ -81,7 +82,7 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
return PreferencesOptionItem(
imagePaths: controller.imagePaths,
settingOption: settingOption,
preferencesSetting: localSettingOption!.setting,
preferencesSetting: localSettingOption,
optionType: availableSettingOptions[index],
onTapPreferencesOptionAction: controller.updateStateSettingOption,
);
@@ -4,9 +4,7 @@ import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
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/domain/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';
@@ -28,8 +28,8 @@ class ThreadDetailLocalDataSourceImpl implements ThreadDetailDataSource {
@override
Future<bool> getThreadDetailStatus() {
return Future.sync(() async {
final preferencesRoot = await _preferencesSettingManager.loadPreferences();
return preferencesRoot.setting.threadDetail.isEnabled;
final threadConfig = await _preferencesSettingManager.getThreadConfig();
return threadConfig.isEnabled;
}).catchError(_exceptionThrower.throwException);
}
}