Skip to content

Commit

Permalink
[Issue#69] Update Preference page UI + clean up preference code reduc…
Browse files Browse the repository at this point in the history
…e boilerplat
  • Loading branch information
ngthailam committed Feb 14, 2024
1 parent 7dd00f5 commit 1ebe2af
Show file tree
Hide file tree
Showing 17 changed files with 207 additions and 341 deletions.
44 changes: 19 additions & 25 deletions lib/data/datasource/account_preference_local_data_source.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,26 @@ class AccountPreferenceLocalDataSourceImpl
@override
Future<AccountPreferenceEntity> 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<void> saveRequireLogin(bool require) async {
final sharedPrefs = await _prefs;
sharedPrefs.setBool(AccountPreferenceEntity.keyRequireLogin, require);
sharedPrefs.setBool(AppPreferenceEnum.requireReLogin.name, require);
}

@override
Expand All @@ -71,32 +65,32 @@ class AccountPreferenceLocalDataSourceImpl
@override
Future<void> enableDarkMode(bool enable) async {
final sharedPrefs = await _prefs;
sharedPrefs.setBool(AccountPreferenceEntity.keyEnableDarkMode, enable);
sharedPrefs.setBool(AppPreferenceEnum.enableDarkMode.name, enable);
}

@override
Future<void> setLanguageCode(String value) async {
final sharedPrefs = await _prefs;
sharedPrefs.setString(AccountPreferenceEntity.keyLanguageCode, value);
sharedPrefs.setString(AppPreferenceEnum.languageCode.name, value);
}

@override
Future<void> saveShowAccName(bool value) async {
final sharedPrefs = await _prefs;
sharedPrefs.setBool(AccountPreferenceEntity.keyShowAccName, value);
sharedPrefs.setBool(AppPreferenceEnum.showAccName.name, value);
}

@override
Future<void> saveRequirePassOnForeground(bool value) async {
final sharedPrefs = await _prefs;
sharedPrefs.setBool(AccountPreferenceEntity.keyRequirePassOnForeground, value);
sharedPrefs.setBool(AppPreferenceEnum.requirePassOnForeground.name, value);
}

@override
Future<void> saveAllowSearchAccName(bool value) async {
final sharedPrefs = await _prefs;
_allowSearchAccName = value;
sharedPrefs.setBool(AccountPreferenceEntity.keyAllowSearchAccName, value);
sharedPrefs.setBool(AppPreferenceEnum.allowSearchAccName.name, value);
}

@override
Expand Down
79 changes: 8 additions & 71 deletions lib/data/entity/account_preference_entity.dart
Original file line number Diff line number Diff line change
@@ -1,84 +1,21 @@
import 'package:collection/collection.dart';
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:flutter_password_saver/domain/model/account_preference.dart';

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<AccountPreferenceItem> 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) ??
prefEnum.defaultValue;
}
}
18 changes: 10 additions & 8 deletions lib/data/repository/account_pref_repo_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,25 @@ class AccountPrefRepoImpl extends AccountPrefRepo {
}

@override
Future<void> saveAccountPreference(
{required PreferenceName name, required value}) {
Future<void> 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:
Expand Down
80 changes: 17 additions & 63 deletions lib/domain/model/account_preference.dart
Original file line number Diff line number Diff line change
@@ -1,90 +1,44 @@
import 'package:collection/collection.dart';
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:equatable/equatable.dart';

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<AccountPreferenceItem> items;

static const List<AccountPreferenceItem> 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<AccountPreferenceItem> 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) ??
prefEnum.defaultValue;
}

@override
List<Object?> 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
Expand Down
2 changes: 1 addition & 1 deletion lib/domain/repository/account_pref_repo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ abstract class AccountPrefRepo {
Future<AccountPreference> getAccountPrefs();

Future<void> saveAccountPreference({
required PreferenceName name,
required AppPreferenceEnum name,
required dynamic value,
});
}
22 changes: 8 additions & 14 deletions lib/domain/usecase/preference/account_preference_use_case.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,18 @@ class AccountPreferenceUseCase {
return _accountPrefRepo.getAccountPrefs();
}

Future<bool> getIsDarkModeEnabled() {
return getAccountPrefs().then((value) {
return value.getItemByName(PreferenceName.enableDarkMode)?.value ??
AccountPreference.enableDarkModeDefault;
});
Future<bool> getIsDarkModeEnabled() async {
final prefs = await getAccountPrefs();
return prefs.getItemValue(AppPreferenceEnum.enableDarkMode);
}

Future<bool> getIsRequirePassOnForeground() async {
final prefs = await getAccountPrefs();
return prefs.getItemValue(PreferenceName.requirePassOnForeground) ??
AccountPreference.requirePassOnForeground;
return prefs.getItemValue(AppPreferenceEnum.requirePassOnForeground);
}

Future<void> saveAccountPreference({
required PreferenceName name,
required AppPreferenceEnum name,
required dynamic value,
}) {
return _accountPrefRepo.saveAccountPreference(
Expand All @@ -35,11 +32,8 @@ class AccountPreferenceUseCase {
);
}

Future<String> getLanguageCode() {
return getAccountPrefs().then((value) {
final prefItemValue =
value.getItemByName(PreferenceName.languageCode)?.value;
return prefItemValue ?? AccountPreference.languageCodeDefault;
});
Future<String> getLanguageCode() async {
final prefs = await getAccountPrefs();
return prefs.getItemValue(AppPreferenceEnum.languageCode);
}
}
7 changes: 7 additions & 0 deletions lib/initializer/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 1ebe2af

Please sign in to comment.