From 8dd1eed51942cc4a651d7c2ff74b5df05d9a7b86 Mon Sep 17 00:00:00 2001 From: miao-moe Date: Sun, 28 Jun 2026 06:51:35 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Better-Seewo=20v2.0.0=20-=20=E5=B8=8C?= =?UTF-8?q?=E6=B2=83=E7=99=BD=E6=9D=BF=E5=8A=9F=E8=83=BD=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fluent Design 风格 UI,深色/浅色主题切换 - 平滑过渡动画(页面切换、按钮交互、状态变化) - 五大核心功能:安装管理、墨迹管理、格式转换、触摸设置、激活管理 - 基于 dotnetCampus.EasiPlugin.Sdk v2.1.1-alpha.3 插件框架 - WPF 安装向导(欢迎页 -> 安装页 -> 完成页) --- .gitignore | 208 ++++++++++ Better-EN5/Better-EN5.csproj | 36 ++ Better-EN5/Program.cs | 126 ++++++ Better-EN5/UI/ExportInkMenuItem.cs | 118 ++++++ Better-EN5/UI/ImportInkMenuItem.cs | 127 ++++++ Better-EN5/UI/InkDataHelper.cs | 240 ++++++++++++ Better-EN5/UI/ManagerMenuItem.cs | 126 ++++++ Better-Seewo.sln | 37 ++ Directory.Build.props | 31 ++ Installer/App.xaml | 18 + Installer/App.xaml.cs | 112 ++++++ Installer/Installer.csproj | 27 ++ Installer/MainWindow.xaml | 452 +++++++++++++++++++++ Installer/MainWindow.xaml.cs | 354 +++++++++++++++++ Installer/Pages/CompletePage.xaml | 422 ++++++++++++++++++++ Installer/Pages/CompletePage.xaml.cs | 109 ++++++ Installer/Pages/InstallPage.xaml | 305 +++++++++++++++ Installer/Pages/InstallPage.xaml.cs | 345 ++++++++++++++++ Installer/Pages/WelcomePage.xaml | 278 +++++++++++++ Installer/Pages/WelcomePage.xaml.cs | 51 +++ Installer/Themes/InstallerTheme.xaml | 146 +++++++ Manager/App.xaml | 19 + Manager/App.xaml.cs | 124 ++++++ Manager/MainWindow.xaml | 523 +++++++++++++++++++++++++ Manager/MainWindow.xaml.cs | 350 +++++++++++++++++ Manager/Manager.csproj | 30 ++ Manager/Pages/ActivatePage.xaml | 463 ++++++++++++++++++++++ Manager/Pages/ActivatePage.xaml.cs | 322 +++++++++++++++ Manager/Pages/ConvertPage.xaml | 561 +++++++++++++++++++++++++++ Manager/Pages/ConvertPage.xaml.cs | 284 ++++++++++++++ Manager/Pages/InkPage.xaml | 527 +++++++++++++++++++++++++ Manager/Pages/InkPage.xaml.cs | 249 ++++++++++++ Manager/Pages/InstallPage.xaml | 458 ++++++++++++++++++++++ Manager/Pages/InstallPage.xaml.cs | 281 ++++++++++++++ Manager/Pages/TouchPage.xaml | 522 +++++++++++++++++++++++++ Manager/Pages/TouchPage.xaml.cs | 274 +++++++++++++ Manager/Themes/DarkTheme.xaml | 118 ++++++ Manager/Themes/LightTheme.xaml | 118 ++++++ NuGet.config | 13 + README.md | 62 +++ 40 files changed, 8966 insertions(+) create mode 100644 .gitignore create mode 100644 Better-EN5/Better-EN5.csproj create mode 100644 Better-EN5/Program.cs create mode 100644 Better-EN5/UI/ExportInkMenuItem.cs create mode 100644 Better-EN5/UI/ImportInkMenuItem.cs create mode 100644 Better-EN5/UI/InkDataHelper.cs create mode 100644 Better-EN5/UI/ManagerMenuItem.cs create mode 100644 Better-Seewo.sln create mode 100644 Directory.Build.props create mode 100644 Installer/App.xaml create mode 100644 Installer/App.xaml.cs create mode 100644 Installer/Installer.csproj create mode 100644 Installer/MainWindow.xaml create mode 100644 Installer/MainWindow.xaml.cs create mode 100644 Installer/Pages/CompletePage.xaml create mode 100644 Installer/Pages/CompletePage.xaml.cs create mode 100644 Installer/Pages/InstallPage.xaml create mode 100644 Installer/Pages/InstallPage.xaml.cs create mode 100644 Installer/Pages/WelcomePage.xaml create mode 100644 Installer/Pages/WelcomePage.xaml.cs create mode 100644 Installer/Themes/InstallerTheme.xaml create mode 100644 Manager/App.xaml create mode 100644 Manager/App.xaml.cs create mode 100644 Manager/MainWindow.xaml create mode 100644 Manager/MainWindow.xaml.cs create mode 100644 Manager/Manager.csproj create mode 100644 Manager/Pages/ActivatePage.xaml create mode 100644 Manager/Pages/ActivatePage.xaml.cs create mode 100644 Manager/Pages/ConvertPage.xaml create mode 100644 Manager/Pages/ConvertPage.xaml.cs create mode 100644 Manager/Pages/InkPage.xaml create mode 100644 Manager/Pages/InkPage.xaml.cs create mode 100644 Manager/Pages/InstallPage.xaml create mode 100644 Manager/Pages/InstallPage.xaml.cs create mode 100644 Manager/Pages/TouchPage.xaml create mode 100644 Manager/Pages/TouchPage.xaml.cs create mode 100644 Manager/Themes/DarkTheme.xaml create mode 100644 Manager/Themes/LightTheme.xaml create mode 100644 NuGet.config create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31758ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,208 @@ +## +## .gitignore - Better-Seewo +## 标准 C# / WPF / Visual Studio 忽略规则 +## + +# ===== Visual Studio / .NET 构建产物 ===== +## 用户特定文件 +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +## Visual Studio 自动生成的文件(差异化临时目录) +*.vspscc +*.vssscc +*.sap + +## 构建结果 +[Bb]in/ +[Oo]bj/ +[Dd]ebug/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]inaries/ +[Ll]og/ +[Ll]ogs/ + +## Visual Studio 缓存/临时文件 +.vs/ +# 保留 .vscode 目录(如使用 VS Code 开发) +!.vscode/ + +## NuGet 包目录 +*.nupkg +*.snupkg +**/[Pp]ackages/* +# 排除 project.json 中的 packages 目录 +!**/[Pp]ackages/repositories.config + +## NuGet 符号包 +*.symbols.nupkg + +## 其他生成文件 +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +*.buildprops +*.buildinfo +*.lastbuildstate +*.resource +*.metagen +*.appx +*.appxbundle +*.appxupload +*.appxdownload +*.msix +*.msixbundle +*.msixupload +*.msixdownload + +# ===== NuGet v3 特定 ===== +*.nuget.props +*.nuget.targets + +# ===== 打包相关 ===== +*.cachefile +*.psess +*.vsp +*.vspx +*.sap + +# ===== Visual Studio profiler ===== +*.psess +*.vsp +*.vspx + +# ===== TypeScript 相关 ===== +*.js.map + +# ===== 单元测试结果 ===== +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# ===== ReSharper ===== +*_i.c +*_p.c +*_h.h +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.bak +*.cache +*.ilk +*.lib +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +*.buildprops +*.buildinfo + +# ===== ReSharper / dotCover / dotTrace ===== +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user +dotCover.html +*.dotCover + +# ===== Rider / JetBrains IDE ===== +.idea/ +*.sln.iml + +# =====_coverage 结果 ===== +*.coverage +*.coveragexml + +# ===== ASP.NET Scaffolding ===== +ScaffoldingReadMe.txt + +# ===== StyleCop ===== +StyleCopReport.xml + +# ===== 文件 by Git 的文件 ===== +*.orig + +# ===== OS 生成的文件 ===== +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +*.stackdump +[Dd]esktop.ini +$RECYCLE.BIN/ +*.cab +*.msi +*.msix +*.msm +*.msp +*.lnk + +# ===== macOS 系统文件 ===== +.DS_Store +.AppleDouble +.LSOverride +Icon +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.Trashes + +# ===== Windows 缩略图缓存 ===== +ehthumbs.db + +# ===== 文件夹配置文件 ===== +[Dd]esktop.ini + +# ===== 下载的包缓存(可重建) --> +/[Pp]ackages + +# ===== Publish 输出 ===== +publish/ diff --git a/Better-EN5/Better-EN5.csproj b/Better-EN5/Better-EN5.csproj new file mode 100644 index 0000000..cab94f6 --- /dev/null +++ b/Better-EN5/Better-EN5.csproj @@ -0,0 +1,36 @@ + + + + + + + + + + Better-EN5 + + + $(SolutionDir)Output\Plugins\Better-EN5\ + + + {EasiPlugin} + + + + + + + + + + + + + + diff --git a/Better-EN5/Program.cs b/Better-EN5/Program.cs new file mode 100644 index 0000000..0beb285 --- /dev/null +++ b/Better-EN5/Program.cs @@ -0,0 +1,126 @@ +/* + * Program.cs + * Better-Seewo EN5 增强插件入口点 + * 所属项目:Better-Seewo + * 作者:雾启工作室 + * + * 说明: + * 本文件是希沃白板 EN5 增强插件的主入口,继承 EasiPlugin 基类。 + * 在 OnRunningAsync 中完成以下初始化工作: + * 1. 检测并排除云课模式运行环境 + * 2. 延迟 3 秒等待白板完全就绪 + * 3. 通过 IUIItemManager 向 BoardEditMenu 注入三个菜单项 + */ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using dotnetCampus.EasiPlugin; + +using Better_Seewo.Better_EN5.UI; + +namespace Better_Seewo.Better_EN5 +{ + /// + /// Better-Seewo EN5 增强插件主类 + /// 继承 EasiPlugin 基类,作为希沃白板 EN5 的功能增强插件入口 + /// + public class Program : EasiPlugin + { + /// + /// 中英文双语资源字典 + /// 用于菜单项标题等多语言支持 + /// + private DictionaryLanguageSource _languageSource; + + /// + /// 三个菜单项实例 + /// + private ExportInkMenuItem _exportInkMenuItem; + private ImportInkMenuItem _importInkMenuItem; + private ManagerMenuItem _managerMenuItem; + + /// + /// 插件运行入口 + /// 当希沃白板 EN5 加载本插件时调用此方法 + /// + protected override async Task OnRunningAsync() + { + // 检测是否为云课模式,如果是则不加载插件 + // 云课模式下部分插件 API 不可用,直接退出避免异常 + if (EN.CommandOptions.IsCloud) + { + return; + } + + // 延迟 3 秒启动,确保白板界面和各项服务已完全就绪 + await Task.Delay(3000); + + // 初始化中英文双语资源 + InitializeLanguageSource(); + + // 创建三个菜单项实例 + _exportInkMenuItem = new ExportInkMenuItem(_languageSource); + _importInkMenuItem = new ImportInkMenuItem(_languageSource); + _managerMenuItem = new ManagerMenuItem(_languageSource); + + // 注册所有菜单项到白板编辑菜单 + RegisterMenuItems(); + } + + /// + /// 初始化中英文双语资源字典 + /// 提供菜单项标题的中文和英文翻译 + /// + private void InitializeLanguageSource() + { + var dictionary = new Dictionary + { + // 导出墨迹菜单项标题 + { "ExportInk.Title", "导出墨迹" }, + { "ExportInk.Title.en", "Export Ink" }, + + // 导入墨迹菜单项标题 + { "ImportInk.Title", "导入墨迹" }, + { "ImportInk.Title.en", "Import Ink" }, + + // 管理器菜单项标题 + { "Manager.Title", "Better-Seewo 管理" }, + { "Manager.Title.en", "Better-Seewo Manager" }, + }; + + _languageSource = new DictionaryLanguageSource(dictionary); + } + + /// + /// 注册所有菜单项到白板的 BoardEditMenu + /// 通过 IUIItemManager 接口向编辑菜单栏注入自定义功能按钮 + /// + private void RegisterMenuItems() + { + // 获取白板 UI 项管理器 + var uiItemManager = EN.GetService(); + + // 依次注册三个菜单项 + uiItemManager.AddMenuItem(_exportInkMenuItem); + uiItemManager.AddMenuItem(_importInkMenuItem); + uiItemManager.AddMenuItem(_managerMenuItem); + } + + /// + /// 取消注册所有菜单项 + /// 在插件卸载或白板关闭时调用,从菜单栏移除已注入的菜单项 + /// + private void UnregisterMenuItems() + { + // 获取白板 UI 项管理器 + var uiItemManager = EN.GetService(); + + // 依次移除三个菜单项 + uiItemManager.RemoveMenuItem(_exportInkMenuItem); + uiItemManager.RemoveMenuItem(_importInkMenuItem); + uiItemManager.RemoveMenuItem(_managerMenuItem); + } + } +} diff --git a/Better-EN5/UI/ExportInkMenuItem.cs b/Better-EN5/UI/ExportInkMenuItem.cs new file mode 100644 index 0000000..13ad8a3 --- /dev/null +++ b/Better-EN5/UI/ExportInkMenuItem.cs @@ -0,0 +1,118 @@ +/* + * ExportInkMenuItem.cs + * "导出墨迹" 菜单项 + * 所属项目:Better-Seewo + * 作者:雾启工作室 + * + * 说明: + * 实现白板编辑菜单中的"导出墨迹"功能。 + * 点击后将当前白板的墨迹数据导出为 .ink.json 格式的 JSON 文件。 + * 默认文件名为"课件墨迹.ink.json"。 + */ + +using System; +using System.IO; +using System.Threading.Tasks; +using System.Windows; + +using dotnetCampus.EasiPlugin; + +using Newtonsoft.Json; + +namespace Better_Seewo.Better_EN5.UI +{ + /// + /// 导出墨迹菜单项 + /// 实现 IMenuPluginItem 接口,在白板编辑菜单中显示"导出墨迹"按钮 + /// 点击后打开文件保存对话框,将当前白板墨迹序列化为 JSON 文件 + /// + public class ExportInkMenuItem : IMenuPluginItem + { + /// + /// 菜单项唯一标识符 + /// + public Guid Id { get; } = new Guid("A1B2C3D4-E5F6-7890-ABCD-EF1234567890"); + + /// + /// 菜单项显示标题 + /// 根据当前语言环境显示"导出墨迹"或"Export Ink" + /// + public string Title { get; } + + /// + /// 菜单项排序提示值 + /// 值越大越靠前,998 表示在菜单中靠前的位置 + /// + public int SortHint { get; } = 998; + + /// + /// 语言资源源,用于获取多语言文本 + /// + private readonly DictionaryLanguageSource _languageSource; + + /// + /// 构造函数 + /// + /// 中英文双语资源字典 + public ExportInkMenuItem(DictionaryLanguageSource languageSource) + { + _languageSource = languageSource; + // 从语言资源中获取菜单项标题,默认中文 + Title = _languageSource.GetString("ExportInk.Title") ?? "导出墨迹"; + } + + /// + /// 获取菜单项图标 + /// 返回菜单项在工具栏中显示的图标资源路径 + /// + /// 图标资源路径字符串 + public string GetMenuIcon() + { + // 返回导出图标路径 + return "pack://application:,,,/Better-EN5;component/Resources/export_icon.png"; + } + + /// + /// 菜单项点击事件处理 + /// 打开文件保存对话框,将当前白板墨迹导出为 .ink.json 文件 + /// + public async Task OnClickAsync() + { + await Task.Run(() => + { + // 从白板获取当前墨迹数据 + var inkData = InkDataHelper.ExportInkData(); + + if (inkData == null) + { + MessageBox.Show("当前白板没有可导出的墨迹数据。", "提示", + MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + // 创建文件保存对话框 + var saveFileDialog = new Microsoft.Win32.SaveFileDialog + { + // 默认文件名 + FileName = "课件墨迹.ink.json", + // 文件过滤器 + Filter = "墨迹 JSON 文件 (*.ink.json)|*.ink.json|所有文件 (*.*)|*.*", + // 默认扩展名 + DefaultExt = ".ink.json", + // 对话框标题 + Title = "导出墨迹", + }; + + // 显示保存对话框 + if (saveFileDialog.ShowDialog() == true) + { + // 使用 Newtonsoft.Json 将墨迹数据序列化为格式化的 JSON 字符串 + string json = JsonConvert.SerializeObject(inkData, Formatting.Indented); + + // 写入文件 + File.WriteAllText(saveFileDialog.FileName, json); + } + }); + } + } +} diff --git a/Better-EN5/UI/ImportInkMenuItem.cs b/Better-EN5/UI/ImportInkMenuItem.cs new file mode 100644 index 0000000..e91bd21 --- /dev/null +++ b/Better-EN5/UI/ImportInkMenuItem.cs @@ -0,0 +1,127 @@ +/* + * ImportInkMenuItem.cs + * "导入墨迹" 菜单项 + * 所属项目:Better-Seewo + * 作者:雾启工作室 + * + * 说明: + * 实现白板编辑菜单中的"导入墨迹"功能。 + * 点击后打开文件选择对话框,选择 .ink.json 文件导入到当前白板。 + * 默认文件名为"课件墨迹.ink.json"。 + */ + +using System; +using System.IO; +using System.Threading.Tasks; +using System.Windows; + +using dotnetCampus.EasiPlugin; + +using Newtonsoft.Json; + +namespace Better_Seewo.Better_EN5.UI +{ + /// + /// 导入墨迹菜单项 + /// 实现 IMenuPluginItem 接口,在白板编辑菜单中显示"导入墨迹"按钮 + /// 点击后打开文件选择对话框,读取 JSON 文件并将墨迹数据应用到白板 + /// + public class ImportInkMenuItem : IMenuPluginItem + { + /// + /// 菜单项唯一标识符 + /// + public Guid Id { get; } = new Guid("B2C3D4E5-F6A7-8901-BCDE-F12345678901"); + + /// + /// 菜单项显示标题 + /// 根据当前语言环境显示"导入墨迹"或"Import Ink" + /// + public string Title { get; } + + /// + /// 菜单项排序提示值 + /// 值越大越靠前,997 表示在菜单中位于"导出墨迹"之后 + /// + public int SortHint { get; } = 997; + + /// + /// 语言资源源,用于获取多语言文本 + /// + private readonly DictionaryLanguageSource _languageSource; + + /// + /// 构造函数 + /// + /// 中英文双语资源字典 + public ImportInkMenuItem(DictionaryLanguageSource languageSource) + { + _languageSource = languageSource; + // 从语言资源中获取菜单项标题,默认中文 + Title = _languageSource.GetString("ImportInk.Title") ?? "导入墨迹"; + } + + /// + /// 获取菜单项图标 + /// 返回菜单项在工具栏中显示的图标资源路径 + /// + /// 图标资源路径字符串 + public string GetMenuIcon() + { + // 返回导入图标路径 + return "pack://application:,,,/Better-EN5;component/Resources/import_icon.png"; + } + + /// + /// 菜单项点击事件处理 + /// 打开文件选择对话框,读取 .ink.json 文件并将墨迹数据导入到当前白板 + /// + public async Task OnClickAsync() + { + await Task.Run(() => + { + // 创建文件选择对话框 + var openFileDialog = new Microsoft.Win32.OpenFileDialog + { + // 默认文件名 + FileName = "课件墨迹.ink.json", + // 文件过滤器 + Filter = "墨迹 JSON 文件 (*.ink.json)|*.ink.json|所有文件 (*.*)|*.*", + // 默认扩展名 + DefaultExt = ".ink.json", + // 对话框标题 + Title = "导入墨迹", + }; + + // 显示打开对话框 + if (openFileDialog.ShowDialog() == true) + { + try + { + // 读取 JSON 文件内容 + string json = File.ReadAllText(openFileDialog.FileName); + + // 使用 Newtonsoft.Json 反序列化墨迹数据 + var inkData = JsonConvert.DeserializeObject(json); + + if (inkData == null) + { + MessageBox.Show("无法解析所选文件的墨迹数据。", "导入失败", + MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + // 将墨迹数据应用到白板 + InkDataHelper.ImportInkData(inkData); + } + catch (Exception ex) + { + // 捕获并提示导入过程中的异常 + MessageBox.Show($"导入墨迹时发生错误:\n{ex.Message}", "导入失败", + MessageBoxButton.OK, MessageBoxImage.Error); + } + } + }); + } + } +} diff --git a/Better-EN5/UI/InkDataHelper.cs b/Better-EN5/UI/InkDataHelper.cs new file mode 100644 index 0000000..9d0a36e --- /dev/null +++ b/Better-EN5/UI/InkDataHelper.cs @@ -0,0 +1,240 @@ +/* + * InkDataHelper.cs + * 墨迹数据辅助类 + * 所属项目:Better-Seewo + * 作者:雾启工作室 + * + * 说明: + * 提供墨迹数据的导出和导入功能。 + * ExportInkData:从白板获取当前墨迹数据并封装为可序列化的模型 + * ImportInkData:将墨迹数据模型应用到白板 + * InkStrokeCollection:墨迹笔画集合数据模型,用于 JSON 序列化 + */ + +using System; +using System.Collections.Generic; +using System.Linq; + +using Newtonsoft.Json; + +using dotnetCampus.EasiPlugin; + +namespace Better_Seewo.Better_EN5.UI +{ + /// + /// 墨迹数据辅助类 + /// 提供从白板导出墨迹数据和向白板导入墨迹数据的静态方法 + /// + public static class InkDataHelper + { + /// + /// 从当前白板获取墨迹数据并导出为 InkStrokeCollection 模型 + /// 通过白板 SDK 接口读取当前页面的所有墨迹笔画信息 + /// + /// + /// 包含所有墨迹笔画数据的 InkStrokeCollection; + /// 如果白板没有墨迹则返回 null + /// + public static InkStrokeCollection ExportInkData() + { + // 获取白板当前页面的墨迹对象集合 + var inkObjects = EN.BoardEditMenu.GetCurrentPageInkObjects(); + + if (inkObjects == null || inkObjects.Count == 0) + { + return null; + } + + // 构建墨迹笔画集合 + var collection = new InkStrokeCollection + { + // 导出时间戳 + ExportTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + // 版本号,用于后续格式兼容 + Version = "1.0", + }; + + // 遍历所有墨迹对象,提取笔画数据 + foreach (var inkObject in inkObjects) + { + var stroke = new InkStroke + { + // 笔画唯一标识 + Id = inkObject.Id.ToString(), + // 笔画类型(如自由画笔、直线、圆形等) + StrokeType = inkObject.StrokeType.ToString(), + // 笔画颜色(ARGB 格式) + Color = inkObject.Color.ToArgb(), + // 笔画粗细(像素) + Thickness = inkObject.Thickness, + // 笔画的点集合(每个点包含 X、Y 坐标和压力值) + Points = inkObject.GetPoints().Select(p => new InkPoint + { + X = p.X, + Y = p.Y, + // 压力值,用于支持压感笔 + Pressure = p.Pressure, + }).ToList(), + }; + + collection.Strokes.Add(stroke); + } + + return collection; + } + + /// + /// 将墨迹数据导入到当前白板 + /// 读取 InkStrokeCollection 模型并通过白板 SDK 接口创建对应的墨迹笔画 + /// + /// 要导入的墨迹数据集合 + public static void ImportInkData(InkStrokeCollection inkData) + { + if (inkData == null || inkData.Strokes == null || inkData.Strokes.Count == 0) + { + return; + } + + // 遍历所有笔画数据,逐个创建墨迹对象并添加到白板 + foreach (var stroke in inkData.Strokes) + { + // 解析颜色值 + var color = System.Drawing.Color.FromArgb(stroke.Color); + + // 将 InkPoint 列表转换为白板 SDK 所需的点集合 + var points = stroke.Points.Select(p => new InkPointData + { + X = p.X, + Y = p.Y, + Pressure = p.Pressure, + }).ToArray(); + + // 创建墨迹对象并添加到当前白板页面 + var inkObject = EN.BoardEditMenu.CreateInkObject( + strokeType: ParseStrokeType(stroke.StrokeType), + color: color, + thickness: stroke.Thickness, + points: points + ); + + // 将墨迹对象添加到白板 + EN.BoardEditMenu.AddInkObjectToCurrentPage(inkObject); + } + } + + /// + /// 解析笔画类型字符串为枚举值 + /// + /// 笔画类型字符串 + /// 对应的笔画类型枚举 + private static StrokeType ParseStrokeType(string strokeTypeStr) + { + // 尝试解析字符串为枚举值,解析失败则使用默认的自由画笔类型 + if (Enum.TryParse(strokeTypeStr, out var result)) + { + return result; + } + return StrokeType.FreeDraw; + } + } + + #region 墨迹数据模型 + + /// + /// 墨迹笔画集合数据模型 + /// 包含一组墨迹笔画的完整信息,用于 JSON 序列化和反序列化 + /// + public class InkStrokeCollection + { + /// + /// 导出版本号 + /// 用于后续格式升级时的兼容性判断 + /// + [JsonProperty("version")] + public string Version { get; set; } + + /// + /// 导出时间戳 + /// 记录墨迹导出的具体时间 + /// + [JsonProperty("exportTime")] + public string ExportTime { get; set; } + + /// + /// 笔画集合 + /// 包含当前白板页面上的所有墨迹笔画数据 + /// + [JsonProperty("strokes")] + public List Strokes { get; set; } = new List(); + } + + /// + /// 单条墨迹笔画数据模型 + /// 描述一笔连续的墨迹,包含颜色、粗细、点集合等属性 + /// + public class InkStroke + { + /// + /// 笔画唯一标识 + /// 原始白板中该笔画的 ID,导入时可用于匹配和覆盖 + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// 笔画类型 + /// 如 FreeDraw(自由画笔)、Line(直线)、Ellipse(椭圆)等 + /// + [JsonProperty("strokeType")] + public string StrokeType { get; set; } + + /// + /// 笔画颜色 + /// 使用 ARGB 整数值表示(与 System.Drawing.Color.FromArgb 兼容) + /// + [JsonProperty("color")] + public int Color { get; set; } + + /// + /// 笔画粗细 + /// 单位为像素,表示笔画的线条宽度 + /// + [JsonProperty("thickness")] + public double Thickness { get; set; } + + /// + /// 笔画点集合 + /// 一组有序的坐标点,构成笔画的路径 + /// + [JsonProperty("points")] + public List Points { get; set; } = new List(); + } + + /// + /// 墨迹点数据模型 + /// 表示墨迹路径上的一个采样点,包含坐标和压力值 + /// + public class InkPoint + { + /// + /// X 轴坐标 + /// + [JsonProperty("x")] + public double X { get; set; } + + /// + /// Y 轴坐标 + /// + [JsonProperty("y")] + public double Y { get; set; } + + /// + /// 压力值 + /// 用于支持压感笔设备,值范围为 0.0 ~ 1.0 + /// + [JsonProperty("pressure")] + public double Pressure { get; set; } + } + + #endregion +} diff --git a/Better-EN5/UI/ManagerMenuItem.cs b/Better-EN5/UI/ManagerMenuItem.cs new file mode 100644 index 0000000..951711d --- /dev/null +++ b/Better-EN5/UI/ManagerMenuItem.cs @@ -0,0 +1,126 @@ +/* + * ManagerMenuItem.cs + * "Better-Seewo 管理" 菜单项 + * 所属项目:Better-Seewo + * 作者:雾启工作室 + * + * 说明: + * 实现白板编辑菜单中的"Better-Seewo 管理"功能。 + * 点击后启动 Better-Seewo Manager 管理器程序(Manager.exe)。 + * 管理器程序与插件位于同一目录下。 + */ + +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; + +using dotnetCampus.EasiPlugin; + +namespace Better_Seewo.Better_EN5.UI +{ + /// + /// 管理器启动菜单项 + /// 实现 IMenuPluginItem 接口,在白板编辑菜单中显示"Better-Seewo 管理"按钮 + /// 点击后启动 Better-Seewo Manager 管理器桌面应用程序 + /// + public class ManagerMenuItem : IMenuPluginItem + { + /// + /// 菜单项唯一标识符 + /// + public Guid Id { get; } = new Guid("C3D4E5F6-A7B8-9012-CDEF-123456789012"); + + /// + /// 菜单项显示标题 + /// 根据当前语言环境显示"Better-Seewo 管理"或"Better-Seewo Manager" + /// + public string Title { get; } + + /// + /// 菜单项排序提示值 + /// 值越大越靠前,999 表示在菜单中位于最前方 + /// + public int SortHint { get; } = 999; + + /// + /// 语言资源源,用于获取多语言文本 + /// + private readonly DictionaryLanguageSource _languageSource; + + /// + /// 构造函数 + /// + /// 中英文双语资源字典 + public ManagerMenuItem(DictionaryLanguageSource languageSource) + { + _languageSource = languageSource; + // 从语言资源中获取菜单项标题,默认中文 + Title = _languageSource.GetString("Manager.Title") ?? "Better-Seewo 管理"; + } + + /// + /// 获取菜单项图标 + /// 返回菜单项在工具栏中显示的图标资源路径 + /// + /// 图标资源路径字符串 + public string GetMenuIcon() + { + // 返回管理器图标路径 + return "pack://application:,,,/Better-EN5;component/Resources/manager_icon.png"; + } + + /// + /// 菜单项点击事件处理 + /// 启动 Better-Seewo Manager 管理器程序 + /// 管理器位于与插件相同的目录下(Manager.exe) + /// + public async Task OnClickAsync() + { + await Task.Run(() => + { + try + { + // 获取当前插件所在的目录路径 + string pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + // 构建管理器可执行文件的完整路径 + string managerPath = Path.Combine(pluginDirectory, "Manager.exe"); + + // 检查管理器程序是否存在 + if (!File.Exists(managerPath)) + { + System.Windows.MessageBox.Show( + $"未找到管理器程序:\n{managerPath}\n\n请确认 Manager.exe 已正确安装。", + "启动失败", + System.Windows.MessageBoxButton.OK, + System.Windows.MessageBoxImage.Warning); + return; + } + + // 启动管理器进程 + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = managerPath, + // 使用 ShellExecute 以便系统正确处理文件关联 + UseShellExecute = true, + // 工作目录设置为插件目录 + WorkingDirectory = pluginDirectory, + }; + + Process.Start(startInfo); + } + catch (Exception ex) + { + // 捕获并提示启动过程中的异常 + System.Windows.MessageBox.Show( + $"启动管理器时发生错误:\n{ex.Message}", + "启动失败", + System.Windows.MessageBoxButton.OK, + System.Windows.MessageBoxImage.Error); + } + }); + } + } +} diff --git a/Better-Seewo.sln b/Better-Seewo.sln new file mode 100644 index 0000000..c21bdb8 --- /dev/null +++ b/Better-Seewo.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Better-EN5", "Better-EN5\Better-EN5.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Manager", "Manager\Manager.csproj", "{B2C3D4E5-F678-90AB-CDEF-123456789ABC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Installer", "Installer\Installer.csproj", "{C3D4E5F6-7890-ABCD-EF12-3456789ABC01}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789ABC}.Release|Any CPU.Build.0 = Release|Any CPU + {C3D4E5F6-7890-ABCD-EF12-3456789ABC01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3D4E5F6-7890-ABCD-EF12-3456789ABC01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3D4E5F6-7890-ABCD-EF12-3456789ABC01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3D4E5F6-7890-ABCD-EF12-3456789ABC01}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D4E5F678-90AB-CDEF-1234-56789ABCDEF0} + EndGlobalSection +EndGlobal diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..c7cb01f --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,31 @@ + + + + + + 雾启工作室 + + Better-Seewo + + 2.0.0 + + 雾生万象,启以为光 -- 希沃白板功能增强插件 + + + + + + net6.0-windows + + true + + WinExe + + Better_Seewo + + true + + diff --git a/Installer/App.xaml b/Installer/App.xaml new file mode 100644 index 0000000..d855995 --- /dev/null +++ b/Installer/App.xaml @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/Installer/App.xaml.cs b/Installer/App.xaml.cs new file mode 100644 index 0000000..6fb3b43 --- /dev/null +++ b/Installer/App.xaml.cs @@ -0,0 +1,112 @@ +/* + * App.xaml.cs - Better-Seewo 安装程序应用程序逻辑 + * 负责全局异常处理和安装状态管理 + * 作者:雾启工作室 + */ + +using System; +using System.IO; +using System.Windows; + +namespace Better_Seewo.Installer +{ + /// + /// App 的交互逻辑 - 管理安装程序全局状态 + /// + public partial class App : Application + { + /// + /// 应用程序版本号 + /// + public const string AppVersion = "2.0.0"; + + /// + /// 默认安装路径 + /// + public static readonly string DefaultInstallPath = + @"C:\Program Files (x86)\Seewo\EasiNote5\Plugins\Better-EN5"; + + /// + /// 当前实际选择的安装路径 + /// + public static string InstallPath { get; set; } = DefaultInstallPath; + + /// + /// 安装是否正在进行中 + /// + public static bool IsInstalling { get; set; } + + /// + /// 安装是否已完成 + /// + public static bool IsInstallCompleted { get; set; } + + /// + /// 安装开始时间(用于计算安装耗时) + /// + public static DateTime InstallStartTime { get; set; } + + /// + /// 应用程序启动时初始化全局异常处理 + /// + protected override void OnStartup(StartupEventArgs e) + { + // 注册全局未处理异常事件 + DispatcherUnhandledException += App_DispatcherUnhandledException; + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + + base.OnStartup(e); + } + + /// + /// UI 线程未处理异常捕获,防止程序崩溃并提示用户 + /// + private void App_DispatcherUnhandledException(object sender, + System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + { + // 记录异常信息到日志文件 + LogError(e.Exception); + // 标记异常已处理,防止程序崩溃 + e.Handled = true; + // 弹出友好提示 + MessageBox.Show( + $"安装过程中发生错误:\n{e.Exception.Message}\n\n详细信息已记录到日志。", + "Better-Seewo 安装程序", + MessageBoxButton.OK, + MessageBoxImage.Warning + ); + } + + /// + /// 非 UI 线程未处理异常捕获 + /// + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception ex) + { + LogError(ex); + } + } + + /// + /// 将错误信息记录到日志文件 + /// + private static void LogError(Exception ex) + { + try + { + // 日志文件存放在临时目录下 + string logDir = Path.Combine(Path.GetTempPath(), "Better-Seewo", "Installer", "Logs"); + Directory.CreateDirectory(logDir); + + string logFile = Path.Combine(logDir, $"error_{DateTime.Now:yyyyMMdd}.log"); + string logContent = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {ex}\n\n"; + File.AppendAllText(logFile, logContent); + } + catch + { + // 日志写入失败时静默处理 + } + } + } +} diff --git a/Installer/Installer.csproj b/Installer/Installer.csproj new file mode 100644 index 0000000..3406792 --- /dev/null +++ b/Installer/Installer.csproj @@ -0,0 +1,27 @@ + + + + + + + + + + Better-Seewo.Installer + + + $(SolutionDir)Output\Installer\ + + + + + + + + diff --git a/Installer/MainWindow.xaml b/Installer/MainWindow.xaml new file mode 100644 index 0000000..eaf96a3 --- /dev/null +++ b/Installer/MainWindow.xaml @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Manager/MainWindow.xaml.cs b/Manager/MainWindow.xaml.cs new file mode 100644 index 0000000..e375c0d --- /dev/null +++ b/Manager/MainWindow.xaml.cs @@ -0,0 +1,350 @@ +/* + * MainWindow.xaml.cs - Better-Seewo 管理器主窗口逻辑 + * 负责自定义标题栏拖动、窗口控制、页面导航、主题切换和动画效果 + * 作者:雾启工作室 + */ + +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; + +namespace Better_Seewo.Manager +{ + /// + /// MainWindow 的交互逻辑 - Fluent Design 风格主窗口 + /// + public partial class MainWindow : Window + { + /// + /// 导航指示条动画时长(毫秒) + /// + private const int IndicatorAnimationDuration = 200; + + /// + /// 页面淡入淡出动画时长(毫秒) + /// + private const int PageTransitionDuration = 300; + + /// + /// 指示条目标宽度 + /// + private const double IndicatorTargetWidth = 3; + + /// + /// 当前选中的导航按钮名称 + /// + private string _currentNavTag = "Install"; + + /// + /// 构造函数,初始化窗口组件 + /// + public MainWindow() + { + InitializeComponent(); + // 默认选中安装页面 + SetActiveNavigation("BtnInstall", "IndicatorInstall"); + } + + /// + /// 窗口加载完成事件处理 - 触发入场动画和初始页面加载 + /// + private void Window_Loaded(object sender, RoutedEventArgs e) + { + // 入场动画已通过 XAML Trigger 触发 + // 导航到默认页面 + NavigateToPage("Install"); + } + + #region ===== 自定义标题栏拖动 ===== + + /// + /// 标题栏鼠标左键按下 - 实现窗口拖动 + /// + private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + // 如果点击的是按钮区域则不触发拖动 + if (e.Source is Button) return; + + // 调用 DragMove 实现窗口拖动 + if (e.LeftButton == MouseButtonState.Pressed) + { + DragMove(); + } + } + + /// + /// 标题栏鼠标双击 - 切换最大化/还原 + /// + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + // 双击标题栏区域切换窗口状态 + if (e.ClickCount == 2) + { + ToggleMaximize(); + } + } + + #endregion + + #region ===== 窗口控制按钮 ===== + + /// + /// 最小化按钮点击 + /// + private void BtnMinimize_Click(object sender, RoutedEventArgs e) + { + // 将窗口最小化到任务栏 + WindowState = WindowState.Minimized; + } + + /// + /// 最大化/还原按钮点击 + /// + private void BtnMaximize_Click(object sender, RoutedEventArgs e) + { + ToggleMaximize(); + } + + /// + /// 关闭按钮点击 - 关闭应用程序 + /// + private void BtnClose_Click(object sender, RoutedEventArgs e) + { + Application.Current.Shutdown(); + } + + /// + /// 切换窗口最大化/还原状态 + /// + private void ToggleMaximize() + { + if (WindowState == WindowState.Maximized) + { + WindowState = WindowState.Normal; + // 更新按钮图标为最大化图标 + BtnMaximize.Content = "\uE922"; + } + else + { + WindowState = WindowState.Maximized; + // 更新按钮图标为还原图标 + BtnMaximize.Content = "\uE923"; + } + } + + #endregion + + #region ===== 导航按钮切换 ===== + + /// + /// 导航按钮点击事件 - 切换Frame页面内容 + /// + private void NavButton_Click(object sender, RoutedEventArgs e) + { + if (sender is Button btn && btn.Tag is string tag) + { + // 如果点击的是当前已选中项,则忽略 + if (tag == _currentNavTag) return; + + // 更新当前选中项 + _currentNavTag = tag; + + // 根据按钮名称设置选中状态和指示条动画 + SetActiveNavigation(btn.Name, GetIndicatorName(btn.Name)); + + // 导航到对应页面 + NavigateToPage(tag); + } + } + + /// + /// 根据按钮名称获取对应的指示条名称 + /// + /// 按钮名称 + /// 指示条名称 + private string GetIndicatorName(string buttonName) + { + return buttonName switch + { + "BtnInstall" => "IndicatorInstall", + "BtnInk" => "IndicatorInk", + "BtnConvert" => "IndicatorConvert", + "BtnTouch" => "IndicatorTouch", + "BtnActivate" => "IndicatorActivate", + _ => "IndicatorInstall" + }; + } + + /// + /// 设置当前选中的导航按钮,并触发指示条动画 + /// + /// 选中的按钮名称 + /// 对应的指示条名称 + private void SetActiveNavigation(string activeButtonName, string activeIndicatorName) + { + // 所有导航按钮列表 + string[] buttonNames = { "BtnInstall", "BtnInk", "BtnConvert", "BtnTouch", "BtnActivate" }; + // 所有指示条列表 + string[] indicatorNames = { "IndicatorInstall", "IndicatorInk", "IndicatorConvert", "IndicatorTouch", "IndicatorActivate" }; + + for (int i = 0; i < buttonNames.Length; i++) + { + // 查找按钮 + var btn = FindName(buttonNames[i]) as Button; + // 查找指示条 + var indicator = FindName(indicatorNames[i]) as Border; + + if (btn == null || indicator == null) continue; + + if (buttonNames[i] == activeButtonName) + { + // 选中状态:高亮前景色,显示指示条 + btn.Foreground = (Brush)FindResource("AccentBrush"); + + // 播放指示条展开动画(宽度从0到3px) + AnimateIndicatorWidth(indicator, IndicatorTargetWidth); + } + else + { + // 非选中状态:恢复默认前景色,隐藏指示条 + btn.Foreground = (Brush)FindResource("TextSecondaryBrush"); + + // 播放指示条收缩动画(宽度从当前值到0) + AnimateIndicatorWidth(indicator, 0); + } + } + } + + /// + /// 为导航指示条播放宽度动画 + /// + /// 指示条控件 + /// 目标宽度 + private void AnimateIndicatorWidth(Border indicator, double targetWidth) + { + if (indicator == null) return; + + // 创建宽度动画 + var widthAnimation = new DoubleAnimation + { + From = indicator.Width, + To = targetWidth, + Duration = TimeSpan.FromMilliseconds(IndicatorAnimationDuration), + EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } + }; + + // 应用动画到指示条的Width属性 + indicator.BeginAnimation(WidthProperty, widthAnimation); + } + + #endregion + + #region ===== 页面导航 ===== + + /// + /// 导航到指定页面,带淡入淡出动画效果 + /// + /// 页面标识(Install/Ink/Convert/Touch/Activate) + private void NavigateToPage(string pageTag) + { + // 创建淡出动画(当前页面) + var fadeOutAnimation = new DoubleAnimation + { + From = 1.0, + To = 0.0, + Duration = TimeSpan.FromMilliseconds(PageTransitionDuration / 2), + EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn } + }; + + // 淡出动画完成后切换页面 + fadeOutAnimation.Completed += (s, e) => + { + // 根据页面标识加载对应页面 + // TODO: 创建各个功能页面后取消注释 + // switch (pageTag) + // { + // case "Install": + // ContentFrame.Navigate(new Pages.InstallPage()); + // break; + // case "Ink": + // ContentFrame.Navigate(new Pages.InkPage()); + // break; + // case "Convert": + // ContentFrame.Navigate(new Pages.ConvertPage()); + // break; + // case "Touch": + // ContentFrame.Navigate(new Pages.TouchPage()); + // break; + // case "Activate": + // ContentFrame.Navigate(new Pages.ActivatePage()); + // break; + // } + + // 创建淡入动画(新页面) + var fadeInAnimation = new DoubleAnimation + { + From = 0.0, + To = 1.0, + Duration = TimeSpan.FromMilliseconds(PageTransitionDuration / 2), + EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut } + }; + + // 应用淡入动画到Frame + ContentFrame.BeginAnimation(OpacityProperty, fadeInAnimation); + }; + + // 应用淡出动画到Frame + ContentFrame.BeginAnimation(OpacityProperty, fadeOutAnimation); + } + + #endregion + + #region ===== 主题切换 ===== + + /// + /// 主题切换按钮点击事件 + /// + private void BtnThemeToggle_Click(object sender, RoutedEventArgs e) + { + // 切换到相反主题 + bool newIsDark = !App.IsDarkTheme; + + // 调用 App.SwitchTheme 切换主题资源 + App.SwitchTheme(newIsDark); + + // 更新主题图标 + UpdateThemeIcon(newIsDark); + } + + /// + /// 根据当前主题更新切换按钮的图标 + /// + /// 当前是否为深色主题 + private void UpdateThemeIcon(bool isDark) + { + if (ThemeIcon == null) return; + + if (isDark) + { + // 深色主题时显示太阳图标(提示可以切换到浅色) + ThemeIcon.Data = Geometry.Parse( + "M12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,2L14.39,5.42C13.73,5.14 13,5 12,5C11,5 10.27,5.14 9.61,5.42L12,2M3.34,7L7.5,6.35C7,7 6.63,7.73 6.43,8.5L3.34,7M3.36,17L6.44,15.5C6.64,16.28 7,17 7.5,17.65L3.36,17M20.64,7L17.55,8.5C17.36,7.72 17,7 16.5,6.35L20.64,7M20.65,17L16.5,17.65C17,17 17.37,16.27 17.57,15.5L20.65,17M12,22L9.61,18.58C10.27,18.86 11,19 12,19C13,19 13.73,18.86 14.39,18.58L12,22Z" + ); + } + else + { + // 浅色主题时显示月亮图标(提示可以切换到深色) + ThemeIcon.Data = Geometry.Parse( + "M17.75,4.09L15.22,6.03L16.13,9.09L13.5,7.28L10.87,9.09L11.78,6.03L9.25,4.09L12.44,4L13.5,1L14.56,4L17.75,4.09M21.25,11L19.61,12.25L20.2,14.23L18.5,13.06L16.8,14.23L17.39,12.25L15.75,11L17.81,10.95L18.5,9L19.19,10.95L21.25,11M18.97,15.95C19.8,15.87 20.69,17.05 20.16,17.8C19.84,18.25 19.38,18.57 18.97,18.95C16.73,21.04 14.04,22.5 11,22.5C7.96,22.5 5.27,21.04 3.03,18.95C2.62,18.57 2.16,18.25 1.84,17.8C1.31,17.05 2.2,15.87 3.03,15.95C7.33,16.37 10.17,12.37 11,9.42C11.83,12.37 14.67,16.37 18.97,15.95Z" + ); + } + } + + #endregion + } +} diff --git a/Manager/Manager.csproj b/Manager/Manager.csproj new file mode 100644 index 0000000..92bbdab --- /dev/null +++ b/Manager/Manager.csproj @@ -0,0 +1,30 @@ + + + + + + + + + + Better-Seewo.Manager + + + $(SolutionDir)Output\Manager\ + + + + + + + + + + + diff --git a/Manager/Pages/ActivatePage.xaml b/Manager/Pages/ActivatePage.xaml new file mode 100644 index 0000000..a6f20d4 --- /dev/null +++ b/Manager/Pages/ActivatePage.xaml @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +