From b8bcad2107cc4c7e2af734ccacd35df44c60f93a Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Fri, 22 Dec 2023 22:02:10 +0800 Subject: [PATCH] 1.9.0 package --- .../IO/Http/Sharding/HttpShardCopyWorker.cs | 6 +- .../Snap.Hutao/Core/IO/StreamCopyWorker.cs | 2 +- .../Snap.Hutao/Package.appxmanifest | 2 +- .../Package.development.appxmanifest | 2 +- .../Snap.Hutao/Resource/Localization/SH.resx | 11 +++- .../Service/Abstraction/IUpdateService.cs | 8 --- .../Snap.Hutao/Service/AppOptions.cs | 2 +- .../Snap.Hutao/Service/AppOptionsExtension.cs | 2 +- .../Snap.Hutao/Service/SupportedCultures.cs | 1 + .../Service/Update/IUpdateService.cs | 13 ++++ .../Service/{ => Update}/UpdateService.cs | 41 ++++++++++-- .../Snap.Hutao/Service/Update/UpdateStatus.cs | 30 +++++++++ .../Snap.Hutao/Service/UpdateStatus.cs | 25 -------- .../Snap.Hutao/View/Page/SettingPage.xaml | 2 +- src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml | 32 +++++++++- .../Snap.Hutao/View/TitleView.xaml.cs | 62 ++++++++++++++++--- .../Snap.Hutao/Web/Hutao/IPInformation.cs | 10 ++- 17 files changed, 189 insertions(+), 62 deletions(-) delete mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Abstraction/IUpdateService.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Update/IUpdateService.cs rename src/Snap.Hutao/Snap.Hutao/Service/{ => Update}/UpdateService.cs (72%) create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateStatus.cs delete mode 100644 src/Snap.Hutao/Snap.Hutao/Service/UpdateStatus.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Sharding/HttpShardCopyWorker.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Sharding/HttpShardCopyWorker.cs index f8263402..8753e5a8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Sharding/HttpShardCopyWorker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Sharding/HttpShardCopyWorker.cs @@ -130,7 +130,7 @@ internal sealed class HttpShardCopyWorker : IDisposable BytesRead = bytesRead; } - public int BytesRead { get; set; } + public int BytesRead { get; } } private sealed class ShardProgress : IProgress @@ -152,11 +152,11 @@ internal sealed class HttpShardCopyWorker : IDisposable public void Report(ShardStatus value) { Interlocked.Add(ref totalBytesRead, value.BytesRead); - if (stopwatch.GetElapsedTime().TotalMilliseconds > 500) + if (stopwatch.GetElapsedTime().TotalMilliseconds > 1000 || totalBytesRead == contentLength) { lock (syncRoot) { - if (stopwatch.GetElapsedTime().TotalMilliseconds > 500) + if (stopwatch.GetElapsedTime().TotalMilliseconds > 1000 || totalBytesRead == contentLength) { workerProgress.Report(statusFactory(totalBytesRead, contentLength)); stopwatch = ValueStopwatch.StartNew(); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs index 975b7933..31455288 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs @@ -65,7 +65,7 @@ internal class StreamCopyWorker await destination.WriteAsync(buffer[..bytesRead]).ConfigureAwait(false); totalBytesRead += bytesRead; - if (stopwatch.GetElapsedTime().TotalMilliseconds > 500) + if (stopwatch.GetElapsedTime().TotalMilliseconds > 1000) { progress.Report(statusFactory(totalBytesRead)); stopwatch = ValueStopwatch.StartNew(); diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index b63fffde..83d23e38 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="1.9.0.0" /> Snap Hutao diff --git a/src/Snap.Hutao/Snap.Hutao/Package.development.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.development.appxmanifest index 27ae4cf4..a1893fe0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.development.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.development.appxmanifest @@ -12,7 +12,7 @@ + Version="1.9.0.0" /> Snap Hutao Dev diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 0c931e3f..5b3a21e5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -995,6 +995,9 @@ 不支持的 UIGF 版本 + + 发现新版本 {0} + 多个用户记录为选中状态 @@ -2621,6 +2624,12 @@ 上传数据 + + 是否立即安装? + + + 胡桃 {0} 版本已准备就绪 + 自动连点 @@ -2877,7 +2886,7 @@ 国际服 亚服 - 国际服 台服 + 国际服 港澳台服 国际服 欧服 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/IUpdateService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/IUpdateService.cs deleted file mode 100644 index 162fecc4..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/Abstraction/IUpdateService.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Service.Abstraction; - -internal interface IUpdateService -{ -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs index be60187b..97bef4f0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs @@ -74,7 +74,7 @@ internal sealed partial class AppOptions : DbStoreOptions set => SetOption(ref currentCulture, SettingEntry.Culture, value, value => value.Name); } - public List> Regions { get; } = KnownRegions.Get(); + public Lazy>> LazyRegions { get; } = new(KnownRegions.Get); public Region Region { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs index a534248f..ff06c942 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs @@ -16,6 +16,6 @@ internal static class AppOptionsExtension public static NameValue? GetCurrentRegionForSelectionOrDefault(this AppOptions appOptions) { - return appOptions.Regions.SingleOrDefault(c => c.Value.Value == appOptions.Region.Value); + return appOptions.LazyRegions.Value.SingleOrDefault(c => c.Value.Value == appOptions.Region.Value); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/SupportedCultures.cs b/src/Snap.Hutao/Snap.Hutao/Service/SupportedCultures.cs index 975f437f..e91dc992 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/SupportedCultures.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/SupportedCultures.cs @@ -13,6 +13,7 @@ internal static class SupportedCultures ToNameValue(CultureInfo.GetCultureInfo("zh-Hans")), ToNameValue(CultureInfo.GetCultureInfo("zh-Hant")), ToNameValue(CultureInfo.GetCultureInfo("en")), + ToNameValue(CultureInfo.GetCultureInfo("ru")), ToNameValue(CultureInfo.GetCultureInfo("ja")), ToNameValue(CultureInfo.GetCultureInfo("id")), ToNameValue(CultureInfo.GetCultureInfo("ko")), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Update/IUpdateService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Update/IUpdateService.cs new file mode 100644 index 00000000..a928ac22 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Update/IUpdateService.cs @@ -0,0 +1,13 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Service.Update; + +namespace Snap.Hutao.Service.Abstraction; + +internal interface IUpdateService +{ + ValueTask CheckForUpdateAndDownloadAsync(IProgress progress, CancellationToken token = default); + + void LaunchInstaller(); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UpdateService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateService.cs similarity index 72% rename from src/Snap.Hutao/Snap.Hutao/Service/UpdateService.cs rename to src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateService.cs index f6fa7ef4..2f96a4fd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/UpdateService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateService.cs @@ -2,15 +2,17 @@ // Licensed under the MIT license. using Snap.Hutao.Core; +using Snap.Hutao.Core.IO; using Snap.Hutao.Core.IO.Hashing; using Snap.Hutao.Core.IO.Http.Sharding; using Snap.Hutao.Service.Abstraction; using Snap.Hutao.Web.Hutao; using Snap.Hutao.Web.Hutao.Response; +using System.Diagnostics; using System.IO; using System.Net.Http; -namespace Snap.Hutao.Service; +namespace Snap.Hutao.Service.Update; [ConstructorGenerated] [Injection(InjectAs.Singleton, typeof(IUpdateService))] @@ -18,7 +20,7 @@ internal sealed partial class UpdateService : IUpdateService { private readonly IServiceProvider serviceProvider; - public async ValueTask InitializeAsync(IProgress progress, CancellationToken token = default) + public async ValueTask CheckForUpdateAndDownloadAsync(IProgress progress, CancellationToken token = default) { using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -34,16 +36,26 @@ internal sealed partial class UpdateService : IUpdateService } HutaoVersionInformation versionInformation = response.Data; + string msixPath = GetUpdatePackagePath(); + + if (scope.ServiceProvider.GetRequiredService().Version >= versionInformation.Version) + { + if (File.Exists(msixPath)) + { + File.Delete(msixPath); + } + + return false; + } + + progress.Report(new(versionInformation.Version.ToString(), 0, 0)); if (versionInformation.Sha256 is not { } sha256) { return false; } - string dataFolder = scope.ServiceProvider.GetRequiredService().DataFolder; - string msixPath = Path.Combine(dataFolder, "UpdateCache/Snap.Hutao.msix"); - - if (await CheckUpdateCacheSHA256Async(msixPath, sha256, token).ConfigureAwait(false)) + if (File.Exists(msixPath) && await CheckUpdateCacheSHA256Async(msixPath, sha256, token).ConfigureAwait(false)) { return true; } @@ -52,12 +64,29 @@ internal sealed partial class UpdateService : IUpdateService } } + public void LaunchInstaller() + { + Process.Start(new ProcessStartInfo() + { + UseShellExecute = true, + FileName = GetUpdatePackagePath(), + }); + } + private static async ValueTask CheckUpdateCacheSHA256Async(string filePath, string remoteHash, CancellationToken token = default) { string localHash = await SHA256.HashFileAsync(filePath, token).ConfigureAwait(false); return string.Equals(localHash, remoteHash, StringComparison.OrdinalIgnoreCase); } + private string GetUpdatePackagePath() + { + string dataFolder = serviceProvider.GetRequiredService().DataFolder; + string directory = Path.Combine(dataFolder, "UpdateCache"); + Directory.CreateDirectory(directory); + return Path.Combine(directory, "Snap.Hutao.msix"); + } + private async ValueTask DownloadUpdatePackageAsync(HutaoVersionInformation versionInformation, string filePath, IProgress progress, CancellationToken token = default) { using (IServiceScope scope = serviceProvider.CreateScope()) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateStatus.cs b/src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateStatus.cs new file mode 100644 index 00000000..bba21f7f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Update/UpdateStatus.cs @@ -0,0 +1,30 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.Common; + +namespace Snap.Hutao.Service.Update; + +internal sealed class UpdateStatus +{ + public UpdateStatus(string version, long bytesRead, long totalBytes) + { + Version = version; + VersionDescription = SH.FormatServiceUpdateStatusVersionDescription(Version); + BytesRead = bytesRead; + TotalBytes = totalBytes; + ProgressDescription = bytesRead != totalBytes + ? $"{Converters.ToFileSizeString(bytesRead)}/{Converters.ToFileSizeString(totalBytes)}" + : string.Empty; + } + + public string? Version { get; set; } + + public string VersionDescription { get; } + + public double BytesRead { get; set; } + + public double TotalBytes { get; set; } + + public string ProgressDescription { get; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/UpdateStatus.cs b/src/Snap.Hutao/Snap.Hutao/Service/UpdateStatus.cs deleted file mode 100644 index 163492e8..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/UpdateStatus.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using CommunityToolkit.Common; - -namespace Snap.Hutao.Service; - -internal sealed class UpdateStatus -{ - public UpdateStatus(string version, long bytesRead, long totalBytes) - { - Version = version; - BytesRead = bytesRead; - TotalBytes = totalBytes; - ProgressDescription = $"{Converters.ToFileSizeString(bytesRead)}/{Converters.ToFileSizeString(totalBytes)}"; - } - - public string? Version { get; set; } - - public long BytesRead { get; set; } - - public long TotalBytes { get; set; } - - public string ProgressDescription { get; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml index 57e80abf..9a212cb1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml @@ -312,7 +312,7 @@ diff --git a/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml b/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml index 5838f970..4d6d9cee 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml @@ -24,11 +24,11 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs index 3eea5f49..60a7d2e1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/TitleView.xaml.cs @@ -1,10 +1,15 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Core; using Snap.Hutao.Core.Windowing.HotKey; +using Snap.Hutao.Factory.ContentDialog; +using Snap.Hutao.Factory.Progress; +using Snap.Hutao.Service.Abstraction; +using Snap.Hutao.Service.Update; namespace Snap.Hutao.View; @@ -12,19 +17,19 @@ namespace Snap.Hutao.View; /// 标题视图 /// [HighQuality] +[INotifyPropertyChanged] internal sealed partial class TitleView : UserControl { - /// - /// 构造一个新的标题视图 - /// + private CancellationTokenSource checkUpdateTaskCancellationTokenSource = new(); + private UpdateStatus? updateStatus; + public TitleView() { + Loaded += OnTitleViewLoaded; + Unloaded += OnTitleViewUnloaded; InitializeComponent(); } - /// - /// 标题 - /// public string Title { [SuppressMessage("", "IDE0027")] @@ -38,9 +43,6 @@ internal sealed partial class TitleView : UserControl } } - /// - /// 获取可拖动区域 - /// public FrameworkElement DragArea { get => DragableGrid; @@ -49,4 +51,44 @@ internal sealed partial class TitleView : UserControl public RuntimeOptions RuntimeOptions { get; } = Ioc.Default.GetRequiredService(); public HotKeyOptions HotKeyOptions { get; } = Ioc.Default.GetRequiredService(); -} + + public UpdateStatus? UpdateStatus { get => updateStatus; set => SetProperty(ref updateStatus, value); } + + private void OnTitleViewLoaded(object sender, RoutedEventArgs e) + { + DoCheckUpdateAsync(checkUpdateTaskCancellationTokenSource.Token).SafeForget(); + Loaded -= OnTitleViewLoaded; + } + + private void OnTitleViewUnloaded(object sender, RoutedEventArgs e) + { + checkUpdateTaskCancellationTokenSource.Cancel(); + Unloaded -= OnTitleViewUnloaded; + } + + private async ValueTask DoCheckUpdateAsync(CancellationToken token) + { + IServiceProvider serviceProvider = Ioc.Default; + IUpdateService updateService = serviceProvider.GetRequiredService(); + + IProgressFactory progressFactory = serviceProvider.GetRequiredService(); + IProgress progress = progressFactory.CreateForMainThread(status => UpdateStatus = status); + if (await updateService.CheckForUpdateAndDownloadAsync(progress, token).ConfigureAwait(false)) + { + ContentDialogResult result = await serviceProvider + .GetRequiredService() + .CreateForConfirmCancelAsync( + SH.FormatViewTitileUpdatePackageReadyTitle(UpdateStatus?.Version), + SH.ViewTitileUpdatePackageReadyContent, + ContentDialogButton.Primary) + .ConfigureAwait(false); + if (result == ContentDialogResult.Primary) + { + updateService.LaunchInstaller(); + } + } + + await serviceProvider.GetRequiredService().SwitchToMainThreadAsync(); + UpdateStatus = null; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/IPInformation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/IPInformation.cs index f7ee777d..411db77e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/IPInformation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/IPInformation.cs @@ -1,9 +1,11 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using System.Text.RegularExpressions; + namespace Snap.Hutao.Web.Hutao; -internal sealed class IPInformation +internal sealed partial class IPInformation { private const string Unknown = "Unknown"; @@ -26,6 +28,10 @@ internal sealed class IPInformation return SH.WebHutaoServiceUnAvailable; } - return SH.FormatViewPageSettingDeviceIpDescription(Ip, Division); + string maskedIp = IpRegex().Replace(Ip, "$1.$2.*.*"); + return SH.FormatViewPageSettingDeviceIpDescription(maskedIp, Division); } + + [GeneratedRegex(@"(\d+)\.(\d+)\.\d+\.\d+")] + private static partial Regex IpRegex(); } \ No newline at end of file