diff --git a/BetterGenshinImpact.sln.DotSettings b/BetterGenshinImpact.sln.DotSettings index 46e57701..8cc26dc7 100644 --- a/BetterGenshinImpact.sln.DotSettings +++ b/BetterGenshinImpact.sln.DotSettings @@ -1,2 +1,5 @@  - True \ No newline at end of file + True + True + True + True \ No newline at end of file diff --git a/BetterGenshinImpact/Assets/Strings/md2html.html b/BetterGenshinImpact/Assets/Strings/md2html.html index f559099d..429babf3 100644 --- a/BetterGenshinImpact/Assets/Strings/md2html.html +++ b/BetterGenshinImpact/Assets/Strings/md2html.html @@ -18,14 +18,10 @@ ::-webkit-scrollbar-thumb:hover { background: #555; } - .body { - background-color: #202020; - color: #e6edf3; - } .markdown-body { margin: 0; padding: 8px; - background-color: #202020; + background-color: #202020 !important; height: 100% } * { diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 35f51ce0..80e7e7e4 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -48,6 +48,7 @@ + diff --git a/BetterGenshinImpact/Helpers/Win32/CredentialManagerHelper.cs b/BetterGenshinImpact/Helpers/Win32/CredentialManagerHelper.cs new file mode 100644 index 00000000..3bc4efa7 --- /dev/null +++ b/BetterGenshinImpact/Helpers/Win32/CredentialManagerHelper.cs @@ -0,0 +1,52 @@ +using System; +using Meziantou.Framework.Win32; + +namespace BetterGenshinImpact.Helpers.Win32; + +public static class CredentialManagerHelper +{ + public static void SaveCredential(string applicationName, string userName, string secret, string comment, + CredentialPersistence persistence) + { + CredentialManager.WriteCredential( + applicationName: applicationName, + userName: userName, + secret: secret, + comment: comment, + persistence: persistence); + } + + public static Credential? ReadCredential(string applicationName) + { + var credential = CredentialManager.ReadCredential(applicationName); + if (credential == null) + { + Console.WriteLine("No credential found."); + return null; + } + + Console.WriteLine($"UserName: {credential.UserName}"); + Console.WriteLine($"Secret: {credential.Password}"); + Console.WriteLine($"Comment: {credential.Comment}"); + + return credential; + } + + public static void UpdateCredential(string applicationName, string newUserName, string newSecret, string newComment) + { + SaveCredential(applicationName, newUserName, newSecret, newComment, CredentialPersistence.LocalMachine); + } + + public static void DeleteCredential(string applicationName) + { + try + { + CredentialManager.DeleteCredential(applicationName); + Console.WriteLine("Credential deleted successfully."); + } + catch (Exception ex) + { + Console.WriteLine($"Error deleting credential: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Helpers/Win32/MirrorChyanHelper.cs b/BetterGenshinImpact/Helpers/Win32/MirrorChyanHelper.cs new file mode 100644 index 00000000..0aff18d7 --- /dev/null +++ b/BetterGenshinImpact/Helpers/Win32/MirrorChyanHelper.cs @@ -0,0 +1,93 @@ +using System; +using Windows.System; +using BetterGenshinImpact.View.Windows; +using Meziantou.Framework.Win32; +using Wpf.Ui.Violeta.Controls; + +namespace BetterGenshinImpact.Helpers.Win32; + +public static class MirrorChyanHelper +{ + public static readonly string MirrorChyanCdkAppName = "KachinaInstaller_MirrorChyanCDK_BetterGI"; + + + public static string? GetCdk() + { + var credential = CredentialManagerHelper.ReadCredential(MirrorChyanCdkAppName); + return credential?.Password; + } + + public static string? GetAndPromptCdk() + { + var credential = CredentialManagerHelper.ReadCredential(MirrorChyanCdkAppName); + if (credential == null || credential.Password == null) + { + var cdk = PromptDialog.Prompt("Mirror酱是独立的第三方软件下载平台,提供付费的软件下载加速服务。\n如果你有 Mirror酱的 CDK,可以在这里输入。", + "请输入Mirror酱CDK", + string.Empty, + new PromptDialogConfig + { + ShowLeftButton = true, + LeftButtonText = "获取CDK", + LeftButtonClick = (sender, args) => + { + Launcher.LaunchUriAsync(new Uri("https://mirrorchyan.com/zh/get-start")); + } + } + ); + if (string.IsNullOrEmpty(cdk)) + { + Toast.Warning("输入CDK为空,无法继续操作"); + return null; + } + + CredentialManagerHelper.SaveCredential( + MirrorChyanCdkAppName, + string.Empty, + cdk, + string.Empty, + CredentialPersistence.LocalMachine); + return cdk; + } + else + { + return credential.Password; + } + } + + public static void EditCdk() + { + var credential = CredentialManagerHelper.ReadCredential(MirrorChyanCdkAppName); + var cdk = PromptDialog.Prompt("Mirror酱是独立的第三方软件下载平台,提供付费的软件下载加速服务。\n如果你有 Mirror酱的 CDK,可以在这里输入。", + "修改Mirror酱CDK", + credential?.Password!, + new PromptDialogConfig + { + ShowLeftButton = true, + LeftButtonText = "获取CDK", + LeftButtonClick = (sender, args) => + { + Launcher.LaunchUriAsync(new Uri("https://mirrorchyan.com/zh/get-start")); + } + } + ); + if (string.IsNullOrEmpty(cdk)) + { + DeleteCdk(); + } + else + { + CredentialManagerHelper.SaveCredential( + MirrorChyanCdkAppName, + string.Empty, + cdk, + string.Empty, + CredentialPersistence.LocalMachine); + } + } + + public static void DeleteCdk() + { + CredentialManagerHelper.DeleteCredential(MirrorChyanCdkAppName); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Model/UpdateOption.cs b/BetterGenshinImpact/Model/UpdateOption.cs index eb68bf53..7d4f0721 100644 --- a/BetterGenshinImpact/Model/UpdateOption.cs +++ b/BetterGenshinImpact/Model/UpdateOption.cs @@ -3,6 +3,8 @@ public sealed class UpdateOption { public UpdateTrigger Trigger { get; set; } = default; + + public UpdateChannel Channel { get; set; } = UpdateChannel.Stable; } public enum UpdateTrigger @@ -10,3 +12,10 @@ public enum UpdateTrigger Auto, Manual, } + + +public enum UpdateChannel +{ + Stable, + Alpha, +} \ No newline at end of file diff --git a/BetterGenshinImpact/Service/Model/MirrorChyan/LatestResponse.cs b/BetterGenshinImpact/Service/Model/MirrorChyan/LatestResponse.cs new file mode 100644 index 00000000..f6c099f5 --- /dev/null +++ b/BetterGenshinImpact/Service/Model/MirrorChyan/LatestResponse.cs @@ -0,0 +1,117 @@ +using System.Text.Json.Serialization; + +namespace BetterGenshinImpact.Service.Model.MirrorChyan; + +#nullable enable +#pragma warning disable CS8618 +#pragma warning disable CS8601 +#pragma warning disable CS8603 +public partial class LatestResponse +{ + /// + /// 响应代码,https://github.com/MirrorChyan/docs/blob/main/ErrorCode.md + /// + [JsonPropertyName("code")] + public long Code { get; set; } + + /// + /// 响应数据 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("data")] + public Data Data { get; set; } + + /// + /// 响应信息 + /// + [JsonPropertyName("msg")] + public string Msg { get; set; } +} + +/// +/// 响应数据 +/// +public partial class Data +{ + /// + /// 更新包架构 + /// + [JsonPropertyName("arch")] + public string Arch { get; set; } + + /// + /// CDK过期时间戳 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("cdk_expired_time")] + public double? CdkExpiredTime { get; set; } + + /// + /// 更新频道,stable | beta | alpha + /// + [JsonPropertyName("channel")] + public string Channel { get; set; } + + /// + /// 自定义数据 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("custom_data")] + public string CustomData { get; set; } + + /// + /// 文件大小 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("filesize")] + public long? Filesize { get; set; } + + /// + /// 更新包系统 + /// + [JsonPropertyName("os")] + public string Os { get; set; } + + /// + /// 发版日志 + /// + [JsonPropertyName("release_note")] + public string ReleaseNote { get; set; } + + /// + /// sha256 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("sha256")] + public string Sha256 { get; set; } + + /// + /// 更新包类型,incremental | full + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("update_type")] + public string UpdateType { get; set; } + + /// + /// 下载地址 + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("url")] + public string Url { get; set; } + + /// + /// 资源版本名称 + /// + [JsonPropertyName("version_name")] + public string VersionName { get; set; } + + /// + /// 资源版本号仅内部使用 + /// + [JsonPropertyName("version_number")] + public long VersionNumber { get; set; } +} + +#pragma warning restore CS8618 +#pragma warning restore CS8601 +#pragma warning restore CS8603 \ No newline at end of file diff --git a/BetterGenshinImpact/Service/UpdateService.cs b/BetterGenshinImpact/Service/UpdateService.cs index e5cf9d9c..3d720cb1 100644 --- a/BetterGenshinImpact/Service/UpdateService.cs +++ b/BetterGenshinImpact/Service/UpdateService.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Json; @@ -18,6 +19,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; +using BetterGenshinImpact.Service.Model.MirrorChyan; +using Wpf.Ui.Violeta.Controls; namespace BetterGenshinImpact.Service; @@ -37,7 +40,7 @@ public class UpdateService : IUpdateService _configService = configService; Config = _configService.Get(); } - + /// /// Please call me in main thread @@ -50,13 +53,13 @@ public class UpdateService : IUpdateService #if DEBUG && false return; #endif - string newVersion = await GetLatestVersionAsync(); + string newVersion = await GetLatestVersionAsync(option); if (string.IsNullOrWhiteSpace(newVersion)) { return; } - + // ---- 如果是调试模式且手动的检查更新的情况下,强制打开更新窗口 ----- // 方便调试窗口 if (RuntimeHelper.IsDebuggerAttached && option.Trigger == UpdateTrigger.Manual) @@ -72,7 +75,7 @@ public class UpdateService : IUpdateService { await MessageBox.InformationAsync("当前已是最新版本!"); } - + return; } @@ -87,7 +90,8 @@ public class UpdateService : IUpdateService } catch (Exception e) { - Debug.WriteLine("获取最新版本信息失败:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message); + Debug.WriteLine("获取最新版本信息失败:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + + Environment.NewLine + e.Message); _logger.LogWarning("获取 BetterGI 最新版本信息失败"); } } @@ -110,7 +114,14 @@ public class UpdateService : IUpdateService break; case CheckUpdateWindow.CheckUpdateWindowButton.OtherUpdate: - Process.Start(new ProcessStartInfo(DownloadPageUrl) { UseShellExecute = true }); + if (option.Channel == UpdateChannel.Stable) + { + Process.Start(new ProcessStartInfo(DownloadPageUrl) { UseShellExecute = true }); + } + else + { + Process.Start(new ProcessStartInfo("https://github.com/babalae/better-genshin-impact/actions/workflows/publish.yml") { UseShellExecute = true }); + } break; case CheckUpdateWindow.CheckUpdateWindowButton.Update: @@ -122,12 +133,12 @@ public class UpdateService : IUpdateService await MessageBox.ErrorAsync("更新程序不存在,请选择其他更新方式!"); return; } + // 启动 Process.Start(updaterExePath, "-I"); - + // 退出程序 Application.Current.Shutdown(); - } break; @@ -144,11 +155,118 @@ public class UpdateService : IUpdateService } }; - win.NavigateToHtml(await GetReleaseMarkdownHtmlAsync()); + if (option.Channel == UpdateChannel.Stable) + { + win.NavigateToHtml(await GetReleaseMarkdownHtmlAsync()); + } + win.ShowDialog(); } - private async Task GetLatestVersionAsync() + private async Task GetLatestVersionAsync(UpdateOption option) + { + if (option.Channel == UpdateChannel.Stable) + { + return await UpdateFromOss(); + } + else + { + return await UpdateFromMirrorChyan(); + } + } + + /// + /// 文档 + /// https://apifox.com/apidoc/shared/ffdc8453-597d-4ba6-bd3c-5e375c10c789 + /// + /// + private async Task UpdateFromMirrorChyan() + { + try + { + const string url = "https://mirrorchyan.com/api/resources/BGI/latest"; + var queryParams = new Dictionary + { + { "user_agent", "BetterGI" }, + { "os", "win" }, + { "arch", "x64" }, + { "channel", "alpha" } + }; + + using var httpClient = new HttpClient(); + + var finalUrl = $"{url}?{string.Join("&", queryParams.Select(x => $"{x.Key}={x.Value}"))}"; + var response = await httpClient.GetAsync(finalUrl); + LatestResponse? result = null; + if (response.StatusCode == HttpStatusCode.OK) + { + response.EnsureSuccessStatusCode(); + result = await response.Content.ReadFromJsonAsync(); + } + else + { + // 即使是403、400也尝试读取响应体 + var content = await response.Content.ReadAsStringAsync(); + result = JsonConvert.DeserializeObject(content); + } + + if (result != null) + { + if (result.Code == 0) + { + return result.Data.VersionName; + } + else if (result.Code < 0) + { + Toast.Error( + $"Mirror酱源更新检查失败,意料之外的严重错误,请及时联系 Mirror 酱的技术支持处理\n,错误代码:{result.Code},错误信息:{result.Msg}"); + return string.Empty; + } + else + { + ToastError(result); + } + } + } + catch (Exception e) + { + _logger.LogDebug(e, "Mirror源更新检查失败"); + Toast.Warning($"Mirror源更新检查失败,{e.Message}"); + + } + + return string.Empty; + } + + private static void ToastError(LatestResponse response) + { + if (response.Code == 7001) + { + Toast.Warning("Mirror酱 CDK 已过期,请重新获取CDK"); + } + else if (response.Code == 7002) + { + Toast.Warning("Mirror酱 CDK 错误!"); + } + else if (response.Code == 7003) + { + Toast.Warning("Mirror酱 CDK 今日下载次数已达上限"); + } + else if (response.Code == 7004) + { + Toast.Warning("Mirror酱 CDK 类型和待下载的资源不匹配"); + } + else if (response.Code == 7005) + { + Toast.Warning("Mirror酱 CDK 已被封禁"); + } + else + { + Toast.Warning($"Mirror酱源更新检查失败,错误信息:{response.Msg}"); + } + } + + private async Task UpdateFromOss() { try { @@ -181,7 +299,9 @@ public class UpdateService : IUpdateService { using HttpClient httpClient = new(); httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); - string jsonString = await httpClient.GetStringAsync("https://api.github.com/repos/babalae/better-genshin-impact/releases/latest"); + string jsonString = + await httpClient.GetStringAsync( + "https://api.github.com/repos/babalae/better-genshin-impact/releases/latest"); var jsonDict = JsonConvert.DeserializeObject>(jsonString); if (jsonDict != null) @@ -191,7 +311,8 @@ public class UpdateService : IUpdateService string md = $"# {name}{new string('\n', 2)}{body}"; md = WebUtility.HtmlEncode(md); - string md2html = ResourceHelper.GetString($"pack://application:,,,/Assets/Strings/md2html.html", Encoding.UTF8); + string md2html = ResourceHelper.GetString($"pack://application:,,,/Assets/Strings/md2html.html", + Encoding.UTF8); var html = md2html.Replace("{{content}}", md); return html; @@ -240,4 +361,4 @@ public class UpdateService : IUpdateService """; } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/View/Pages/CommonSettingsPage.xaml b/BetterGenshinImpact/View/Pages/CommonSettingsPage.xaml index b81bf91c..10bc5280 100644 --- a/BetterGenshinImpact/View/Pages/CommonSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/CommonSettingsPage.xaml @@ -1176,7 +1176,7 @@ Grid.RowSpan="2" Grid.Column="1" Margin="0,0,20,0" - Command="{Binding OpenKeyBindingsWindowCommand}" + Command="{Binding CheckUpdateCommand}" Content="检查更新" /> @@ -1192,20 +1192,50 @@ + + + + + + diff --git a/BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml b/BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml index 78a93e6f..7e58bb31 100644 --- a/BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml +++ b/BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml @@ -11,7 +11,8 @@ x:Name="app" Title="发现新版本" Width="680" - Height="800" + MinHeight="10" + SizeToContent="Height" Background="#202020" ExtendsContentIntoTitleBar="True" FontFamily="{DynamicResource TextThemeFontFamily}" @@ -19,11 +20,13 @@ WindowStartupLocation="CenterOwner" mc:Ignorable="d"> - + - @@ -33,8 +36,8 @@ - - + + @@ -47,12 +50,12 @@ @@ -61,7 +64,7 @@ Appearance="Success" Icon="{ui:SymbolIcon ArrowDownload24}" Content="立即更新" - Command="{Binding UpdateCommand}" /> + Command="{Binding UpdateFromSteambirdCommand}" /> @@ -86,15 +89,21 @@ - + Content="修改CDK" + Command="{Binding EditCdkCommand}" /> + - + ? UserInteraction = null!; - [ObservableProperty] - private bool showUpdateStatus = false; + [ObservableProperty] private bool showUpdateStatus = false; - [ObservableProperty] - private string updateStatusMessage = string.Empty; + [ObservableProperty] private string updateStatusMessage = string.Empty; + + private UpdateOption _option; public CheckUpdateWindow(UpdateOption option) { + _option = option ?? throw new ArgumentNullException(nameof(option)); DataContext = this; InitializeComponent(); - + + // 存在CDK则显示修改按钮 + if (string.IsNullOrEmpty(MirrorChyanHelper.GetCdk())) + { + EditCdkButton.Visibility = Visibility.Collapsed; + } + if (option.Trigger == UpdateTrigger.Manual) { IgnoreButton.Visibility = Visibility.Collapsed; } + if (option.Channel == UpdateChannel.Alpha) + { + WebpagePanel.Height = 0; + WebpagePanel.Visibility = Visibility.Collapsed; + UpdateStatusMessageGrid.Height = 0; + ShowUpdateStatus = false; + + // 删除前两行 + MyGrid.RowDefinitions.RemoveAt(0); + MyGrid.RowDefinitions.RemoveAt(0); + + // 注意:删除行定义后,需要调整剩余元素的 Grid.Row 属性 + foreach (FrameworkElement child in MyGrid.Children) + { + int currentRow = System.Windows.Controls.Grid.GetRow(child); + if (currentRow > 1) // 如果元素在第三行或之后 + { + Grid.SetRow(child, currentRow - 2); // 行号减2 + } + } + + if (ServerPanel.Children.Count > 0) + { + ServerPanel.Children.RemoveAt(0); + } + SizeToContent = SizeToContent.Height; // 设置高度为自动 + UpdateLayout(); + } + + Closing += OnClosing; } @@ -73,6 +117,55 @@ public partial class CheckUpdateWindow : FluentWindow } } + + [RelayCommand] + private async Task UpdateFromSteambirdAsync() + { + await RunUpdaterAsync("-I"); + } + + [RelayCommand] + private async Task UpdateFromMirrorChyanAsync() + { + var cdk = MirrorChyanHelper.GetAndPromptCdk(); + if (string.IsNullOrEmpty(cdk)) + { + return; + } + + if (_option.Channel == UpdateChannel.Stable) + { + await RunUpdaterAsync("--source mirrorc"); + } + else + { + await RunUpdaterAsync("--source mirrorc-alpha"); + } + } + + /// + /// --source mirrorc + /// --source mirrorc-alpha + /// --source github + /// --dfs-extras {"hutao-token": "...."} + /// + private async Task RunUpdaterAsync(string parameters) + { + // 唤起更新程序 + string updaterExePath = Global.Absolute("BetterGI.update.exe"); + if (!File.Exists(updaterExePath)) + { + await MessageBox.ErrorAsync("更新程序不存在,请选择其他更新方式!"); + return; + } + + // 启动 + Process.Start(updaterExePath, parameters); + + // 退出程序 + Application.Current.Shutdown(); + } + [RelayCommand] private async Task IgnoreAsync() { @@ -90,6 +183,12 @@ public partial class CheckUpdateWindow : FluentWindow await UserInteraction.Invoke(this, CheckUpdateWindowButton.Cancel); } } + + [RelayCommand] + private void EditCdk() + { + MirrorChyanHelper.EditCdk(); + } public enum CheckUpdateWindowButton { diff --git a/BetterGenshinImpact/View/Windows/PromptDialog.xaml b/BetterGenshinImpact/View/Windows/PromptDialog.xaml index b1a95bbe..717d7e3b 100644 --- a/BetterGenshinImpact/View/Windows/PromptDialog.xaml +++ b/BetterGenshinImpact/View/Windows/PromptDialog.xaml @@ -28,21 +28,36 @@ - - + + + + + + + - - + HorizontalAlignment="Left" + Appearance="Success" + Content="左下角按钮" + Grid.Column="0" /> + + + + + + + diff --git a/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs b/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs index 14093048..5fb97c8a 100644 --- a/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs +++ b/BetterGenshinImpact/View/Windows/PromptDialog.xaml.cs @@ -3,13 +3,37 @@ using System.Windows.Controls; namespace BetterGenshinImpact.View.Windows; +/// +/// 对话框配置类,用于控制对话框中的元素显示 +/// +public class PromptDialogConfig +{ + /// + /// 是否显示左下角按钮 + /// + public bool ShowLeftButton { get; set; } = false; + + /// + /// 左下角按钮的文本 + /// + public string LeftButtonText { get; set; } = "左下角按钮"; + + /// + /// 左下角按钮的点击事件 + /// + public RoutedEventHandler? LeftButtonClick { get; set; } +} + public partial class PromptDialog { - public PromptDialog(string question, string title, UIElement uiElement, string defaultValue) + private readonly PromptDialogConfig _config; + + public PromptDialog(string question, string title, UIElement uiElement, string defaultValue, PromptDialogConfig? config = null) { InitializeComponent(); MyTitleBar.Title = title; TxtQuestion.Text = question; + _config = config ?? new PromptDialogConfig(); DynamicContent.Content = uiElement; if (DynamicContent.Content is TextBox textBox) @@ -21,31 +45,50 @@ public partial class PromptDialog comboBox.Text = defaultValue; } + // 配置左下角按钮 + ConfigureLeftButton(); + this.Loaded += PromptDialogLoaded; } + private void ConfigureLeftButton() + { + if (_config.ShowLeftButton) + { + BtnLeftBottom.Content = _config.LeftButtonText; + if (_config.LeftButtonClick != null) + { + BtnLeftBottom.Click += _config.LeftButtonClick; + } + } + else + { + BtnLeftBottom.Visibility = Visibility.Collapsed; + } + } + private void PromptDialogLoaded(object sender, RoutedEventArgs e) { DynamicContent.Focus(); } - public static string Prompt(string question, string title, string defaultValue = "") + public static string Prompt(string question, string title, string defaultValue = "", PromptDialogConfig? config = null) { - var inst = new PromptDialog(question, title, new TextBox(), defaultValue); + var inst = new PromptDialog(question, title, new TextBox(), defaultValue, config); inst.ShowDialog(); return inst.DialogResult == true ? inst.ResponseText : defaultValue; } - public static string Prompt(string question, string title, UIElement uiElement, string defaultValue = "") + public static string Prompt(string question, string title, UIElement uiElement, string defaultValue = "", PromptDialogConfig? config = null) { - var inst = new PromptDialog(question, title, uiElement, defaultValue); + var inst = new PromptDialog(question, title, uiElement, defaultValue, config); inst.ShowDialog(); return inst.DialogResult == true ? inst.ResponseText : defaultValue; } - public static string Prompt(string question, string title, UIElement uiElement, Size size) + public static string Prompt(string question, string title, UIElement uiElement, Size size, PromptDialogConfig? config = null) { - var inst = new PromptDialog(question, title, uiElement, "") + var inst = new PromptDialog(question, title, uiElement, "", config) { Width = size.Width, Height = size.Height diff --git a/BetterGenshinImpact/ViewModel/Pages/CommonSettingsPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/CommonSettingsPageViewModel.cs index fb41c4c2..aa1b39dc 100644 --- a/BetterGenshinImpact/ViewModel/Pages/CommonSettingsPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/CommonSettingsPageViewModel.cs @@ -9,6 +9,7 @@ using System.IO.Compression; using System.Linq; using System.Threading.Tasks; using System.Windows; +using Windows.System; using BetterGenshinImpact.Core.Config; using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Script; @@ -16,6 +17,8 @@ using BetterGenshinImpact.GameTask; using BetterGenshinImpact.GameTask.AutoTrackPath; using BetterGenshinImpact.GameTask.Common.Element.Assets; using BetterGenshinImpact.Helpers; +using BetterGenshinImpact.Helpers.Win32; +using BetterGenshinImpact.Model; using BetterGenshinImpact.Service.Interface; using BetterGenshinImpact.Service.Notification; using BetterGenshinImpact.View.Converters; @@ -25,9 +28,11 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging.Messages; +using Meziantou.Framework.Win32; using Microsoft.Extensions.Localization; using Microsoft.Win32; using Wpf.Ui; +using Wpf.Ui.Violeta.Controls; namespace BetterGenshinImpact.ViewModel.Pages; @@ -42,8 +47,8 @@ public partial class CommonSettingsPageViewModel : ViewModel private string _selectedCountry = string.Empty; - [ObservableProperty] - private List _adventurersGuildCountry = ["无","枫丹", "稻妻", "璃月", "蒙德"]; + [ObservableProperty] private List _adventurersGuildCountry = ["无", "枫丹", "稻妻", "璃月", "蒙德"]; + public CommonSettingsPageViewModel(IConfigService configService, INavigationService navigationService, NotificationService notificationService) { @@ -57,17 +62,18 @@ public partial class CommonSettingsPageViewModel : ViewModel public ObservableCollection CountryList { get; } = new(); public ObservableCollection Areas { get; } = new(); - [ObservableProperty] - private FrozenDictionary _languageDict = new string[] { "zh-Hans", "zh-Hant", "en", "fr" } - .ToFrozenDictionary( - c => c, - c => - { - CultureInfo.CurrentUICulture = new CultureInfo(c); - var stringLocalizer = App.GetService>() ?? throw new NullReferenceException(); - return stringLocalizer["简体中文"].ToString(); - } - ); + [ObservableProperty] private FrozenDictionary _languageDict = + new string[] { "zh-Hans", "zh-Hant", "en", "fr" } + .ToFrozenDictionary( + c => c, + c => + { + CultureInfo.CurrentUICulture = new CultureInfo(c); + var stringLocalizer = App.GetService>() ?? + throw new NullReferenceException(); + return stringLocalizer["简体中文"].ToString(); + } + ); public string SelectedCountry { @@ -238,7 +244,7 @@ public partial class CommonSettingsPageViewModel : ViewModel } } } - + [RelayCommand] private void OpenAboutWindow() { @@ -246,7 +252,7 @@ public partial class CommonSettingsPageViewModel : ViewModel aboutWindow.Owner = Application.Current.MainWindow; aboutWindow.ShowDialog(); } - + [RelayCommand] private void OpenKeyBindingsWindow() { @@ -260,4 +266,31 @@ public partial class CommonSettingsPageViewModel : ViewModel { await OcrFactory.ChangeCulture(type.Key); } + + [RelayCommand] + private async Task CheckUpdateAsync() + { + await App.GetService()!.CheckUpdateAsync(new UpdateOption + { + Trigger = UpdateTrigger.Manual, + Channel = UpdateChannel.Stable + }); + } + + [RelayCommand] + private async Task CheckUpdateAlphaAsync() + { + await App.GetService()!.CheckUpdateAsync(new UpdateOption + { + Trigger = UpdateTrigger.Manual, + Channel = UpdateChannel.Alpha, + }); + } + + [RelayCommand] + private async Task GotoGithubActionAsync() + { + await Launcher.LaunchUriAsync( + new Uri("https://github.com/babalae/better-genshin-impact/actions/workflows/publish.yml")); + } } \ No newline at end of file