啊
This commit is contained in:
@@ -0,0 +1,802 @@
|
||||
using Ink_Canvas;
|
||||
using Ink_Canvas.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using UpdateChannel = Ink_Canvas.UpdateChannel;
|
||||
using UpdatePackageArchitecture = Ink_Canvas.UpdatePackageArchitecture;
|
||||
using TelemetryUploadLevel = Ink_Canvas.TelemetryUploadLevel;
|
||||
|
||||
namespace Ink_Canvas.Services
|
||||
{
|
||||
public class SettingsService
|
||||
{
|
||||
private static SettingsService _instance;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
private Settings _settings;
|
||||
private MainWindow _mainWindow;
|
||||
private bool _isChangingUpdateChannelInternally = false;
|
||||
private bool _isChangingUpdatePackageArchInternally = false;
|
||||
|
||||
public static readonly string settingsFileName = Path.Combine("Configs", "Settings.json");
|
||||
|
||||
public event Action<string, object> SettingChanged;
|
||||
|
||||
public static SettingsService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new SettingsService();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private SettingsService() { }
|
||||
|
||||
public void Initialize(Settings settings, MainWindow mainWindow = null)
|
||||
{
|
||||
_settings = settings;
|
||||
_mainWindow = mainWindow;
|
||||
}
|
||||
|
||||
public Settings Settings => _settings;
|
||||
|
||||
#region Core Settings Management
|
||||
|
||||
public Settings LoadSettings(bool isStartup = false, bool skipAutoUpdateCheck = false)
|
||||
{
|
||||
Settings loadedSettings = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(App.RootPath + settingsFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
string text = File.ReadAllText(App.RootPath + settingsFileName);
|
||||
loadedSettings = JsonConvert.DeserializeObject<Settings>(text);
|
||||
|
||||
if (loadedSettings != null)
|
||||
{
|
||||
CleanupObsoleteSettings(text, ref loadedSettings);
|
||||
}
|
||||
|
||||
if (loadedSettings == null)
|
||||
{
|
||||
LogHelper.WriteLogToFile("配置文件解析失败,尝试从备份恢复", LogHelper.LogType.Warning);
|
||||
if (AutoBackupManager.TryRestoreFromBackup())
|
||||
{
|
||||
text = File.ReadAllText(App.RootPath + settingsFileName);
|
||||
loadedSettings = JsonConvert.DeserializeObject<Settings>(text);
|
||||
if (loadedSettings != null)
|
||||
{
|
||||
CleanupObsoleteSettings(text, ref loadedSettings);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedSettings == null)
|
||||
{
|
||||
LogHelper.WriteLogToFile("从备份恢复失败,使用默认设置", LogHelper.LogType.Warning);
|
||||
loadedSettings = new Settings();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"配置文件加载失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
|
||||
LogHelper.WriteLogToFile("尝试从备份恢复配置文件", LogHelper.LogType.Warning);
|
||||
if (AutoBackupManager.TryRestoreFromBackup())
|
||||
{
|
||||
try
|
||||
{
|
||||
string text = File.ReadAllText(App.RootPath + settingsFileName);
|
||||
loadedSettings = JsonConvert.DeserializeObject<Settings>(text);
|
||||
if (loadedSettings != null)
|
||||
{
|
||||
CleanupObsoleteSettings(text, ref loadedSettings);
|
||||
}
|
||||
}
|
||||
catch (Exception restoreEx)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"从备份恢复后重新加载失败: {restoreEx.Message}", LogHelper.LogType.Error);
|
||||
loadedSettings = new Settings();
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedSettings == null)
|
||||
{
|
||||
LogHelper.WriteLogToFile("从备份恢复失败,使用默认设置", LogHelper.LogType.Warning);
|
||||
loadedSettings = new Settings();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("配置文件不存在,尝试从备份恢复", LogHelper.LogType.Warning);
|
||||
if (AutoBackupManager.TryRestoreFromBackup())
|
||||
{
|
||||
try
|
||||
{
|
||||
string text = File.ReadAllText(App.RootPath + settingsFileName);
|
||||
loadedSettings = JsonConvert.DeserializeObject<Settings>(text);
|
||||
if (loadedSettings != null)
|
||||
{
|
||||
CleanupObsoleteSettings(text, ref loadedSettings);
|
||||
}
|
||||
}
|
||||
catch (Exception restoreEx)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"从备份恢复后加载失败: {restoreEx.Message}", LogHelper.LogType.Error);
|
||||
loadedSettings = new Settings();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("备份恢复失败,使用默认设置", LogHelper.LogType.Warning);
|
||||
loadedSettings = new Settings();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error);
|
||||
loadedSettings = new Settings();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (loadedSettings?.Appearance != null)
|
||||
{
|
||||
var preferredLanguage = loadedSettings.Appearance.Language ?? string.Empty;
|
||||
if (!string.IsNullOrWhiteSpace(preferredLanguage))
|
||||
{
|
||||
LocalizationHelper.TrySetCulture(preferredLanguage);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"从配置应用界面语言失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProcessProtectionManager.ApplyFromSettings();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
_settings = loadedSettings;
|
||||
return loadedSettings;
|
||||
}
|
||||
|
||||
public void SaveSettingsToFile()
|
||||
{
|
||||
if (_settings == null) return;
|
||||
|
||||
var text = JsonConvert.SerializeObject(_settings, Formatting.Indented);
|
||||
try
|
||||
{
|
||||
string configsDir = Path.Combine(App.RootPath, "Configs");
|
||||
if (!Directory.Exists(configsDir))
|
||||
{
|
||||
ProcessProtectionManager.WithWriteAccess(configsDir, () => Directory.CreateDirectory(configsDir));
|
||||
}
|
||||
|
||||
var path = App.RootPath + settingsFileName;
|
||||
ProcessProtectionManager.WithWriteAccess(path, () => File.WriteAllText(path, text));
|
||||
}
|
||||
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
|
||||
}
|
||||
|
||||
private void CleanupObsoleteSettings(string userConfigJson, ref Settings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
Settings defaultSettings = new Settings();
|
||||
|
||||
JObject defaultConfigObj = JObject.FromObject(defaultSettings);
|
||||
EnsureDefaultConfigSchemaIncludesIgnoredNullKeys(defaultConfigObj);
|
||||
JObject userConfigObj = JObject.Parse(userConfigJson);
|
||||
|
||||
bool hasChanges = false;
|
||||
|
||||
RemoveObsoleteProperties(userConfigObj, defaultConfigObj, ref hasChanges);
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
string cleanedJson = userConfigObj.ToString(Formatting.Indented);
|
||||
settings = JsonConvert.DeserializeObject<Settings>(cleanedJson);
|
||||
SaveSettingsToFile();
|
||||
LogHelper.WriteLogToFile("已清理过期配置项", LogHelper.LogType.Event);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"清理过期配置时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureDefaultConfigSchemaIncludesIgnoredNullKeys(JObject defaultConfigObj)
|
||||
{
|
||||
if (defaultConfigObj == null) return;
|
||||
if (defaultConfigObj["appearance"] is JObject appearance && !appearance.ContainsKey("hitokotoCategories"))
|
||||
appearance["hitokotoCategories"] = JValue.CreateNull();
|
||||
}
|
||||
|
||||
private void RemoveObsoleteProperties(JObject userObj, JObject defaultObj, ref bool hasChanges)
|
||||
{
|
||||
if (userObj == null || defaultObj == null)
|
||||
return;
|
||||
|
||||
List<string> keysToRemove = new List<string>();
|
||||
|
||||
foreach (var property in userObj.Properties())
|
||||
{
|
||||
string propertyName = property.Name;
|
||||
|
||||
if (!defaultObj.ContainsKey(propertyName))
|
||||
{
|
||||
keysToRemove.Add(propertyName);
|
||||
continue;
|
||||
}
|
||||
|
||||
JToken userValue = property.Value;
|
||||
JToken defaultValue = defaultObj[propertyName];
|
||||
|
||||
if (userValue != null && defaultValue != null)
|
||||
{
|
||||
if (userValue.Type == JTokenType.Object && defaultValue.Type == JTokenType.Object)
|
||||
{
|
||||
RemoveObsoleteProperties(userValue as JObject, defaultValue as JObject, ref hasChanges);
|
||||
}
|
||||
else if (userValue.Type == JTokenType.Array && defaultValue.Type == JTokenType.Array)
|
||||
{
|
||||
JArray userArray = userValue as JArray;
|
||||
JArray defaultArray = defaultValue as JArray;
|
||||
|
||||
if (userArray != null && defaultArray != null && userArray.Count > 0 && defaultArray.Count > 0)
|
||||
{
|
||||
if (userArray[0].Type == JTokenType.Object && defaultArray[0].Type == JTokenType.Object)
|
||||
{
|
||||
for (int i = 0; i < userArray.Count; i++)
|
||||
{
|
||||
if (userArray[i] is JObject userItemObj && defaultArray[0] is JObject defaultItemObj)
|
||||
{
|
||||
RemoveObsoleteProperties(userItemObj, defaultItemObj, ref hasChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var key in keysToRemove)
|
||||
{
|
||||
userObj.Remove(key);
|
||||
hasChanges = true;
|
||||
LogHelper.WriteLogToFile($"已删除过期配置项: {key}", LogHelper.LogType.Event);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Generic Setting Methods
|
||||
|
||||
public void Set<T>(Expression<Func<Settings, T>> propertyExpression, T value, bool saveToFile = true)
|
||||
{
|
||||
if (_settings == null) return;
|
||||
|
||||
var propertyName = GetPropertyName(propertyExpression);
|
||||
var property = typeof(Settings).GetProperty(propertyName);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
property.SetValue(_settings, value);
|
||||
if (saveToFile) SaveSettingsToFile();
|
||||
SettingChanged?.Invoke(propertyName, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set<TCategory, TProperty>(Expression<Func<Settings, TCategory>> categoryExpression, Expression<Func<TCategory, TProperty>> propertyExpression, TProperty value, bool saveToFile = true)
|
||||
{
|
||||
if (_settings == null) return;
|
||||
|
||||
var categoryPropertyName = GetPropertyName(categoryExpression);
|
||||
var categoryProperty = typeof(Settings).GetProperty(categoryPropertyName);
|
||||
|
||||
if (categoryProperty != null)
|
||||
{
|
||||
var categoryInstance = categoryProperty.GetValue(_settings);
|
||||
if (categoryInstance != null)
|
||||
{
|
||||
var propertyName = GetPropertyName(propertyExpression);
|
||||
var property = typeof(TCategory).GetProperty(propertyName);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
property.SetValue(categoryInstance, value);
|
||||
if (saveToFile) SaveSettingsToFile();
|
||||
SettingChanged?.Invoke($"{categoryPropertyName}.{propertyName}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T Get<T>(Expression<Func<Settings, T>> propertyExpression)
|
||||
{
|
||||
if (_settings == null) return default;
|
||||
|
||||
var propertyName = GetPropertyName(propertyExpression);
|
||||
var property = typeof(Settings).GetProperty(propertyName);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
return (T)property.GetValue(_settings);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public TProperty Get<TCategory, TProperty>(Expression<Func<Settings, TCategory>> categoryExpression, Expression<Func<TCategory, TProperty>> propertyExpression)
|
||||
{
|
||||
if (_settings == null) return default;
|
||||
|
||||
var categoryPropertyName = GetPropertyName(categoryExpression);
|
||||
var categoryProperty = typeof(Settings).GetProperty(categoryPropertyName);
|
||||
|
||||
if (categoryProperty != null)
|
||||
{
|
||||
var categoryInstance = categoryProperty.GetValue(_settings);
|
||||
if (categoryInstance != null)
|
||||
{
|
||||
var propertyName = GetPropertyName(propertyExpression);
|
||||
var property = typeof(TCategory).GetProperty(propertyName);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
return (TProperty)property.GetValue(categoryInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
private string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> expression)
|
||||
{
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
return memberExpression.Member.Name;
|
||||
}
|
||||
throw new ArgumentException("Expression is not a property access", nameof(expression));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Convenience Methods for Common Settings
|
||||
|
||||
#region Advanced Settings
|
||||
|
||||
public void SetNoFocusMode(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Advanced, a => a.IsNoFocusMode, enabled, saveToFile);
|
||||
if (_mainWindow != null)
|
||||
{
|
||||
_mainWindow.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
_mainWindow.ApplyNoFocusMode();
|
||||
if (_settings.Advanced.IsAlwaysOnTop)
|
||||
{
|
||||
_mainWindow.ApplyAlwaysOnTop();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAlwaysOnTop(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Advanced, a => a.IsAlwaysOnTop, enabled, saveToFile);
|
||||
if (_mainWindow != null)
|
||||
{
|
||||
_mainWindow.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
_mainWindow.ApplyAlwaysOnTop();
|
||||
_mainWindow.UpdateUIAccessTopMostVisibility();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUIAccessTopMost(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Advanced, a => a.EnableUIAccessTopMost, enabled, saveToFile);
|
||||
if (_mainWindow != null)
|
||||
{
|
||||
_mainWindow.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
_mainWindow.ApplyUIAccessTopMost();
|
||||
}));
|
||||
}
|
||||
App.IsUIAccessTopMostEnabled = enabled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Canvas Settings
|
||||
|
||||
public void SetInkFadeEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.EnableInkFade, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetInkFadeTime(int timeMs, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.InkFadeTime, timeMs, saveToFile);
|
||||
}
|
||||
|
||||
public void SetHideInkFadeControlInPenMenu(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.HideInkFadeControlInPenMenu, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetEraserAutoSwitchBack(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.EnableEraserAutoSwitchBack, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetEraserAutoSwitchBackDelay(int seconds, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.EraserAutoSwitchBackDelaySeconds, seconds, saveToFile);
|
||||
}
|
||||
|
||||
public void SetBrushAutoRestore(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.EnableBrushAutoRestore, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetBrushAutoRestoreTimes(string times, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.BrushAutoRestoreTimes, times, saveToFile);
|
||||
}
|
||||
|
||||
public void SetBrushAutoRestoreColor(string color, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.BrushAutoRestoreColor, color, saveToFile);
|
||||
}
|
||||
|
||||
public void SetBrushAutoRestoreWidth(double width, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.BrushAutoRestoreWidth, width, saveToFile);
|
||||
}
|
||||
|
||||
public void SetBrushAutoRestoreAlpha(int alpha, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.BrushAutoRestoreAlpha, alpha, saveToFile);
|
||||
}
|
||||
|
||||
public void SetInkWidth(double width, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.InkWidth, width, saveToFile);
|
||||
}
|
||||
|
||||
public void SetHighlighterWidth(double width, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.HighlighterWidth, width, saveToFile);
|
||||
}
|
||||
|
||||
public void SetInkAlpha(double alpha, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.InkAlpha, alpha, saveToFile);
|
||||
}
|
||||
|
||||
public void SetEraserSize(int size, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.EraserSize, size, saveToFile);
|
||||
}
|
||||
|
||||
public void SetEraserType(int type, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Canvas, c => c.EraserType, type, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Appearance Settings
|
||||
|
||||
public void SetTheme(int themeIndex, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Appearance, a => a.Theme, themeIndex, saveToFile);
|
||||
}
|
||||
|
||||
public void SetLanguage(string languageCode, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Appearance, a => a.Language, languageCode ?? string.Empty, saveToFile);
|
||||
LocalizationHelper.TrySetCulture(languageCode);
|
||||
}
|
||||
|
||||
public void SetFloatingBarOpacity(double opacity, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Appearance, a => a.ViewboxFloatingBarOpacityValue, opacity, saveToFile);
|
||||
}
|
||||
|
||||
public void SetFloatingBarScale(double scale, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Appearance, a => a.ViewboxFloatingBarScaleTransformValue, scale, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PowerPoint Settings
|
||||
|
||||
public void SetPPTOnlyMode(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.ModeSettings, m => m.IsPPTOnlyMode, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetPowerPointSupport(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.PowerPointSettings, p => p.PowerPointSupport, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetShowGestureButtonInSlideShow(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.PowerPointSettings, p => p.ShowGestureButtonInSlideShow, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetPPTTimeCapsuleEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.PowerPointSettings, p => p.EnablePPTTimeCapsule, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetPPTTimeCapsulePosition(int position, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.PowerPointSettings, p => p.PPTTimeCapsulePosition, position, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Gesture Settings
|
||||
|
||||
public void SetTwoFingerZoomEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Gesture, g => g.IsEnableTwoFingerZoom, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetTwoFingerTranslateEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Gesture, g => g.IsEnableTwoFingerTranslate, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetTwoFingerRotationEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Gesture, g => g.IsEnableTwoFingerRotation, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetMultiTouchModeEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Gesture, g => g.IsEnableMultiTouchMode, enabled, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Startup Settings
|
||||
|
||||
public void SetAutoUpdate(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.IsAutoUpdate, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetUpdateChannel(UpdateChannel channel, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.UpdateChannel, channel, saveToFile);
|
||||
}
|
||||
|
||||
public void SetTelemetryUploadLevel(TelemetryUploadLevel level, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.TelemetryUploadLevel, level, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Automation Settings
|
||||
|
||||
public void SetAutoSaveStrokesEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Automation, a => a.IsEnableAutoSaveStrokes, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetAutoSaveStrokesInterval(int minutes, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Automation, a => a.AutoSaveStrokesIntervalMinutes, minutes, saveToFile);
|
||||
}
|
||||
|
||||
public void SetAutoSavedStrokesLocation(string path, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Automation, a => a.AutoSavedStrokesLocation, path, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region InkToShape Settings
|
||||
|
||||
public void SetInkToShapeEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.InkToShape, i => i.IsInkToShapeEnabled, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetShapeRecognitionEngine(int engine, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.InkToShape, i => i.ShapeRecognitionEngine, engine, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Security Settings
|
||||
|
||||
public void SetPasswordEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Security, s => s.PasswordEnabled, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetProcessProtectionEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Security, s => s.EnableProcessProtection, enabled, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Camera Settings
|
||||
|
||||
public void SetCameraRotationAngle(int angle, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Camera, c => c.RotationAngle, angle, saveToFile);
|
||||
}
|
||||
|
||||
public void SetCameraResolution(int width, int height, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Camera, c => c.ResolutionWidth, width, saveToFile);
|
||||
Set(s => s.Camera, c => c.ResolutionHeight, height, saveToFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Startup Settings - Complete Functionality
|
||||
|
||||
public bool CheckRunAtStartup()
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\Ink Canvas Annotation.lnk");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Settings 中没有 IsRunAtStartup 属性,所以这个方法被注释掉了
|
||||
// public void SetRunAtStartup(bool enabled, bool saveToFile = true)
|
||||
// {
|
||||
// Set(s => s.Startup, s => s.IsRunAtStartup, enabled, saveToFile);
|
||||
// }
|
||||
|
||||
public void SetFoldAtStartup(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.IsFoldAtStartup, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetUpdatePackageArchitecture(UpdatePackageArchitecture arch, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.UpdatePackageArchitecture, arch, saveToFile);
|
||||
}
|
||||
|
||||
public void SetAutoUpdateWithSilence(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.IsAutoUpdateWithSilence, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void SetAutoUpdateWithSilenceStartTime(string time, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.AutoUpdateWithSilenceStartTime, time, saveToFile);
|
||||
}
|
||||
|
||||
public void SetAutoUpdateWithSilenceEndTime(string time, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.AutoUpdateWithSilenceEndTime, time, saveToFile);
|
||||
}
|
||||
|
||||
public void SetNibModeEnabled(bool enabled, bool saveToFile = true)
|
||||
{
|
||||
Set(s => s.Startup, s => s.IsEnableNibMode, enabled, saveToFile);
|
||||
}
|
||||
|
||||
public void CheckUpdateChannelAndTelemetryConsistency(bool isLoaded)
|
||||
{
|
||||
if (_settings == null) return;
|
||||
|
||||
var currentChannel = _settings.Startup.UpdateChannel;
|
||||
if (currentChannel == UpdateChannel.Release) return;
|
||||
|
||||
if (!_settings.Startup.HasAcceptedTelemetryPrivacy)
|
||||
{
|
||||
_settings.Startup.UpdateChannel = UpdateChannel.Release;
|
||||
DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release);
|
||||
SaveSettingsToFile();
|
||||
LogHelper.WriteLogToFile($"启动检测 | 用户未同意隐私协议,已切换回 Release 通道");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings.Startup.TelemetryUploadLevel == TelemetryUploadLevel.None)
|
||||
{
|
||||
_isChangingUpdateChannelInternally = true;
|
||||
try
|
||||
{
|
||||
_settings.Startup.UpdateChannel = UpdateChannel.Release;
|
||||
DeviceIdentifier.UpdateUsageChannel(UpdateChannel.Release);
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isChangingUpdateChannelInternally = false;
|
||||
}
|
||||
LogHelper.WriteLogToFile($"启动检测 | 用户未启用遥测,已切换回 Release 通道");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
public static string GetThemeName(int themeIndex)
|
||||
{
|
||||
return themeIndex switch
|
||||
{
|
||||
0 => "浅色主题",
|
||||
1 => "深色主题",
|
||||
2 => "跟随系统",
|
||||
_ => "未知主题"
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetLanguageCode(int languageIndex)
|
||||
{
|
||||
return languageIndex switch
|
||||
{
|
||||
1 => "zh-CN",
|
||||
2 => "en-US",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetLanguageIndex(string languageCode)
|
||||
{
|
||||
return languageCode switch
|
||||
{
|
||||
"zh-CN" => 1,
|
||||
"en-US" => 2,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Ink_Canvas;
|
||||
using Ink_Canvas.Services;
|
||||
|
||||
namespace Ink_Canvas
|
||||
{
|
||||
public static class SettingsServiceDemo
|
||||
{
|
||||
public static void ListAllSettings()
|
||||
{
|
||||
var settingsType = typeof(Settings);
|
||||
var allProperties = new List<string>();
|
||||
|
||||
Console.WriteLine("=== Settings 所有属性列表 ===\n");
|
||||
|
||||
foreach (var categoryProp in settingsType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (categoryProp.PropertyType.IsClass && categoryProp.PropertyType != typeof(string) && categoryProp.PropertyType != typeof(List<string>) && categoryProp.PropertyType != typeof(List<CustomFloatingBarIcon>) && categoryProp.PropertyType != typeof(List<CustomPickNameBackground>) && categoryProp.PropertyType != typeof(Dictionary<string, bool>) && categoryProp.PropertyType != typeof(List<string>) && categoryProp.PropertyType != typeof(DateTime))
|
||||
{
|
||||
Console.WriteLine($"\n--- 分类: {categoryProp.Name} ---\n");
|
||||
|
||||
foreach (var settingProp in categoryProp.PropertyType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
var propName = $"{categoryProp.Name}.{settingProp.Name}";
|
||||
allProperties.Add(propName);
|
||||
Console.WriteLine($" {settingProp.Name,-60} ({settingProp.PropertyType.Name})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{categoryProp.Name,-60} ({categoryProp.PropertyType.Name})");
|
||||
allProperties.Add(categoryProp.Name);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"\n\n总计: {allProperties.Count} 个设置项\n");
|
||||
|
||||
Console.WriteLine("=== SettingsService 访问示例 ===\n");
|
||||
|
||||
Console.WriteLine("// 方式1: 泛型 Set/Get");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Canvas, c => c.InkWidth, 3.5);");
|
||||
Console.WriteLine("double inkWidth = SettingsService.Instance.Get(s => s.Canvas, c => c.InkWidth);");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("// 方式2: 便捷方法");
|
||||
Console.WriteLine("SettingsService.Instance.SetTheme(1);");
|
||||
Console.WriteLine("SettingsService.Instance.SetNoFocusMode(true);");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("// 方式3: 直接访问 Settings 对象");
|
||||
Console.WriteLine("var settings = SettingsService.Instance.Settings;");
|
||||
Console.WriteLine("if (settings != null) {");
|
||||
Console.WriteLine(" settings.Canvas.InkWidth = 3.5;");
|
||||
Console.WriteLine(" settings.Appearance.Theme = 1;");
|
||||
Console.WriteLine(" SettingsService.Instance.Save();");
|
||||
Console.WriteLine("}");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("// 任意设置项示例:");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Automation, a => a.IsAutoFoldInEasiNote, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.PowerPointSettings, p => p.PowerPointSupport, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Gesture, g => g.IsEnableTwoFingerZoom, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Advanced, a => a.IsAlwaysOnTop, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Startup, s => s.IsAutoUpdate, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Security, s => s.PasswordEnabled, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Camera, c => c.RotationAngle, 90);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.InkToShape, i => i.IsInkToShapeEnabled, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.RandSettings, r => r.EnableQuickDraw, true);");
|
||||
Console.WriteLine("SettingsService.Instance.Set(s => s.Appearance, a => a.ViewboxFloatingBarOpacityValue, 0.8);");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user