mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-25 02:48:54 +01:00
Refactor: decouple pref and storage to ease unit test
This commit is contained in:
parent
456975360a
commit
ba0f441635
2 changed files with 195 additions and 108 deletions
|
@ -75,7 +75,11 @@ void _initLog() {
|
|||
}
|
||||
|
||||
Future<void> _initPref() async {
|
||||
await Pref().init();
|
||||
final provider = PrefSharedPreferencesProvider();
|
||||
await provider.init();
|
||||
final pref = Pref.scoped(provider);
|
||||
Pref.setGlobalInstance(pref);
|
||||
|
||||
if (Pref().getLastVersion() == null) {
|
||||
if (Pref().getSetupProgress() == null) {
|
||||
// new install
|
||||
|
|
299
lib/pref.dart
299
lib/pref.dart
|
@ -9,21 +9,21 @@ import 'package:nc_photos/use_case/compat/v32.dart';
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class Pref {
|
||||
factory Pref() => _inst;
|
||||
|
||||
Pref.scoped();
|
||||
|
||||
Future<void> init() async {
|
||||
if (await CompatV32.isPrefNeedMigration()) {
|
||||
await CompatV32.migratePref();
|
||||
factory Pref() {
|
||||
_inst ??= Pref.scoped(PrefMemoryProvider());
|
||||
return _inst!;
|
||||
}
|
||||
return SharedPreferences.getInstance().then((pref) {
|
||||
_pref = pref;
|
||||
});
|
||||
|
||||
Pref.scoped(this.provider);
|
||||
|
||||
/// Set the global [Pref] instance returned by the default constructor
|
||||
static void setGlobalInstance(Pref pref) {
|
||||
assert(_inst == null);
|
||||
_inst = pref;
|
||||
}
|
||||
|
||||
List<PrefAccount>? getAccounts2() {
|
||||
final jsonObjs = _pref.getStringList(_toKey(PrefKey.accounts2));
|
||||
final jsonObjs = provider.getStringList(PrefKey.accounts2);
|
||||
return jsonObjs?.map((e) => PrefAccount.fromJson(jsonDecode(e))).toList();
|
||||
}
|
||||
|
||||
|
@ -31,127 +31,129 @@ class Pref {
|
|||
getAccounts2() ?? def;
|
||||
Future<bool> setAccounts2(List<PrefAccount> value) {
|
||||
final jsons = value.map((e) => jsonEncode(e.toJson())).toList();
|
||||
return _setStringList(PrefKey.accounts2, jsons);
|
||||
return provider.setStringList(PrefKey.accounts2, jsons);
|
||||
}
|
||||
|
||||
int? getCurrentAccountIndex() =>
|
||||
_pref.getInt(_toKey(PrefKey.currentAccountIndex));
|
||||
int? getCurrentAccountIndex() => provider.getInt(PrefKey.currentAccountIndex);
|
||||
int getCurrentAccountIndexOr(int def) => getCurrentAccountIndex() ?? def;
|
||||
Future<bool> setCurrentAccountIndex(int value) =>
|
||||
_setInt(PrefKey.currentAccountIndex, value);
|
||||
provider.setInt(PrefKey.currentAccountIndex, value);
|
||||
|
||||
int? getHomePhotosZoomLevel() =>
|
||||
_pref.getInt(_toKey(PrefKey.homePhotosZoomLevel));
|
||||
int? getHomePhotosZoomLevel() => provider.getInt(PrefKey.homePhotosZoomLevel);
|
||||
int getHomePhotosZoomLevelOr(int def) => getHomePhotosZoomLevel() ?? def;
|
||||
Future<bool> setHomePhotosZoomLevel(int value) =>
|
||||
_setInt(PrefKey.homePhotosZoomLevel, value);
|
||||
provider.setInt(PrefKey.homePhotosZoomLevel, value);
|
||||
|
||||
int? getAlbumBrowserZoomLevel() =>
|
||||
_pref.getInt(_toKey(PrefKey.albumBrowserZoomLevel));
|
||||
provider.getInt(PrefKey.albumBrowserZoomLevel);
|
||||
int getAlbumBrowserZoomLevelOr(int def) => getAlbumBrowserZoomLevel() ?? def;
|
||||
Future<bool> setAlbumBrowserZoomLevel(int value) =>
|
||||
_setInt(PrefKey.albumBrowserZoomLevel, value);
|
||||
provider.setInt(PrefKey.albumBrowserZoomLevel, value);
|
||||
|
||||
int? getHomeAlbumsSort() => _pref.getInt(_toKey(PrefKey.homeAlbumsSort));
|
||||
int? getHomeAlbumsSort() => provider.getInt(PrefKey.homeAlbumsSort);
|
||||
int getHomeAlbumsSortOr(int def) => getHomeAlbumsSort() ?? def;
|
||||
Future<bool> setHomeAlbumsSort(int value) =>
|
||||
_setInt(PrefKey.homeAlbumsSort, value);
|
||||
provider.setInt(PrefKey.homeAlbumsSort, value);
|
||||
|
||||
bool? isEnableExif() => _pref.getBool(_toKey(PrefKey.enableExif));
|
||||
bool? isEnableExif() => provider.getBool(PrefKey.enableExif);
|
||||
bool isEnableExifOr([bool def = true]) => isEnableExif() ?? def;
|
||||
Future<bool> setEnableExif(bool value) => _setBool(PrefKey.enableExif, value);
|
||||
Future<bool> setEnableExif(bool value) =>
|
||||
provider.setBool(PrefKey.enableExif, value);
|
||||
|
||||
int? getViewerScreenBrightness() =>
|
||||
_pref.getInt(_toKey(PrefKey.viewerScreenBrightness));
|
||||
provider.getInt(PrefKey.viewerScreenBrightness);
|
||||
int getViewerScreenBrightnessOr([int def = -1]) =>
|
||||
getViewerScreenBrightness() ?? def;
|
||||
Future<bool> setViewerScreenBrightness(int value) =>
|
||||
_setInt(PrefKey.viewerScreenBrightness, value);
|
||||
provider.setInt(PrefKey.viewerScreenBrightness, value);
|
||||
|
||||
bool? isViewerForceRotation() =>
|
||||
_pref.getBool(_toKey(PrefKey.viewerForceRotation));
|
||||
provider.getBool(PrefKey.viewerForceRotation);
|
||||
bool isViewerForceRotationOr([bool def = false]) =>
|
||||
isViewerForceRotation() ?? def;
|
||||
Future<bool> setViewerForceRotation(bool value) =>
|
||||
_setBool(PrefKey.viewerForceRotation, value);
|
||||
provider.setBool(PrefKey.viewerForceRotation, value);
|
||||
|
||||
int? getSetupProgress() => _pref.getInt(_toKey(PrefKey.setupProgress));
|
||||
int? getSetupProgress() => provider.getInt(PrefKey.setupProgress);
|
||||
int getSetupProgressOr([int def = 0]) => getSetupProgress() ?? def;
|
||||
Future<bool> setSetupProgress(int value) =>
|
||||
_setInt(PrefKey.setupProgress, value);
|
||||
provider.setInt(PrefKey.setupProgress, value);
|
||||
|
||||
/// Return the version number when the app last ran
|
||||
int? getLastVersion() => _pref.getInt(_toKey(PrefKey.lastVersion));
|
||||
int? getLastVersion() => provider.getInt(PrefKey.lastVersion);
|
||||
int getLastVersionOr(int def) => getLastVersion() ?? def;
|
||||
Future<bool> setLastVersion(int value) => _setInt(PrefKey.lastVersion, value);
|
||||
Future<bool> setLastVersion(int value) =>
|
||||
provider.setInt(PrefKey.lastVersion, value);
|
||||
|
||||
bool? isDarkTheme() => _pref.getBool(_toKey(PrefKey.darkTheme));
|
||||
bool? isDarkTheme() => provider.getBool(PrefKey.darkTheme);
|
||||
bool isDarkThemeOr(bool def) => isDarkTheme() ?? def;
|
||||
Future<bool> setDarkTheme(bool value) => _setBool(PrefKey.darkTheme, value);
|
||||
Future<bool> setDarkTheme(bool value) =>
|
||||
provider.setBool(PrefKey.darkTheme, value);
|
||||
|
||||
bool? isFollowSystemTheme() =>
|
||||
_pref.getBool(_toKey(PrefKey.followSystemTheme));
|
||||
bool? isFollowSystemTheme() => provider.getBool(PrefKey.followSystemTheme);
|
||||
bool isFollowSystemThemeOr(bool def) => isFollowSystemTheme() ?? def;
|
||||
Future<bool> setFollowSystemTheme(bool value) =>
|
||||
_setBool(PrefKey.followSystemTheme, value);
|
||||
provider.setBool(PrefKey.followSystemTheme, value);
|
||||
|
||||
bool? isUseBlackInDarkTheme() =>
|
||||
_pref.getBool(_toKey(PrefKey.useBlackInDarkTheme));
|
||||
provider.getBool(PrefKey.useBlackInDarkTheme);
|
||||
bool isUseBlackInDarkThemeOr(bool def) => isUseBlackInDarkTheme() ?? def;
|
||||
Future<bool> setUseBlackInDarkTheme(bool value) =>
|
||||
_setBool(PrefKey.useBlackInDarkTheme, value);
|
||||
provider.setBool(PrefKey.useBlackInDarkTheme, value);
|
||||
|
||||
int? getLanguage() => _pref.getInt(_toKey(PrefKey.language));
|
||||
int? getLanguage() => provider.getInt(PrefKey.language);
|
||||
int getLanguageOr(int def) => getLanguage() ?? def;
|
||||
Future<bool> setLanguage(int value) => _setInt(PrefKey.language, value);
|
||||
Future<bool> setLanguage(int value) =>
|
||||
provider.setInt(PrefKey.language, value);
|
||||
|
||||
int? getSlideshowDuration() =>
|
||||
_pref.getInt(_toKey(PrefKey.slideshowDuration));
|
||||
int? getSlideshowDuration() => provider.getInt(PrefKey.slideshowDuration);
|
||||
int getSlideshowDurationOr(int def) => getSlideshowDuration() ?? def;
|
||||
Future<bool> setSlideshowDuration(int value) =>
|
||||
_setInt(PrefKey.slideshowDuration, value);
|
||||
provider.setInt(PrefKey.slideshowDuration, value);
|
||||
|
||||
bool? isSlideshowShuffle() =>
|
||||
_pref.getBool(_toKey(PrefKey.isSlideshowShuffle));
|
||||
bool? isSlideshowShuffle() => provider.getBool(PrefKey.isSlideshowShuffle);
|
||||
bool isSlideshowShuffleOr(bool def) => isSlideshowShuffle() ?? def;
|
||||
Future<bool> setSlideshowShuffle(bool value) =>
|
||||
_setBool(PrefKey.isSlideshowShuffle, value);
|
||||
provider.setBool(PrefKey.isSlideshowShuffle, value);
|
||||
|
||||
bool? isSlideshowRepeat() => _pref.getBool(_toKey(PrefKey.isSlideshowRepeat));
|
||||
bool? isSlideshowRepeat() => provider.getBool(PrefKey.isSlideshowRepeat);
|
||||
bool isSlideshowRepeatOr(bool def) => isSlideshowRepeat() ?? def;
|
||||
Future<bool> setSlideshowRepeat(bool value) =>
|
||||
_setBool(PrefKey.isSlideshowRepeat, value);
|
||||
provider.setBool(PrefKey.isSlideshowRepeat, value);
|
||||
|
||||
bool? isAlbumBrowserShowDate() =>
|
||||
_pref.getBool(_toKey(PrefKey.isAlbumBrowserShowDate));
|
||||
provider.getBool(PrefKey.isAlbumBrowserShowDate);
|
||||
bool isAlbumBrowserShowDateOr([bool def = false]) =>
|
||||
isAlbumBrowserShowDate() ?? def;
|
||||
Future<bool> setAlbumBrowserShowDate(bool value) =>
|
||||
_setBool(PrefKey.isAlbumBrowserShowDate, value);
|
||||
provider.setBool(PrefKey.isAlbumBrowserShowDate, value);
|
||||
|
||||
bool? hasNewSharedAlbum() => _pref.getBool(_toKey(PrefKey.newSharedAlbum));
|
||||
bool? hasNewSharedAlbum() => provider.getBool(PrefKey.newSharedAlbum);
|
||||
bool hasNewSharedAlbumOr(bool def) => hasNewSharedAlbum() ?? def;
|
||||
Future<bool> setNewSharedAlbum(bool value) =>
|
||||
_setBool(PrefKey.newSharedAlbum, value);
|
||||
provider.setBool(PrefKey.newSharedAlbum, value);
|
||||
|
||||
bool? isLabEnableSharedAlbum() =>
|
||||
_pref.getBool(_toKey(PrefKey.labEnableSharedAlbum));
|
||||
provider.getBool(PrefKey.labEnableSharedAlbum);
|
||||
bool isLabEnableSharedAlbumOr(bool def) => isLabEnableSharedAlbum() ?? def;
|
||||
Future<bool> setLabEnableSharedAlbum(bool value) =>
|
||||
_setBool(PrefKey.labEnableSharedAlbum, value);
|
||||
provider.setBool(PrefKey.labEnableSharedAlbum, value);
|
||||
|
||||
Future<bool> _setBool(PrefKey key, bool value) async {
|
||||
return _onPostSet(await _pref.setBool(_toKey(key), value), key, value);
|
||||
}
|
||||
final PrefProvider provider;
|
||||
|
||||
Future<bool> _setInt(PrefKey key, int value) async {
|
||||
return _onPostSet(await _pref.setInt(_toKey(key), value), key, value);
|
||||
}
|
||||
static Pref? _inst;
|
||||
}
|
||||
|
||||
Future<bool> _setStringList(PrefKey key, List<String> value) async {
|
||||
return _onPostSet(
|
||||
await _pref.setStringList(_toKey(key), value), key, value);
|
||||
}
|
||||
/// Provide the data for [Pref]
|
||||
abstract class PrefProvider {
|
||||
bool? getBool(PrefKey key);
|
||||
Future<bool> setBool(PrefKey key, bool value);
|
||||
|
||||
int? getInt(PrefKey key);
|
||||
Future<bool> setInt(PrefKey key, int value);
|
||||
|
||||
List<String>? getStringList(PrefKey key);
|
||||
Future<bool> setStringList(PrefKey key, List<String> value);
|
||||
|
||||
bool _onPostSet(bool result, PrefKey key, dynamic value) {
|
||||
if (result) {
|
||||
|
@ -161,56 +163,90 @@ class Pref {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String _toKey(PrefKey key) {
|
||||
switch (key) {
|
||||
case PrefKey.accounts2:
|
||||
return "accounts2";
|
||||
case PrefKey.currentAccountIndex:
|
||||
return "currentAccountIndex";
|
||||
case PrefKey.homePhotosZoomLevel:
|
||||
return "homePhotosZoomLevel";
|
||||
case PrefKey.albumBrowserZoomLevel:
|
||||
return "albumViewerZoomLevel";
|
||||
case PrefKey.homeAlbumsSort:
|
||||
return "homeAlbumsSort";
|
||||
case PrefKey.enableExif:
|
||||
return "isEnableExif";
|
||||
case PrefKey.viewerScreenBrightness:
|
||||
return "viewerScreenBrightness";
|
||||
case PrefKey.viewerForceRotation:
|
||||
return "viewerForceRotation";
|
||||
case PrefKey.setupProgress:
|
||||
return "setupProgress";
|
||||
case PrefKey.lastVersion:
|
||||
return "lastVersion";
|
||||
case PrefKey.darkTheme:
|
||||
return "isDarkTheme";
|
||||
case PrefKey.followSystemTheme:
|
||||
return "isFollowSystemTheme";
|
||||
case PrefKey.useBlackInDarkTheme:
|
||||
return "isUseBlackInDarkTheme";
|
||||
case PrefKey.language:
|
||||
return "language";
|
||||
case PrefKey.newSharedAlbum:
|
||||
return "hasNewSharedAlbum";
|
||||
case PrefKey.labEnableSharedAlbum:
|
||||
return "isLabEnableSharedAlbum";
|
||||
case PrefKey.slideshowDuration:
|
||||
return "slideshowDuration";
|
||||
case PrefKey.isSlideshowShuffle:
|
||||
return "isSlideshowShuffle";
|
||||
case PrefKey.isSlideshowRepeat:
|
||||
return "isSlideshowRepeat";
|
||||
case PrefKey.isAlbumBrowserShowDate:
|
||||
return "isAlbumBrowserShowDate";
|
||||
/// [Pref] stored with [SharedPreferences] lib
|
||||
class PrefSharedPreferencesProvider extends PrefProvider {
|
||||
Future<void> init() async {
|
||||
if (await CompatV32.isPrefNeedMigration()) {
|
||||
await CompatV32.migratePref();
|
||||
}
|
||||
return SharedPreferences.getInstance().then((pref) {
|
||||
_pref = pref;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
getBool(PrefKey key) => _pref.getBool(key.toStringKey());
|
||||
|
||||
@override
|
||||
setBool(PrefKey key, bool value) async {
|
||||
return _onPostSet(
|
||||
await _pref.setBool(key.toStringKey(), value), key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
getInt(PrefKey key) => _pref.getInt(key.toStringKey());
|
||||
|
||||
@override
|
||||
setInt(PrefKey key, int value) async {
|
||||
return _onPostSet(await _pref.setInt(key.toStringKey(), value), key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
getStringList(PrefKey key) => _pref.getStringList(key.toStringKey());
|
||||
|
||||
@override
|
||||
setStringList(PrefKey key, List<String> value) async {
|
||||
return _onPostSet(
|
||||
await _pref.setStringList(key.toStringKey(), value), key, value);
|
||||
}
|
||||
|
||||
static late final _inst = Pref.scoped();
|
||||
late SharedPreferences _pref;
|
||||
}
|
||||
|
||||
/// [Pref] stored in memory
|
||||
class PrefMemoryProvider extends PrefProvider {
|
||||
PrefMemoryProvider([
|
||||
Map<String, dynamic> initialData = const <String, dynamic>{},
|
||||
]) : _data = Map.of(initialData);
|
||||
|
||||
@override
|
||||
getBool(PrefKey key) => _data[key.toStringKey()];
|
||||
|
||||
@override
|
||||
setBool(PrefKey key, bool value) async {
|
||||
return _onPostSet(() {
|
||||
_data[key.toStringKey()] = value;
|
||||
return true;
|
||||
}(), key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
getInt(PrefKey key) => _data[key.toStringKey()];
|
||||
|
||||
@override
|
||||
setInt(PrefKey key, int value) async {
|
||||
return _onPostSet(() {
|
||||
_data[key.toStringKey()] = value;
|
||||
return true;
|
||||
}(), key, value);
|
||||
}
|
||||
|
||||
@override
|
||||
getStringList(PrefKey key) => _data[key.toStringKey()];
|
||||
|
||||
@override
|
||||
setStringList(PrefKey key, List<String> value) async {
|
||||
return _onPostSet(() {
|
||||
_data[key.toStringKey()] = value;
|
||||
return true;
|
||||
}(), key, value);
|
||||
}
|
||||
|
||||
final Map<String, dynamic> _data;
|
||||
}
|
||||
|
||||
class PrefAccount {
|
||||
const PrefAccount(
|
||||
this.account, [
|
||||
|
@ -274,6 +310,53 @@ enum PrefKey {
|
|||
isAlbumBrowserShowDate,
|
||||
}
|
||||
|
||||
extension on PrefKey {
|
||||
String toStringKey() {
|
||||
switch (this) {
|
||||
case PrefKey.accounts2:
|
||||
return "accounts2";
|
||||
case PrefKey.currentAccountIndex:
|
||||
return "currentAccountIndex";
|
||||
case PrefKey.homePhotosZoomLevel:
|
||||
return "homePhotosZoomLevel";
|
||||
case PrefKey.albumBrowserZoomLevel:
|
||||
return "albumViewerZoomLevel";
|
||||
case PrefKey.homeAlbumsSort:
|
||||
return "homeAlbumsSort";
|
||||
case PrefKey.enableExif:
|
||||
return "isEnableExif";
|
||||
case PrefKey.viewerScreenBrightness:
|
||||
return "viewerScreenBrightness";
|
||||
case PrefKey.viewerForceRotation:
|
||||
return "viewerForceRotation";
|
||||
case PrefKey.setupProgress:
|
||||
return "setupProgress";
|
||||
case PrefKey.lastVersion:
|
||||
return "lastVersion";
|
||||
case PrefKey.darkTheme:
|
||||
return "isDarkTheme";
|
||||
case PrefKey.followSystemTheme:
|
||||
return "isFollowSystemTheme";
|
||||
case PrefKey.useBlackInDarkTheme:
|
||||
return "isUseBlackInDarkTheme";
|
||||
case PrefKey.language:
|
||||
return "language";
|
||||
case PrefKey.newSharedAlbum:
|
||||
return "hasNewSharedAlbum";
|
||||
case PrefKey.labEnableSharedAlbum:
|
||||
return "isLabEnableSharedAlbum";
|
||||
case PrefKey.slideshowDuration:
|
||||
return "slideshowDuration";
|
||||
case PrefKey.isSlideshowShuffle:
|
||||
return "isSlideshowShuffle";
|
||||
case PrefKey.isSlideshowRepeat:
|
||||
return "isSlideshowRepeat";
|
||||
case PrefKey.isAlbumBrowserShowDate:
|
||||
return "isAlbumBrowserShowDate";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PrefExtension on Pref {
|
||||
Account? getCurrentAccount() {
|
||||
try {
|
||||
|
|
Loading…
Reference in a new issue