nc-photos/lib/pref.dart
2021-11-25 21:02:41 +08:00

383 lines
12 KiB
Dart

import 'dart:convert';
import 'package:event_bus/event_bus.dart';
import 'package:kiwi/kiwi.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/type.dart';
import 'package:nc_photos/use_case/compat/v32.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Pref {
factory Pref() {
_inst ??= Pref.scoped(PrefMemoryProvider());
return _inst!;
}
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 = provider.getStringList(PrefKey.accounts2);
return jsonObjs?.map((e) => PrefAccount.fromJson(jsonDecode(e))).toList();
}
List<PrefAccount> getAccounts2Or(List<PrefAccount> def) =>
getAccounts2() ?? def;
Future<bool> setAccounts2(List<PrefAccount> value) {
final jsons = value.map((e) => jsonEncode(e.toJson())).toList();
return provider.setStringList(PrefKey.accounts2, jsons);
}
int? getCurrentAccountIndex() => provider.getInt(PrefKey.currentAccountIndex);
int getCurrentAccountIndexOr(int def) => getCurrentAccountIndex() ?? def;
Future<bool> setCurrentAccountIndex(int value) =>
provider.setInt(PrefKey.currentAccountIndex, value);
int? getHomePhotosZoomLevel() => provider.getInt(PrefKey.homePhotosZoomLevel);
int getHomePhotosZoomLevelOr(int def) => getHomePhotosZoomLevel() ?? def;
Future<bool> setHomePhotosZoomLevel(int value) =>
provider.setInt(PrefKey.homePhotosZoomLevel, value);
int? getAlbumBrowserZoomLevel() =>
provider.getInt(PrefKey.albumBrowserZoomLevel);
int getAlbumBrowserZoomLevelOr(int def) => getAlbumBrowserZoomLevel() ?? def;
Future<bool> setAlbumBrowserZoomLevel(int value) =>
provider.setInt(PrefKey.albumBrowserZoomLevel, value);
int? getHomeAlbumsSort() => provider.getInt(PrefKey.homeAlbumsSort);
int getHomeAlbumsSortOr(int def) => getHomeAlbumsSort() ?? def;
Future<bool> setHomeAlbumsSort(int value) =>
provider.setInt(PrefKey.homeAlbumsSort, value);
bool? isEnableExif() => provider.getBool(PrefKey.enableExif);
bool isEnableExifOr([bool def = true]) => isEnableExif() ?? def;
Future<bool> setEnableExif(bool value) =>
provider.setBool(PrefKey.enableExif, value);
int? getViewerScreenBrightness() =>
provider.getInt(PrefKey.viewerScreenBrightness);
int getViewerScreenBrightnessOr([int def = -1]) =>
getViewerScreenBrightness() ?? def;
Future<bool> setViewerScreenBrightness(int value) =>
provider.setInt(PrefKey.viewerScreenBrightness, value);
bool? isViewerForceRotation() =>
provider.getBool(PrefKey.viewerForceRotation);
bool isViewerForceRotationOr([bool def = false]) =>
isViewerForceRotation() ?? def;
Future<bool> setViewerForceRotation(bool value) =>
provider.setBool(PrefKey.viewerForceRotation, value);
int? getSetupProgress() => provider.getInt(PrefKey.setupProgress);
int getSetupProgressOr([int def = 0]) => getSetupProgress() ?? def;
Future<bool> setSetupProgress(int value) =>
provider.setInt(PrefKey.setupProgress, value);
/// Return the version number when the app last ran
int? getLastVersion() => provider.getInt(PrefKey.lastVersion);
int getLastVersionOr(int def) => getLastVersion() ?? def;
Future<bool> setLastVersion(int value) =>
provider.setInt(PrefKey.lastVersion, value);
bool? isDarkTheme() => provider.getBool(PrefKey.darkTheme);
bool isDarkThemeOr(bool def) => isDarkTheme() ?? def;
Future<bool> setDarkTheme(bool value) =>
provider.setBool(PrefKey.darkTheme, value);
bool? isFollowSystemTheme() => provider.getBool(PrefKey.followSystemTheme);
bool isFollowSystemThemeOr(bool def) => isFollowSystemTheme() ?? def;
Future<bool> setFollowSystemTheme(bool value) =>
provider.setBool(PrefKey.followSystemTheme, value);
bool? isUseBlackInDarkTheme() =>
provider.getBool(PrefKey.useBlackInDarkTheme);
bool isUseBlackInDarkThemeOr(bool def) => isUseBlackInDarkTheme() ?? def;
Future<bool> setUseBlackInDarkTheme(bool value) =>
provider.setBool(PrefKey.useBlackInDarkTheme, value);
int? getLanguage() => provider.getInt(PrefKey.language);
int getLanguageOr(int def) => getLanguage() ?? def;
Future<bool> setLanguage(int value) =>
provider.setInt(PrefKey.language, value);
int? getSlideshowDuration() => provider.getInt(PrefKey.slideshowDuration);
int getSlideshowDurationOr(int def) => getSlideshowDuration() ?? def;
Future<bool> setSlideshowDuration(int value) =>
provider.setInt(PrefKey.slideshowDuration, value);
bool? isSlideshowShuffle() => provider.getBool(PrefKey.isSlideshowShuffle);
bool isSlideshowShuffleOr(bool def) => isSlideshowShuffle() ?? def;
Future<bool> setSlideshowShuffle(bool value) =>
provider.setBool(PrefKey.isSlideshowShuffle, value);
bool? isSlideshowRepeat() => provider.getBool(PrefKey.isSlideshowRepeat);
bool isSlideshowRepeatOr(bool def) => isSlideshowRepeat() ?? def;
Future<bool> setSlideshowRepeat(bool value) =>
provider.setBool(PrefKey.isSlideshowRepeat, value);
bool? isAlbumBrowserShowDate() =>
provider.getBool(PrefKey.isAlbumBrowserShowDate);
bool isAlbumBrowserShowDateOr([bool def = false]) =>
isAlbumBrowserShowDate() ?? def;
Future<bool> setAlbumBrowserShowDate(bool value) =>
provider.setBool(PrefKey.isAlbumBrowserShowDate, value);
bool? hasNewSharedAlbum() => provider.getBool(PrefKey.newSharedAlbum);
bool hasNewSharedAlbumOr(bool def) => hasNewSharedAlbum() ?? def;
Future<bool> setNewSharedAlbum(bool value) =>
provider.setBool(PrefKey.newSharedAlbum, value);
int? getGpsMapProvider() => provider.getInt(PrefKey.gpsMapProvider);
int getGpsMapProviderOr(int def) => getGpsMapProvider() ?? def;
Future<bool> setGpsMapProvider(int value) =>
provider.setInt(PrefKey.gpsMapProvider, value);
bool? isLabEnableSharedAlbum() =>
provider.getBool(PrefKey.labEnableSharedAlbum);
bool isLabEnableSharedAlbumOr(bool def) => isLabEnableSharedAlbum() ?? def;
Future<bool> setLabEnableSharedAlbum(bool value) =>
provider.setBool(PrefKey.labEnableSharedAlbum, value);
final PrefProvider provider;
static Pref? _inst;
}
/// 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) {
KiwiContainer().resolve<EventBus>().fire(PrefUpdatedEvent(key, value));
return true;
} else {
return false;
}
}
}
/// [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);
}
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, [
this.settings = const AccountSettings(),
]);
factory PrefAccount.fromJson(JsonObj json) {
return PrefAccount(
Account.fromJson(json["account"].cast<String, dynamic>()),
AccountSettings.fromJson(json["settings"].cast<String, dynamic>()),
);
}
JsonObj toJson() => {
"account": account.toJson(),
"settings": settings.toJson(),
};
PrefAccount copyWith({
Account? account,
AccountSettings? settings,
}) {
return PrefAccount(
account ?? this.account,
settings ?? this.settings,
);
}
@override
toString() {
return "$runtimeType {"
"account: $account, "
"settings: $settings, "
"}";
}
final Account account;
final AccountSettings settings;
}
enum PrefKey {
accounts2,
currentAccountIndex,
homePhotosZoomLevel,
albumBrowserZoomLevel,
homeAlbumsSort,
enableExif,
viewerScreenBrightness,
viewerForceRotation,
setupProgress,
lastVersion,
darkTheme,
followSystemTheme,
useBlackInDarkTheme,
language,
newSharedAlbum,
labEnableSharedAlbum,
slideshowDuration,
isSlideshowShuffle,
isSlideshowRepeat,
isAlbumBrowserShowDate,
gpsMapProvider,
}
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";
case PrefKey.gpsMapProvider:
return "gpsMapProvider";
}
}
}
extension PrefExtension on Pref {
Account? getCurrentAccount() {
try {
return Pref().getAccounts2()![Pref().getCurrentAccountIndex()!].account;
} catch (_) {
return null;
}
}
AccountSettings getAccountSettings(Account account) {
return Pref()
.getAccounts2()!
.firstWhere((element) => element.account == account)
.settings;
}
}