Revert "啊"

This reverts commit 441e600b5d.
This commit is contained in:
PrefacedCorg
2026-04-07 00:33:19 +08:00
parent 441e600b5d
commit 1ec07421b5
5 changed files with 391 additions and 945 deletions
-802
View File
@@ -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
}
}
-75
View File
@@ -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);");
}
}
}
+142
View File
@@ -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
View File
@@ -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
{
+82 -6
View File
@@ -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;
}
}