From d43ea33200d03c34bf3d6ce561da375a7500f6f2 Mon Sep 17 00:00:00 2001 From: ngthailam98 Date: Wed, 14 Feb 2024 16:38:52 +0700 Subject: [PATCH] [Issue#69] Update Preference page UI + clean up preference code reduce boilerplat --- .../account_preference_local_data_source.dart | 44 ++-- .../entity/account_preference_entity.dart | 81 +------ .../entity/account_preference_entity.g.dart | 84 +------ .../repository/account_pref_repo_impl.dart | 18 +- lib/domain/model/account_preference.dart | 82 ++----- lib/domain/model/account_preference.g.dart | 8 +- lib/domain/repository/account_pref_repo.dart | 2 +- .../account_preference_use_case.dart | 22 +- lib/initializer/app_router.dart | 7 + lib/main.dart | 13 +- .../auth/data/repo/auth_repo_impl.dart | 3 +- .../page/gateway/bloc/gateway_bloc.dart | 2 +- .../page/info/list/info_page.dart | 4 +- .../page/password/list/password_page.dart | 11 +- .../preferences/bloc/preferences_event.dart | 2 +- .../page/preferences/preferences_page.dart | 225 ++++++++---------- .../pref_item_choose_language_widget.dart | 26 +- .../widget/pref_item_switch_widget.dart | 10 +- .../widget/pref_item_widget_factory.dart | 4 +- 19 files changed, 226 insertions(+), 422 deletions(-) diff --git a/lib/data/datasource/account_preference_local_data_source.dart b/lib/data/datasource/account_preference_local_data_source.dart index 546a2aa..4a38ffd 100644 --- a/lib/data/datasource/account_preference_local_data_source.dart +++ b/lib/data/datasource/account_preference_local_data_source.dart @@ -34,32 +34,26 @@ class AccountPreferenceLocalDataSourceImpl @override Future getAccountPrefs() async { final sharedPrefs = await _prefs; - _allowSearchAccName = - sharedPrefs.getBool(AccountPreferenceEntity.keyAllowSearchAccName) ?? - AccountPreference.allowSearchAccNameDefault; + return AccountPreferenceEntity( - requireLogin: - sharedPrefs.getBool(AccountPreferenceEntity.keyRequireLogin) ?? - AccountPreference.requireLoginDefault, - enableDarkMode: - sharedPrefs.getBool(AccountPreferenceEntity.keyEnableDarkMode) ?? - AccountPreference.enableDarkModeDefault, - languageCode: - sharedPrefs.getString(AccountPreferenceEntity.keyLanguageCode) ?? - AccountPreference.languageCodeDefault, - showAccName: - sharedPrefs.getBool(AccountPreferenceEntity.keyShowAccName) ?? - AccountPreference.showAccountNameDefault, - allowSearchAccName: _allowSearchAccName, - requirePassOnForeground: sharedPrefs - .getBool(AccountPreferenceEntity.keyRequirePassOnForeground) ?? - AccountPreference.requirePassOnForeground); + items: AppPreferenceEnum.values + .map((e) => AccountPreferenceItem( + name: e, value: getOrDefault(sharedPrefs, e))) + .toList(), + ); + } + + dynamic getOrDefault( + SharedPreferences sharedPref, + AppPreferenceEnum prefEnum, + ) { + return sharedPref.get(prefEnum.name) ?? prefEnum.defaultValue; } @override Future saveRequireLogin(bool require) async { final sharedPrefs = await _prefs; - sharedPrefs.setBool(AccountPreferenceEntity.keyRequireLogin, require); + sharedPrefs.setBool(AppPreferenceEnum.requireReLogin.name, require); } @override @@ -71,32 +65,32 @@ class AccountPreferenceLocalDataSourceImpl @override Future enableDarkMode(bool enable) async { final sharedPrefs = await _prefs; - sharedPrefs.setBool(AccountPreferenceEntity.keyEnableDarkMode, enable); + sharedPrefs.setBool(AppPreferenceEnum.enableDarkMode.name, enable); } @override Future setLanguageCode(String value) async { final sharedPrefs = await _prefs; - sharedPrefs.setString(AccountPreferenceEntity.keyLanguageCode, value); + sharedPrefs.setString(AppPreferenceEnum.languageCode.name, value); } @override Future saveShowAccName(bool value) async { final sharedPrefs = await _prefs; - sharedPrefs.setBool(AccountPreferenceEntity.keyShowAccName, value); + sharedPrefs.setBool(AppPreferenceEnum.showAccName.name, value); } @override Future saveRequirePassOnForeground(bool value) async { final sharedPrefs = await _prefs; - sharedPrefs.setBool(AccountPreferenceEntity.keyRequirePassOnForeground, value); + sharedPrefs.setBool(AppPreferenceEnum.requirePassOnForeground.name, value); } @override Future saveAllowSearchAccName(bool value) async { final sharedPrefs = await _prefs; _allowSearchAccName = value; - sharedPrefs.setBool(AccountPreferenceEntity.keyAllowSearchAccName, value); + sharedPrefs.setBool(AppPreferenceEnum.allowSearchAccName.name, value); } @override diff --git a/lib/data/entity/account_preference_entity.dart b/lib/data/entity/account_preference_entity.dart index 909c968..46468db 100644 --- a/lib/data/entity/account_preference_entity.dart +++ b/lib/data/entity/account_preference_entity.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:copy_with_extension/copy_with_extension.dart'; import 'package:flutter_password_saver/domain/model/account_preference.dart'; @@ -5,80 +6,18 @@ part 'account_preference_entity.g.dart'; @CopyWith() class AccountPreferenceEntity { - static const keyRequireLogin = 'requireLogin'; - static const keyEnableDarkMode = 'enableDarkMode'; - static const keyLanguageCode = 'languageCode'; - static const keyShowAccName = 'showAccName'; - static const keyRequirePassOnForeground = 'requirePassOnForeground'; - static const keyAllowSearchAccName = 'allowSearchAccName'; - AccountPreferenceEntity({ - required this.requireLogin, - required this.enableDarkMode, - required this.languageCode, - required this.showAccName, - required this.allowSearchAccName, - required this.requirePassOnForeground, + required this.items, }); - final bool requireLogin; - final bool enableDarkMode; - final String languageCode; - final bool showAccName; - final bool allowSearchAccName; - final bool requirePassOnForeground; + final List items; - factory AccountPreferenceEntity.fromAccountPreference( - AccountPreference preference) { - return AccountPreferenceEntity( - // Require login - requireLogin: preference.getItemValue(PreferenceName.requirePass) ?? - AccountPreference.requireLoginDefault, - // Dark mode - enableDarkMode: preference.getItemValue(PreferenceName.enableDarkMode) ?? - AccountPreference.enableDarkModeDefault, - // Language code - languageCode: preference.getItemValue(PreferenceName.languageCode) ?? - AccountPreference.languageCodeDefault, - // Show acc name always - showAccName: preference.getItemValue(PreferenceName.showAccName) ?? - AccountPreference.showAccountNameDefault, - // Allow user to search account name too - allowSearchAccName: - preference.getItemValue(PreferenceName.allowSearchAccName) ?? - AccountPreference.allowSearchAccNameDefault, - requirePassOnForeground: - preference.getItemValue(PreferenceName.requirePassOnForeground) ?? - AccountPreference.requirePassOnForeground, - ); - } + AccountPreference toModel() => AccountPreference(items: items); - AccountPreference toModel() => AccountPreference( - items: [ - AccountPreferenceItem( - name: PreferenceName.requirePass, - value: requireLogin, - ), - AccountPreferenceItem( - name: PreferenceName.enableDarkMode, - value: enableDarkMode, - ), - AccountPreferenceItem( - name: PreferenceName.languageCode, - value: languageCode, - ), - AccountPreferenceItem( - name: PreferenceName.showAccName, - value: showAccName, - ), - AccountPreferenceItem( - name: PreferenceName.allowSearchAccName, - value: allowSearchAccName, - ), - AccountPreferenceItem( - name: PreferenceName.requirePassOnForeground, - value: requirePassOnForeground, - ), - ], - ); + dynamic getItemValue(AppPreferenceEnum prefEnum) { + return items + .firstWhereOrNull((element) => element.name == prefEnum) + ?.value ?? + prefEnum.defaultValue; + } } diff --git a/lib/data/entity/account_preference_entity.g.dart b/lib/data/entity/account_preference_entity.g.dart index c1defd6..9b34862 100644 --- a/lib/data/entity/account_preference_entity.g.dart +++ b/lib/data/entity/account_preference_entity.g.dart @@ -7,17 +7,7 @@ part of 'account_preference_entity.dart'; // ************************************************************************** abstract class _$AccountPreferenceEntityCWProxy { - AccountPreferenceEntity allowSearchAccName(bool allowSearchAccName); - - AccountPreferenceEntity enableDarkMode(bool enableDarkMode); - - AccountPreferenceEntity languageCode(String languageCode); - - AccountPreferenceEntity requireLogin(bool requireLogin); - - AccountPreferenceEntity requirePassOnForeground(bool requirePassOnForeground); - - AccountPreferenceEntity showAccName(bool showAccName); + AccountPreferenceEntity items(List items); /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `AccountPreferenceEntity(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. /// @@ -26,12 +16,7 @@ abstract class _$AccountPreferenceEntityCWProxy { /// AccountPreferenceEntity(...).copyWith(id: 12, name: "My name") /// ```` AccountPreferenceEntity call({ - bool? allowSearchAccName, - bool? enableDarkMode, - String? languageCode, - bool? requireLogin, - bool? requirePassOnForeground, - bool? showAccName, + List? items, }); } @@ -43,29 +28,8 @@ class _$AccountPreferenceEntityCWProxyImpl const _$AccountPreferenceEntityCWProxyImpl(this._value); @override - AccountPreferenceEntity allowSearchAccName(bool allowSearchAccName) => - this(allowSearchAccName: allowSearchAccName); - - @override - AccountPreferenceEntity enableDarkMode(bool enableDarkMode) => - this(enableDarkMode: enableDarkMode); - - @override - AccountPreferenceEntity languageCode(String languageCode) => - this(languageCode: languageCode); - - @override - AccountPreferenceEntity requireLogin(bool requireLogin) => - this(requireLogin: requireLogin); - - @override - AccountPreferenceEntity requirePassOnForeground( - bool requirePassOnForeground) => - this(requirePassOnForeground: requirePassOnForeground); - - @override - AccountPreferenceEntity showAccName(bool showAccName) => - this(showAccName: showAccName); + AccountPreferenceEntity items(List items) => + this(items: items); @override @@ -76,45 +40,13 @@ class _$AccountPreferenceEntityCWProxyImpl /// AccountPreferenceEntity(...).copyWith(id: 12, name: "My name") /// ```` AccountPreferenceEntity call({ - Object? allowSearchAccName = const $CopyWithPlaceholder(), - Object? enableDarkMode = const $CopyWithPlaceholder(), - Object? languageCode = const $CopyWithPlaceholder(), - Object? requireLogin = const $CopyWithPlaceholder(), - Object? requirePassOnForeground = const $CopyWithPlaceholder(), - Object? showAccName = const $CopyWithPlaceholder(), + Object? items = const $CopyWithPlaceholder(), }) { return AccountPreferenceEntity( - allowSearchAccName: allowSearchAccName == const $CopyWithPlaceholder() || - allowSearchAccName == null - ? _value.allowSearchAccName - // ignore: cast_nullable_to_non_nullable - : allowSearchAccName as bool, - enableDarkMode: enableDarkMode == const $CopyWithPlaceholder() || - enableDarkMode == null - ? _value.enableDarkMode + items: items == const $CopyWithPlaceholder() || items == null + ? _value.items // ignore: cast_nullable_to_non_nullable - : enableDarkMode as bool, - languageCode: - languageCode == const $CopyWithPlaceholder() || languageCode == null - ? _value.languageCode - // ignore: cast_nullable_to_non_nullable - : languageCode as String, - requireLogin: - requireLogin == const $CopyWithPlaceholder() || requireLogin == null - ? _value.requireLogin - // ignore: cast_nullable_to_non_nullable - : requireLogin as bool, - requirePassOnForeground: - requirePassOnForeground == const $CopyWithPlaceholder() || - requirePassOnForeground == null - ? _value.requirePassOnForeground - // ignore: cast_nullable_to_non_nullable - : requirePassOnForeground as bool, - showAccName: - showAccName == const $CopyWithPlaceholder() || showAccName == null - ? _value.showAccName - // ignore: cast_nullable_to_non_nullable - : showAccName as bool, + : items as List, ); } } diff --git a/lib/data/repository/account_pref_repo_impl.dart b/lib/data/repository/account_pref_repo_impl.dart index 9c613ff..1422f5d 100644 --- a/lib/data/repository/account_pref_repo_impl.dart +++ b/lib/data/repository/account_pref_repo_impl.dart @@ -19,23 +19,25 @@ class AccountPrefRepoImpl extends AccountPrefRepo { } @override - Future saveAccountPreference( - {required PreferenceName name, required value}) { + Future saveAccountPreference({ + required AppPreferenceEnum name, + required value, + }) { switch (name) { - case PreferenceName.requirePass: + case AppPreferenceEnum.requireReLogin: return _accountPreferenceLocalDataSource .saveRequireLogin(value as bool); - case PreferenceName.enableDarkMode: + case AppPreferenceEnum.enableDarkMode: return _accountPreferenceLocalDataSource.enableDarkMode(value as bool); - case PreferenceName.languageCode: + case AppPreferenceEnum.languageCode: return _accountPreferenceLocalDataSource .setLanguageCode(value as String); - case PreferenceName.showAccName: + case AppPreferenceEnum.showAccName: return _accountPreferenceLocalDataSource.saveShowAccName(value as bool); - case PreferenceName.allowSearchAccName: + case AppPreferenceEnum.allowSearchAccName: return _accountPreferenceLocalDataSource .saveAllowSearchAccName(value as bool); - case PreferenceName.requirePassOnForeground: + case AppPreferenceEnum.requirePassOnForeground: return _accountPreferenceLocalDataSource .saveRequirePassOnForeground(value as bool); default: diff --git a/lib/domain/model/account_preference.dart b/lib/domain/model/account_preference.dart index f2294eb..cef931d 100644 --- a/lib/domain/model/account_preference.dart +++ b/lib/domain/model/account_preference.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:copy_with_extension/copy_with_extension.dart'; import 'package:equatable/equatable.dart'; @@ -5,86 +6,41 @@ part 'account_preference.g.dart'; @CopyWith() class AccountPreference extends Equatable { - static const requireLoginDefault = true; - static const enableDarkModeDefault = false; - static const languageCodeDefault = 'en'; - static const showAccountNameDefault = true; - static const allowSearchAccNameDefault = true; - static const requirePassOnForeground = true; - - const AccountPreference({this.items = defaultPrefItems}); + const AccountPreference({required this.items}); final List items; - static const List defaultPrefItems = [ - AccountPreferenceItem( - name: PreferenceName.requirePass, - value: requireLoginDefault, - ), - AccountPreferenceItem( - name: PreferenceName.enableDarkMode, - value: enableDarkModeDefault, - ), - AccountPreferenceItem( - name: PreferenceName.languageCode, - value: languageCodeDefault, - ), - AccountPreferenceItem( - name: PreferenceName.showAccName, - value: showAccountNameDefault, - ), - AccountPreferenceItem( - name: PreferenceName.allowSearchAccName, - value: allowSearchAccNameDefault, - ), - AccountPreferenceItem( - name: PreferenceName.requirePassOnForeground, - value: requirePassOnForeground, - ), - ]; - - AccountPreference copyWithNewItem(AccountPreferenceItem item) { - final itemIdx = items.indexWhere((element) => element.name == item.name); - - List newPrefItems = items; - if (itemIdx == -1) { - newPrefItems.add(item); - } else { - newPrefItems[itemIdx] = item; - } - - return copyWith(items: newPrefItems); - } - - AccountPreferenceItem? getItemByName(PreferenceName name) { - final matchingItems = items.where((element) => element.name == name); - return matchingItems.isEmpty ? null : matchingItems.first; - } - - dynamic getItemValue(PreferenceName name) { - return getItemByName(name)?.value; + dynamic getItemValue(AppPreferenceEnum prefEnum) { + return items + .firstWhereOrNull((element) => element.name == prefEnum) + ?.value ?? + prefEnum.defaultValue; } @override List get props => [items]; } -enum PreferenceName { +enum AppPreferenceEnum { // If app require password when user open app from closed to foreground - requirePass, - enableDarkMode, - languageCode, - showAccName, - allowSearchAccName, + requireReLogin(defaultValue: true), + enableDarkMode(defaultValue: false), + languageCode(defaultValue: 'en'), + showAccName(defaultValue: true), + allowSearchAccName(defaultValue: true), // If app require password when user open app from background to foreground - requirePassOnForeground, + requirePassOnForeground(defaultValue: true); + + final dynamic defaultValue; + + const AppPreferenceEnum({required this.defaultValue}); } @CopyWith() class AccountPreferenceItem extends Equatable { const AccountPreferenceItem({required this.name, this.value}); - final PreferenceName name; + final AppPreferenceEnum name; final dynamic value; @override diff --git a/lib/domain/model/account_preference.g.dart b/lib/domain/model/account_preference.g.dart index 7e7a5f2..83e18be 100644 --- a/lib/domain/model/account_preference.g.dart +++ b/lib/domain/model/account_preference.g.dart @@ -58,7 +58,7 @@ extension $AccountPreferenceCopyWith on AccountPreference { } abstract class _$AccountPreferenceItemCWProxy { - AccountPreferenceItem name(PreferenceName name); + AccountPreferenceItem name(AppPreferenceEnum name); AccountPreferenceItem value(dynamic value); @@ -69,7 +69,7 @@ abstract class _$AccountPreferenceItemCWProxy { /// AccountPreferenceItem(...).copyWith(id: 12, name: "My name") /// ```` AccountPreferenceItem call({ - PreferenceName? name, + AppPreferenceEnum? name, dynamic? value, }); } @@ -82,7 +82,7 @@ class _$AccountPreferenceItemCWProxyImpl const _$AccountPreferenceItemCWProxyImpl(this._value); @override - AccountPreferenceItem name(PreferenceName name) => this(name: name); + AccountPreferenceItem name(AppPreferenceEnum name) => this(name: name); @override AccountPreferenceItem value(dynamic value) => this(value: value); @@ -103,7 +103,7 @@ class _$AccountPreferenceItemCWProxyImpl name: name == const $CopyWithPlaceholder() || name == null ? _value.name // ignore: cast_nullable_to_non_nullable - : name as PreferenceName, + : name as AppPreferenceEnum, value: value == const $CopyWithPlaceholder() || value == null ? _value.value // ignore: cast_nullable_to_non_nullable diff --git a/lib/domain/repository/account_pref_repo.dart b/lib/domain/repository/account_pref_repo.dart index d60d6ea..7b06d5a 100644 --- a/lib/domain/repository/account_pref_repo.dart +++ b/lib/domain/repository/account_pref_repo.dart @@ -4,7 +4,7 @@ abstract class AccountPrefRepo { Future getAccountPrefs(); Future saveAccountPreference({ - required PreferenceName name, + required AppPreferenceEnum name, required dynamic value, }); } diff --git a/lib/domain/usecase/preference/account_preference_use_case.dart b/lib/domain/usecase/preference/account_preference_use_case.dart index 09a4ba0..80379c4 100644 --- a/lib/domain/usecase/preference/account_preference_use_case.dart +++ b/lib/domain/usecase/preference/account_preference_use_case.dart @@ -12,21 +12,18 @@ class AccountPreferenceUseCase { return _accountPrefRepo.getAccountPrefs(); } - Future getIsDarkModeEnabled() { - return getAccountPrefs().then((value) { - return value.getItemByName(PreferenceName.enableDarkMode)?.value ?? - AccountPreference.enableDarkModeDefault; - }); + Future getIsDarkModeEnabled() async { + final prefs = await getAccountPrefs(); + return prefs.getItemValue(AppPreferenceEnum.enableDarkMode) as bool; } Future getIsRequirePassOnForeground() async { final prefs = await getAccountPrefs(); - return prefs.getItemValue(PreferenceName.requirePassOnForeground) ?? - AccountPreference.requirePassOnForeground; + return prefs.getItemValue(AppPreferenceEnum.requirePassOnForeground) as bool; } Future saveAccountPreference({ - required PreferenceName name, + required AppPreferenceEnum name, required dynamic value, }) { return _accountPrefRepo.saveAccountPreference( @@ -35,11 +32,8 @@ class AccountPreferenceUseCase { ); } - Future getLanguageCode() { - return getAccountPrefs().then((value) { - final prefItemValue = - value.getItemByName(PreferenceName.languageCode)?.value; - return prefItemValue ?? AccountPreference.languageCodeDefault; - }); + Future getLanguageCode() async { + final prefs = await getAccountPrefs(); + return prefs.getItemValue(AppPreferenceEnum.languageCode) as String; } } diff --git a/lib/initializer/app_router.dart b/lib/initializer/app_router.dart index 9ae5e7a..780c316 100644 --- a/lib/initializer/app_router.dart +++ b/lib/initializer/app_router.dart @@ -8,6 +8,7 @@ import 'package:flutter_password_saver/presentation/page/home/home_page.dart'; import 'package:flutter_password_saver/presentation/page/info/save/save_info_page.dart'; import 'package:flutter_password_saver/presentation/page/password/create/password_save_page.dart'; import 'package:flutter_password_saver/presentation/page/password/list/password_page.dart'; +import 'package:flutter_password_saver/presentation/page/preferences/preferences_page.dart'; import 'package:flutter_password_saver/presentation/page/update_password/update_password_page.dart'; class AppRouter { @@ -20,6 +21,7 @@ class AppRouter { static const String forgetPassword = 'password/forget'; static const String updatePassword = 'account/password/update'; static const String saveInfo = 'info/save'; + static const String preference = 'preference'; // Route after gateway or login or register static const String initialRoute = home; @@ -61,6 +63,11 @@ class AppRouter { settings: settings, builder: (context) => SaveInfoPage(arg: arg), ); + case preference: + return MaterialPageRoute( + settings: settings, + builder: (context) => const PreferencesPage(), + ); default: return null; } diff --git a/lib/main.dart b/lib/main.dart index a16a55f..af23ffc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -66,21 +66,22 @@ class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); static final ValueNotifier themeNotifier = ValueNotifier( - AccountPreference.enableDarkModeDefault - ? ThemeMode.dark - : ThemeMode.light); + AppPreferenceEnum.enableDarkMode.defaultValue + ? ThemeMode.dark + : ThemeMode.light, + ); static final ValueNotifier languageCodeNotifier = - ValueNotifier(AccountPreference.languageCodeDefault); + ValueNotifier(AppPreferenceEnum.languageCode.defaultValue); static void resetDefaultTheme() { - themeNotifier.value = AccountPreference.enableDarkModeDefault + themeNotifier.value = AppPreferenceEnum.enableDarkMode.defaultValue ? ThemeMode.dark : ThemeMode.light; } static void resetDefaultLanguage() { - languageCodeNotifier.value = AccountPreference.languageCodeDefault; + languageCodeNotifier.value = AppPreferenceEnum.languageCode.defaultValue; } @override diff --git a/lib/modules/auth/data/repo/auth_repo_impl.dart b/lib/modules/auth/data/repo/auth_repo_impl.dart index 7de8dc0..10f6551 100644 --- a/lib/modules/auth/data/repo/auth_repo_impl.dart +++ b/lib/modules/auth/data/repo/auth_repo_impl.dart @@ -1,4 +1,5 @@ import 'package:flutter_password_saver/data/datasource/account_preference_local_data_source.dart'; +import 'package:flutter_password_saver/domain/model/account_preference.dart'; import 'package:flutter_password_saver/modules/auth/data/datasource/auth_local_data_source.dart'; import 'package:flutter_password_saver/data/datasource/auth_login_lock_data_source.dart'; import 'package:flutter_password_saver/data/datasource/biometric_data_source.dart'; @@ -110,7 +111,7 @@ class AuthRepoitoryImpl extends AuthRepository { Future isNeedLogin() async { final pref = await _accountPreferenceLocalDataSource.getAccountPrefs(); if (isLoggedIn()) return false; - return pref.requireLogin; + return pref.getItemValue(AppPreferenceEnum.requireReLogin) as bool; } @override diff --git a/lib/presentation/page/gateway/bloc/gateway_bloc.dart b/lib/presentation/page/gateway/bloc/gateway_bloc.dart index d85d45f..543a815 100644 --- a/lib/presentation/page/gateway/bloc/gateway_bloc.dart +++ b/lib/presentation/page/gateway/bloc/gateway_bloc.dart @@ -31,7 +31,7 @@ class GatewayBloc extends Bloc { if (result != null) { // user is registered final pref = await _accountPreferenceUseCase.getAccountPrefs(); - if (pref.getItemByName(PreferenceName.requirePass)?.value == false) { + if (pref.getItemValue(AppPreferenceEnum.requireReLogin) == false) { destinationRouteName = AppRouter.initialRoute; } else { destinationRouteName = AppRouter.login; diff --git a/lib/presentation/page/info/list/info_page.dart b/lib/presentation/page/info/list/info_page.dart index 63f8bc3..4cc8064 100644 --- a/lib/presentation/page/info/list/info_page.dart +++ b/lib/presentation/page/info/list/info_page.dart @@ -9,7 +9,6 @@ import 'package:flutter_password_saver/presentation/page/info/list/bloc/info_blo import 'package:flutter_password_saver/presentation/page/info/list/bloc/info_events.dart'; import 'package:flutter_password_saver/presentation/page/info/list/bloc/info_state.dart'; import 'package:flutter_password_saver/presentation/page/info/list/widgets/info_list_item.dart'; -import 'package:flutter_password_saver/presentation/page/preferences/preferences_page.dart'; import 'package:flutter_password_saver/presentation/utils/load_state.dart'; import 'package:flutter_password_saver/presentation/values/colors.dart'; import 'package:flutter_password_saver/presentation/widget/account_icon_widget.dart'; @@ -145,7 +144,8 @@ class _InfoPageState extends State return AccountIcon( user: user, onTap: () async { - final needsUpdate = await showPreferencePage(ctx); + final needsUpdate = await Navigator.of(context) + .pushNamed(AppRouter.preference); if (needsUpdate == true) { _bloc.add(InfoRefreshDataEvent()); } diff --git a/lib/presentation/page/password/list/password_page.dart b/lib/presentation/page/password/list/password_page.dart index ddb9704..805b8d3 100644 --- a/lib/presentation/page/password/list/password_page.dart +++ b/lib/presentation/page/password/list/password_page.dart @@ -10,7 +10,6 @@ import 'package:flutter_password_saver/presentation/page/password/list/bloc/pass import 'package:flutter_password_saver/presentation/page/password/list/bloc/password_events.dart'; import 'package:flutter_password_saver/presentation/page/password/list/bloc/password_state.dart'; import 'package:flutter_password_saver/presentation/page/password/list/widget/password_list_item.dart'; -import 'package:flutter_password_saver/presentation/page/preferences/preferences_page.dart'; import 'package:flutter_password_saver/presentation/utils/load_state.dart'; import 'package:flutter_password_saver/presentation/utils/ui_utils.dart'; import 'package:flutter_password_saver/presentation/values/colors.dart'; @@ -129,9 +128,10 @@ class _PasswordPageState extends State return PasswordListItem( key: ObjectKey(item), password: item, - prefShowAccName: _bloc.accountPreference - ?.getItemValue(PreferenceName.showAccName) ?? - AccountPreference.showAccountNameDefault, + prefShowAccName: _bloc.accountPreference == null + ? AppPreferenceEnum.showAccName.defaultValue + : _bloc.accountPreference! + .getItemValue(AppPreferenceEnum.showAccName) as bool, ); }, itemCount: _bloc.state.passwords.length, @@ -188,7 +188,8 @@ class _PasswordPageState extends State return AccountIcon( user: user, onTap: () async { - final needsUpdate = await showPreferencePage(ctx); + final needsUpdate = await Navigator.of(context) + .pushNamed(AppRouter.preference); if (needsUpdate == true) { _bloc.add(RefreshDataEvent()); } diff --git a/lib/presentation/page/preferences/bloc/preferences_event.dart b/lib/presentation/page/preferences/bloc/preferences_event.dart index 15f3551..b309770 100644 --- a/lib/presentation/page/preferences/bloc/preferences_event.dart +++ b/lib/presentation/page/preferences/bloc/preferences_event.dart @@ -7,7 +7,7 @@ class PreferenceInitEvent extends PreferenceEvent {} class SavePreferenceEvent extends PreferenceEvent { SavePreferenceEvent({required this.name, required this.value}); - final PreferenceName name; + final AppPreferenceEnum name; final dynamic value; } diff --git a/lib/presentation/page/preferences/preferences_page.dart b/lib/presentation/page/preferences/preferences_page.dart index 8b83b90..e88b080 100644 --- a/lib/presentation/page/preferences/preferences_page.dart +++ b/lib/presentation/page/preferences/preferences_page.dart @@ -20,20 +20,6 @@ import 'package:flutter_password_saver/initializer/app_router.dart'; import 'package:flutter_password_saver/initializer/language_util.dart'; import 'package:flutter_password_saver/initializer/theme_util.dart'; -Future showPreferencePage(BuildContext context) { - return showDialog( - context: context, - barrierDismissible: true, - barrierColor: AppColors.ink300, - builder: (context) { - return const AlertDialog( - contentPadding: EdgeInsets.zero, - content: PreferencesPage(), - ); - }, - ); -} - class PreferencesPage extends StatefulWidget { const PreferencesPage({Key? key}) : super(key: key); @@ -52,88 +38,63 @@ class _PreferencesPageState extends State { @override Widget build(BuildContext context) { - print('zzll 2 ${Theme.of(context).scaffoldBackgroundColor}'); - return PopScope( - canPop: false, - onPopInvoked: (bool didPop) { - if (didPop) { - return; - } - if (mounted) { - Navigator.of(context).pop(_bloc.dataChanged); - } - }, - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: BorderRadius.circular(16), + return Scaffold( + appBar: AppBar( + title: Text(S().preferences), + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () { + Navigator.of(context).pop(_bloc.dataChanged); + }, ), - height: MediaQuery.sizeOf(context).height * 0.7, - width: MediaQuery.sizeOf(context).width * 0.9, - child: BlocProvider( - create: (context) => _bloc..add(PreferenceInitEvent()), - child: BlocConsumer( - listener: ((context, state) { - if (state.deleteLoadState != LoadState.none) { - if (state.deleteLoadState == LoadState.success) { - context.showErrorSnackBar(S().sbDeleteSuccess); - HotRestart.of(context).hotRestart(); - } - - if (state.deleteLoadState == LoadState.failure) { - context.showErrorSnackBar(S().sbDeleteError); - } - } - - if (state.loadState == LoadState.failure) { - context.showErrorSnackBar(S().errorUnknown); - return; - } - - final isEnableDarkMode = - state.preference?.getItemValue(PreferenceName.enableDarkMode); - if (isEnableDarkMode != null && - isEnableDarkMode != isDarkMode()) { - changeThemeMode(); - } - - final isChangeLanguage = - state.preference?.getItemValue(PreferenceName.languageCode); - if (isChangeLanguage != null) { - setLanguage(isChangeLanguage); - } - }), - builder: (context, state) { - if (state.loadState == LoadState.loading) { - return Center( - child: LoadingIndicator( - color: LoadingIndicator.defaultColor, - ), - ); - } - - if (state.preference?.items.isNotEmpty == true) { - if (state.deleteLoadState == LoadState.none) { - return _primary(state); - } else { - return const Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LoadingIndicator(), - ], + ), + body: PopScope( + canPop: false, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + if (mounted) { + Navigator.of(context).pop(_bloc.dataChanged); + } + }, + child: Padding( + padding: const EdgeInsets.all(16), + child: BlocProvider( + create: (context) => _bloc..add(PreferenceInitEvent()), + child: BlocConsumer( + listener: _blocListener, + builder: (context, state) { + if (state.loadState == LoadState.loading) { + return Center( + child: LoadingIndicator( + color: LoadingIndicator.defaultColor, ), ); } - } - if (state.loadState == LoadState.failure) { - return const Center(child: Text('Error')); - } + if (state.preference?.items.isNotEmpty == true) { + if (state.deleteLoadState == LoadState.none) { + return _primary(state); + } else { + return const Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + LoadingIndicator(), + ], + ), + ); + } + } + + if (state.loadState == LoadState.failure) { + return const Center(child: Text('Error')); + } - return const SizedBox.shrink(); - }, + return const SizedBox.shrink(); + }, + ), ), ), ), @@ -144,8 +105,6 @@ class _PreferencesPageState extends State { return Column( mainAxisSize: MainAxisSize.max, children: [ - _appBar(), - const SizedBox(height: 16), _accountDetails(state.user), const SizedBox(height: 16), DeleteAccountButton( @@ -157,35 +116,11 @@ class _PreferencesPageState extends State { color: AppColors.ink200, ), ), - _preferences(state.preference), - ], - ); - } - - Widget _appBar() { - return Stack( - children: [ - _closeBtn(), - Center( - child: Text( - S().preferences, - style: const TextStyle(fontSize: 18), - ), - ), + Expanded(child: _preferences(state.preference)), ], ); } - Widget _closeBtn() { - return Align( - alignment: Alignment.bottomLeft, - child: GestureDetector( - onTap: () => Navigator.of(context).pop(_bloc.dataChanged), - child: const Icon(Icons.close), - ), - ); - } - Widget _accountDetails(User? user) { return Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -223,20 +158,48 @@ class _PreferencesPageState extends State { return const SizedBox.shrink(); } final factory = PrefItemWidgetFactory(); - return Expanded( - child: ListView.builder( - itemCount: items.length, - itemBuilder: (context, i) { - return factory.create( - preferenceItem: items[i], - onUpdate: (AccountPreferenceItem pref) { - _bloc.add( - SavePreferenceEvent(name: pref.name, value: pref.value), - ); - }, - ); - }, - ), + return ListView.builder( + itemCount: items.length, + itemBuilder: (context, i) { + return factory.create( + preferenceItem: items[i], + onUpdate: (AccountPreferenceItem pref) { + _bloc.add( + SavePreferenceEvent(name: pref.name, value: pref.value), + ); + }, + ); + }, ); } + + void _blocListener(BuildContext context, PreferenceState state) { + if (state.deleteLoadState != LoadState.none) { + if (state.deleteLoadState == LoadState.success) { + context.showErrorSnackBar(S().sbDeleteSuccess); + HotRestart.of(context).hotRestart(); + } + + if (state.deleteLoadState == LoadState.failure) { + context.showErrorSnackBar(S().sbDeleteError); + } + } + + if (state.loadState == LoadState.failure) { + context.showErrorSnackBar(S().errorUnknown); + return; + } + + final isEnableDarkMode = + state.preference?.getItemValue(AppPreferenceEnum.enableDarkMode); + if (isEnableDarkMode != null && isEnableDarkMode != isDarkMode()) { + changeThemeMode(); + } + + final isChangeLanguage = + state.preference?.getItemValue(AppPreferenceEnum.languageCode); + if (isChangeLanguage != null) { + setLanguage(isChangeLanguage); + } + } } diff --git a/lib/presentation/page/preferences/widget/pref_item_choose_language_widget.dart b/lib/presentation/page/preferences/widget/pref_item_choose_language_widget.dart index c9c7711..9c3fed9 100644 --- a/lib/presentation/page/preferences/widget/pref_item_choose_language_widget.dart +++ b/lib/presentation/page/preferences/widget/pref_item_choose_language_widget.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_password_saver/domain/model/account_preference.dart'; import 'package:flutter_password_saver/generated/l10n.dart'; +import 'package:flutter_password_saver/initializer/theme_util.dart'; +import 'package:flutter_password_saver/presentation/values/colors.dart'; class PrefItemChooseLanguage extends StatefulWidget { const PrefItemChooseLanguage({ @@ -36,8 +38,7 @@ class _PrefItemChooseLanguageState extends State { Text(S().language), Expanded( child: SizedBox( - width: 150, - height: 100, + height: 60, child: Align( alignment: Alignment.centerRight, child: DropdownButton( @@ -45,10 +46,7 @@ class _PrefItemChooseLanguageState extends State { value: _value, icon: const Icon(Icons.keyboard_arrow_down), items: languageCodes.map((e) { - return DropdownMenuItem( - value: e, - child: Text(_getDisplayText(e)), - ); + return _item(e); }).toList(), onChanged: (String? value) { if (value != null && value != _value) { @@ -78,4 +76,20 @@ class _PrefItemChooseLanguageState extends State { return ''; } } + + DropdownMenuItem _item(String e) { + final isSelected = _value == e; + + var textColor = isDarkMode() + ? (isSelected ? AppColors.white500 : AppColors.white200) + : (isSelected ? AppColors.black500 : AppColors.black200); + + return DropdownMenuItem( + value: e, + child: Text( + _getDisplayText(e), + style: TextStyle(color: textColor), + ), + ); + } } diff --git a/lib/presentation/page/preferences/widget/pref_item_switch_widget.dart b/lib/presentation/page/preferences/widget/pref_item_switch_widget.dart index d643e33..caa076b 100644 --- a/lib/presentation/page/preferences/widget/pref_item_switch_widget.dart +++ b/lib/presentation/page/preferences/widget/pref_item_switch_widget.dart @@ -48,15 +48,15 @@ class _PrefItemSwitcherState extends State { Widget _getTitleWidget() { switch (widget.preferenceItem.name) { - case PreferenceName.requirePass: + case AppPreferenceEnum.requireReLogin: return Text(S().prefRequireLogin); - case PreferenceName.enableDarkMode: + case AppPreferenceEnum.enableDarkMode: return Text(S().prefDarkMode); - case PreferenceName.showAccName: + case AppPreferenceEnum.showAccName: return Text(S().prefDarkModeShowAccName); - case PreferenceName.allowSearchAccName: + case AppPreferenceEnum.allowSearchAccName: return Text(S().prefAllowSearchAccName); - case PreferenceName.requirePassOnForeground: + case AppPreferenceEnum.requirePassOnForeground: return Text(S().prefRequirePassOnForeground); default: return const SizedBox.shrink(); diff --git a/lib/presentation/page/preferences/widget/pref_item_widget_factory.dart b/lib/presentation/page/preferences/widget/pref_item_widget_factory.dart index 4fd3d72..3f7b855 100644 --- a/lib/presentation/page/preferences/widget/pref_item_widget_factory.dart +++ b/lib/presentation/page/preferences/widget/pref_item_widget_factory.dart @@ -9,11 +9,11 @@ class PrefItemWidgetFactory { Function(AccountPreferenceItem)? onUpdate, }) { switch (preferenceItem.name) { - case PreferenceName.languageCode: + case AppPreferenceEnum.languageCode: return PrefItemChooseLanguage( preferenceItem: preferenceItem, onUpdate: onUpdate, - ); + ); default: return PrefItemSwitcher( preferenceItem: preferenceItem,