diff --git a/App.axaml.cs b/App.axaml.cs index 1c87dc09..841dfdf0 100644 --- a/App.axaml.cs +++ b/App.axaml.cs @@ -20,6 +20,7 @@ using System.Threading; #pragma warning disable CS8604 // 引用类型参数可能为 null。 +#pragma warning disable CA2211 // Non-constant fields should not be visible namespace KitX_Dashboard { @@ -146,7 +147,7 @@ public override void OnFrameworkInitializationCompleted() } catch (Exception ex) { - Log.Error("In AnouncementManager.CheckNewAccnouncements()", ex); + Log.Error(ex, "In AnouncementManager.CheckNewAccnouncements()"); } }).Start(); @@ -158,6 +159,7 @@ public override void OnFrameworkInitializationCompleted() } } +#pragma warning restore CA2211 // Non-constant fields should not be visible #pragma warning restore CS8604 // 引用类型参数可能为 null。 // .....'',;;::cccllllllllllllcccc:::;;,,,''...'',,'.. diff --git a/Helper.cs b/Helper.cs index fb0f7712..fe3320ba 100644 --- a/Helper.cs +++ b/Helper.cs @@ -290,6 +290,8 @@ public static void SaveInfo() /// public static void Exit() { + Log.CloseAndFlush(); + Program.WebManager?.Stop(); Program.WebManager?.Dispose(); @@ -305,12 +307,12 @@ public static void Exit() public static void InitEnvironment() { #region 检查 Common.Algorithm 库环境并安装环境 - if (!Algorithm.Interop.Environment.CheckEnvironment()) + if (!Common.Algorithm.Interop.Environment.CheckEnvironment()) new Thread(() => { try { - Algorithm.Interop.Environment.InstallEnvironment(); + Common.Algorithm.Interop.Environment.InstallEnvironment(); } catch (Exception ex) { diff --git a/KitX Dashboard.csproj b/KitX Dashboard.csproj index eb5283f0..4401e4b2 100644 --- a/KitX Dashboard.csproj +++ b/KitX Dashboard.csproj @@ -1,16 +1,22 @@  WinExe - net6.0 + False + net6.0 + net6.0-windows10.0.17763.0 enable copyused true Assets\KitX-Icon-256x.ico ..\KitX Build\Dashboard\ ..\KitX Build\Temp\Dashboard\ - 3.22.04.$([System.DateTime]::UtcNow.Date.Subtract($([System.DateTime]::Parse("2005-07-16"))).TotalDays) - 3.22.04.$([System.DateTime]::UtcNow.Date.Subtract($([System.DateTime]::Parse("2005-07-16"))).TotalDays) - 3.22.04.$([System.DateTime]::UtcNow.Date.Subtract($([System.DateTime]::Parse("2005-07-16"))).TotalDays) + $(Version) + $(Version) + 3.22.10.$([System.DateTime]::UtcNow.Date.Subtract($([System.DateTime]::Parse("2005-06-06"))).TotalDays) + + + + IsBuild4WindowsPlatform + + + + - + - + + diff --git a/Languages/en-us.axaml b/Languages/en-us.axaml index 49816ab1..c989f756 100644 --- a/Languages/en-us.axaml +++ b/Languages/en-us.axaml @@ -13,6 +13,8 @@ Exit Show Main Window s + minute + hour Tip Delete Replace @@ -21,6 +23,8 @@ Task Size Developing ... + Empty + Refresh Verbose Debug Infomation @@ -93,6 +97,7 @@ Developer Settings Show Announcements When Start Show Announcements Now + Open Debug Tool Personalise Display Language Mica Effect @@ -111,6 +116,7 @@ Native IP Filter Greeting Text Update Interval Log File Relative Settings + The log file has taken up space Log File Max Size Log File Max Count Log File Flush Interval diff --git a/Languages/fr-fr.axaml b/Languages/fr-fr.axaml index fc577653..e22cb907 100644 --- a/Languages/fr-fr.axaml +++ b/Languages/fr-fr.axaml @@ -13,6 +13,8 @@ quitter Afficher la fenêtre principale deuxième + minute + Heure indice effacer remplacer @@ -21,6 +23,8 @@ Tâche Taille En développement + vide + rafraîchir détaillé débogage informations @@ -93,6 +97,7 @@ option de développeur Afficher l'annonce au démarrage Voir les dernières annonces + Ouvrir le débogueur personnaliser langue d'affichage Effet mica @@ -111,6 +116,7 @@ Règles de filtrage IP natives Mise à jour du message d'accueil retardée Paramètres liés au fichier journal + Le fichier journal a pris de la place Limite de taille du fichier journal limite du fichier journal Délai du cache du fichier journal diff --git a/Languages/ja-jp.axaml b/Languages/ja-jp.axaml index a4ad8414..9a3aebd6 100644 --- a/Languages/ja-jp.axaml +++ b/Languages/ja-jp.axaml @@ -13,6 +13,8 @@ 終了する メインウィンドウを表示 2番目 + + 時間 ヒント 消去 交換 @@ -21,6 +23,8 @@ 仕事 サイズ 開発中 + 空の + リフレッシュする 详细 调试 情報 @@ -93,6 +97,7 @@ 開発者向けオプション 起動時にアナウンスを表示 最新のお知らせを見る + デバッガーを開く パーソナライズ 表示言語 Mica 効果 @@ -111,6 +116,7 @@ ネイティブ IP フィルタリング ルール あいさつ更新が遅れる ログファイル関連の設定 + ログファイルがスペースを占有しています ログ ファイルのサイズ制限 ログ ファイルの制限 ログ ファイル キャッシュの遅延 diff --git a/Languages/ko-kr.axaml b/Languages/ko-kr.axaml index 66c1f497..68dd43f7 100644 --- a/Languages/ko-kr.axaml +++ b/Languages/ko-kr.axaml @@ -13,6 +13,8 @@ 그만두다 메인 창 표시 + + 힌트 삭제 바꾸다 @@ -21,6 +23,8 @@ 크기 개발 중 + 비어 있는 + 새로 고침 상세한 디버깅 정보 @@ -93,6 +97,7 @@ 개발자 옵션 시작 시 알림 표시 최신 공지사항 보기 + 디버거 열기 개인화 표시 언어 운모 효과 @@ -111,6 +116,7 @@ 기본 IP 필터링 규칙 인사말 업데이트가 지연되었습니다. 로그 파일 관련 설정 + 로그 파일이 공간을 차지했습니다. 로그 파일 크기 제한 로그 파일 제한 로그 파일 캐시 지연 diff --git a/Languages/ru-ru.axaml b/Languages/ru-ru.axaml index 2adacd1a..7aec7263 100644 --- a/Languages/ru-ru.axaml +++ b/Languages/ru-ru.axaml @@ -13,6 +13,8 @@ покидать Показать главное окно второй + минута + Час намекать Удалить заменять @@ -21,6 +23,8 @@ Задача размер В развитие + пустой + обновить подробный отладка Информация @@ -93,6 +97,7 @@ вариант разработчика Показывать объявление при запуске Посмотреть последние объявления + Откройте отладчик персонализировать язык отображения Эффект слюды @@ -111,6 +116,7 @@ Собственные правила IP-фильтрации Обновление приветствия отложено Настройки, связанные с файлом журнала + Файл журнала занял место Ограничение размера файла журнала лимит файла журнала Задержка кеша файла журнала diff --git a/Languages/zh-cn.axaml b/Languages/zh-cn.axaml index 3fb115ce..e892ada7 100644 --- a/Languages/zh-cn.axaml +++ b/Languages/zh-cn.axaml @@ -13,6 +13,8 @@ 退出 显示主窗口 + 分钟 + 小时 提示 删除 替换 @@ -21,6 +23,8 @@ 任务 大小 该部分正在开发中 + 清空 + 刷新 详细 调试 信息 @@ -93,6 +97,7 @@ 开发者选项 启动时显示公告 查看最新公告 + 打开调试工具 个性化 显示语言 云母效果 @@ -111,6 +116,7 @@ 本机IP过滤规则 招呼语更新延迟 日志文件相关设置 + 日志文件已占用空间 日志文件体积限制 日志文件数量限制 日志文件缓存延时 diff --git a/Languages/zh-tw.axaml b/Languages/zh-tw.axaml index c63e2dca..64c37f1f 100644 --- a/Languages/zh-tw.axaml +++ b/Languages/zh-tw.axaml @@ -13,6 +13,8 @@ 退出 顯示主窗口 + 分鐘 + 小時 提示 刪除 替換 @@ -21,6 +23,8 @@ 任務 大小 該部分正在開發中 + 清空 + 刷新 詳細 調試 信息 @@ -93,6 +97,7 @@ 開發者設定 啓動時顯示公告 查看新公告 + 打開調試工具 個性化 顯示語言 雲母效果 @@ -111,11 +116,12 @@ 本機IP過濾器 招呼語更新延遲 日志文檔相關設定 + 日誌文件已佔用空間 日志文檔大小限制 日志文檔數量限制 日志文檔緩衝延時 日志級別 - 更新檢查每綫程處理文件數量 + 更新檢查每綫程處理文件數量 更新 檢查更新 組件名稱 diff --git a/Program.cs b/Program.cs index 15a40d44..b7ba714f 100644 --- a/Program.cs +++ b/Program.cs @@ -1,5 +1,8 @@ using Avalonia; using Avalonia.ReactiveUI; +#if (IsBuild4WindowsPlatform == true) +using DesktopNotifications.Avalonia; +#endif using KitX_Dashboard.Data; using KitX_Dashboard.Services; using KitX_Dashboard.Views; @@ -13,8 +16,6 @@ namespace KitX_Dashboard { internal class Program { - //internal static LoggerManager LocalLogger = new(); - internal static AppConfig Config = new(); internal static WebManager? WebManager; @@ -147,10 +148,13 @@ public static void Main(string[] args) /// Avalonia 配置项, 请不要删除; 同时也用于可视化设计器 public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect().LogToTrace().UseReactiveUI() +#if (IsBuild4WindowsPlatform == true) + .SetupDesktopNotifications() +#endif .With(new Win32PlatformOptions { UseWindowsUIComposition = true, - EnableMultitouch = true + EnableMultitouch = true, }) .With(new MacOSPlatformOptions { diff --git a/Properties/PublishProfiles/linux-arm-single-cut.pubxml b/Properties/PublishProfiles/linux-arm-single-cut.pubxml index d3b878fe..8ab4175a 100644 --- a/Properties/PublishProfiles/linux-arm-single-cut.pubxml +++ b/Properties/PublishProfiles/linux-arm-single-cut.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-linux-arm-single-cut\ - FileSystem - net6.0 - linux-arm - true - false - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-linux-arm-single-cut\ + FileSystem + net6.0 + linux-arm + true + false + true + False + + diff --git a/Properties/PublishProfiles/linux-arm-single.pubxml b/Properties/PublishProfiles/linux-arm-single.pubxml index c3557162..259063a9 100644 --- a/Properties/PublishProfiles/linux-arm-single.pubxml +++ b/Properties/PublishProfiles/linux-arm-single.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-linux-arm-single\ - FileSystem - net6.0 - linux-arm - true - false - false - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-linux-arm-single\ + FileSystem + net6.0 + linux-arm + true + false + false + False + + diff --git a/Properties/PublishProfiles/linux-arm64-single-cut.pubxml b/Properties/PublishProfiles/linux-arm64-single-cut.pubxml index 7c139c18..74438287 100644 --- a/Properties/PublishProfiles/linux-arm64-single-cut.pubxml +++ b/Properties/PublishProfiles/linux-arm64-single-cut.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-linux-arm64-single-cut\ - FileSystem - net6.0 - linux-arm64 - true - false - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-linux-arm64-single-cut\ + FileSystem + net6.0 + linux-arm64 + true + false + true + False + + diff --git a/Properties/PublishProfiles/linux-arm64-single.pubxml b/Properties/PublishProfiles/linux-arm64-single.pubxml index 4de84fa1..107b2de0 100644 --- a/Properties/PublishProfiles/linux-arm64-single.pubxml +++ b/Properties/PublishProfiles/linux-arm64-single.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-linux-arm64-single\ - FileSystem - net6.0 - linux-arm64 - true - false - false - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-linux-arm64-single\ + FileSystem + net6.0 + linux-arm64 + true + false + false + False + + diff --git a/Properties/PublishProfiles/linux-x64-single-cut.pubxml b/Properties/PublishProfiles/linux-x64-single-cut.pubxml index 86037ba9..191e1ac6 100644 --- a/Properties/PublishProfiles/linux-x64-single-cut.pubxml +++ b/Properties/PublishProfiles/linux-x64-single-cut.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-linux-x64-single-cut\ - FileSystem - net6.0 - linux-x64 - true - false - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-linux-x64-single-cut\ + FileSystem + net6.0 + linux-x64 + true + false + true + False + + diff --git a/Properties/PublishProfiles/linux-x64-single.pubxml b/Properties/PublishProfiles/linux-x64-single.pubxml index a0d80c5d..fef21fa6 100644 --- a/Properties/PublishProfiles/linux-x64-single.pubxml +++ b/Properties/PublishProfiles/linux-x64-single.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-linux-x64-single\ - FileSystem - net6.0 - linux-x64 - true - false - false - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-linux-x64-single\ + FileSystem + net6.0 + linux-x64 + true + false + false + False + + diff --git a/Properties/PublishProfiles/osx-x64-single-cut.pubxml b/Properties/PublishProfiles/osx-x64-single-cut.pubxml index e3e62105..c34eacae 100644 --- a/Properties/PublishProfiles/osx-x64-single-cut.pubxml +++ b/Properties/PublishProfiles/osx-x64-single-cut.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-osx-x64-single-cut\ - FileSystem - net6.0 - osx-x64 - true - false - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-osx-x64-single-cut\ + FileSystem + net6.0 + osx-x64 + true + false + true + False + + diff --git a/Properties/PublishProfiles/osx-x64-single.pubxml b/Properties/PublishProfiles/osx-x64-single.pubxml index fd090cd7..ae7928e2 100644 --- a/Properties/PublishProfiles/osx-x64-single.pubxml +++ b/Properties/PublishProfiles/osx-x64-single.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-osx-x64-single\ - FileSystem - net6.0 - osx-x64 - true - false - false - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-osx-x64-single\ + FileSystem + net6.0 + osx-x64 + true + false + false + False + + diff --git a/Properties/PublishProfiles/win-x64-single-cut.pubxml b/Properties/PublishProfiles/win-x64-single-cut.pubxml index e38d1644..9e80eb4a 100644 --- a/Properties/PublishProfiles/win-x64-single-cut.pubxml +++ b/Properties/PublishProfiles/win-x64-single-cut.pubxml @@ -3,16 +3,17 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-win-x64-single-cut\ - FileSystem - net6.0 - win-x64 - true - false - true - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-win-x64-single-cut\ + FileSystem + net6.0 + win-x64 + true + false + true + true + + + diff --git a/Properties/PublishProfiles/win-x64-single.pubxml b/Properties/PublishProfiles/win-x64-single.pubxml index 8cb67fad..f5a48ab2 100644 --- a/Properties/PublishProfiles/win-x64-single.pubxml +++ b/Properties/PublishProfiles/win-x64-single.pubxml @@ -3,16 +3,17 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-win-x64-single\ - FileSystem - net6.0 - win-x64 - true - false - true - false - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-win-x64-single\ + FileSystem + net6.0 + win-x64 + true + false + true + false + + + diff --git a/Properties/PublishProfiles/win-x64.pubxml b/Properties/PublishProfiles/win-x64.pubxml index f9c8d4d4..b8c67388 100644 --- a/Properties/PublishProfiles/win-x64.pubxml +++ b/Properties/PublishProfiles/win-x64.pubxml @@ -3,15 +3,17 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-win-x64\ - FileSystem - net6.0 - win-x64 - false - false - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-win-x64\ + FileSystem + net6.0 + win-x64 + false + false + true + + True + + diff --git a/Properties/PublishProfiles/win-x86-single-cut.pubxml b/Properties/PublishProfiles/win-x86-single-cut.pubxml index a6429432..0a687068 100644 --- a/Properties/PublishProfiles/win-x86-single-cut.pubxml +++ b/Properties/PublishProfiles/win-x86-single-cut.pubxml @@ -3,16 +3,17 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-win-x86-single-cut\ - FileSystem - net6.0 - win-x86 - true - false - true - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-win-x86-single-cut\ + FileSystem + net6.0 + win-x86 + true + false + true + true + + + diff --git a/Properties/PublishProfiles/win-x86-single.pubxml b/Properties/PublishProfiles/win-x86-single.pubxml index c1d99955..2996a237 100644 --- a/Properties/PublishProfiles/win-x86-single.pubxml +++ b/Properties/PublishProfiles/win-x86-single.pubxml @@ -3,16 +3,17 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-win-x86-single\ - FileSystem - net6.0 - win-x86 - true - false - true - false - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-win-x86-single\ + FileSystem + net6.0 + win-x86 + true + false + true + false + + + diff --git a/Properties/PublishProfiles/win-x86.pubxml b/Properties/PublishProfiles/win-x86.pubxml index 66b241a8..ea944816 100644 --- a/Properties/PublishProfiles/win-x86.pubxml +++ b/Properties/PublishProfiles/win-x86.pubxml @@ -3,15 +3,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - - Release - Any CPU - ..\KitX Publish\kitx-win-x86\ - FileSystem - net6.0 - win-x86 - false - false - true - - \ No newline at end of file + + Release + Any CPU + ..\KitX Publish\kitx-win-x86\ + FileSystem + net6.0 + win-x86 + false + false + true + + + diff --git a/Services/DebugService.cs b/Services/DebugService.cs new file mode 100644 index 00000000..40328f7b --- /dev/null +++ b/Services/DebugService.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace KitX_Dashboard.Services +{ + internal class DebugService + { + /// + /// 执行命令 + /// + /// 命令 + /// 执行结果 + internal static string? ExecuteCommand(string cmd) + { + var header = cmd.GetCommandHeader(); + if (header is null) return null; + var args = cmd.Trim()[header.Length..].GetCommandArgs(); + + return header switch + { + "version" => Assembly.GetEntryAssembly()?.GetName()?.Version?.ToString(), + _ => null, + }; + } + } + + internal static class DebugServiceTool + { + /// + /// 获取命令头 + /// + /// 命令 + /// 命令头 + internal static string? GetCommandHeader(this string cmd) + { + var command = cmd.Trim(); + if (command is null) return null; + var header = command.Split(' ')[0]; + return header; + } + + /// + /// 获取命令参数 + /// + /// 命令 + /// 参数字典 + internal static Dictionary? GetCommandArgs(this string cmd) + { + var args = new Dictionary(); + var command = cmd.Trim(); + var pairs = command?.Split(' '); + if (pairs is null) return null; + if (pairs.Length % 2 != 0) return null; + for (var i = 0; i < pairs.Length; i += 2) + { + if (!pairs[i].Trim().StartsWith("--")) return null; + args.Add(pairs[i].Trim(), pairs[i + 1].Trim()); + } + return args; + } + + /// + /// 获取字典中的值 + /// + /// 字典 + /// 键 + /// + internal static string? Value(this Dictionary src, string key) + => src.ContainsKey(key) ? src[key] : null; + } +} diff --git a/Services/DevicesManager.cs b/Services/DevicesManager.cs index d28465dd..da827c2b 100644 --- a/Services/DevicesManager.cs +++ b/Services/DevicesManager.cs @@ -208,7 +208,7 @@ internal static void Watch4MainDevice() { receivedDeviceInfoStruct4Watch?.Clear(); receivedDeviceInfoStruct4Watch = null; - Log.Error("In Watch4MainDevice", ex); + Log.Error(ex, "In Watch4MainDevice"); } }).Start(); } diff --git a/Services/PluginsManager.cs b/Services/PluginsManager.cs index 55c4fd82..b49ddf67 100644 --- a/Services/PluginsManager.cs +++ b/Services/PluginsManager.cs @@ -57,6 +57,8 @@ internal static void Execute(string msg, IPEndPoint endPoint) internal static readonly Queue pluginsToDelete = new(); + internal static readonly object PluginsListOperationLock = new(); + /// /// 持续检查并移除 /// @@ -150,18 +152,12 @@ internal static void ImportPlugin(string[] kxpfiles, bool inGraphic = false) if (workbase == null) throw new Exception("Can not get path of \"KitX\""); } - string releaseDir = Path.GetFullPath($"{workbase}/{GlobalInfo.KXPTempReleasePath}"); foreach (var item in kxpfiles) { try { - if (Directory.Exists(releaseDir)) - Directory.Delete(releaseDir, true); - _ = Directory.CreateDirectory(releaseDir); - KitX.KXP.Helper.Decoder decoder = new(item); - Tuple rst = decoder.Decode(releaseDir); - Directory.Delete(releaseDir, true); + Tuple rst = decoder.GetLoaderAndPluginStruct(); LoaderStruct loaderStruct = JsonSerializer.Deserialize(rst.Item1); PluginStruct pluginStruct = JsonSerializer.Deserialize(rst.Item2); AppConfig? config = null; @@ -174,20 +170,24 @@ internal static void ImportPlugin(string[] kxpfiles, bool inGraphic = false) Console.WriteLine($"No config file found!"); if (!inGraphic) Environment.Exit(ErrorCodes.ConfigFileDidntExists); } - string pluginsavedir = config?.App.LocalPluginsFileDirectory; + string pluginsavedir = config?.App?.LocalPluginsFileDirectory; + if (pluginsavedir != null) + pluginsavedir = Path.GetFullPath(pluginsavedir); string thisplugindir = $"{pluginsavedir}/" + $"{pluginStruct.PublisherName}_{pluginStruct.AuthorName}/" + $"{pluginStruct.Name}/" + $"{pluginStruct.Version}/"; + thisplugindir = Path.GetFullPath(thisplugindir); if (Directory.Exists(thisplugindir)) Directory.Delete(thisplugindir, true); _ = Directory.CreateDirectory(thisplugindir); _ = decoder.Decode(thisplugindir); - Program.PluginsList.Plugins.Add(new Plugin() - { - InstallPath = thisplugindir - }); + if (!Program.PluginsList.Plugins.Exists(x => x.InstallPath.Equals(thisplugindir))) + Program.PluginsList.Plugins.Add(new() + { + InstallPath = thisplugindir + }); } catch (Exception e) { @@ -222,34 +222,62 @@ internal static void KeepCheckAndRemoveOrDelete() }; timer.Elapsed += (_, _) => { - bool isPluginsListUpdated = false; - - if (pluginsToRemoveFromDB.Count > 0) + try { - isPluginsListUpdated = true; - while (pluginsToRemoveFromDB.Count > 0) + bool isPluginsListUpdated = false; + + if (pluginsToRemoveFromDB.Count > 0) { - Program.PluginsList.Plugins.Remove(pluginsToRemoveFromDB.Dequeue()); + isPluginsListUpdated = true; + while (pluginsToRemoveFromDB.Count > 0) + { + Plugin pg = pluginsToRemoveFromDB.Dequeue(); + lock (PluginsListOperationLock) + { + Program.PluginsList.Plugins.RemoveAt( + Program.PluginsList.Plugins.FindIndex( + x => + { + if (x.InstallPath != null) + return x.InstallPath.Equals(pg.InstallPath); + else return false; + })); + } + } } - } - if (pluginsToDelete.Count > 0) - { - isPluginsListUpdated = true; - while (pluginsToDelete.Count > 0) + if (pluginsToDelete.Count > 0) { - Plugin pg = pluginsToDelete.Dequeue(); - Program.PluginsList.Plugins.Remove(pg); - string pgfiledir = Path.GetFullPath( - $"{Program.Config.App.LocalPluginsFileDirectory}/" + - $"{pg.PluginDetails.PublisherName}_{pg.PluginDetails.AuthorName}/" + - $"{pg.PluginDetails.Name}/{pg.PluginDetails.Version}/" - ); - Directory.Delete(pgfiledir, true); + isPluginsListUpdated = true; + while (pluginsToDelete.Count > 0) + { + Plugin pg = pluginsToDelete.Dequeue(); + lock (PluginsListOperationLock) + { + Program.PluginsList.Plugins.RemoveAt( + Program.PluginsList.Plugins.FindIndex( + x => + { + if (x.InstallPath != null) + return x.InstallPath.Equals(pg.InstallPath); + else return false; + })); + } + string pgfiledir = Path.GetFullPath( + $"{Program.Config.App.LocalPluginsFileDirectory}/" + + $"{pg.PluginDetails.PublisherName}_{pg.PluginDetails.AuthorName}/" + + $"{pg.PluginDetails.Name}/{pg.PluginDetails.Version}/" + ); + Directory.Delete(pgfiledir, true); + } } - } - if (isPluginsListUpdated) EventHandlers.Invoke(nameof(EventHandlers.PluginsListChanged)); + if (isPluginsListUpdated) EventHandlers.Invoke(nameof(EventHandlers.PluginsListChanged)); + } + catch (Exception ex) + { + Log.Error("In PluginsManager.KeepCheckAndRemoveOrDelete()", ex); + } }; timer.Start(); } diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs index 7b6ce5c1..426c8364 100644 --- a/ViewModels/MainWindowViewModel.cs +++ b/ViewModels/MainWindowViewModel.cs @@ -1,8 +1,14 @@ using Avalonia.Controls; +#if (IsBuild4WindowsPlatform == true) +using Avalonia; +using DesktopNotifications; +using System.IO; +#endif using KitX_Dashboard.Commands; using KitX_Dashboard.Data; using KitX_Dashboard.Services; using KitX_Dashboard.Views; +using Serilog; using System; using System.Threading; @@ -10,6 +16,11 @@ namespace KitX_Dashboard.ViewModels { internal class MainWindowViewModel : ViewModelBase { + +#if (IsBuild4WindowsPlatform == true) + private static bool _firstTime2RefreshGreeting = true; +#endif + public MainWindowViewModel() { InitCommands(); @@ -19,12 +30,15 @@ internal void InitCommands() { TrayIconClickedCommand = new(TrayIconClicked); ExitCommand = new(Exit); + RefreshGreetingCommand = new(RefreshGreeting); } internal DelegateCommand? TrayIconClickedCommand { get; set; } internal DelegateCommand? ExitCommand { get; set; } + internal DelegateCommand? RefreshGreetingCommand { get; set; } + internal void TrayIconClicked(object mainWindow) { MainWindow? win = mainWindow as MainWindow; @@ -43,10 +57,44 @@ internal void Exit(object mainWindow) new Thread(() => { - Thread.Sleep(GlobalInfo.LastBreakAfterExit); - Environment.Exit(0); + try + { + Thread.Sleep(GlobalInfo.LastBreakAfterExit); + Environment.Exit(0); + } + catch (Exception ex) + { + Log.Warning(ex, $"In MainWindow.Exit(): {ex.Message}"); + } }).Start(); } + + internal void RefreshGreeting(object mainWindow) + { + MainWindow? win = mainWindow as MainWindow; + win?.UpdateGreetingText(); +#if (IsBuild4WindowsPlatform == true) + if (_firstTime2RefreshGreeting) + { + _firstTime2RefreshGreeting = false; + try + { + var notificationManager = + AvaloniaLocator.Current.GetService() + ?? throw new InvalidDataException("Missing notification manager."); + notificationManager.ShowNotification(new() + { + Title = GlobalInfo.AppName, + Body = "(ノω<。)ノ))☆.。", + }); + } + catch (Exception ex) + { + Log.Warning(ex, ex.Message); + } + } +#endif + } } } diff --git a/ViewModels/Pages/Controls/DevelopingViewModel.cs b/ViewModels/Pages/Controls/DevelopingViewModel.cs index f6a9e15e..bb1cafb4 100644 --- a/ViewModels/Pages/Controls/DevelopingViewModel.cs +++ b/ViewModels/Pages/Controls/DevelopingViewModel.cs @@ -4,12 +4,7 @@ internal class DevelopingViewModel : ViewModelBase { public DevelopingViewModel() { - InitCommands(); - } - - private void InitCommands() - { - + } } } diff --git a/ViewModels/Pages/Controls/PluginBarViewModel.cs b/ViewModels/Pages/Controls/PluginBarViewModel.cs index 9e288181..64057d76 100644 --- a/ViewModels/Pages/Controls/PluginBarViewModel.cs +++ b/ViewModels/Pages/Controls/PluginBarViewModel.cs @@ -146,29 +146,33 @@ internal void Launch(object _) try { string? loaderName = PluginDetail?.RequiredLoaderStruct.LoaderName; - string loaderFile = $"{Program.Config.Loaders.InstallPath}/{loaderName}/{loaderName}"; - if (OperatingSystem.IsWindows()) - loaderFile += ".exe"; - loaderFile = Path.GetFullPath(loaderFile); - var pd = PluginDetail?.PluginDetails; string pluginPath = $"{PluginDetail?.InstallPath}/{pd?.RootStartupFileName}"; string pluginFile = Path.GetFullPath(pluginPath); - - Log.Information($"Launch: {pluginFile} through {loaderFile}"); - - if (File.Exists(loaderFile) && File.Exists(pluginFile)) + string connectStr = $"{DevicesServer.DefaultDeviceInfoStruct.IPv4}" + + $":{GlobalInfo.PluginServerPort}"; + if (PluginDetail != null && PluginDetail.RequiredLoaderStruct.SelfLoad) + Process.Start(pluginFile, $"--connect {connectStr}"); + else { - string arg = $"--load \"{pluginFile}\" " + - $"--connect {DevicesServer.DefaultDeviceInfoStruct.IPv4}:" + - $"{GlobalInfo.PluginServerPort}"; - Log.Information($"Launch Argument: {arg}"); - Process.Start(loaderFile, arg); + string loaderFile = $"{Program.Config.Loaders.InstallPath}/{loaderName}/{loaderName}"; + if (OperatingSystem.IsWindows()) + loaderFile += ".exe"; + loaderFile = Path.GetFullPath(loaderFile); + + Log.Information($"Launch: {pluginFile} through {loaderFile}"); + + if (File.Exists(loaderFile) && File.Exists(pluginFile)) + { + string arg = $"--load \"{pluginFile}\" --connect {connectStr}"; + Log.Information($"Launch Argument: {arg}"); + Process.Start(loaderFile, arg); + } } } catch (Exception ex) { - Log.Error("In PluginBarViewModel.Launch()", ex); + Log.Error(ex, "In PluginBarViewModel.Launch()"); } }).Start(); } diff --git a/ViewModels/Pages/Controls/Settings_GeneralViewModel.cs b/ViewModels/Pages/Controls/Settings_GeneralViewModel.cs index ddfd3edd..3d4b5f7a 100644 --- a/ViewModels/Pages/Controls/Settings_GeneralViewModel.cs +++ b/ViewModels/Pages/Controls/Settings_GeneralViewModel.cs @@ -1,8 +1,11 @@ -using KitX_Dashboard.Commands; +using Common.ExternalConsole; +using KitX_Dashboard.Commands; using KitX_Dashboard.Services; using Serilog; using System; using System.ComponentModel; +using System.Diagnostics; +using System.IO; using System.Threading; namespace KitX_Dashboard.ViewModels.Pages.Controls @@ -10,9 +13,14 @@ namespace KitX_Dashboard.ViewModels.Pages.Controls internal class Settings_GeneralViewModel : ViewModelBase, INotifyPropertyChanged { + private static Manager _manager = new(); + private static int _consolesCount = 0; + internal Settings_GeneralViewModel() { InitCommands(); + + InitEvents(); } /// @@ -21,6 +29,16 @@ internal Settings_GeneralViewModel() private void InitCommands() { ShowAnnouncementsNowCommand = new(ShowAnnouncementsNow); + OpenDebugToolCommand = new(OpenDebugTool); + } + + /// + /// 初始化事件 + /// + private void InitEvents() + { + EventHandlers.DevelopSettingsChanged += + () => PropertyChanged?.Invoke(this, new(nameof(DeveloperSettingEnabled))); } /// @@ -70,6 +88,14 @@ internal static int ShowAnnouncementsStatus } } + /// + /// 是否启用了开发者设置 + /// + internal static bool DeveloperSettingEnabled + { + get => Program.Config.App.DeveloperSetting; + } + /// /// 开发者设置项 /// @@ -89,6 +115,11 @@ internal static int DeveloperSettingStatus /// internal DelegateCommand? ShowAnnouncementsNowCommand { get; set; } + /// + /// 打开调试工具命令 + /// + internal DelegateCommand? OpenDebugToolCommand { get; set; } + private void ShowAnnouncementsNow(object _) { new Thread(async () => @@ -104,6 +135,51 @@ private void ShowAnnouncementsNow(object _) }).Start(); } + private void OpenDebugTool(object _) + { + ++_consolesCount; + var name = $"KitX_DebugTool_{_consolesCount}"; + var console = _manager.Register(name); + try + { + console.Start(); + + ProcessStartInfo psi = new() + { + FileName = Path.GetFullPath($"./Common.ExternalConsole.Console" + + $"{(OperatingSystem.IsWindows() ? ".exe" : "")}"), + Arguments = $"--connect CommonExternalConsole{name}", + CreateNoWindow = false, + UseShellExecute = true, + }; + Process.Start(psi); + + // Receive Thread + new Thread(() => + { + try + { + while (true) + { + var remote = console.ReadLine(); + if (remote is null) continue; + var result = DebugService.ExecuteCommand(remote); + console.WriteLine(result ?? "No this command."); + } + } + catch (Exception ex) + { + Log.Warning(ex, $"In OpenDebugTool(_): Receive Thread: {ex.Message}"); + } + }).Start(); + } + catch (Exception ex) + { + console.Dispose(); + Log.Error(ex, $"In OpenDebugTool(_): {ex.Message}"); + } + } + public new event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/ViewModels/Pages/Controls/Settings_PerformenceViewModel.cs b/ViewModels/Pages/Controls/Settings_PerformenceViewModel.cs index 8d594bf6..200753cd 100644 --- a/ViewModels/Pages/Controls/Settings_PerformenceViewModel.cs +++ b/ViewModels/Pages/Controls/Settings_PerformenceViewModel.cs @@ -1,12 +1,16 @@ using Avalonia; using Avalonia.Controls; +using Common.BasicHelper.IO; +using KitX_Dashboard.Commands; using KitX_Dashboard.Data; using KitX_Dashboard.Models; using KitX_Dashboard.Services; using Serilog; +using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; +using System.Threading; #pragma warning disable CS8604 // 引用类型参数可能为 null。 @@ -18,6 +22,8 @@ internal class Settings_PerformenceViewModel : ViewModelBase, INotifyPropertyCha internal Settings_PerformenceViewModel() { InitEvents(); + + InitCommands(); } private void InitEvents() @@ -52,6 +58,12 @@ private void InitEvents() }; } + private void InitCommands() + { + EmptyLogsCommand = new(EmptyLogs); + RefreshLogsUsageCommand = new(RefreshLogsUsage); + } + /// /// 保存变更 /// @@ -110,6 +122,13 @@ internal static bool LogReletiveAreaExpanded } } + /// + /// 日志文件空间占用 + /// 单位, MB + /// + internal static int LogFileSizeUsage => (int)(DirectoryHelper.GetDirectorySize + (Path.GetFullPath(Program.Config.Log.LogFilePath)) / 1000 / 1024); + /// /// 单个文件体积限制上限 /// @@ -243,6 +262,46 @@ internal SurpportLogLevel? CurrentLogLevel } } + /// + /// 清空日志命令 + /// + internal DelegateCommand? EmptyLogsCommand { get; set; } + + /// + /// 刷新日志占用命令 + /// + internal DelegateCommand? RefreshLogsUsageCommand { get; set; } + + private void EmptyLogs(object obj) + { + try + { + new Thread(() => + { + DirectoryInfo dir = new(Path.GetFullPath(Program.Config.Log.LogFilePath)); + foreach (var file in dir.GetFiles()) + { + try + { + File.Delete(file.FullName); + } + catch (Exception ex) + { + Log.Error(ex, $"In Settings_Performence.EmptyLogs(): {ex.Message}"); + } + } + PropertyChanged?.Invoke(this, new(nameof(LogFileSizeUsage))); + }).Start(); + } + catch (Exception ex) + { + Log.Error(ex, $"In Settings_Performence.EmptyLogs(): {ex.Message}"); + } + } + + private void RefreshLogsUsage(object obj) => + PropertyChanged?.Invoke(this, new(nameof(LogFileSizeUsage))); + public new event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/ViewModels/Pages/Controls/Settings_UpdateViewModel.cs b/ViewModels/Pages/Controls/Settings_UpdateViewModel.cs index 75713d98..31799ffd 100644 --- a/ViewModels/Pages/Controls/Settings_UpdateViewModel.cs +++ b/ViewModels/Pages/Controls/Settings_UpdateViewModel.cs @@ -35,8 +35,6 @@ internal Settings_UpdateViewModel() InitEvents(); InitCommands(); - - InitData(); } /// @@ -62,14 +60,6 @@ internal void InitCommands() CheckUpdateCommand = new(CheckUpdate); } - /// - /// 初始化数据 - /// - internal void InitData() - { - - } - internal int canUpdateCount = 0; /// diff --git a/ViewModels/Pages/RepoPageViewModel.cs b/ViewModels/Pages/RepoPageViewModel.cs index c6482170..5918e943 100644 --- a/ViewModels/Pages/RepoPageViewModel.cs +++ b/ViewModels/Pages/RepoPageViewModel.cs @@ -127,7 +127,7 @@ internal async void ImportPlugin(object win) } catch (Exception ex) { - Log.Error("In RepoPageViewModel.ImportPlugin()", ex); + Log.Error(ex, "In RepoPageViewModel.ImportPlugin()"); } }).Start(); } @@ -142,24 +142,29 @@ internal void RefreshPlugins(object _) //LiteDatabase? pgdb = Program.PluginsDataBase; PluginBars.Clear(); - foreach (var item in Program.PluginsList.Plugins) + lock (PluginsManager.PluginsListOperationLock) { - try + foreach (var item in Program.PluginsList.Plugins) { - Plugin plugin = new() + try { - InstallPath = item.InstallPath, - PluginDetails = JsonSerializer.Deserialize( - File.ReadAllText(Path.GetFullPath($"{item.InstallPath}/PluginStruct.json"))), - RequiredLoaderStruct = JsonSerializer.Deserialize( - File.ReadAllText(Path.GetFullPath($"{item.InstallPath}/LoaderStruct.json"))), - InstalledDevices = new() - }; - PluginBars.Add(new(plugin, ref pluginBars)); - } - catch (Exception ex) - { - Log.Error("In RefreshPlugins()", ex); + Plugin plugin = new() + { + InstallPath = item.InstallPath, + PluginDetails = JsonSerializer.Deserialize( + File.ReadAllText( + Path.GetFullPath($"{item.InstallPath}/PluginStruct.json"))), + RequiredLoaderStruct = JsonSerializer.Deserialize( + File.ReadAllText( + Path.GetFullPath($"{item.InstallPath}/LoaderStruct.json"))), + InstalledDevices = new() + }; + PluginBars.Add(new(plugin, ref pluginBars)); + } + catch (Exception ex) + { + Log.Error(ex, "In RefreshPlugins()"); + } } } } diff --git a/ViewModels/PluginDetailWindowViewModel.cs b/ViewModels/PluginDetailWindowViewModel.cs index c5eaccc9..aaea6d1a 100644 --- a/ViewModels/PluginDetailWindowViewModel.cs +++ b/ViewModels/PluginDetailWindowViewModel.cs @@ -1,23 +1,28 @@ -using Avalonia.Controls; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; using Avalonia.Media.Imaging; +using FluentAvalonia.Styling; using KitX.Web.Rules; using KitX_Dashboard.Commands; +using KitX_Dashboard.Services; using Serilog; using System; -using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.IO; using System.Linq; using System.Text; -using System.Threading.Tasks; namespace KitX_Dashboard.ViewModels { - internal class PluginDetailWindowViewModel : ViewModelBase + internal class PluginDetailWindowViewModel : ViewModelBase, INotifyPropertyChanged { public PluginDetailWindowViewModel() { InitCommands(); + + InitEvents(); } internal void InitCommands() @@ -25,6 +30,12 @@ internal void InitCommands() FinishCommand = new(Finish); } + internal void InitEvents() + { + EventHandlers.ThemeConfigChanged += + () => PropertyChanged?.Invoke(this, new(nameof(ViewModels.PluginDetailWindowViewModel.TintColor))); + } + internal PluginStruct? PluginDetail { get; set; } internal string? DisplayName @@ -105,6 +116,19 @@ internal string? TotalDescriptionInMarkdown internal string? LastUpdateDate => PluginDetail?.LastUpdateDate.ToString("yyyy.MM.dd"); + internal static Color TintColor => Program.Config.App.Theme switch + { + "Light" => Colors.WhiteSmoke, + "Dark" => Colors.Black, + "Follow" => AvaloniaLocator.Current.GetService()?.RequestedTheme switch + { + "Light" => Colors.WhiteSmoke, + "Dark" => Colors.Black, + _ => Color.Parse(Program.Config.App.ThemeColor) + }, + _ => Color.Parse(Program.Config.App.ThemeColor), + }; + private readonly ObservableCollection functions = new(); private readonly ObservableCollection tags = new(); @@ -141,11 +165,11 @@ internal void InitFunctionsAndTags() { StringBuilder sb = new(); sb.Append(func.ReturnValueType); - sb.Append(" "); + sb.Append(' '); if (func.DisplayNames.ContainsKey(langKey)) sb.Append(func.DisplayNames[langKey]); else sb.Append(func.Name); - sb.Append("("); + sb.Append('('); if (func.Parameters.Count != func.ParametersType.Count) throw new InvalidDataException("Parameters return type count " + "didn't match parameters count."); @@ -154,14 +178,14 @@ internal void InitFunctionsAndTags() { sb.Append(func.ParametersType[index]); ++index; - sb.Append(" "); + sb.Append(' '); if (param.Value.ContainsKey(langKey)) sb.Append(param.Value[langKey]); else sb.Append(param.Key); if (index != func.Parameters.Count) sb.Append(", "); } - sb.Append(")"); + sb.Append(')'); Functions.Add(sb.ToString()); } foreach (var tag in PluginDetail.Value.Tags) @@ -179,5 +203,7 @@ internal void Finish(object parent) { (parent as Window)?.Close(); } + + public new event PropertyChangedEventHandler? PropertyChanged; } } diff --git a/Views/MainWindow.axaml b/Views/MainWindow.axaml index 90e2fb63..b5f157e6 100644 --- a/Views/MainWindow.axaml +++ b/Views/MainWindow.axaml @@ -18,7 +18,19 @@ Icon="avares://KitX.Assets/KitX-Icon-32x32.png" mc:Ignorable="d"> - + + + + @@ -50,8 +62,6 @@ - - - + - + @@ -80,15 +84,9 @@ Tag="Page_Lib" ToolTip.Tip="{DynamicResource Text_MainWindow_NavigationView_Lib}"> - + - + @@ -96,15 +94,9 @@ Tag="Page_Repo" ToolTip.Tip="{DynamicResource Text_MainWindow_NavigationView_Repo}"> - + - + @@ -112,15 +104,9 @@ Tag="Page_Device" ToolTip.Tip="{DynamicResource Text_MainWindow_NavigationView_Devices}"> - + - + @@ -131,15 +117,9 @@ Tag="Page_Market" ToolTip.Tip="{DynamicResource Text_MainWindow_NavigationView_Market}"> - + - + @@ -147,15 +127,9 @@ Tag="Page_Account" ToolTip.Tip="{DynamicResource Text_MainWindow_NavigationView_Account}"> - + - + @@ -163,15 +137,9 @@ Tag="Page_Settings" ToolTip.Tip="{DynamicResource Text_MainWindow_NavigationView_Settings}"> - + - + @@ -179,9 +147,18 @@ + TextWrapping="Wrap"> + + + + + + diff --git a/Views/MainWindow.axaml.cs b/Views/MainWindow.axaml.cs index 3bb7186b..392e6952 100644 --- a/Views/MainWindow.axaml.cs +++ b/Views/MainWindow.axaml.cs @@ -178,7 +178,7 @@ private static void SaveChanges() /// /// 更新招呼语 /// - private void UpdateGreetingText() + internal void UpdateGreetingText() { try { diff --git a/Views/Pages/Controls/Settings_General.axaml b/Views/Pages/Controls/Settings_General.axaml index 50c4e63d..69e557e5 100644 --- a/Views/Pages/Controls/Settings_General.axaml +++ b/Views/Pages/Controls/Settings_General.axaml @@ -121,6 +121,14 @@ +