mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-07 03:17:16 +08:00
First update UI layout
This commit is contained in:
parent
dd19afaca5
commit
6b0746d2bd
@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterGenshinImpact.Test",
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.WindowsInput", "Fischless.WindowsInput\Fischless.WindowsInput.csproj", "{9D00BC7A-9280-4AC9-8951-4502EDB71B76}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Updater", "Build\Updater\Updater.csproj", "{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -123,6 +125,14 @@ Global
|
||||
{9D00BC7A-9280-4AC9-8951-4502EDB71B76}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9D00BC7A-9280-4AC9-8951-4502EDB71B76}.Release|x64.ActiveCfg = Release|x64
|
||||
{9D00BC7A-9280-4AC9-8951-4502EDB71B76}.Release|x64.Build.0 = Release|x64
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -130,6 +140,7 @@ Global
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15} = {458E1106-43A4-47E6-B11B-D243035D4C76}
|
||||
{673344BC-B860-44AE-AD88-D33465BDE25B} = {458E1106-43A4-47E6-B11B-D243035D4C76}
|
||||
{F18CF5A3-A83C-4CC6-8150-D3C40EC3140F} = {458E1106-43A4-47E6-B11B-D243035D4C76}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {352D8B78-9DE3-4E58-985F-FADD22594DB4}
|
||||
|
@ -10,8 +10,8 @@ using BetterGenshinImpact.View;
|
||||
using BetterGenshinImpact.View.Pages;
|
||||
using BetterGenshinImpact.ViewModel;
|
||||
using BetterGenshinImpact.ViewModel.Pages;
|
||||
using BetterGenshinImpact.ViewModel.Pages.View;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
@ -22,9 +22,6 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using BetterGenshinImpact.View.Pages.View;
|
||||
using BetterGenshinImpact.ViewModel.Pages.OneDragon;
|
||||
using BetterGenshinImpact.ViewModel.Pages.View;
|
||||
using Wpf.Ui;
|
||||
using Wpf.Ui.Violeta.Controls;
|
||||
|
||||
@ -77,6 +74,7 @@ public partial class App : Application
|
||||
services.AddHostedService<ApplicationHostService>();
|
||||
// Page resolver service
|
||||
services.AddSingleton<IPageService, PageService>();
|
||||
services.AddSingleton<IUpdateService, UpdateService>();
|
||||
|
||||
// Service containing navigation, same as INavigationWindow... but without window
|
||||
services.AddSingleton<INavigationService, NavigationService>();
|
||||
|
@ -42,6 +42,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="Downloader" Version="3.3.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
@ -71,7 +72,7 @@
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="4.0.2" />
|
||||
<PackageReference Include="WPF-UI" Version="3.0.5" />
|
||||
<PackageReference Include="WPF-UI.Tray" Version="3.0.5" />
|
||||
<PackageReference Include="WPF-UI.Violeta" Version="3.0.5.23" />
|
||||
<PackageReference Include="WPF-UI.Violeta" Version="3.0.5.26" />
|
||||
<PackageReference Include="YoloV8" Version="4.1.7" />
|
||||
<PackageReference Include="gong-wpf-dragdrop" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
12
BetterGenshinImpact/Model/UpdateOption.cs
Normal file
12
BetterGenshinImpact/Model/UpdateOption.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace BetterGenshinImpact.Model;
|
||||
|
||||
public sealed class UpdateOption
|
||||
{
|
||||
public UpdateTrigger Trigger { get; set; } = default;
|
||||
}
|
||||
|
||||
public enum UpdateTrigger
|
||||
{
|
||||
Auto,
|
||||
Manual,
|
||||
}
|
13
BetterGenshinImpact/Service/Interface/IUpdateService.cs
Normal file
13
BetterGenshinImpact/Service/Interface/IUpdateService.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using BetterGenshinImpact.Model;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterGenshinImpact.Service.Interface;
|
||||
|
||||
public interface IUpdateService
|
||||
{
|
||||
/// <summary>
|
||||
/// I will check the update and completed the update if needed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task CheckUpdateAsync(UpdateOption option);
|
||||
}
|
307
BetterGenshinImpact/Service/UpdateService.cs
Normal file
307
BetterGenshinImpact/Service/UpdateService.cs
Normal file
@ -0,0 +1,307 @@
|
||||
using BetterGenshinImpact.Core.Config;
|
||||
using BetterGenshinImpact.Helpers;
|
||||
using BetterGenshinImpact.Helpers.Http;
|
||||
using BetterGenshinImpact.Model;
|
||||
using BetterGenshinImpact.Service.Interface;
|
||||
using BetterGenshinImpact.Threading;
|
||||
using BetterGenshinImpact.View.Windows;
|
||||
using Downloader;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace BetterGenshinImpact.Service;
|
||||
|
||||
public class UpdateService : IUpdateService
|
||||
{
|
||||
private readonly ILogger<UpdateService> _logger;
|
||||
private readonly IConfigService _configService;
|
||||
|
||||
private const string InstallationUrlPrefix = "https://raw.githubusercontent.com/bettergi/bettergi-installation-data/refs/heads/main/installation";
|
||||
private const string HashUrl = "https://raw.githubusercontent.com/bettergi/bettergi-installation-data/refs/heads/main/hash.json";
|
||||
private const string NoticUrl = "https://hui-config.oss-cn-hangzhou.aliyuncs.com/bgi/notice.json";
|
||||
private const string DownloadPageUrl = "https://bgi.huiyadan.com/download.html";
|
||||
|
||||
public AllConfig Config { get; set; }
|
||||
|
||||
public UpdateService(IConfigService configService)
|
||||
{
|
||||
_logger = App.GetLogger<UpdateService>();
|
||||
_configService = configService;
|
||||
Config = _configService.Get();
|
||||
}
|
||||
|
||||
private class XYZ
|
||||
{
|
||||
public string X { get; set; } = string.Empty;
|
||||
public string Y { get; set; } = string.Empty;
|
||||
public string Z { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Please call me in main thread
|
||||
/// </summary>
|
||||
/// <param name="option"></param>
|
||||
public async Task CheckUpdateAsync(UpdateOption option)
|
||||
{
|
||||
try
|
||||
{
|
||||
string newVersion = await GetLatestVersionAsync();
|
||||
|
||||
#if DEBUG && true
|
||||
newVersion = "256.256.256.256";
|
||||
#endif
|
||||
|
||||
if (string.IsNullOrWhiteSpace(newVersion))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Global.IsNewVersion(newVersion))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Config.NotShowNewVersionNoticeEndVersion)
|
||||
&& !Global.IsNewVersion(Config.NotShowNewVersionNoticeEndVersion, newVersion))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CheckUpdateWindow win = new()
|
||||
{
|
||||
Owner = Application.Current.MainWindow,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
Title = $"发现新版本 {newVersion}",
|
||||
UserInteraction = async (sender, button) =>
|
||||
{
|
||||
CheckUpdateWindow win = (CheckUpdateWindow)sender;
|
||||
CancellationTokenSource? tokenSource = new();
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case CheckUpdateWindow.CheckUpdateWindowButton.BackgroundUpdate:
|
||||
// TBD
|
||||
break;
|
||||
|
||||
case CheckUpdateWindow.CheckUpdateWindowButton.OtherUpdate:
|
||||
Process.Start(new ProcessStartInfo(DownloadPageUrl) { UseShellExecute = true });
|
||||
break;
|
||||
|
||||
case CheckUpdateWindow.CheckUpdateWindowButton.Update:
|
||||
{
|
||||
win.ShowUpdateStatus = true;
|
||||
|
||||
try
|
||||
{
|
||||
win.UpdateStatusMessage = "正在获取更新代理...";
|
||||
|
||||
(string fastProxyUrl, string jsonString) = await ProxySpeedTester.GetFastestProxyAsync(HashUrl);
|
||||
|
||||
win.UpdateStatusMessage = $"获取更新代理成功 {fastProxyUrl.Replace("{0}", string.Empty)}";
|
||||
|
||||
Dictionary<string, string>? hashDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);
|
||||
|
||||
if (hashDict == null)
|
||||
{
|
||||
win.UpdateStatusMessage = "获取更新列表失败,更新已取消。";
|
||||
return;
|
||||
}
|
||||
|
||||
List<(string, string, string)> downloadList = [];
|
||||
|
||||
foreach (KeyValuePair<string, string> hashPair in hashDict)
|
||||
{
|
||||
string targetFileName = Path.GetFullPath($@".\update\{hashPair.Key}.zip");
|
||||
string sourceFileName = Path.GetFullPath($@".\{hashPair.Value}");
|
||||
|
||||
if (IsNeedDownload(sourceFileName, hashPair.Value))
|
||||
{
|
||||
string url = string.Format(fastProxyUrl, $"{InstallationUrlPrefix}/{hashPair.Key}.zip").Replace("\\", "/");
|
||||
downloadList.Add((hashPair.Key, url, targetFileName));
|
||||
}
|
||||
}
|
||||
|
||||
SemaphoreSlimParallel downloadParallel = await SemaphoreSlimParallel.ForEach(downloadList, async item =>
|
||||
{
|
||||
DownloadConfiguration downloadOpt = new();
|
||||
DownloadService downloader = new(downloadOpt);
|
||||
|
||||
//downloader.DownloadFileCompleted += (sender, e) =>
|
||||
//{
|
||||
// if (e.Error != null)
|
||||
// {
|
||||
// _logger.LogError(e.Error, "下载失败");
|
||||
// win.UpdateStatusMessage = $"下载失败:{e.Error.Message}";
|
||||
// }
|
||||
//};
|
||||
|
||||
(string shortName, string url, string fileName) = item;
|
||||
|
||||
win.UpdateStatusMessage = $"正在下载 {shortName}";
|
||||
await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: tokenSource.Token);
|
||||
|
||||
win.UpdateStatusMessage = $"正在解压 {shortName}";
|
||||
}, 3);
|
||||
|
||||
await downloadParallel.DisposeAsync();
|
||||
|
||||
win.UpdateStatusMessage = "下载已完成";
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "更新失败");
|
||||
win.UpdateStatusMessage = $"更新失败:{e.Message}";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CheckUpdateWindow.CheckUpdateWindowButton.Ignore:
|
||||
Config.NotShowNewVersionNoticeEndVersion = newVersion;
|
||||
win.Close();
|
||||
break;
|
||||
|
||||
case CheckUpdateWindow.CheckUpdateWindowButton.Cancel:
|
||||
if (tokenSource != null)
|
||||
{
|
||||
if (MessageBox.Question("正在更新中,确定要取消更新吗?") == MessageBoxResult.Yes)
|
||||
{
|
||||
win.ShowUpdateStatus = false;
|
||||
tokenSource?.Cancel();
|
||||
win.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
win.ShowUpdateStatus = false;
|
||||
win.Close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
win.NavigateToHtml(await GetReleaseMarkdownHtmlAsync());
|
||||
win.ShowDialog();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine("获取最新版本信息失败:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||||
_logger.LogWarning("获取 BetterGI 最新版本信息失败");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> GetLatestVersionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpClient httpClient = new();
|
||||
Notice? notice = await httpClient.GetFromJsonAsync<Notice>(NoticUrl);
|
||||
|
||||
if (notice != null)
|
||||
{
|
||||
return notice.Version;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ = e;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private async Task<string> GetReleaseMarkdownHtmlAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
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");
|
||||
var jsonDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
|
||||
|
||||
if (jsonDict != null)
|
||||
{
|
||||
string? name = jsonDict["name"] as string;
|
||||
string? body = jsonDict["body"] as string;
|
||||
string md = $"# {name}{new string('\n', 2)}{body}";
|
||||
|
||||
md = WebUtility.HtmlEncode(md);
|
||||
string md2html = ResourceHelper.GetString($"pack://application:,,,/Assets/Strings/md2html.html", Encoding.UTF8);
|
||||
var html = md2html.Replace("{{content}}", md);
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ = e;
|
||||
}
|
||||
|
||||
return GetReleaseMarkdownHtmlFallback();
|
||||
}
|
||||
|
||||
private string GetReleaseMarkdownHtmlFallback()
|
||||
{
|
||||
return
|
||||
"""
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>更新日志</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #212121;
|
||||
color: white;
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
.message {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="message">
|
||||
获取更新日志失败,请自行选择是否更新!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
}
|
||||
|
||||
private static bool IsNeedDownload(string sourceFileName, string targetSha256)
|
||||
{
|
||||
if (File.Exists(sourceFileName))
|
||||
{
|
||||
using SHA256 sha256 = SHA256.Create();
|
||||
using FileStream fileStream = new(sourceFileName, FileMode.Open, FileAccess.Read);
|
||||
byte[] hashBytes = sha256.ComputeHash(fileStream);
|
||||
string sourceSha256 = BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToUpper();
|
||||
|
||||
if (sourceSha256 == targetSha256)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
59
BetterGenshinImpact/Threading/SemaphoreSlimParallel.cs
Normal file
59
BetterGenshinImpact/Threading/SemaphoreSlimParallel.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterGenshinImpact.Threading;
|
||||
|
||||
public class SemaphoreSlimParallel : IAsyncDisposable
|
||||
{
|
||||
private readonly SemaphoreSlim _semaphore;
|
||||
private readonly List<Task> _tasks = [];
|
||||
|
||||
private SemaphoreSlimParallel(int maxDegreeOfParallelism)
|
||||
{
|
||||
_semaphore = new SemaphoreSlim(maxDegreeOfParallelism);
|
||||
}
|
||||
|
||||
public static async Task<SemaphoreSlimParallel> ForEach<T>(
|
||||
IEnumerable<T> items,
|
||||
Func<T, Task> action,
|
||||
int maxDegreeOfParallelism,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var parallelExecutor = new SemaphoreSlimParallel(maxDegreeOfParallelism);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
await parallelExecutor._semaphore.WaitAsync(cancellationToken);
|
||||
var task = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await action(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parallelExecutor._semaphore.Release();
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
parallelExecutor._tasks.Add(task);
|
||||
}
|
||||
|
||||
return parallelExecutor;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 等待所有任务完成
|
||||
await Task.WhenAll(_tasks);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semaphore.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using BetterGenshinImpact.ViewModel.Pages;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Microsoft.Web.WebView2.Wpf;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace BetterGenshinImpact.View.Controls.Webview;
|
||||
@ -20,7 +19,6 @@ public class WebpageWindow : Window
|
||||
};
|
||||
|
||||
Content = wp;
|
||||
// Background = new SolidColorBrush(Color.FromRgb(0x20, 0x20, 0x20));
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
|
74
BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml
Normal file
74
BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml
Normal file
@ -0,0 +1,74 @@
|
||||
<ui:FluentWindow x:Class="BetterGenshinImpact.View.Windows.CheckUpdateWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:BetterGenshinImpact.View.Windows"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:vio="http://schemas.lepo.co/wpfui/2022/xaml/violeta"
|
||||
xmlns:webview="clr-namespace:BetterGenshinImpact.View.Controls.Webview"
|
||||
x:Name="app"
|
||||
Title="发现新版本"
|
||||
Width="680"
|
||||
Height="450"
|
||||
Background="#202020"
|
||||
ExtendsContentIntoTitleBar="True"
|
||||
FontFamily="{DynamicResource TextThemeFontFamily}"
|
||||
WindowBackdropType="None"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<ui:Grid Margin="0,48,0,0" RowDefinitions="Auto,*,Auto">
|
||||
<webview:WebpagePanel x:Name="WebpagePanel"
|
||||
Grid.Row="1"
|
||||
Margin="12,0,12,0" />
|
||||
<ui:Grid Grid.Row="0"
|
||||
Margin="16,0,16,0"
|
||||
ColumnDefinitions="Auto,*"
|
||||
Visibility="{Binding ShowUpdateStatus, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<vio:Loading Grid.Column="0" />
|
||||
<ui:StackPanel Grid.Column="1" Margin="16,0,0,0">
|
||||
<TextBlock Text="{Binding UpdateStatusMessage}" />
|
||||
</ui:StackPanel>
|
||||
</ui:Grid>
|
||||
<ui:Grid Grid.Row="2"
|
||||
Margin="8"
|
||||
ColumnDefinitions="*,Auto,Auto,Auto,Auto">
|
||||
<ui:Button Grid.Column="0"
|
||||
MinWidth="90"
|
||||
Margin="8,0,8,0"
|
||||
Command="{Binding BackgroundUpdateCommand}"
|
||||
Content="后台更新"
|
||||
Visibility="Collapsed" />
|
||||
<ui:Button Grid.Column="0"
|
||||
MinWidth="90"
|
||||
Margin="8,0,8,0"
|
||||
Command="{Binding OtherUpdateCommand}"
|
||||
Content="其他更新方式..." />
|
||||
<ui:Button Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="8,0,8,0"
|
||||
Appearance="Success"
|
||||
Command="{Binding UpdateCommand}"
|
||||
Content="立即更新" />
|
||||
<ui:Button Grid.Column="2"
|
||||
MinWidth="90"
|
||||
Margin="8,0,8,0"
|
||||
Command="{Binding IgnoreCommand}"
|
||||
Content="不再提示" />
|
||||
<ui:Button Grid.Column="3"
|
||||
MinWidth="90"
|
||||
Margin="8,0,8,0"
|
||||
Command="{Binding CancelCommand}"
|
||||
Content="取消" />
|
||||
</ui:Grid>
|
||||
</ui:Grid>
|
||||
<ui:TitleBar Title="{Binding Title, ElementName=app}"
|
||||
ShowMaximize="False"
|
||||
ShowMinimize="False">
|
||||
<ui:TitleBar.Icon>
|
||||
<ui:ImageIcon Source="pack://application:,,,/Assets/Images/logo.png" />
|
||||
</ui:TitleBar.Icon>
|
||||
</ui:TitleBar>
|
||||
</Grid>
|
||||
</ui:FluentWindow>
|
95
BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml.cs
Normal file
95
BetterGenshinImpact/View/Windows/CheckUpdateWindow.xaml.cs
Normal file
@ -0,0 +1,95 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace BetterGenshinImpact.View.Windows;
|
||||
|
||||
[ObservableObject]
|
||||
public partial class CheckUpdateWindow : FluentWindow
|
||||
{
|
||||
public Func<object, CheckUpdateWindowButton, Task> UserInteraction = null!;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool showUpdateStatus = false;
|
||||
|
||||
[ObservableProperty]
|
||||
private string updateStatusMessage = string.Empty;
|
||||
|
||||
public CheckUpdateWindow()
|
||||
{
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
|
||||
Closing += OnClosing;
|
||||
}
|
||||
|
||||
protected void OnClosing(object? sender, CancelEventArgs e)
|
||||
{
|
||||
if (ShowUpdateStatus)
|
||||
{
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void NavigateToHtml(string html)
|
||||
{
|
||||
WebpagePanel?.NavigateToHtml(html);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task BackgroundUpdateAsync()
|
||||
{
|
||||
if (UserInteraction != null)
|
||||
{
|
||||
await UserInteraction.Invoke(this, CheckUpdateWindowButton.BackgroundUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OtherUpdateAsync()
|
||||
{
|
||||
if (UserInteraction != null)
|
||||
{
|
||||
await UserInteraction.Invoke(this, CheckUpdateWindowButton.OtherUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task UpdateAsync()
|
||||
{
|
||||
if (UserInteraction != null)
|
||||
{
|
||||
await UserInteraction.Invoke(this, CheckUpdateWindowButton.Update);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task IgnoreAsync()
|
||||
{
|
||||
if (UserInteraction != null)
|
||||
{
|
||||
await UserInteraction.Invoke(this, CheckUpdateWindowButton.Ignore);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task CancelAsync()
|
||||
{
|
||||
if (UserInteraction != null)
|
||||
{
|
||||
await UserInteraction.Invoke(this, CheckUpdateWindowButton.Cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public enum CheckUpdateWindowButton
|
||||
{
|
||||
BackgroundUpdate,
|
||||
OtherUpdate,
|
||||
Update,
|
||||
Ignore,
|
||||
Cancel,
|
||||
}
|
||||
}
|
@ -14,8 +14,6 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Wpf.Ui;
|
||||
@ -100,15 +98,7 @@ public partial class MainWindowViewModel : ObservableObject, IViewModel
|
||||
MessageBox.Warning("PaddleOcr预热失败,解决方案:https://bgi.huiyadan.com/faq.html," + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Run(GetNewestInfoAsync);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine("获取最新版本信息失败:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||||
_logger.LogWarning("获取 BetterGI 最新版本信息失败");
|
||||
}
|
||||
await App.GetService<IUpdateService>()!.CheckUpdateAsync(new UpdateOption());
|
||||
|
||||
// Win11下 BitBlt截图方式不可用,需要关闭窗口优化功能
|
||||
if (OsVersionHelper.IsWindows11_OrGreater && TaskContext.Instance().Config.AutoFixWin11BitBlt)
|
||||
@ -119,53 +109,4 @@ public partial class MainWindowViewModel : ObservableObject, IViewModel
|
||||
// 更新仓库
|
||||
ScriptRepoUpdater.Instance.AutoUpdate();
|
||||
}
|
||||
|
||||
private async Task GetNewestInfoAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
var notice = await httpClient.GetFromJsonAsync<Notice>(@"https://hui-config.oss-cn-hangzhou.aliyuncs.com/bgi/notice.json");
|
||||
if (notice != null && !string.IsNullOrWhiteSpace(notice.Version))
|
||||
{
|
||||
if (Global.IsNewVersion(notice.Version))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Config.NotShowNewVersionNoticeEndVersion)
|
||||
&& !Global.IsNewVersion(Config.NotShowNewVersionNoticeEndVersion, notice.Version))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await UIDispatcherHelper.Invoke(async () =>
|
||||
{
|
||||
var uiMessageBox = new Wpf.Ui.Controls.MessageBox
|
||||
{
|
||||
Title = "更新提示",
|
||||
Content = $"存在最新版本 {notice.Version},点击确定前往下载页面下载最新版本",
|
||||
PrimaryButtonText = "确定",
|
||||
SecondaryButtonText = "不再提示",
|
||||
CloseButtonText = "取消",
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
Owner = Application.Current.MainWindow,
|
||||
};
|
||||
|
||||
var result = await uiMessageBox.ShowDialogAsync();
|
||||
if (result == Wpf.Ui.Controls.MessageBoxResult.Primary)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo("https://bgi.huiyadan.com/download.html") { UseShellExecute = true });
|
||||
}
|
||||
else if (result == Wpf.Ui.Controls.MessageBoxResult.Secondary)
|
||||
{
|
||||
Config.NotShowNewVersionNoticeEndVersion = notice.Version;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine("获取最新版本信息失败:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||||
_logger.LogWarning("获取 BetterGI 最新版本信息失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
Build/Updater/Program.cs
Normal file
44
Build/Updater/Program.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Updater;
|
||||
|
||||
internal sealed class Program
|
||||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
// Avoid user interaction
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Chattering ms
|
||||
Thread.Sleep(200);
|
||||
|
||||
string sourcePath = args[0];
|
||||
string targetPath = args[1];
|
||||
|
||||
if (!Directory.Exists(sourcePath))
|
||||
{
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(targetPath))
|
||||
{
|
||||
Directory.CreateDirectory(targetPath);
|
||||
}
|
||||
|
||||
// No fallback measures
|
||||
foreach (string file in Directory.GetFiles(sourcePath))
|
||||
{
|
||||
string fileName = Path.GetFileName(file);
|
||||
string targetFile = Path.Combine(targetPath, fileName);
|
||||
|
||||
File.Copy(file, targetFile, true);
|
||||
}
|
||||
}
|
||||
}
|
9
Build/Updater/Updater.csproj
Normal file
9
Build/Updater/Updater.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user