mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-12 21:06:43 +02:00
511 lines
13 KiB
Dart
511 lines
13 KiB
Dart
// Exposes functions used to save/load app settings
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:fluttertoast/fluttertoast.dart';
|
|
import 'package:obtainium/app_sources/github.dart';
|
|
import 'package:obtainium/main.dart';
|
|
import 'package:obtainium/providers/apps_provider.dart';
|
|
import 'package:obtainium/providers/source_provider.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:shared_storage/shared_storage.dart' as saf;
|
|
|
|
String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}';
|
|
String obtainiumId = 'dev.imranr.obtainium';
|
|
String obtainiumUrl = 'https://github.com/ImranR98/Obtainium';
|
|
Color obtainiumThemeColor = const Color(0xFF6438B5);
|
|
|
|
enum ThemeSettings { system, light, dark }
|
|
|
|
enum SortColumnSettings { added, nameAuthor, authorName, releaseDate }
|
|
|
|
enum SortOrderSettings { ascending, descending }
|
|
|
|
class SettingsProvider with ChangeNotifier {
|
|
SharedPreferences? prefs;
|
|
String? defaultAppDir;
|
|
bool justStarted = true;
|
|
|
|
String sourceUrl = 'https://github.com/ImranR98/Obtainium';
|
|
|
|
// Not done in constructor as we want to be able to await it
|
|
Future<void> initializeSettings() async {
|
|
prefs = await SharedPreferences.getInstance();
|
|
defaultAppDir = (await getExternalStorageDirectory())!.path;
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get useSystemFont {
|
|
return prefs?.getBool('useSystemFont') ?? false;
|
|
}
|
|
|
|
set useSystemFont(bool useSystemFont) {
|
|
prefs?.setBool('useSystemFont', useSystemFont);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get useShizuku {
|
|
return prefs?.getBool('useShizuku') ?? false;
|
|
}
|
|
|
|
set useShizuku(bool useShizuku) {
|
|
prefs?.setBool('useShizuku', useShizuku);
|
|
notifyListeners();
|
|
}
|
|
|
|
ThemeSettings get theme {
|
|
return ThemeSettings.values[prefs?.getInt('theme') ??
|
|
ThemeSettings.system.index];
|
|
}
|
|
|
|
set theme(ThemeSettings t) {
|
|
prefs?.setInt('theme', t.index);
|
|
notifyListeners();
|
|
}
|
|
|
|
Color get themeColor {
|
|
int? colorCode = prefs?.getInt('themeColor');
|
|
return (colorCode != null) ? Color(colorCode) : obtainiumThemeColor;
|
|
}
|
|
|
|
set themeColor(Color themeColor) {
|
|
prefs?.setInt('themeColor', themeColor.value);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get useMaterialYou {
|
|
return prefs?.getBool('useMaterialYou') ?? false;
|
|
}
|
|
|
|
set useMaterialYou(bool useMaterialYou) {
|
|
prefs?.setBool('useMaterialYou', useMaterialYou);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get useBlackTheme {
|
|
return prefs?.getBool('useBlackTheme') ?? false;
|
|
}
|
|
|
|
set useBlackTheme(bool useBlackTheme) {
|
|
prefs?.setBool('useBlackTheme', useBlackTheme);
|
|
notifyListeners();
|
|
}
|
|
|
|
int get updateInterval {
|
|
return prefs?.getInt('updateInterval') ?? 360;
|
|
}
|
|
|
|
set updateInterval(int min) {
|
|
prefs?.setInt('updateInterval', min);
|
|
notifyListeners();
|
|
}
|
|
|
|
double get updateIntervalSliderVal {
|
|
return prefs?.getDouble('updateIntervalSliderVal') ?? 6.0;
|
|
}
|
|
|
|
set updateIntervalSliderVal(double val) {
|
|
prefs?.setDouble('updateIntervalSliderVal', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get checkOnStart {
|
|
return prefs?.getBool('checkOnStart') ?? false;
|
|
}
|
|
|
|
set checkOnStart(bool checkOnStart) {
|
|
prefs?.setBool('checkOnStart', checkOnStart);
|
|
notifyListeners();
|
|
}
|
|
|
|
SortColumnSettings get sortColumn {
|
|
return SortColumnSettings.values[prefs?.getInt('sortColumn') ??
|
|
SortColumnSettings.nameAuthor.index];
|
|
}
|
|
|
|
set sortColumn(SortColumnSettings s) {
|
|
prefs?.setInt('sortColumn', s.index);
|
|
notifyListeners();
|
|
}
|
|
|
|
SortOrderSettings get sortOrder {
|
|
return SortOrderSettings.values[prefs?.getInt('sortOrder') ??
|
|
SortOrderSettings.ascending.index];
|
|
}
|
|
|
|
set sortOrder(SortOrderSettings s) {
|
|
prefs?.setInt('sortOrder', s.index);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool checkAndFlipFirstRun() {
|
|
bool result = prefs?.getBool('firstRun') ?? true;
|
|
if (result) {
|
|
prefs?.setBool('firstRun', false);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool get welcomeShown {
|
|
return prefs?.getBool('welcomeShown') ?? false;
|
|
}
|
|
|
|
set welcomeShown(bool welcomeShown) {
|
|
prefs?.setBool('welcomeShown', welcomeShown);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool checkJustStarted() {
|
|
if (justStarted) {
|
|
justStarted = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Future<bool> getInstallPermission({bool enforce = false}) async {
|
|
while (!(await Permission.requestInstallPackages.isGranted)) {
|
|
// Explicit request as InstallPlugin request sometimes bugged
|
|
Fluttertoast.showToast(
|
|
msg: tr('pleaseAllowInstallPerm'),
|
|
toastLength: Toast.LENGTH_LONG,
|
|
);
|
|
if ((await Permission.requestInstallPackages.request()) ==
|
|
PermissionStatus.granted) {
|
|
return true;
|
|
}
|
|
if (!enforce) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool get showAppWebpage {
|
|
return prefs?.getBool('showAppWebpage') ?? false;
|
|
}
|
|
|
|
set showAppWebpage(bool show) {
|
|
prefs?.setBool('showAppWebpage', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get pinUpdates {
|
|
return prefs?.getBool('pinUpdates') ?? true;
|
|
}
|
|
|
|
set pinUpdates(bool show) {
|
|
prefs?.setBool('pinUpdates', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get buryNonInstalled {
|
|
return prefs?.getBool('buryNonInstalled') ?? false;
|
|
}
|
|
|
|
set buryNonInstalled(bool show) {
|
|
prefs?.setBool('buryNonInstalled', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get groupByCategory {
|
|
return prefs?.getBool('groupByCategory') ?? false;
|
|
}
|
|
|
|
set groupByCategory(bool show) {
|
|
prefs?.setBool('groupByCategory', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get hideTrackOnlyWarning {
|
|
return prefs?.getBool('hideTrackOnlyWarning') ?? false;
|
|
}
|
|
|
|
set hideTrackOnlyWarning(bool show) {
|
|
prefs?.setBool('hideTrackOnlyWarning', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get hideAPKOriginWarning {
|
|
return prefs?.getBool('hideAPKOriginWarning') ?? false;
|
|
}
|
|
|
|
set hideAPKOriginWarning(bool show) {
|
|
prefs?.setBool('hideAPKOriginWarning', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
String? getSettingString(String settingId) {
|
|
String? str = prefs?.getString(settingId);
|
|
return str?.isNotEmpty == true ? str : null;
|
|
}
|
|
|
|
void setSettingString(String settingId, String value) {
|
|
prefs?.setString(settingId, value);
|
|
notifyListeners();
|
|
}
|
|
|
|
Map<String, int> get categories =>
|
|
Map<String, int>.from(jsonDecode(prefs?.getString('categories') ?? '{}'));
|
|
|
|
void setCategories(Map<String, int> cats, {AppsProvider? appsProvider}) {
|
|
if (appsProvider != null) {
|
|
List<App> changedApps = appsProvider
|
|
.getAppValues()
|
|
.map((a) {
|
|
var n1 = a.app.categories.length;
|
|
a.app.categories.removeWhere((c) => !cats.keys.contains(c));
|
|
return n1 > a.app.categories.length ? a.app : null;
|
|
})
|
|
.where((element) => element != null)
|
|
.map((e) => e as App)
|
|
.toList();
|
|
if (changedApps.isNotEmpty) {
|
|
appsProvider.saveApps(changedApps);
|
|
}
|
|
}
|
|
prefs?.setString('categories', jsonEncode(cats));
|
|
notifyListeners();
|
|
}
|
|
|
|
Locale? get forcedLocale {
|
|
var flSegs = prefs?.getString('forcedLocale')?.split('-');
|
|
var fl = flSegs != null && flSegs.isNotEmpty
|
|
? Locale(flSegs[0], flSegs.length > 1 ? flSegs[1] : null)
|
|
: null;
|
|
var set = supportedLocales.where((element) => element.key == fl).isNotEmpty
|
|
? fl
|
|
: null;
|
|
return set;
|
|
}
|
|
|
|
set forcedLocale(Locale? fl) {
|
|
if (fl == null) {
|
|
prefs?.remove('forcedLocale');
|
|
} else if (supportedLocales
|
|
.where((element) => element.key == fl)
|
|
.isNotEmpty) {
|
|
prefs?.setString('forcedLocale', fl.toLanguageTag());
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
bool setEqual(Set<String> a, Set<String> b) =>
|
|
a.length == b.length && a.union(b).length == a.length;
|
|
|
|
void resetLocaleSafe(BuildContext context) {
|
|
if (context.supportedLocales.contains(context.deviceLocale)) {
|
|
context.resetLocale();
|
|
} else {
|
|
context.setLocale(context.fallbackLocale!);
|
|
context.deleteSaveLocale();
|
|
}
|
|
}
|
|
|
|
bool get removeOnExternalUninstall {
|
|
return prefs?.getBool('removeOnExternalUninstall') ?? false;
|
|
}
|
|
|
|
set removeOnExternalUninstall(bool show) {
|
|
prefs?.setBool('removeOnExternalUninstall', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get checkUpdateOnDetailPage {
|
|
return prefs?.getBool('checkUpdateOnDetailPage') ?? true;
|
|
}
|
|
|
|
set checkUpdateOnDetailPage(bool show) {
|
|
prefs?.setBool('checkUpdateOnDetailPage', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get disablePageTransitions {
|
|
return prefs?.getBool('disablePageTransitions') ?? false;
|
|
}
|
|
|
|
set disablePageTransitions(bool show) {
|
|
prefs?.setBool('disablePageTransitions', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get reversePageTransitions {
|
|
return prefs?.getBool('reversePageTransitions') ?? false;
|
|
}
|
|
|
|
set reversePageTransitions(bool show) {
|
|
prefs?.setBool('reversePageTransitions', show);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get enableBackgroundUpdates {
|
|
return prefs?.getBool('enableBackgroundUpdates') ?? true;
|
|
}
|
|
|
|
set enableBackgroundUpdates(bool val) {
|
|
prefs?.setBool('enableBackgroundUpdates', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get bgUpdatesOnWiFiOnly {
|
|
return prefs?.getBool('bgUpdatesOnWiFiOnly') ?? false;
|
|
}
|
|
|
|
set bgUpdatesOnWiFiOnly(bool val) {
|
|
prefs?.setBool('bgUpdatesOnWiFiOnly', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get bgUpdatesWhileChargingOnly {
|
|
return prefs?.getBool('bgUpdatesWhileChargingOnly') ?? false;
|
|
}
|
|
|
|
set bgUpdatesWhileChargingOnly(bool val) {
|
|
prefs?.setBool('bgUpdatesWhileChargingOnly', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
DateTime get lastCompletedBGCheckTime {
|
|
int? temp = prefs?.getInt('lastCompletedBGCheckTime');
|
|
return temp != null
|
|
? DateTime.fromMillisecondsSinceEpoch(temp)
|
|
: DateTime.fromMillisecondsSinceEpoch(0);
|
|
}
|
|
|
|
set lastCompletedBGCheckTime(DateTime val) {
|
|
prefs?.setInt('lastCompletedBGCheckTime', val.millisecondsSinceEpoch);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get showDebugOpts {
|
|
return prefs?.getBool('showDebugOpts') ?? false;
|
|
}
|
|
|
|
set showDebugOpts(bool val) {
|
|
prefs?.setBool('showDebugOpts', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get highlightTouchTargets {
|
|
return prefs?.getBool('highlightTouchTargets') ?? false;
|
|
}
|
|
|
|
set highlightTouchTargets(bool val) {
|
|
prefs?.setBool('highlightTouchTargets', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<Uri?> getExportDir() async {
|
|
var uriString = prefs?.getString('exportDir');
|
|
if (uriString != null) {
|
|
Uri? uri = Uri.parse(uriString);
|
|
if (!(await saf.canRead(uri) ?? false) ||
|
|
!(await saf.canWrite(uri) ?? false)) {
|
|
uri = null;
|
|
prefs?.remove('exportDir');
|
|
notifyListeners();
|
|
}
|
|
return uri;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> pickExportDir({bool remove = false}) async {
|
|
var existingSAFPerms = (await saf.persistedUriPermissions()) ?? [];
|
|
var currentOneWayDataSyncDir = await getExportDir();
|
|
Uri? newOneWayDataSyncDir;
|
|
if (!remove) {
|
|
newOneWayDataSyncDir = (await saf.openDocumentTree());
|
|
}
|
|
if (currentOneWayDataSyncDir?.path != newOneWayDataSyncDir?.path) {
|
|
if (newOneWayDataSyncDir == null) {
|
|
prefs?.remove('exportDir');
|
|
} else {
|
|
prefs?.setString('exportDir', newOneWayDataSyncDir.toString());
|
|
}
|
|
notifyListeners();
|
|
}
|
|
for (var e in existingSAFPerms) {
|
|
await saf.releasePersistableUriPermission(e.uri);
|
|
}
|
|
}
|
|
|
|
bool get autoExportOnChanges {
|
|
return prefs?.getBool('autoExportOnChanges') ?? false;
|
|
}
|
|
|
|
set autoExportOnChanges(bool val) {
|
|
prefs?.setBool('autoExportOnChanges', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get onlyCheckInstalledOrTrackOnlyApps {
|
|
return prefs?.getBool('onlyCheckInstalledOrTrackOnlyApps') ?? false;
|
|
}
|
|
|
|
set onlyCheckInstalledOrTrackOnlyApps(bool val) {
|
|
prefs?.setBool('onlyCheckInstalledOrTrackOnlyApps', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get exportSettings {
|
|
return prefs?.getBool('exportSettings') ?? false;
|
|
}
|
|
|
|
set exportSettings(bool val) {
|
|
prefs?.setBool('exportSettings', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get parallelDownloads {
|
|
return prefs?.getBool('parallelDownloads') ?? false;
|
|
}
|
|
|
|
set parallelDownloads(bool val) {
|
|
prefs?.setBool('parallelDownloads', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
List<String> get searchDeselected {
|
|
return prefs?.getStringList('searchDeselected') ??
|
|
SourceProvider().sources.map((s) => s.name).toList();
|
|
}
|
|
|
|
set searchDeselected(List<String> list) {
|
|
prefs?.setStringList('searchDeselected', list);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get beforeNewInstallsShareToAppVerifier {
|
|
return prefs?.getBool('beforeNewInstallsShareToAppVerifier') ?? true;
|
|
}
|
|
|
|
set beforeNewInstallsShareToAppVerifier(bool val) {
|
|
prefs?.setBool('beforeNewInstallsShareToAppVerifier', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get shizukuPretendToBeGooglePlay {
|
|
return prefs?.getBool('shizukuPretendToBeGooglePlay') ?? false;
|
|
}
|
|
|
|
set shizukuPretendToBeGooglePlay(bool val) {
|
|
prefs?.setBool('shizukuPretendToBeGooglePlay', val);
|
|
notifyListeners();
|
|
}
|
|
|
|
bool get useFGService {
|
|
return prefs?.getBool('useFGService') ?? false;
|
|
}
|
|
|
|
set useFGService(bool val) {
|
|
prefs?.setBool('useFGService', val);
|
|
notifyListeners();
|
|
}
|
|
}
|