Save preferences to same directory to binary file on Windows

This commit is contained in:
2023-08-30 22:09:39 +08:00
parent 63b5e9f71e
commit 6f3a400ed8
12 changed files with 257 additions and 6 deletions

11
lib/config/base.dart Normal file
View File

@@ -0,0 +1,11 @@
abstract interface class Config {
Future<bool> clear();
bool containsKey(String key);
Object? get(String key);
String? getString(String key);
Future<bool> setString(String key, String value);
int? getInt(String key);
Future<bool> setInt(String key, int value);
bool? getBool(String key);
Future<bool> setBool(String key, bool value);
}

View File

@@ -0,0 +1,43 @@
import 'base.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesConfig implements Config {
SharedPreferencesConfig(this._prefs);
final SharedPreferences _prefs;
@override
Future<bool> clear() {
return _prefs.clear();
}
@override
bool containsKey(String key) {
return _prefs.containsKey(key);
}
@override
Object? get(String key) {
return _prefs.get(key);
}
@override
String? getString(String key) {
return _prefs.getString(key);
}
@override
Future<bool> setString(String key, String value) {
return _prefs.setString(key, value);
}
@override
int? getInt(String key) {
return _prefs.getInt(key);
}
@override
Future<bool> setInt(String key, int value) {
return _prefs.setInt(key, value);
}
@override
bool? getBool(String key) {
return _prefs.getBool(key);
}
@override
Future<bool> setBool(String key, bool value) {
return _prefs.setBool(key, value);
}
}

108
lib/config/windows.dart Normal file
View File

@@ -0,0 +1,108 @@
import 'dart:convert' show json;
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'base.dart';
import '../globals.dart';
final _log = Logger("WindowsConfig");
class WindowsConfig implements Config {
WindowsConfig();
FileSystem fs = const LocalFileSystem();
Map<String, Object>? _cachedPreferences;
File? _filePath;
Future<File?> filePath() async {
if (_filePath != null) return _filePath;
final String? exe = await platformPath.getCurrentExe();
if (exe == null) return null;
final dir = path.dirname(exe);
final name = path.basenameWithoutExtension(exe);
return _filePath = fs.file(path.join(dir, "$name.json"));
}
Future<Map<String, Object>> reload() async {
Map<String, Object> preferences = <String, Object>{};
final File? localDataFile = await filePath();
if (localDataFile != null && localDataFile.existsSync()) {
final String stringMap = localDataFile.readAsStringSync();
if (stringMap.isNotEmpty) {
final Object? data = json.decode(stringMap);
if (data is Map) {
preferences = data.cast<String, Object>();
}
}
}
_cachedPreferences = preferences;
return preferences;
}
Future<Map<String, Object>> _readPreferences() async {
return _cachedPreferences ?? await reload();
}
Future<bool> _writePreferences(Map<String, Object> preferences) async {
try {
final File? localDataFile = await filePath();
if (localDataFile == null) {
_log.warning('Unable to determine where to write preferences.');
return false;
}
if (!localDataFile.existsSync()) {
localDataFile.createSync(recursive: true);
}
final String stringMap = json.encode(preferences);
localDataFile.writeAsStringSync(stringMap);
} catch (e) {
_log.severe('Error saving preferences to disk: ', e);
return false;
}
return true;
}
@override
Future<bool> clear() async {
final Map<String, Object> preferences = await _readPreferences();
preferences.clear();
return _writePreferences(preferences);
}
Future<bool> setValue(String key, Object value) async {
final Map<String, Object> preferences = await _readPreferences();
preferences[key] = value;
return _writePreferences(preferences);
}
@override
bool containsKey(String key) {
return _cachedPreferences?.containsKey(key) ?? false;
}
@override
Object? get(String key) => _cachedPreferences?[key];
@override
String? getString(String key) => _cachedPreferences?[key] as String?;
@override
Future<bool> setString(String key, String value) {
return setValue(key, value);
}
@override
int? getInt(String key) => _cachedPreferences?[key] as int?;
@override
Future<bool> setInt(String key, int value) {
return setValue(key, value);
}
@override
bool? getBool(String key) => _cachedPreferences?[key] as bool?;
@override
Future<bool> setBool(String key, bool value) {
return setValue(key, value);
}
}

View File

@@ -9,13 +9,18 @@ import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'api/client.dart';
import 'auth.dart';
import 'config/base.dart';
import 'config/shared_preferences.dart';
import 'config/windows.dart';
import 'platform/path.dart';
import 'utils.dart';
final dio = Dio()
..options.validateStatus = (int? _) {
return true;
}
..options.extra['withCredentials'] = true;
SharedPreferences? _prefs;
Config? _prefs;
EHApi? _api;
Future<void> prepareJar() async {
@@ -28,10 +33,20 @@ Future<void> prepareJar() async {
}
Future<void> preparePrefs() async {
_prefs = await SharedPreferences.getInstance();
if (isWindows) {
try {
var tmp = WindowsConfig();
tmp.reload();
_prefs = tmp;
return;
} catch (e) {
// Do nothing.
}
}
_prefs = SharedPreferencesConfig(await SharedPreferences.getInstance());
}
SharedPreferences get prefs {
Config get prefs {
if (_prefs == null) {
throw Exception('SharedPreferences not initialized');
}
@@ -77,3 +92,4 @@ EHApi get api {
}
final AuthInfo auth = AuthInfo();
final Path platformPath = Path();

View File

@@ -42,6 +42,7 @@ Future<void> initLogger() async {
}
void main() async {
if (!kIsWeb) WidgetsFlutterBinding.ensureInitialized();
bool? usePathUrl = const bool.fromEnvironment("usePathUrl");
if (usePathUrl == true && kIsWeb) {
usePathUrlStrategy();
@@ -49,7 +50,6 @@ void main() async {
if (!kIsWeb) await prepareJar();
await preparePrefs();
if (isDesktop) {
WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
}
await initLogger();

28
lib/platform/path.dart Normal file
View File

@@ -0,0 +1,28 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:logging/logging.dart';
import '../utils.dart';
final Logger _log = Logger("platformPath");
class Path {
static const platform = MethodChannel("lifegpc.eh_downloader_flutter/path");
String? _currentExe;
bool _currentExeLoaded = false;
String? get currentExe => _currentExe;
Future<String?> getCurrentExe() async {
if (_currentExeLoaded) return _currentExe;
try {
final String result = await platform.invokeMethod("getCurrentExe");
_currentExe = result;
} on PlatformException catch (e) {
if (isWindows) {
_log.warning("Failed to get current exe path:", e);
}
}
_currentExeLoaded = true;
return _currentExe;
}
}