From 07103ab0b5fbc58d8e4782b19f7b76ca95240e93 Mon Sep 17 00:00:00 2001 From: zkhssb Date: Mon, 18 Dec 2023 20:59:57 +0800 Subject: [PATCH 01/11] =?UTF-8?q?add/update:=20=E6=9B=B4=E6=96=B0=E5=99=A8?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81,=20zh=5Ftw,=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NectarRCON.Export/NectarRCON.Export.csproj | 6 +- NectarRCON.Tests/NectarRCON.Tests.csproj | 1 + NectarRCON.Tests/UpdaterTests.cs | 40 +++++++ NectarRCON.Updater/AppVersion.cs | 105 +++++++++++++++++ NectarRCON.Updater/GithubUpdater.cs | 91 +++++++++++++++ NectarRCON.Updater/IUpdater.cs | 26 +++++ NectarRCON.Updater/Model/Asset.cs | 14 +++ NectarRCON.Updater/Model/Release.cs | 27 +++++ NectarRCON.Updater/NectarRCON.Updater.csproj | 9 ++ NectarRCON.sln | 8 +- NectarRCON/Resources/Languages/zh_tw.xaml | 112 +++++++++++++++++++ NectarRCON/Services/LanguageService.cs | 1 + README.md | 9 ++ README_EN.md | 9 ++ 14 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 NectarRCON.Tests/UpdaterTests.cs create mode 100644 NectarRCON.Updater/AppVersion.cs create mode 100644 NectarRCON.Updater/GithubUpdater.cs create mode 100644 NectarRCON.Updater/IUpdater.cs create mode 100644 NectarRCON.Updater/Model/Asset.cs create mode 100644 NectarRCON.Updater/Model/Release.cs create mode 100644 NectarRCON.Updater/NectarRCON.Updater.csproj create mode 100644 NectarRCON/Resources/Languages/zh_tw.xaml diff --git a/NectarRCON.Export/NectarRCON.Export.csproj b/NectarRCON.Export/NectarRCON.Export.csproj index cfadb03..88eb041 100644 --- a/NectarRCON.Export/NectarRCON.Export.csproj +++ b/NectarRCON.Export/NectarRCON.Export.csproj @@ -1,9 +1,13 @@ - net7.0 + net7.0-windows enable enable + + + + diff --git a/NectarRCON.Tests/NectarRCON.Tests.csproj b/NectarRCON.Tests/NectarRCON.Tests.csproj index b53a7d2..49e183a 100644 --- a/NectarRCON.Tests/NectarRCON.Tests.csproj +++ b/NectarRCON.Tests/NectarRCON.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/NectarRCON.Tests/UpdaterTests.cs b/NectarRCON.Tests/UpdaterTests.cs new file mode 100644 index 0000000..396921e --- /dev/null +++ b/NectarRCON.Tests/UpdaterTests.cs @@ -0,0 +1,40 @@ +using NectarRCON.Updater; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NectarRCON.Tests +{ + [TestClass] + public class UpdaterTests + { + [TestMethod] + public void Github() + { + IUpdater updater = new GithubUpdater(); + updater.SetVersion("NectarRcon-x86-1.0.0"); + updater.IsLatestVersion(); + } + + [TestMethod] + public void AppVersionTest() + { + AppVersion versionA = AppVersion.ParseVersion("TestApp-x64-1.0.0-beta1"); + AppVersion versionB = AppVersion.ParseVersion("TestApp-x64-1.0.0-beta2"); + + Assert.IsTrue(versionA.Equals(versionA)); + Assert.IsFalse(versionA.Equals(versionB)); + +#pragma warning disable CS1718 // 对同一变量进行了比较 + Assert.IsTrue(versionA == versionA); + Assert.IsFalse(versionA != versionA); + Assert.IsFalse(versionA > versionA); +#pragma warning restore CS1718 // 对同一变量进行了比较 + + Assert.IsTrue(versionB > versionA); + Assert.IsFalse(versionB < versionA); + } + } +} diff --git a/NectarRCON.Updater/AppVersion.cs b/NectarRCON.Updater/AppVersion.cs new file mode 100644 index 0000000..618fe16 --- /dev/null +++ b/NectarRCON.Updater/AppVersion.cs @@ -0,0 +1,105 @@ +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; + +namespace NectarRCON.Updater +{ + public class AppVersion + { + public string AppName { get; set; } = string.Empty; + public int Version { get; set; } + public int Major { get;set; } + public int Minor { get;set; } + public int Patch { get;set; } + public int? Build { get; set; } + public string PreReleaseType { get; set; } = string.Empty; + public string Platform { get; set; } = string.Empty; + public bool IsPreRelease + => !string.IsNullOrEmpty(PreReleaseType); + + public override string ToString() + { + return $"{AppName}-{Platform}-{Major}.{Minor}.{Patch}" + (IsPreRelease ? $"-{PreReleaseType}{Build}" : string.Empty); + } + + public override bool Equals(object? obj) + { + return obj?.ToString() == ToString(); + } + + public static bool operator <(AppVersion a, AppVersion b) + { + return a.Version < b.Version || (a.Build ?? 0) < (b.Build ?? 0); + } + + public static bool operator >(AppVersion a, AppVersion b) + { + return a.Version > b.Version || (a.Build ?? 0) > (b.Build ?? 0); + } + + public static bool operator ==(AppVersion a, AppVersion b) + { + return a.Version == b.Version && (a.Build ?? 0) == (b.Build ?? 0); + } + + public static bool operator !=(AppVersion a, AppVersion b) + { + return a.Version != b.Version || (a.Build ?? 0) != (b.Build ?? 0); + } + + private AppVersion() { } + + public static AppVersion ParseVersion(string version) + { + string[] versionParts = version.Split("-"); + if (versionParts.Length > 2) + { + AppVersion result = new(); + string name = versionParts[0]; + string platform = versionParts[1]; + string ver = versionParts[2]; + string preRelease = string.Empty; + + if (versionParts.Length > 3) + { + preRelease = versionParts[3]; + } + + Regex versionRegex = new(@"(?\d+)\.(?\d+)\.(?\d+)"); + Match versionMatch = versionRegex.Match(ver); + + if (versionMatch.Success) + { + result.Version = int.Parse(versionMatch.Groups["major"].Value + versionMatch.Groups["minor"].Value + versionMatch.Groups["patch"].Value); + result.Major = int.Parse(versionMatch.Groups["major"].Value); + result.Minor = int.Parse(versionMatch.Groups["minor"].Value); + result.Patch = int.Parse(versionMatch.Groups["patch"].Value); + } + + Regex preReleaseRegex = new(@"(?[a-zA-Z]+)(?\d+)"); + Match preReleaseMatch = preReleaseRegex.Match(preRelease); + + if (preReleaseMatch.Success) + { + if (preReleaseMatch.Groups["build"].Success) + { + result.Build = int.Parse(preReleaseMatch.Groups["build"].Value); + } + if (preReleaseMatch.Groups["preRelease"].Success) + { + result.PreReleaseType = preReleaseMatch.Groups["preRelease"].Value; + } + } + + result.Platform = platform; + result.AppName = name; + return result; + } + throw new InvalidOperationException("Invalid version format"); + } + + public override int GetHashCode() + { + return RuntimeHelpers.GetHashCode(ToString()); + } + } +} diff --git a/NectarRCON.Updater/GithubUpdater.cs b/NectarRCON.Updater/GithubUpdater.cs new file mode 100644 index 0000000..1f43cf3 --- /dev/null +++ b/NectarRCON.Updater/GithubUpdater.cs @@ -0,0 +1,91 @@ +using NectarRCON.Updater.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace NectarRCON.Updater +{ + public class GithubUpdater : IUpdater + { + private static readonly HttpClient _client = new() + { + BaseAddress = new Uri("https://api.github.com/repos/zkhssb/NectarRcon/") + }; + private bool _preEnable = false; + private AppVersion? _version; + + /// + /// 获取最新版本, null为没找到 + /// + /// 是否允许pre版本 + private AppVersion? GetLatestVersion(bool enablePre) + { + if (_version is null) + return null; + using(HttpRequestMessage request = new(HttpMethod.Get, "releases/latest")) + { + request.Headers.Add("User-Agent", $"{_version.AppName}-AppUpdater"); + using(HttpResponseMessage response = _client.Send(request)) + { + if (!response.IsSuccessStatusCode) + throw new HttpRequestException(response.StatusCode.ToString()); + string resultString = string.Empty; + Task.Run(async () => + { + resultString = await response.Content.ReadAsStringAsync(); + }).Wait(); + Release release = JsonSerializer.Deserialize(resultString) ?? throw new JsonException(); + foreach(var asset in release.Assets) + { + string fileName = Path.GetFileNameWithoutExtension(asset.Name); + try + { + fileName = "NectarRcon-x86-1.0.0-beta2"; + AppVersion version = AppVersion.ParseVersion(fileName); + if(version.AppName.ToLower() == _version.AppName.ToLower() && version.Platform.ToLower() == _version.Platform.ToLower()) + { + if (version.IsPreRelease && !enablePre) + continue; + if (version > _version) + { + return version; + } + } + } + catch (InvalidOperationException) { } // Invalid version format + } + return null; + } + } + } + + public bool IsLatestVersion() + { + GetLatestVersion(_preEnable); + return true; + } + + public void Setup() + { + throw new NotImplementedException(); + } + + public void SetVersion(string version) + { + _version = AppVersion.ParseVersion(version); + } + + public void SetPreEnable(bool value) + { + _preEnable = value; + } + + public AppVersion GetLatestVersion() + { + throw new NotImplementedException(); + } + } +} diff --git a/NectarRCON.Updater/IUpdater.cs b/NectarRCON.Updater/IUpdater.cs new file mode 100644 index 0000000..ca0067f --- /dev/null +++ b/NectarRCON.Updater/IUpdater.cs @@ -0,0 +1,26 @@ +namespace NectarRCON.Updater +{ + public interface IUpdater + { + /// + /// 设置版本 + /// + void SetVersion(string version); + /// + /// 是最新版 + /// + bool IsLatestVersion(); + /// + /// 获取最新版本 + /// + AppVersion GetLatestVersion(); + /// + /// 开始安装 + /// + void Setup(); + /// + /// 设置是否启用获取预发布版本更新 + /// + void SetPreEnable(bool value); + } +} diff --git a/NectarRCON.Updater/Model/Asset.cs b/NectarRCON.Updater/Model/Asset.cs new file mode 100644 index 0000000..235c83b --- /dev/null +++ b/NectarRCON.Updater/Model/Asset.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace NectarRCON.Updater.Model +{ + public class Asset + { + [JsonPropertyName("name")] + public required string Name { get; set; } + [JsonPropertyName("url")] + public required string Url { get; set; } + [JsonPropertyName("created_at")] + public required DateTime CreatedAt { get; set; } + } +} diff --git a/NectarRCON.Updater/Model/Release.cs b/NectarRCON.Updater/Model/Release.cs new file mode 100644 index 0000000..c753d84 --- /dev/null +++ b/NectarRCON.Updater/Model/Release.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace NectarRCON.Updater.Model +{ + public class Release + { + [JsonPropertyName("tag_name")] + public required string TagName { get; set; } + + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("created_at")] + public required DateTime CreatedAt { get; set; } + + [JsonPropertyName("assets")] + public required IEnumerable Assets { get; set; } + + [JsonPropertyName("body")] + public required string Body { get; set; } + } +} diff --git a/NectarRCON.Updater/NectarRCON.Updater.csproj b/NectarRCON.Updater/NectarRCON.Updater.csproj new file mode 100644 index 0000000..cb6a55a --- /dev/null +++ b/NectarRCON.Updater/NectarRCON.Updater.csproj @@ -0,0 +1,9 @@ + + + + net7.0-windows + enable + enable + + + diff --git a/NectarRCON.sln b/NectarRCON.sln index 2a952cb..d3a99e5 100644 --- a/NectarRCON.sln +++ b/NectarRCON.sln @@ -11,7 +11,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NectarRCON.Export", "Nectar EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NectarRCON.Adapter.Minecraft", "NectarRCON.Adapter.Minecraft\NectarRCON.Adapter.Minecraft.csproj", "{D4B97850-FF59-4AA1-A19F-2C22F80A8B20}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NectarRCON.Core", "NectarRCON.Core\NectarRCON.Core.csproj", "{8C15668B-69F3-4138-BCE6-0BB6A65F3B2F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NectarRCON.Core", "NectarRCON.Core\NectarRCON.Core.csproj", "{8C15668B-69F3-4138-BCE6-0BB6A65F3B2F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NectarRCON.Updater", "NectarRCON.Updater\NectarRCON.Updater.csproj", "{D6C910A7-3590-492B-9CA1-C3D586FF2C41}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -39,6 +41,10 @@ Global {8C15668B-69F3-4138-BCE6-0BB6A65F3B2F}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C15668B-69F3-4138-BCE6-0BB6A65F3B2F}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C15668B-69F3-4138-BCE6-0BB6A65F3B2F}.Release|Any CPU.Build.0 = Release|Any CPU + {D6C910A7-3590-492B-9CA1-C3D586FF2C41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6C910A7-3590-492B-9CA1-C3D586FF2C41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6C910A7-3590-492B-9CA1-C3D586FF2C41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6C910A7-3590-492B-9CA1-C3D586FF2C41}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NectarRCON/Resources/Languages/zh_tw.xaml b/NectarRCON/Resources/Languages/zh_tw.xaml new file mode 100644 index 0000000..9764644 --- /dev/null +++ b/NectarRCON/Resources/Languages/zh_tw.xaml @@ -0,0 +1,112 @@ + + zh_tw + 繁体中文(zh_tw) + 伺服器 + 伺服器列表 + 伺服器分組 + 日誌 + 清空日誌 + 程式 + 設定 + 關於 + 檢查更新 + RCON管理器 + UI語言 + UI主題 + 深色主題 + 淺色主題 + 跟隨系統 + Rcon密碼管理 + 伺服器命令回溯記錄數 + + 連線 + 編輯 + 刪除 + 密碼 + 伺服器列表 + 新增伺服器 + 輸入伺服器名稱來搜尋... + 此操作將會刪除伺服器! (包括記錄的密碼)\n您確定要刪除嗎? + + 新增伺服器 + 伺服器名稱 + 伺服器地址 + 伺服器端口 + 新增 + 取消 + 相同名稱的伺服器已經存在,請換一個名稱! + 伺服器名稱或伺服器地址不可為空,請更改! + + 爱发电 + MCBBS + Github + + 解析目标地址時遇到錯誤:%s\n請檢查伺服器地址是否合法! + + 編輯密碼 + 密碼 + 無需密碼 + + 執行 + 執行成功 + + 編輯 + + 執行過程中出現異常,應用即將結束。如果您無法理解以下錯誤,請在 GitHub 上提交問題並詳細描述發生的情況。 + 錯誤 + 警告 + 資訊 + 確定 + 取消 + 不可使用 + 連接 + 移除 + 刪除 + 新增 + + 正在連接伺服器... + 連接伺服器失敗! + 無法連接到遠程伺服器:%s\n請檢查伺服器RCON地址配置是否正確,以及檢查服務端是否開啟了RCON選項! + Rcon密碼錯誤,請檢查您的伺服器密碼是否正確! + + 連接伺服器並認證成功! + 連接已斷開! + 開始連接 + + 無法連接到伺服器,因此無法使用遠程命令功能,請嘗試回到伺服器列表重新連接到本伺服器! + + 無法解析伺服器列表 /servers.json %s\n點選"是"重置伺服器列表(需重新添加伺服器,但記錄的密碼不會消失)\n點選"取消"關閉程式! + 無法解析伺服器列表 /servers.json %s\n點選"是"關閉程式! + 無法儲存檔案 /servers.json\n如果您剛剛進行了添加伺服器操作,請注意,本次儲存並未生效!\n%s + + 無法解析密碼列表 /passwords.json %s\n點選"是"重置密碼列表(需重新設定密碼,但記錄的伺服器不會消失)\n點選"取消"關閉程式! + 無法解析密碼列表 /passwords.json %s\n點選"是"關閉程式! + 無法儲存檔案 /passwords.json\n如果您剛剛進行了設定密碼操作,請注意,本次儲存並未生效!\n%s + + 無法解析配置檔案 /config.json JSON解析失敗:%s\n點選"是"重置配置檔案!\n點選"否"退出程式! + 無法解析配置檔案 /config.json:%s\n點選"是"重置配置檔案!\n點選"否"退出程式! + 無法儲存配置檔案 /config.json:%s\n如果您剛剛更改了配置檔案,請注意,儲存並未生效! + + 讀取和解析組檔案"{0}"時發生錯誤,請嘗試刪除或修復檔案以解決此錯誤! + 相同的 GroupId 已存在(現有值: {0},重複值: {1}) + 相同的 Name 已存在(現有Id: {0},重複Id: {1}) + 檔案中已存在具有相同內部 ID 的分組,請再次嘗試建立 + {0} 檔案名與內部 ID {1} 不匹配 + 相同的組名已存在 + + 點擊「+添加」添加一個分組吧! + 添加分組後,您可以將命令廣播到該分組的所有伺服器 + 該分組沒有任何伺服器,請點擊「+添加」添加一個伺服器吧! + 是否要刪除分組 {0}? + + 新建分組 + 分組名稱 + + 選擇伺服器 + 沒有可用的伺服器 + + 離線 + \ No newline at end of file diff --git a/NectarRCON/Services/LanguageService.cs b/NectarRCON/Services/LanguageService.cs index 2351f22..3d680e9 100644 --- a/NectarRCON/Services/LanguageService.cs +++ b/NectarRCON/Services/LanguageService.cs @@ -57,6 +57,7 @@ public void Refresh() } // 从内部文件加载 _defaultLanguages.Add("zh_cn", "pack://application:,,,/NectarRCON;component/Resources/Languages/zh_cn.xaml"); + _defaultLanguages.Add("zh_tw", "pack://application:,,,/NectarRCON;component/Resources/Languages/zh_tw.xaml"); _defaultLanguages.Add("en_us", "pack://application:,,,/NectarRCON;component/Resources/Languages/en_us.xaml"); foreach (KeyValuePair language in _defaultLanguages) { diff --git a/README.md b/README.md index a200183..38efbb7 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,15 @@ NectarRCON 学习 WPF 时突发奇想做的一个工具,代码可能不太美观(各种乱七八糟,一锅乱炖的写法) +<<<<<<< Updated upstream +======= +## 项目依赖 + +| 名字 | 地址 | +| ------------------------- | ------------------------------- | +| WPF-UI (作者已废弃的版本) | https://github.com/lepoco/wpfui | + +>>>>>>> Stashed changes ## 部分截图
diff --git a/README_EN.md b/README_EN.md index 0058eb7..8ec723a 100644 --- a/README_EN.md +++ b/README_EN.md @@ -50,6 +50,15 @@ NectarRCON A tool I came up with while learning WPF. The code may not be aesthetically pleasing (a mishmash of various things, written in a haphazard manner) +<<<<<<< Updated upstream +======= +## Project Dependencies + +| Name | Address | +| --------------------------- | ------------------------------- | +| WPF-UI (Deprecated Version) | https://github.com/lepoco/wpfui | + +>>>>>>> Stashed changes ## Screenshots
From f8fc60bec5edc669d60b15aed72b8d3a19563389 Mon Sep 17 00:00:00 2001 From: zkhssb Date: Mon, 18 Dec 2023 21:16:09 +0800 Subject: [PATCH 02/11] update: .gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 9491a2f..ffae5ed 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +# NectarRcon Config +config.json +servers.json +passwords.json + # User-specific files *.rsuser *.suo From 4193364af9b206a944646a8a2baccf91c0ee58e2 Mon Sep 17 00:00:00 2001 From: zkhssb Date: Tue, 23 Jan 2024 20:11:34 +0800 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=A4=9A?= =?UTF-8?q?=E6=AC=A1=E6=8F=90=E7=A4=BA=E8=BF=9E=E6=8E=A5=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=20https://github.com/zkhssb/NectarR?= =?UTF-8?q?CON/issues/6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NectarRCON/ViewModels/MainPageViewModel.cs | 66 ++++++++++++---------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/NectarRCON/ViewModels/MainPageViewModel.cs b/NectarRCON/ViewModels/MainPageViewModel.cs index f575a0b..c932860 100644 --- a/NectarRCON/ViewModels/MainPageViewModel.cs +++ b/NectarRCON/ViewModels/MainPageViewModel.cs @@ -16,6 +16,7 @@ using TextBox = Wpf.Ui.Controls.TextBox; namespace NectarRCON.ViewModels; + public partial class MainPageViewModel : ObservableObject { private readonly ILogService _logService; @@ -27,13 +28,12 @@ public partial class MainPageViewModel : ObservableObject private readonly IConnectingDialogService _connectingDialogService; private readonly IMessageBoxService _messageBoxService; - private MainPage? _page = null; - private TextBox? _logTextBox = null; + private MainPage? _page; + private TextBox? _logTextBox; + + [ObservableProperty] private string _commandText = string.Empty; + [ObservableProperty] private string _logText = string.Empty; - [ObservableProperty] - private string _commandText = string.Empty; - [ObservableProperty] - private string _logText = string.Empty; public MainPageViewModel() { _logService = App.GetService(); @@ -46,16 +46,17 @@ public MainPageViewModel() WeakReferenceMessenger.Default.Register(this, OnClear); // 选择连接服务 - _rconConnectService = _rconConnectionInfoService.HasMultipleInformation ? - App.GetService(typeof(RconMultiConnection)) : - App.GetService(typeof(RconSingleConnection)); - + _rconConnectService = _rconConnectionInfoService.HasMultipleInformation + ? App.GetService(typeof(RconMultiConnection)) + : App.GetService(typeof(RconSingleConnection)); } - public void OnClear(object sender, ClearLogValueMessage msg) + + private void OnClear(object sender, ClearLogValueMessage msg) { _logService.Clear(); LogText = string.Empty; } + private void OnMessage(ServerInformation info, string msg) { string logMsg = string.IsNullOrEmpty(msg) @@ -64,20 +65,22 @@ private void OnMessage(ServerInformation info, string msg) LogText += _logService.Log($"{info.Name}:" + logMsg); _logTextBox?.ScrollToEnd(); } + private void OnClosed(ServerInformation info) { LogText += _logService.Log($"{info.Name}\t{_languageService.GetKey("text.server.closed")}"); } + [RelayCommand] - public async void Load(RoutedEventArgs e) + private async void Load(RoutedEventArgs e) { try { _connectingDialogService.Show(); // 选择连接服务 - _rconConnectService = _rconConnectionInfoService.HasMultipleInformation ? - App.GetService(typeof(RconMultiConnection)) : - App.GetService(typeof(RconSingleConnection)); + _rconConnectService = _rconConnectionInfoService.HasMultipleInformation + ? App.GetService(typeof(RconMultiConnection)) + : App.GetService(typeof(RconSingleConnection)); WeakReferenceMessenger.Default.Send(new MainPageLoadValueMessage() { @@ -98,21 +101,20 @@ public async void Load(RoutedEventArgs e) catch (SocketException ex) { _messageBoxService.Show(_languageService.GetKey("text.server.connect.fail.text") - .Replace("\\n", "\n") - .Replace("%s", ex.Message), _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error); + .Replace("\\n", "\n") + .Replace("%s", ex.Message), _languageService.GetKey("text.error"), MessageBoxButton.OK, + MessageBoxImage.Error); } catch (AuthenticationException ex) { _messageBoxService.Show(ex.Message + _languageService.GetKey("text.server.connect.auth_fail") - .Replace("\\n", "\n"), _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error); - if (_rconConnectionInfoService.HasMultipleInformation) - { - _navigationService.Navigate(typeof(GroupPage)); - } - else - { - _navigationService.Navigate(typeof(ServersPage)); - } + .Replace("\\n", "\n"), _languageService.GetKey("text.error"), MessageBoxButton.OK, + MessageBoxImage.Error); + + // 如果认证失败 就根据当前模式返回对应页面 + _navigationService.Navigate(_rconConnectionInfoService.HasMultipleInformation + ? typeof(GroupPage) + : typeof(ServersPage)); } finally { @@ -133,7 +135,7 @@ private void OnConnected(ServerInformation info) } [RelayCommand] - public void Exit() + private void Exit() { WeakReferenceMessenger.Default.Send(new MainPageLoadValueMessage() { @@ -143,9 +145,11 @@ public void Exit() _rconConnectService.Close(); _rconConnectService.OnMessage -= OnMessage; _rconConnectService.OnClosed -= OnClosed; + _rconConnectService.OnConnected -= OnConnected; } + [RelayCommand] - public void Run() + private void Run() { if (_rconConnectService.IsConnected()) { @@ -157,11 +161,13 @@ public void Run() else { _rconConnectService.Close(); - MessageBox.Show(_languageService.GetKey("text.server.not_connect.text"), _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show(_languageService.GetKey("text.server.not_connect.text"), + _languageService.GetKey("text.error"), MessageBoxButton.OK, MessageBoxImage.Error); } } + [RelayCommand] - public void KeyDown(KeyEventArgs e) + private void KeyDown(KeyEventArgs e) { var textBox = (System.Windows.Controls.TextBox)e.Source; _commandText = textBox.Text; From a7de37c4f2319048ef0ee756cfb5eb091138b453 Mon Sep 17 00:00:00 2001 From: zkhssb Date: Tue, 23 Jan 2024 20:38:00 +0800 Subject: [PATCH 04/11] =?UTF-8?q?Add=20=E5=A2=9E=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8C=81=E4=B9=85=E5=8C=96=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NectarRCON/Dp/DpFile.cs | 75 +++++++++++++++++++++++++++++++++ NectarRCON/Dp/RconSettingsDp.cs | 14 ++++++ 2 files changed, 89 insertions(+) create mode 100644 NectarRCON/Dp/DpFile.cs create mode 100644 NectarRCON/Dp/RconSettingsDp.cs diff --git a/NectarRCON/Dp/DpFile.cs b/NectarRCON/Dp/DpFile.cs new file mode 100644 index 0000000..349bdf0 --- /dev/null +++ b/NectarRCON/Dp/DpFile.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace NectarRCON.Dp; + +/// +/// 数据持久化文件 +/// +public abstract class DpFile +{ + /// + /// 文件名 + /// + protected abstract string Name { get; } + + /// + /// 文件路径 + /// + protected virtual string BasePath => string.Empty; + + /// + /// 实例映射 + /// + private static readonly Dictionary InstanceMapping = []; + + /// + /// 保存数据 + /// + public void Save() + { + var json = JsonSerializer.Serialize((object)this); + var filePath = Path.Combine(AppContext.BaseDirectory,"dp", BasePath, Name); + Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); + File.WriteAllText(filePath, json); + } + + /// + /// 加载数据 + /// + /// 文件名 + /// 文件路径 + /// 类型 + /// 实例 + private static T? Load(string name, string? basePath = null) + where T : DpFile + { + var filePath = Path.Combine(AppContext.BaseDirectory, "dp", basePath ?? string.Empty, name); + if (!File.Exists(filePath)) return null; + var json = File.ReadAllText(filePath); + return JsonSerializer.Deserialize(json); + } + + /// + /// 以单例模式加载数据 + /// + /// 类型 + /// 实例 + public static T LoadSingleton() + where T:DpFile + { + // 先从_instanceMapping拿数据 + if (InstanceMapping.TryGetValue(typeof(T), out var cachedInstance)) + { + return (T)cachedInstance; + } + + // 如果缓存没有 则使用找到此DPFile的无参构造函数 使用反射实例化后存放到_instanceMapping + var instance = Activator.CreateInstance(); + // 从instance中获取Name 随后load + InstanceMapping[typeof(T)] = Load(instance.Name, instance.BasePath) ?? instance; + return (T)InstanceMapping[typeof(T)]; + } +} \ No newline at end of file diff --git a/NectarRCON/Dp/RconSettingsDp.cs b/NectarRCON/Dp/RconSettingsDp.cs new file mode 100644 index 0000000..00a8355 --- /dev/null +++ b/NectarRCON/Dp/RconSettingsDp.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace NectarRCON.Dp; + +public class RconSettingsDp:DpFile +{ + protected override string Name => "rcon_settings.json"; + + /// + /// 连接时掉线自动尝试重连 + /// + [JsonPropertyName("auto_reconnect")] + public bool AutoReconnect { get; set; } = true; +} \ No newline at end of file From f7331456289a011454f4d4f36c2a8cf5a5c97dfe Mon Sep 17 00:00:00 2001 From: zkhssb Date: Tue, 23 Jan 2024 20:40:19 +0800 Subject: [PATCH 05/11] =?UTF-8?q?Add=20SettingsPage=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=85=B3=E4=BA=8ERcon=E7=9A=84=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NectarRCON/NectarRCON.csproj | 1 + NectarRCON/Resources/Languages/en_us.xaml | 3 +++ NectarRCON/Resources/Languages/zh_cn.xaml | 5 +++- NectarRCON/Resources/Languages/zh_tw.xaml | 3 +++ NectarRCON/ViewModels/SettingPageViewModel.cs | 14 +++++++++++ NectarRCON/Views/Pages/SettingPage.xaml | 25 ++++++++++++++++--- 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/NectarRCON/NectarRCON.csproj b/NectarRCON/NectarRCON.csproj index 4f7bd6e..a373bd3 100644 --- a/NectarRCON/NectarRCON.csproj +++ b/NectarRCON/NectarRCON.csproj @@ -8,6 +8,7 @@ Resources\Icon.ico app.manifest 1.0.0-beta3 + 12 diff --git a/NectarRCON/Resources/Languages/en_us.xaml b/NectarRCON/Resources/Languages/en_us.xaml index b698aec..528bded 100644 --- a/NectarRCON/Resources/Languages/en_us.xaml +++ b/NectarRCON/Resources/Languages/en_us.xaml @@ -15,12 +15,15 @@ CheckUpdate RCONManager UI Language + UI Settings UI Theme Dark Theme Light Theme System Theme Rcon passwords... Command Record Limit + Rcon + Auto Reconnect Connect Edit diff --git a/NectarRCON/Resources/Languages/zh_cn.xaml b/NectarRCON/Resources/Languages/zh_cn.xaml index 5d5d02a..0762be0 100644 --- a/NectarRCON/Resources/Languages/zh_cn.xaml +++ b/NectarRCON/Resources/Languages/zh_cn.xaml @@ -15,13 +15,16 @@ 检查更新 RCON管理器 UI语言 + 界面设置 UI主题 深色主题 浅色主题 跟随系统 Rcon密码管理 服务器命令回溯记录数 - + Rcon全局设置 + 掉线自动重连 + 连接 编辑 删除 diff --git a/NectarRCON/Resources/Languages/zh_tw.xaml b/NectarRCON/Resources/Languages/zh_tw.xaml index 9764644..f7c3d60 100644 --- a/NectarRCON/Resources/Languages/zh_tw.xaml +++ b/NectarRCON/Resources/Languages/zh_tw.xaml @@ -15,12 +15,15 @@ 檢查更新 RCON管理器 UI語言 + 界面設定 UI主題 深色主題 淺色主題 跟隨系統 Rcon密碼管理 伺服器命令回溯記錄數 + Rcon全局設定 + 斷綫自動重連 連線 編輯 diff --git a/NectarRCON/ViewModels/SettingPageViewModel.cs b/NectarRCON/ViewModels/SettingPageViewModel.cs index 1d1609a..f97a2b8 100644 --- a/NectarRCON/ViewModels/SettingPageViewModel.cs +++ b/NectarRCON/ViewModels/SettingPageViewModel.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Windows; using System.Windows.Controls; +using NectarRCON.Dp; using Wpf.Ui.Mvvm.Contracts; namespace NectarRCON.ViewModels; @@ -17,11 +18,15 @@ public partial class SettingPageViewModel : ObservableObject private readonly ILanguageService _languageService; private readonly IConfigService _configService; private readonly IThemeService _themeService; + private readonly RconSettingsDp _rconSettingsDp = DpFile.LoadSingleton(); [ObservableProperty] private int _languageSelectedIndex = -1; [ObservableProperty] private int _themeSelectedIndex = -1; + + [ObservableProperty] + private bool _rconAutoReconnect; [ObservableProperty] private ObservableCollection _languages = new(); @@ -30,7 +35,16 @@ public SettingPageViewModel() _languageService = App.GetService(); _configService = App.GetService(); _themeService = App.GetService(); + + RconAutoReconnect = _rconSettingsDp.AutoReconnect; + } + + partial void OnRconAutoReconnectChanged(bool value) + { + _rconSettingsDp.AutoReconnect = value; + _rconSettingsDp.Save(); } + [RelayCommand] public void PageLoad(RoutedEventArgs e) { diff --git a/NectarRCON/Views/Pages/SettingPage.xaml b/NectarRCON/Views/Pages/SettingPage.xaml index 2fb6d5c..536cbfc 100644 --- a/NectarRCON/Views/Pages/SettingPage.xaml +++ b/NectarRCON/Views/Pages/SettingPage.xaml @@ -28,9 +28,15 @@ + + @@ -72,6 +78,19 @@ + + + + +