@@ -1,802 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
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);");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,6 +655,148 @@
|
||||
Padding="15,5" Margin="0,10,0,0"/>
|
||||
</ikw:SimpleStackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Name="GroupBoxStartup">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Margin="0,12,0,0" Text="{i18n:I18n Key=Startup_Start}" FontWeight="Bold" Foreground="#fafafa"
|
||||
FontSize="26" />
|
||||
</GroupBox.Header>
|
||||
<ikw:SimpleStackPanel Spacing="6">
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=Startup_NoFocusMode}" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchNoFocusMode"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchNoFocusMode_Toggled" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=Startup_NoBorderMode}" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchWindowMode"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchWindowMode_Toggled" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=Startup_TopMost}" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchAlwaysOnTop"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchAlwaysOnTop_Toggled" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Name="UIAccessTopMostPanel" Visibility="Collapsed">
|
||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=Startup_UIATopMost}" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchUIAccessTopMost"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchUIAccessTopMost_Toggled" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<TextBlock Name="UIAccessTopMostDescription" Text="{i18n:I18n Key=Startup_UIAccessTopMostHint}" TextWrapping="Wrap" Foreground="#a1a1aa" Visibility="Collapsed" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent=""
|
||||
Name="ToggleSwitchIsAutoUpdate" Header="{i18n:I18n Key=Header_AutoUpdate}"
|
||||
FontFamily="Microsoft YaHei UI"
|
||||
Toggled="ToggleSwitchIsAutoUpdate_Toggled" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent=""
|
||||
Name="ToggleSwitchIsAutoUpdateWithSilence" Header="{i18n:I18n Key=Header_SilentUpdate}"
|
||||
FontFamily="Microsoft YaHei UI"
|
||||
Toggled="ToggleSwitchIsAutoUpdateWithSilence_Toggled" />
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_SilentUpdateHint}" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
|
||||
<!-- 更新包架构 -->
|
||||
<ikw:SimpleStackPanel Spacing="8" Margin="0,8,0,0">
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_UpdatePackageArchitecture}" FontSize="15" FontWeight="Bold" Foreground="#fafafa"/>
|
||||
<ui:RadioButtons x:Name="UpdatePackageArchitectureSelector" Margin="0,4,0,0">
|
||||
<RadioButton Content="{i18n:I18n Key=Update_PackageArch_X86}" GroupName="UpdatePackageArchitecture"
|
||||
Tag="X86" Checked="UpdatePackageArchitectureSelector_Checked"/>
|
||||
<RadioButton Content="{i18n:I18n Key=Update_PackageArch_X64}" GroupName="UpdatePackageArchitecture"
|
||||
Tag="X64" Checked="UpdatePackageArchitectureSelector_Checked"/>
|
||||
</ui:RadioButtons>
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_UpdatePackageArchitectureHint}" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
</ikw:SimpleStackPanel>
|
||||
|
||||
<!-- 更新通道选择 -->
|
||||
<ikw:SimpleStackPanel Spacing="8" Margin="0,8,0,0">
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_UpdateChannel}" FontSize="15" FontWeight="Bold" Foreground="#fafafa"/>
|
||||
<ui:RadioButtons x:Name="UpdateChannelSelector" Margin="0,4,0,0">
|
||||
<RadioButton Content="{i18n:I18n Key=Update_Release}" GroupName="UpdateChannel"
|
||||
Tag="Release" Checked="UpdateChannelSelector_Checked"/>
|
||||
<RadioButton Content="{i18n:I18n Key=Update_Preview}" GroupName="UpdateChannel"
|
||||
Tag="Preview" Checked="UpdateChannelSelector_Checked"/>
|
||||
<RadioButton Content="{i18n:I18n Key=Update_Beta}" GroupName="UpdateChannel"
|
||||
Tag="Beta" Checked="UpdateChannelSelector_Checked"/>
|
||||
</ui:RadioButtons>
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_UpdateChannelHint}" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
</ikw:SimpleStackPanel>
|
||||
|
||||
<!-- 手动更新按钮 -->
|
||||
<Button x:Name="ManualUpdateButton" Content="{i18n:I18n Key=Btn_ManualUpdate}" Margin="0,8,0,0"
|
||||
Width="220" HorizontalAlignment="Left" Click="ManualUpdateButton_Click"
|
||||
Visibility="{Binding ElementName=ToggleSwitchIsAutoUpdate, Path=IsOn, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_ManualUpdateHint}"
|
||||
TextWrapping="Wrap" Foreground="#a1a1aa"
|
||||
Visibility="{Binding ElementName=ToggleSwitchIsAutoUpdate, Path=IsOn, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
|
||||
<!-- 版本修复按钮 -->
|
||||
<Button x:Name="FixVersionButton" Content="{i18n:I18n Key=Btn_FixVersion}" Margin="0,8,0,0"
|
||||
Width="220" HorizontalAlignment="Left" Click="FixVersionButton_Click"/>
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_FixVersionHint}"
|
||||
TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<Button x:Name="HistoryRollbackButton" Content="{i18n:I18n Key=Btn_HistoryRollback}" Width="220" Margin="0,10,0,0" Click="HistoryRollbackButton_Click"/>
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_HistoryRollbackHint}"
|
||||
TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<Border BorderBrush="White" BorderThickness="1" CornerRadius="5" Padding="12"
|
||||
Visibility="{Binding ElementName=ToggleSwitchIsAutoUpdateWithSilence, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<ikw:SimpleStackPanel Spacing="12">
|
||||
<TextBlock
|
||||
Text="{i18n:I18n Key=Startup_SilentUpdateFullHint}"
|
||||
TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<ikw:SimpleStackPanel x:Name="AutoUpdateTimePeriodBlock" Spacing="12">
|
||||
<ikw:SimpleStackPanel Spacing="12">
|
||||
<TextBlock Text="{i18n:I18n Key=Startup_SilentUpdateTimePeriod}" FontSize="15" FontWeight="Bold"
|
||||
TextWrapping="Wrap" Foreground="#fafafa" />
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" Spacing="12">
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,10,0" VerticalAlignment="Center"
|
||||
Text="{i18n:I18n Key=Startup_StartTime}" FontSize="14" TextWrapping="Wrap"
|
||||
Foreground="#fafafa" />
|
||||
<ComboBox x:Name="AutoUpdateWithSilenceStartTimeComboBox"
|
||||
Width="90"
|
||||
SelectionChanged="AutoUpdateWithSilenceStartTimeComboBox_SelectionChanged" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,10,0" VerticalAlignment="Center"
|
||||
Text="{i18n:I18n Key=Startup_EndTime}" FontSize="14" TextWrapping="Wrap"
|
||||
Foreground="#fafafa" />
|
||||
<ComboBox x:Name="AutoUpdateWithSilenceEndTimeComboBox"
|
||||
Width="90"
|
||||
SelectionChanged="AutoUpdateWithSilenceEndTimeComboBox_SelectionChanged" />
|
||||
</ikw:SimpleStackPanel>
|
||||
</ikw:SimpleStackPanel>
|
||||
<TextBlock Width="340" HorizontalAlignment="Left"
|
||||
Text="{i18n:I18n Key=Startup_TimePeriodHint}"
|
||||
TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
</ikw:SimpleStackPanel>
|
||||
</ikw:SimpleStackPanel>
|
||||
</ikw:SimpleStackPanel>
|
||||
</Border>
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=Startup_RunAtStartup}" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchRunAtStartup"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchRunAtStartup_Toggled" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=Startup_FoldAtStartup}" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchFoldAtStartup"
|
||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchFoldAtStartup_Toggled" />
|
||||
</ikw:SimpleStackPanel>
|
||||
<!--
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchAutoHideCanvas" Header="自动隐藏画板" FontFamily="Microsoft YaHei UI" Toggled="ToggleSwitchAutoHideCanvas_Toggled"/>
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchAutoEnterModeFinger" Header="自动进入手指模式" FontFamily="Microsoft YaHei UI" Toggled="ToggleSwitchAutoEnterModeFinger_Toggled"/>
|
||||
-->
|
||||
</ikw:SimpleStackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Name="GroupBoxCanvas">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Margin="0,12,0,0" Text="{i18n:I18n Key=Canvas_GroupTitle}" FontWeight="Bold" Foreground="#fafafa"
|
||||
|
||||
+167
-62
@@ -1,5 +1,4 @@
|
||||
using Ink_Canvas.Helpers;
|
||||
using Ink_Canvas.Services;
|
||||
using Ink_Canvas.Windows;
|
||||
using iNKORE.UI.WPF.Modern;
|
||||
using iNKORE.UI.WPF.Modern.Controls;
|
||||
@@ -330,9 +329,11 @@ namespace Ink_Canvas
|
||||
BlackBoardRightSidePageListScrollViewer.ReleaseTouchCapture(e.TouchDevice);
|
||||
e.Handled = true;
|
||||
};
|
||||
// 初始化无焦点模式
|
||||
// 初始化无焦点模式开关
|
||||
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
|
||||
ApplyNoFocusMode();
|
||||
// 初始化窗口置顶
|
||||
// 初始化窗口置顶开关
|
||||
ToggleSwitchAlwaysOnTop.IsOn = Settings.Advanced.IsAlwaysOnTop;
|
||||
ApplyAlwaysOnTop();
|
||||
|
||||
// 添加窗口激活事件处理,确保置顶状态在窗口重新激活时得到保持
|
||||
@@ -1180,10 +1181,6 @@ namespace Ink_Canvas
|
||||
//加载设置
|
||||
LoadSettings(true);
|
||||
ApplyLanguageFromSettings();
|
||||
|
||||
// 初始化设置服务
|
||||
SettingsService.Instance.Initialize(Settings, this);
|
||||
|
||||
AutoBackupManager.Initialize(Settings);
|
||||
CheckUpdateChannelAndTelemetryConsistency();
|
||||
|
||||
@@ -1371,9 +1368,15 @@ namespace Ink_Canvas
|
||||
}
|
||||
|
||||
// 确保开关和设置同步
|
||||
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
|
||||
ApplyNoFocusMode();
|
||||
ToggleSwitchAlwaysOnTop.IsOn = Settings.Advanced.IsAlwaysOnTop;
|
||||
ApplyAlwaysOnTop();
|
||||
|
||||
// 初始化UIA置顶开关
|
||||
ToggleSwitchUIAccessTopMost.IsOn = Settings.Advanced.EnableUIAccessTopMost;
|
||||
UpdateUIAccessTopMostVisibility();
|
||||
|
||||
App.IsUIAccessTopMostEnabled = Settings.Advanced.EnableUIAccessTopMost;
|
||||
|
||||
// 初始化橡皮擦自动切换回批注模式开关
|
||||
@@ -2538,6 +2541,9 @@ namespace Ink_Canvas
|
||||
|
||||
switch (sectionTag.ToLower())
|
||||
{
|
||||
case "startup":
|
||||
targetGroupBox = GroupBoxStartup;
|
||||
break;
|
||||
case "canvas":
|
||||
targetGroupBox = GroupBoxCanvas;
|
||||
break;
|
||||
@@ -2991,7 +2997,7 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyNoFocusMode()
|
||||
private void ApplyNoFocusMode()
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(this).Handle;
|
||||
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
@@ -3011,7 +3017,7 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyAlwaysOnTop()
|
||||
private void ApplyAlwaysOnTop()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -3207,29 +3213,30 @@ namespace Ink_Canvas
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
var toggle = sender as ToggleSwitch;
|
||||
bool enabled = toggle != null && toggle.IsOn;
|
||||
Settings.Advanced.IsNoFocusMode = toggle != null && toggle.IsOn;
|
||||
SaveSettingsToFile();
|
||||
|
||||
if (isTemporarilyDisablingNoFocusMode)
|
||||
{
|
||||
isTemporarilyDisablingNoFocusMode = false;
|
||||
}
|
||||
|
||||
SettingsService.Instance.SetNoFocusMode(enabled);
|
||||
ApplyNoFocusMode();
|
||||
|
||||
// 如果启用了窗口置顶,需要重新应用置顶设置以处理无焦点模式的变化
|
||||
if (Settings.Advanced.IsAlwaysOnTop)
|
||||
{
|
||||
ApplyAlwaysOnTop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ToggleSwitchAlwaysOnTop_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
var toggle = sender as ToggleSwitch;
|
||||
bool enabled = toggle != null && toggle.IsOn;
|
||||
|
||||
SettingsService.Instance.SetAlwaysOnTop(enabled);
|
||||
Settings.Advanced.IsAlwaysOnTop = toggle != null && toggle.IsOn;
|
||||
SaveSettingsToFile();
|
||||
ApplyAlwaysOnTop();
|
||||
UpdateUIAccessTopMostVisibility();
|
||||
}
|
||||
@@ -3238,10 +3245,14 @@ namespace Ink_Canvas
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
var toggle = sender as ToggleSwitch;
|
||||
bool enabled = toggle != null && toggle.IsOn;
|
||||
bool newValue = toggle != null && toggle.IsOn;
|
||||
|
||||
SettingsService.Instance.SetUIAccessTopMost(enabled);
|
||||
Settings.Advanced.EnableUIAccessTopMost = newValue;
|
||||
SaveSettingsToFile();
|
||||
ApplyUIAccessTopMost();
|
||||
|
||||
App.IsUIAccessTopMostEnabled = newValue;
|
||||
|
||||
}
|
||||
|
||||
private void Window_Activated(object sender, EventArgs e)
|
||||
@@ -3428,18 +3439,19 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
bool enabled = ToggleSwitchEnableInkFade.IsOn;
|
||||
SettingsService.Instance.SetInkFadeEnabled(enabled);
|
||||
_inkFadeManager.IsEnabled = enabled;
|
||||
Settings.Canvas.EnableInkFade = ToggleSwitchEnableInkFade.IsOn;
|
||||
_inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
|
||||
|
||||
// 同步批注子面板中的开关状态
|
||||
if (ToggleSwitchInkFadeInPanel != null)
|
||||
{
|
||||
ToggleSwitchInkFadeInPanel.IsOn = enabled;
|
||||
ToggleSwitchInkFadeInPanel.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
// 同步普通画笔面板中的开关状态
|
||||
if (ToggleSwitchInkFadeInPanel2 != null)
|
||||
{
|
||||
ToggleSwitchInkFadeInPanel2.IsOn = enabled;
|
||||
ToggleSwitchInkFadeInPanel2.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3456,12 +3468,12 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
int timeMs = (int)e.NewValue;
|
||||
SettingsService.Instance.SetInkFadeTime(timeMs);
|
||||
Settings.Canvas.InkFadeTime = (int)e.NewValue;
|
||||
if (_inkFadeManager != null)
|
||||
{
|
||||
_inkFadeManager.UpdateFadeTime(timeMs);
|
||||
_inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
|
||||
}
|
||||
LogHelper.WriteLogToFile($"墨迹渐隐时间已更新为 {Settings.Canvas.InkFadeTime}ms", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3478,18 +3490,19 @@ namespace Ink_Canvas
|
||||
{
|
||||
try
|
||||
{
|
||||
bool enabled = ToggleSwitchInkFadeInPanel.IsOn;
|
||||
SettingsService.Instance.SetInkFadeEnabled(enabled);
|
||||
_inkFadeManager.IsEnabled = enabled;
|
||||
Settings.Canvas.EnableInkFade = ToggleSwitchInkFadeInPanel.IsOn;
|
||||
_inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
|
||||
|
||||
// 同步设置面板中的开关状态
|
||||
if (ToggleSwitchEnableInkFade != null)
|
||||
{
|
||||
ToggleSwitchEnableInkFade.IsOn = enabled;
|
||||
ToggleSwitchEnableInkFade.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
// 同步普通画笔面板中的开关状态
|
||||
if (ToggleSwitchInkFadeInPanel2 != null)
|
||||
{
|
||||
ToggleSwitchInkFadeInPanel2.IsOn = enabled;
|
||||
ToggleSwitchInkFadeInPanel2.IsOn = Settings.Canvas.EnableInkFade;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3513,11 +3526,14 @@ namespace Ink_Canvas
|
||||
{
|
||||
if (isLoaded)
|
||||
{
|
||||
bool hidden = ToggleSwitchHideInkFadeControlInPenMenu.IsOn;
|
||||
SettingsService.Instance.SetHideInkFadeControlInPenMenu(hidden);
|
||||
Settings.Canvas.HideInkFadeControlInPenMenu = ToggleSwitchHideInkFadeControlInPenMenu.IsOn;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
// 立即更新墨迹渐隐控制开关的可见性
|
||||
UpdateInkFadeControlVisibility();
|
||||
|
||||
LogHelper.WriteLogToFile($"在笔工具菜单中隐藏墨迹渐隐控制开关已{(Settings.Canvas.HideInkFadeControlInPenMenu ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3525,18 +3541,24 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 橡皮擦自动切换回批注模式开关切换事件处理
|
||||
/// </summary>
|
||||
private void ToggleSwitchEnableEraserAutoSwitchBack_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
bool enabled = ToggleSwitchEnableEraserAutoSwitchBack.IsOn;
|
||||
SettingsService.Instance.SetEraserAutoSwitchBack(enabled);
|
||||
Settings.Canvas.EnableEraserAutoSwitchBack = ToggleSwitchEnableEraserAutoSwitchBack.IsOn;
|
||||
SaveSettingsToFile();
|
||||
|
||||
if (!enabled)
|
||||
// 如果禁用,停止计时器
|
||||
if (!Settings.Canvas.EnableEraserAutoSwitchBack)
|
||||
{
|
||||
StopEraserAutoSwitchBackTimer();
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"橡皮擦自动切换回批注模式已{(Settings.Canvas.EnableEraserAutoSwitchBack ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3544,18 +3566,24 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 橡皮擦自动切换延迟时间滑块值改变事件处理
|
||||
/// </summary>
|
||||
private void EraserAutoSwitchBackDelaySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
int delaySeconds = (int)e.NewValue;
|
||||
SettingsService.Instance.SetEraserAutoSwitchBackDelay(delaySeconds);
|
||||
Settings.Canvas.EraserAutoSwitchBackDelaySeconds = (int)e.NewValue;
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 如果计时器正在运行,重新启动以应用新的延迟时间
|
||||
if (_eraserAutoSwitchBackTimer != null && _eraserAutoSwitchBackTimer.IsEnabled)
|
||||
{
|
||||
StartEraserAutoSwitchBackTimer();
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"橡皮擦自动切换延迟时间已更新为 {Settings.Canvas.EraserAutoSwitchBackDelaySeconds} 秒", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3563,15 +3591,18 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据开关状态启用或禁用画笔自动恢复:更新设置并保存,启用时初始化并安排恢复定时器,禁用时停止计时器。
|
||||
/// </summary>
|
||||
private void ToggleSwitchBrushAutoRestore_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
bool enabled = ToggleSwitchBrushAutoRestore.IsOn;
|
||||
SettingsService.Instance.SetBrushAutoRestore(enabled);
|
||||
Settings.Canvas.EnableBrushAutoRestore = ToggleSwitchBrushAutoRestore.IsOn;
|
||||
SaveSettingsToFile();
|
||||
|
||||
if (enabled)
|
||||
if (Settings.Canvas.EnableBrushAutoRestore)
|
||||
{
|
||||
InitBrushAutoRestoreTimer();
|
||||
ScheduleBrushAutoRestore();
|
||||
@@ -3603,8 +3634,8 @@ namespace Ink_Canvas
|
||||
if (!isLoaded) return;
|
||||
if (Settings?.Canvas == null) return;
|
||||
|
||||
string times = BrushAutoRestoreTimesTextBox.Text ?? string.Empty;
|
||||
SettingsService.Instance.SetBrushAutoRestoreTimes(times);
|
||||
Settings.Canvas.BrushAutoRestoreTimes = BrushAutoRestoreTimesTextBox.Text ?? string.Empty;
|
||||
SaveSettingsToFile();
|
||||
if (Settings.Canvas.EnableBrushAutoRestore)
|
||||
{
|
||||
ScheduleBrushAutoRestore();
|
||||
@@ -3632,7 +3663,8 @@ namespace Ink_Canvas
|
||||
if (ComboBoxBrushAutoRestoreColor.SelectedItem is ComboBoxItem item)
|
||||
{
|
||||
string hex = item.Tag as string ?? string.Empty;
|
||||
SettingsService.Instance.SetBrushAutoRestoreColor(hex);
|
||||
Settings.Canvas.BrushAutoRestoreColor = hex;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -3656,7 +3688,8 @@ namespace Ink_Canvas
|
||||
if (!isLoaded) return;
|
||||
if (Settings?.Canvas == null) return;
|
||||
|
||||
SettingsService.Instance.SetBrushAutoRestoreWidth(e.NewValue);
|
||||
Settings.Canvas.BrushAutoRestoreWidth = e.NewValue;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3675,7 +3708,8 @@ namespace Ink_Canvas
|
||||
if (!isLoaded) return;
|
||||
if (Settings?.Canvas == null) return;
|
||||
|
||||
SettingsService.Instance.SetBrushAutoRestoreAlpha((int)e.NewValue);
|
||||
Settings.Canvas.BrushAutoRestoreAlpha = (int)e.NewValue;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3710,19 +3744,25 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PPT放映模式显示手势按钮开关切换事件处理
|
||||
/// </summary>
|
||||
private void ToggleSwitchShowGestureButtonInSlideShow_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
var toggle = sender as ToggleSwitch;
|
||||
bool enabled = toggle != null && toggle.IsOn;
|
||||
SettingsService.Instance.SetShowGestureButtonInSlideShow(enabled);
|
||||
Settings.PowerPointSettings.ShowGestureButtonInSlideShow = toggle != null && toggle.IsOn;
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 如果当前在PPT放映模式,需要立即更新手势按钮的显示状态
|
||||
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
|
||||
{
|
||||
UpdateGestureButtonVisibilityInPPTMode();
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"PPT放映模式显示手势按钮已{(Settings.PowerPointSettings.ShowGestureButtonInSlideShow ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3736,14 +3776,17 @@ namespace Ink_Canvas
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
var toggle = sender as ToggleSwitch;
|
||||
bool enabled = toggle != null && toggle.IsOn;
|
||||
SettingsService.Instance.SetPPTTimeCapsuleEnabled(enabled);
|
||||
Settings.PowerPointSettings.EnablePPTTimeCapsule = toggle != null && toggle.IsOn;
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 如果当前在PPT放映模式,需要立即更新时间胶囊和快捷面板的显示状态
|
||||
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
|
||||
{
|
||||
UpdatePPTTimeCapsuleVisibility();
|
||||
UpdatePPTQuickPanelVisibility();
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"PPT时间显示胶囊已{(Settings.PowerPointSettings.EnablePPTTimeCapsule ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -3758,13 +3801,16 @@ namespace Ink_Canvas
|
||||
if (!isLoaded) return;
|
||||
if (ComboBoxPPTTimeCapsulePosition != null)
|
||||
{
|
||||
int position = ComboBoxPPTTimeCapsulePosition.SelectedIndex;
|
||||
SettingsService.Instance.SetPPTTimeCapsulePosition(position);
|
||||
Settings.PowerPointSettings.PPTTimeCapsulePosition = ComboBoxPPTTimeCapsulePosition.SelectedIndex;
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 如果当前在PPT放映模式,需要立即更新时间胶囊的位置
|
||||
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
|
||||
{
|
||||
UpdatePPTTimeCapsulePosition();
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"PPT时间胶囊位置已更改为: {ComboBoxPPTTimeCapsulePosition.SelectedIndex}", LogHelper.LogType.Event);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -4293,6 +4339,9 @@ namespace Ink_Canvas
|
||||
|
||||
#region 模式切换相关
|
||||
|
||||
/// <summary>
|
||||
/// 模式切换开关事件处理
|
||||
/// </summary>
|
||||
private void ToggleSwitchMode_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -4300,10 +4349,13 @@ namespace Ink_Canvas
|
||||
var toggle = sender as ToggleSwitch;
|
||||
if (toggle != null)
|
||||
{
|
||||
bool enabled = toggle.IsOn;
|
||||
SettingsService.Instance.SetPPTOnlyMode(enabled);
|
||||
Settings.ModeSettings.IsPPTOnlyMode = toggle.IsOn;
|
||||
|
||||
if (enabled)
|
||||
// 保存设置到文件
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 如果切换到仅PPT模式,立即隐藏主窗口
|
||||
if (Settings.ModeSettings.IsPPTOnlyMode)
|
||||
{
|
||||
Hide();
|
||||
LogHelper.WriteLogToFile("已切换到仅PPT模式,主窗口已隐藏", LogHelper.LogType.Event);
|
||||
@@ -4312,6 +4364,7 @@ namespace Ink_Canvas
|
||||
else
|
||||
{
|
||||
StopPptOnlyVisibilityProbeTimer();
|
||||
// 如果切换到正常模式,显示主窗口
|
||||
Show();
|
||||
LogHelper.WriteLogToFile("已切换到正常模式,主窗口已显示", LogHelper.LogType.Event);
|
||||
}
|
||||
@@ -4393,6 +4446,9 @@ namespace Ink_Canvas
|
||||
|
||||
#region Theme Toggle
|
||||
|
||||
/// <summary>
|
||||
/// 主题下拉框选择变化事件
|
||||
/// </summary>
|
||||
private void ComboBoxTheme_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
@@ -4402,10 +4458,33 @@ namespace Ink_Canvas
|
||||
System.Windows.Controls.ComboBox comboBox = sender as System.Windows.Controls.ComboBox;
|
||||
if (comboBox != null)
|
||||
{
|
||||
int themeIndex = comboBox.SelectedIndex;
|
||||
SettingsService.Instance.SetTheme(themeIndex);
|
||||
ApplyTheme(themeIndex);
|
||||
ShowNotification($"已切换到{SettingsService.GetThemeName(themeIndex)}");
|
||||
Settings.Appearance.Theme = comboBox.SelectedIndex;
|
||||
|
||||
// 应用新主题
|
||||
ApplyTheme(comboBox.SelectedIndex);
|
||||
|
||||
// 保存设置
|
||||
SaveSettingsToFile();
|
||||
|
||||
// 显示通知
|
||||
string themeName;
|
||||
switch (comboBox.SelectedIndex)
|
||||
{
|
||||
case 0:
|
||||
themeName = "浅色主题";
|
||||
break;
|
||||
case 1:
|
||||
themeName = "深色主题";
|
||||
break;
|
||||
case 2:
|
||||
themeName = "跟随系统";
|
||||
break;
|
||||
default:
|
||||
themeName = "未知主题";
|
||||
break;
|
||||
}
|
||||
|
||||
ShowNotification($"已切换到{themeName}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -4427,9 +4506,25 @@ namespace Ink_Canvas
|
||||
if (ComboBoxLanguage == null) return;
|
||||
|
||||
var index = ComboBoxLanguage.SelectedIndex;
|
||||
string language = SettingsService.GetLanguageCode(index);
|
||||
string language;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 1:
|
||||
language = "zh-CN";
|
||||
break;
|
||||
case 2:
|
||||
language = "en-US";
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
language = string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
Settings.Appearance.Language = language;
|
||||
SaveSettingsToFile();
|
||||
|
||||
SettingsService.Instance.SetLanguage(language);
|
||||
LocalizationHelper.TrySetCulture(language);
|
||||
|
||||
_isReloadingForLanguageChange = true;
|
||||
@@ -4535,11 +4630,21 @@ namespace Ink_Canvas
|
||||
/// <summary>
|
||||
/// 更新UIA置顶开关的可见性
|
||||
/// </summary>
|
||||
internal void UpdateUIAccessTopMostVisibility()
|
||||
private void UpdateUIAccessTopMostVisibility()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 移除了 UIAccessTopMostPanel 的可见性控制,因为 UI 已移至新设置窗口
|
||||
var visibility = Settings.Advanced.IsAlwaysOnTop ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
if (UIAccessTopMostPanel != null)
|
||||
{
|
||||
UIAccessTopMostPanel.Visibility = visibility;
|
||||
}
|
||||
|
||||
if (UIAccessTopMostDescription != null)
|
||||
{
|
||||
UIAccessTopMostDescription.Visibility = visibility;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -4550,7 +4655,7 @@ namespace Ink_Canvas
|
||||
/// <summary>
|
||||
/// 应用UIA置顶功能
|
||||
/// </summary>
|
||||
internal void ApplyUIAccessTopMost()
|
||||
private void ApplyUIAccessTopMost()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -216,8 +216,23 @@ namespace Ink_Canvas
|
||||
{
|
||||
}
|
||||
|
||||
// 检查开机自启动(不再设置 UI 控件,Settings 中没有 IsRunAtStartup 属性)
|
||||
// var runAtStartup = SettingsService.Instance.CheckRunAtStartup();
|
||||
try
|
||||
{
|
||||
if (File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Startup) +
|
||||
"\\Ink Canvas Annotation.lnk"))
|
||||
{
|
||||
ToggleSwitchRunAtStartup.IsOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleSwitchRunAtStartup.IsOn = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile(ex.ToString(), LogHelper.LogType.Error);
|
||||
ToggleSwitchRunAtStartup.IsOn = false;
|
||||
}
|
||||
|
||||
if (Settings.Startup != null)
|
||||
{
|
||||
@@ -235,16 +250,22 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
// 设置笔尖模式(不再设置 UI 控件)
|
||||
if (Settings.Startup.IsEnableNibMode)
|
||||
{
|
||||
ToggleSwitchEnableNibMode.IsOn = true;
|
||||
BoardToggleSwitchEnableNibMode.IsOn = true;
|
||||
BoundsWidth = Settings.Advanced.NibModeBoundsWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleSwitchEnableNibMode.IsOn = false;
|
||||
BoardToggleSwitchEnableNibMode.IsOn = false;
|
||||
BoundsWidth = Settings.Advanced.FingerModeBoundsWidth;
|
||||
}
|
||||
|
||||
// 设置自动更新相关选项
|
||||
ToggleSwitchIsAutoUpdate.IsOn = Settings.Startup.IsAutoUpdate;
|
||||
|
||||
// 只有在启用了自动更新功能时才检查更新
|
||||
if (Settings.Startup.IsAutoUpdate && !skipAutoUpdateCheck)
|
||||
{
|
||||
@@ -261,13 +282,66 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
// 不再初始化 UI 控件,已移至 SettingsService
|
||||
ToggleSwitchIsAutoUpdateWithSilence.Visibility = Settings.Startup.IsAutoUpdate ? Visibility.Visible : Visibility.Collapsed;
|
||||
if (Settings.Startup.IsAutoUpdateWithSilence)
|
||||
{
|
||||
ToggleSwitchIsAutoUpdateWithSilence.IsOn = true;
|
||||
}
|
||||
|
||||
// 初始化更新通道选择
|
||||
foreach (var radioButton in UpdateChannelSelector.Items)
|
||||
{
|
||||
if (radioButton is RadioButton rb)
|
||||
{
|
||||
if (rb.Tag.ToString() == Settings.Startup.UpdateChannel.ToString())
|
||||
{
|
||||
rb.IsChecked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化更新包架构
|
||||
if (UpdatePackageArchitectureSelector != null)
|
||||
{
|
||||
_isChangingUpdatePackageArchInternally = true;
|
||||
try
|
||||
{
|
||||
string wantTag = Settings.Startup.UpdatePackageArchitecture == UpdatePackageArchitecture.X64 ? "X64" : "X86";
|
||||
foreach (var item in UpdatePackageArchitectureSelector.Items)
|
||||
{
|
||||
if (item is RadioButton rb && rb.Tag != null &&
|
||||
string.Equals(rb.Tag.ToString(), wantTag, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
rb.IsChecked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isChangingUpdatePackageArchInternally = false;
|
||||
}
|
||||
}
|
||||
|
||||
AutoUpdateTimePeriodBlock.Visibility = Settings.Startup.IsAutoUpdateWithSilence
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
|
||||
AutoUpdateWithSilenceTimeComboBox.InitializeAutoUpdateWithSilenceTimeComboBoxOptions(
|
||||
AutoUpdateWithSilenceStartTimeComboBox, AutoUpdateWithSilenceEndTimeComboBox);
|
||||
AutoUpdateWithSilenceStartTimeComboBox.SelectedItem = Settings.Startup.AutoUpdateWithSilenceStartTime;
|
||||
AutoUpdateWithSilenceEndTimeComboBox.SelectedItem = Settings.Startup.AutoUpdateWithSilenceEndTime;
|
||||
|
||||
ToggleSwitchFoldAtStartup.IsOn = Settings.Startup.IsFoldAtStartup;
|
||||
}
|
||||
else
|
||||
{
|
||||
Settings.Startup = new Startup();
|
||||
Settings.Startup.IsEnableNibMode = false;
|
||||
BoundsWidth = Settings.Advanced.FingerModeBoundsWidth;
|
||||
Settings.Startup.IsEnableNibMode = false; // 默认关闭笔尖模式
|
||||
ToggleSwitchEnableNibMode.IsOn = false; // 默认关闭笔尖模式
|
||||
BoardToggleSwitchEnableNibMode.IsOn = false; // 默认关闭笔尖模式
|
||||
BoundsWidth = Settings.Advanced.FingerModeBoundsWidth; // 使用手指模式边界宽度
|
||||
}
|
||||
|
||||
// 恢复崩溃后操作设置
|
||||
@@ -277,10 +351,12 @@ namespace Ink_Canvas
|
||||
if (Settings.Startup.CrashAction == 0)
|
||||
{
|
||||
App.CrashAction = App.CrashActionType.SilentRestart;
|
||||
if (RadioCrashSilentRestart != null) RadioCrashSilentRestart.IsChecked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
App.CrashAction = App.CrashActionType.NoAction;
|
||||
if (RadioCrashNoAction != null) RadioCrashNoAction.IsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user