TF-3769 Enable toggle thread detail feature in setting

TF-3769 Thread Detail fallback to single email when get thread fails

TF-3769 Thread Detail fix font height thread

TF-3769 Thread Detail init with get status

TF-3769 Thread Detail fix font height email receiver and sender

TF-3769 Thread Detail refactor reset thread detail ui action UpdatedThreadDetailSettingAction

TF-3769 Thread Detail refresh settings on app lifecycle changed

TF-3769 Thread Detail fix font height email receiver and sender

TF-3769 Thread Detail fix scroll view exception of single email

TF-3769 Thread Detail refactor local setting

TF-3769 Thread Detail optimize get cache setting

TF-3769 Thread Detail fix font height email receiver

TF-3769 Thread Detail refactor local setting cache

TF-3769 Thread Detail fix font height email receiver and sender

TF-3769 Thread Detail use CacheExceptionThrower for ManageAccountDataSourceImpl

TF-3769 Thread Detail fix changing email in tablet view

TF-3769 Thread Detail refresh on setting changed

TF-3769 Thread Detail fix receiver alignments

TF-3769 Thread Detail fix receiver alignments

TF-3769 Thread Detail default setting enabled

TF-3769 Thread Detail fix font style email receiver and sender

TF-3769 Thread Detail fix toggle setting when responsive

TF-3769 Thread Detail adjust receive time position when single email

TF-3769 Thread Detail revert initializeThreadDetailEmails to void

TF-3769 Thread Detail fix CI on initializeThreadDetailEmails test

TF-3769 Thread Detail fix spacing email sender

TF-3769 Thread Detail update receiver color mobile

TF-3769 Thread Detail update collapsed preview letter spacing

TF-3769 Thread Detail update receiver color mobile

TF-3769 Thread Detail fix receive time position

TF-3769 Thread Detail add mark read button mobile collapsed email

TF-3769 Thread Detail fix font style email receiver and sender

TF-3769 Thread Detail update collapsed preview font weight

TF-3769 Thread Detail fix position email receiver and sender
This commit is contained in:
DatDang
2025-05-29 17:07:44 +07:00
committed by Dat H. Pham
parent c9ca3925cb
commit 1bc45e35f3
57 changed files with 830 additions and 165 deletions
@@ -0,0 +1,6 @@
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<SupportedLocalSetting, LocalSettingOptions?> {
bool? get threadDetailEnabled => (this[SupportedLocalSetting.threadDetail]?.setting as ThreadDetailLocalSettingDetail?)?.value;
}
@@ -1,15 +1,16 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/base_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/data/datasource/preferences_datasource.dart';
import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/preferences_datasource_impl.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/repository/preferences_repository_impl.dart';
import 'package:tmail_ui_user/features/manage_account/domain/repository/preferences_repository.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/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/manage_account_dashboard_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/menu/manage_account_menu_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings/settings_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_bindings.dart';
import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart';
import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart';
class ManageAccountDashBoardBindings extends BaseBindings {
@@ -28,14 +29,15 @@ class ManageAccountDashBoardBindings extends BaseBindings {
@override
void bindingsDataSource() {
Get.lazyPut<PreferencesDataSource>(() => Get.find<PreferencesDataSourceImpl>());
Get.lazyPut<ManageAccountDataSource>(() => Get.find<ManageAccountDataSourceImpl>());
}
@override
void bindingsDataSourceImpl() {
Get.lazyPut(() => PreferencesDataSourceImpl(
Get.lazyPut(() => ManageAccountDataSourceImpl(
Get.find<LanguageCacheManager>(),
Get.find<RemoteExceptionThrower>()));
Get.find<LocalSettingCacheManager>(),
Get.find<CacheExceptionThrower>()));
}
@override
@@ -43,11 +45,11 @@ class ManageAccountDashBoardBindings extends BaseBindings {
@override
void bindingsRepository() {
Get.lazyPut<PreferencesRepository>(() => Get.find<PreferencesRepositoryImpl>());
Get.lazyPut<ManageAccountRepository>(() => Get.find<ManageAccountRepositoryImpl>());
}
@override
void bindingsRepositoryImpl() {
Get.lazyPut(() => PreferencesRepositoryImpl(Get.find<PreferencesDataSource>()));
Get.lazyPut(() => ManageAccountRepositoryImpl(Get.find<ManageAccountDataSource>()));
}
}
@@ -0,0 +1,32 @@
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<T> extends Equatable {
const LocalSettingDetail(this.value);
final T value;
Map<String, dynamic> toJson();
}
class LocalSettingDetailConverter extends JsonConverter<LocalSettingDetail, Map<String, dynamic>> {
const LocalSettingDetailConverter();
@override
LocalSettingDetail fromJson(Map<String, dynamic> json) {
final type = json['type'] as String?;
if (type == SupportedLocalSetting.threadDetail.name) {
return ThreadDetailLocalSettingDetail.fromJson(json);
}
throw UnimplementedError();
}
@override
Map<String, dynamic> toJson(LocalSettingDetail object) {
return object.toJson();
}
}
@@ -0,0 +1,24 @@
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<bool> {
const ThreadDetailLocalSettingDetail(
super.value, [
this.type = SupportedLocalSetting.threadDetail,
]);
@JsonKey(defaultValue: SupportedLocalSetting.threadDetail)
final SupportedLocalSetting type;
factory ThreadDetailLocalSettingDetail.fromJson(Map<String, dynamic> json) =>
_$ThreadDetailLocalSettingDetailFromJson(json);
@override
Map<String, dynamic> toJson() => _$ThreadDetailLocalSettingDetailToJson(this);
@override
List<Object?> get props => [value, type];
}
@@ -0,0 +1,26 @@
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<String, dynamic> json) =>
_$LocalSettingOptionsFromJson(json);
Map<String, dynamic> toJson() => _$LocalSettingOptionsToJson(this);
@override
List<Object?> get props => [setting];
}
@@ -1,11 +1,14 @@
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/main/localizations/app_localizations.dart';
enum SettingOptionType {
readReceipt,
senderPriority;
senderPriority,
thread;
String getTitle(AppLocalizations appLocalizations) {
switch(this) {
@@ -13,6 +16,8 @@ enum SettingOptionType {
return appLocalizations.emailReadReceipts;
case SettingOptionType.senderPriority:
return appLocalizations.senderSetImportantFlag;
case SettingOptionType.thread:
return appLocalizations.thread;
}
}
@@ -22,6 +27,8 @@ enum SettingOptionType {
return appLocalizations.emailReadReceiptsSettingExplanation;
case SettingOptionType.senderPriority:
return appLocalizations.senderImportantSettingExplanation;
case SettingOptionType.thread:
return appLocalizations.threadSettingExplanation;
}
}
@@ -31,15 +38,29 @@ enum SettingOptionType {
return appLocalizations.emailReadReceiptsToggleDescription;
case SettingOptionType.senderPriority:
return appLocalizations.senderImportantSettingToggleDescription;
case SettingOptionType.thread:
return appLocalizations.threadToggleDescription;
}
}
bool isEnabled(TMailServerSettingOptions settingOption) {
bool isEnabled(
TMailServerSettingOptions? settingOption,
Map<SupportedLocalSetting, LocalSettingOptions?> localSettings,
) {
switch(this) {
case SettingOptionType.readReceipt:
return settingOption.isAlwaysReadReceipts;
return settingOption?.isAlwaysReadReceipts ?? false;
case SettingOptionType.senderPriority:
return settingOption.isDisplaySenderPriority;
return settingOption?.isDisplaySenderPriority ?? false;
case SettingOptionType.thread:
return localSettings.threadDetailEnabled ?? true;
}
}
bool get isLocal {
return switch (this) {
thread => true,
_ => false,
};
}
}
@@ -1,4 +1,7 @@
import 'package:get/get.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/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/preferences/bindings/preferences_interactors_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/preferences/preferences_controller.dart';
import 'package:tmail_ui_user/features/server_settings/domain/usecases/get_server_setting_interactor.dart';
@@ -13,6 +16,15 @@ class PreferencesBindings extends Bindings {
Get.lazyPut(() => PreferencesController(
Get.find<GetServerSettingInteractor>(),
Get.find<UpdateServerSettingInteractor>(),
Get.find<GetLocalSettingsInteractor>(),
Get.find<UpdateLocalSettingsInteractor>(),
));
Get.lazyPut(() => GetLocalSettingsInteractor(
Get.find<ManageAccountRepository>(),
));
Get.lazyPut(() => UpdateLocalSettingsInteractor(
Get.find<ManageAccountRepository>(),
));
}
}
@@ -1,10 +1,11 @@
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/interactors_bindings.dart';
import 'package:tmail_ui_user/features/manage_account/data/datasource/preferences_datasource.dart';
import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/preferences_datasource_impl.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/repository/preferences_repository_impl.dart';
import 'package:tmail_ui_user/features/manage_account/domain/repository/preferences_repository.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/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';
import 'package:tmail_ui_user/features/server_settings/data/datasource/server_settings_data_source.dart';
import 'package:tmail_ui_user/features/server_settings/data/datasource_impl/remote_server_settings_data_source_impl.dart';
@@ -28,8 +29,8 @@ class PreferencesInteractorsBindings extends InteractorsBindings {
() => Get.find<RemoteServerSettingsDataSourceImpl>(tag: composerId),
tag: composerId,
);
Get.lazyPut<PreferencesDataSource>(
() => Get.find<PreferencesDataSourceImpl>(tag: composerId),
Get.lazyPut<ManageAccountDataSource>(
() => Get.find<ManageAccountDataSourceImpl>(tag: composerId),
tag: composerId,
);
}
@@ -40,8 +41,9 @@ class PreferencesInteractorsBindings extends InteractorsBindings {
Get.find<ServerSettingsAPI>(),
Get.find<RemoteExceptionThrower>(),
), tag: composerId);
Get.lazyPut(() => PreferencesDataSourceImpl(
Get.lazyPut(() => ManageAccountDataSourceImpl(
Get.find<LanguageCacheManager>(),
Get.find<LocalSettingCacheManager>(),
Get.find<CacheExceptionThrower>(),
), tag: composerId);
}
@@ -57,7 +59,7 @@ class PreferencesInteractorsBindings extends InteractorsBindings {
tag: composerId,
);
Get.lazyPut(
() => SaveLanguageInteractor(Get.find<PreferencesRepository>(tag: composerId)),
() => SaveLanguageInteractor(Get.find<ManageAccountRepository>(tag: composerId)),
tag: composerId,
);
}
@@ -68,8 +70,8 @@ class PreferencesInteractorsBindings extends InteractorsBindings {
() => Get.find<ServerSettingsRepositoryImpl>(tag: composerId),
tag: composerId,
);
Get.lazyPut<PreferencesRepository>(
() => Get.find<PreferencesRepositoryImpl>(tag: composerId),
Get.lazyPut<ManageAccountRepository>(
() => Get.find<ManageAccountRepositoryImpl>(tag: composerId),
tag: composerId,
);
}
@@ -81,7 +83,7 @@ class PreferencesInteractorsBindings extends InteractorsBindings {
tag: composerId,
);
Get.lazyPut(
() => PreferencesRepositoryImpl(Get.find<PreferencesDataSource>(tag: composerId)),
() => ManageAccountRepositoryImpl(Get.find<ManageAccountDataSource>(tag: composerId)),
tag: composerId,
);
}
@@ -94,10 +96,10 @@ class PreferencesInteractorsBindings extends InteractorsBindings {
Get.delete<UpdateServerSettingInteractor>(tag: composerId);
Get.delete<GetServerSettingInteractor>(tag: composerId);
Get.delete<PreferencesDataSourceImpl>(tag: composerId);
Get.delete<PreferencesDataSource>(tag: composerId);
Get.delete<PreferencesRepositoryImpl>(tag: composerId);
Get.delete<PreferencesRepository>(tag: composerId);
Get.delete<ManageAccountDataSourceImpl>(tag: composerId);
Get.delete<ManageAccountDataSource>(tag: composerId);
Get.delete<ManageAccountRepositoryImpl>(tag: composerId);
Get.delete<ManageAccountRepository>(tag: composerId);
Get.delete<SaveLanguageInteractor>(tag: composerId);
}
}
@@ -5,7 +5,13 @@ 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/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/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/server_settings/domain/state/get_server_setting_state.dart';
import 'package:tmail_ui_user/features/server_settings/domain/state/update_server_setting_state.dart';
@@ -18,12 +24,17 @@ class PreferencesController extends BaseController {
PreferencesController(
this._getServerSettingInteractor,
this._updateServerSettingInteractor,
this._getLocalSettingInteractor,
this._updateLocalSettingsInteractor,
);
final GetServerSettingInteractor _getServerSettingInteractor;
final UpdateServerSettingInteractor _updateServerSettingInteractor;
final GetLocalSettingsInteractor _getLocalSettingInteractor;
final UpdateLocalSettingsInteractor _updateLocalSettingsInteractor;
final settingOption = Rxn<TMailServerSettingOptions>();
final localSettings = Rxn(<SupportedLocalSetting, LocalSettingOptions?>{});
bool get isLoading => viewState.value.fold(
(failure) => false,
@@ -43,6 +54,14 @@ class PreferencesController extends BaseController {
_updateSettingOptionValue(newSettingOption: success.settingOption);
} else if (success is UpdateServerSettingSuccess) {
_updateSettingOptionValue(newSettingOption: success.settingOption);
} else if (success is GetLocalSettingsSuccess) {
_updateLocalSettingOptionValue(
newLocalSettings: success.localSettings,
);
} else if (success is UpdateLocalSettingsSuccess) {
_updateLocalSettingOptionValue(
newLocalSettings: success.localSettings,
);
} else {
super.handleSuccessViewState(success);
}
@@ -71,16 +90,41 @@ class PreferencesController extends BaseController {
settingOption.value = newSettingOption;
}
void _updateLocalSettingOptionValue({
required Map<SupportedLocalSetting, LocalSettingOptions?> newLocalSettings
}) {
localSettings.value = newLocalSettings;
}
void _getSettingOption() {
consumeState(_getLocalSettingInteractor.execute(SupportedLocalSetting.values));
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) {
if (optionType.isLocal) {
Map<SupportedLocalSetting, LocalSettingOptions?> newLocalSettings = {};
switch(optionType) {
case SettingOptionType.thread:
var currentLocalSettings = Map<SupportedLocalSetting, LocalSettingOptions?>.from(localSettings.value ?? {});
currentLocalSettings[SupportedLocalSetting.threadDetail] = LocalSettingOptions(setting: ThreadDetailLocalSettingDetail(!isEnabled));
newLocalSettings = currentLocalSettings;
break;
default:
break;
}
consumeState(_updateLocalSettingsInteractor.execute(newLocalSettings));
return;
}
TMailServerSettingOptions? newSettingOption;
switch(optionType) {
case SettingOptionType.readReceipt:
@@ -57,19 +57,30 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
),
Obx(() {
final settingOption = controller.settingOption.value;
final localSettingOption = controller.localSettings;
if (settingOption == null) return const SizedBox.shrink();
if (settingOption == null && (localSettingOption.value?.isEmpty ?? true)) {
return const SizedBox.shrink();
}
final settingOptionList = SettingOptionType.values.toList();
final availableSettingOptions = [
if (settingOption != null) ...SettingOptionType.values.where(
(optionType) => !optionType.isLocal,
),
...SettingOptionType.values.where(
(optionType) => optionType.isLocal,
),
];
return Expanded(
child: ListView.separated(
itemCount: settingOptionList.length,
itemCount: availableSettingOptions.length,
itemBuilder: (context, index) {
return SettingOptionItem(
imagePaths: controller.imagePaths,
settingOption: settingOption,
optionType: settingOptionList[index],
localSettings: localSettingOption.value ?? {},
optionType: availableSettingOptions[index],
onTapSettingOptionAction: controller.updateStateSettingOption,
);
},
@@ -4,6 +4,7 @@ import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:server_settings/server_settings/tmail_server_settings.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/main/localizations/app_localizations.dart';
@@ -12,7 +13,8 @@ typedef OnTapSettingOptionAction = Function(SettingOptionType optionType, bool i
class SettingOptionItem extends StatelessWidget {
final ImagePaths imagePaths;
final TMailServerSettingOptions settingOption;
final TMailServerSettingOptions? settingOption;
final Map<SupportedLocalSetting, LocalSettingOptions?> localSettings;
final SettingOptionType optionType;
final OnTapSettingOptionAction onTapSettingOptionAction;
@@ -20,6 +22,7 @@ class SettingOptionItem extends StatelessWidget {
super.key,
required this.imagePaths,
required this.settingOption,
required this.localSettings,
required this.optionType,
required this.onTapSettingOptionAction,
});
@@ -58,10 +61,10 @@ class SettingOptionItem extends StatelessWidget {
InkWell(
onTap: () => onTapSettingOptionAction(
optionType,
optionType.isEnabled(settingOption),
optionType.isEnabled(settingOption, localSettings),
),
child: SvgPicture.asset(
optionType.isEnabled(settingOption)
optionType.isEnabled(settingOption, localSettings)
? imagePaths.icSwitchOn
: imagePaths.icSwitchOff,
fit: BoxFit.fill,