Files
proxypin/lib/ui/configuration.dart
wanghongenpin 4ff95a3e00 1.2.0 beta
2025-08-10 16:56:51 +08:00

267 lines
7.5 KiB
Dart

/*
* Copyright 2023 Hongen Wang All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:proxypin/network/util/logger.dart';
import 'package:proxypin/utils/platform.dart';
import 'package:path_provider/path_provider.dart';
/// @author wanghongen
/// 2024/1/1
class ColorMapping {
static final Map<String, Color> colors = {
"Blue": Colors.blue,
"Pink": Colors.pink,
"Red": Colors.red,
"Purple": Colors.deepPurple,
"Green": Colors.green,
"Teal": Colors.teal,
"Cyan": Colors.cyan,
"Orange": Colors.orange,
"Yellow": Colors.yellow[900]!,
"Grey": Colors.grey,
};
static Color getColor(String colorName) {
return colors[colorName] ?? Colors.blue;
}
static String getColorName(Color color) {
return colors.entries.firstWhere((entry) => entry.value == color).key;
}
}
class ThemeModel {
ThemeMode mode;
bool useMaterial3;
String color = "Pink";
ThemeModel({this.mode = ThemeMode.system, this.useMaterial3 = true});
ThemeModel copy({ThemeMode? mode, bool? useMaterial3}) => ThemeModel(
mode: mode ?? this.mode,
useMaterial3: useMaterial3 ?? this.useMaterial3,
);
Color get themeColor => ColorMapping.colors[color] ?? Colors.blue;
}
class AppConfiguration {
static const String version = "1.2.0";
ValueNotifier<bool> globalChange = ValueNotifier(false);
ThemeModel _theme = ThemeModel();
Locale? _language;
//是否显示更新内容公告
bool upgradeNoticeV20 = true;
/// 是否启用画中画
ValueNotifier<bool> pipEnabled = ValueNotifier(Platform.isAndroid);
/// 显示画中画图标
ValueNotifier<bool> pipIcon = ValueNotifier(Platform.isAndroid);
/// header默认展示
bool headerExpanded = true;
/// 底部导航栏
bool bottomNavigation = true;
/// 内存清理
int? memoryCleanupThreshold;
///自动已读
bool autoReadEnabled = true;
//桌面window大小
Size? windowSize;
//桌面window位置
Offset? windowPosition;
//左侧面板占比
double panelRatio = 0.3;
AppConfiguration._();
/// 单例
static AppConfiguration? _instance;
static Future<AppConfiguration> get instance async {
if (_instance == null) {
try {
AppConfiguration configuration = AppConfiguration._();
await configuration.initConfig();
_instance = configuration;
} catch (e) {
logger.e("load config error: $e");
_instance = AppConfiguration._();
}
}
return _instance!;
}
static AppConfiguration? get current => _instance;
ThemeMode get themeMode => _theme.mode;
set themeMode(ThemeMode mode) {
if (mode == _theme.mode) return;
_theme.mode = mode;
globalChange.value = !globalChange.value;
flushConfig();
}
///Material3
bool get useMaterial3 => _theme.useMaterial3;
set useMaterial3(bool value) {
if (value == useMaterial3) return;
_theme.useMaterial3 = value;
globalChange.value = !globalChange.value;
flushConfig();
}
Color get themeColor => _theme.themeColor;
set setThemeColor(String colorName) {
var color = ColorMapping.colors[colorName];
if (color == null || color == themeColor) return;
_theme.color = colorName;
globalChange.value = !globalChange.value;
flushConfig();
}
///language
Locale? get language => _language;
set language(Locale? locale) {
if (locale == _language) return;
_language = locale;
globalChange.value = !globalChange.value;
flushConfig();
}
Future<File> get _path async {
if (Platforms.isDesktop()) {
var userHome = Platform.environment['HOME'] ?? Platform.environment['USERPROFILE'];
return File('$userHome${Platform.pathSeparator}.proxypin${Platform.pathSeparator}ui_config.json');
}
final directory = await getApplicationSupportDirectory();
var file = File('${directory.path}${Platform.pathSeparator}ui_config.json');
if (!await file.exists()) {
await file.create();
}
return file;
}
/// 初始化配置
Future<void> initConfig() async {
// 读取配置文件
var file = await _path;
logger.d(file);
var exits = await file.exists();
if (!exits) {
return;
}
var json = await file.readAsString();
if (json.isEmpty) {
return;
}
try {
Map<String, dynamic> config = jsonDecode(json);
var mode =
ThemeMode.values.firstWhere((element) => element.name == config['mode'], orElse: () => ThemeMode.system);
_theme = ThemeModel(mode: mode, useMaterial3: config['useMaterial3'] ?? true);
_theme.color = config['themeColor'] ?? "Blue";
upgradeNoticeV20 = config['upgradeNoticeV20'] ?? true;
_language = config['language'] == null
? null
: Locale.fromSubtags(
languageCode: config['language'],
scriptCode: config['languageScript']
);
pipEnabled.value = config['pipEnabled'] ?? true;
pipIcon.value = config['pipIcon'] ?? false;
headerExpanded = config['headerExpanded'] ?? true;
bottomNavigation = config['bottomNavigation'] ?? true;
memoryCleanupThreshold = config['memoryCleanupThreshold'];
autoReadEnabled = config['autoReadEnabled'] ?? true;
windowSize =
config['windowSize'] == null ? null : Size(config['windowSize']['width'], config['windowSize']['height']);
windowPosition = config['windowPosition'] == null
? null
: Offset(config['windowPosition']['dx'], config['windowPosition']['dy']);
if (config['panelRatio'] != null) {
panelRatio = config['panelRatio'];
}
} catch (e) {
logger.e(e);
}
}
/// 是否正在写入
bool _isWriting = false;
/// 刷新配置文件
flushConfig() async {
if (_isWriting) return;
_isWriting = true;
var file = await _path;
var exists = await file.exists();
if (!exists) {
file = await file.create(recursive: true);
}
var json = jsonEncode(toJson());
await file.writeAsString(json);
_isWriting = false;
}
Map<String, dynamic> toJson() {
return {
'mode': _theme.mode.name,
'themeColor': _theme.color,
'useMaterial3': _theme.useMaterial3,
'upgradeNoticeV20': upgradeNoticeV20,
"language": _language?.languageCode,
"languageScript": _language?.scriptCode,
"headerExpanded": headerExpanded,
"autoReadEnabled": autoReadEnabled,
if (memoryCleanupThreshold != null) 'memoryCleanupThreshold': memoryCleanupThreshold,
if (Platforms.isMobile()) 'pipEnabled': pipEnabled.value,
if (Platforms.isMobile()) 'pipIcon': pipIcon.value ? true : null,
if (Platforms.isMobile()) 'bottomNavigation': bottomNavigation,
if (Platforms.isDesktop())
"windowSize": windowSize == null ? null : {"width": windowSize?.width, "height": windowSize?.height},
if (Platforms.isDesktop())
"windowPosition": windowPosition == null ? null : {"dx": windowPosition?.dx, "dy": windowPosition?.dy},
if (Platforms.isDesktop()) 'panelRatio': panelRatio,
};
}
}