From 1e92edca63613dcd412d4f2e13ad56208e41c4a8 Mon Sep 17 00:00:00 2001
From: Lightczx <1686188646@qq.com>
Date: Fri, 18 Aug 2023 11:48:06 +0800
Subject: [PATCH 01/43] Improve AnnouncementContentViewer DarkMode speed
---
.../Control/AnnouncementContentViewer.xaml.cs | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs
index efbbd466..bd047906 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs
@@ -7,6 +7,7 @@ using Microsoft.Web.WebView2.Core;
using Snap.Hutao.Control;
using Snap.Hutao.Control.Theme;
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
+using System.Text;
using System.Text.RegularExpressions;
using Windows.Foundation;
using Windows.System;
@@ -85,15 +86,15 @@ internal sealed partial class AnnouncementContentViewer : UserControl
if (isDarkMode)
{
- // TODO: rewrite with Span IndexOfAny
- content = content
- .Replace(DarkColor5, LightColor5, StringComparison.Ordinal)
- .Replace(DarkColor4, LightColor4, StringComparison.Ordinal)
- .Replace(DarkColor3, LightColor3, StringComparison.Ordinal)
- .Replace(DarkColor2, LightColor2, StringComparison.Ordinal)
- .Replace(DarkColor1, LightColor1, StringComparison.Ordinal)
- .Replace(DarkAccentColor2, LightAccentColor2, StringComparison.Ordinal)
- .Replace(DarkAccentColor1, LightAccentColor1, StringComparison.Ordinal);
+ StringBuilder contentBuilder = new StringBuilder(content)
+ .Replace(DarkColor5, LightColor5)
+ .Replace(DarkColor4, LightColor4)
+ .Replace(DarkColor3, LightColor3)
+ .Replace(DarkColor2, LightColor2)
+ .Replace(DarkColor1, LightColor1)
+ .Replace(DarkAccentColor2, LightAccentColor2)
+ .Replace(DarkAccentColor1, LightAccentColor1);
+ content = contentBuilder.ToString();
}
string document = $$"""
From 0ea85ae26b0d33f98deca0f7e675b8b7d1637aaf Mon Sep 17 00:00:00 2001
From: Lightczx <1686188646@qq.com>
Date: Fri, 18 Aug 2023 16:41:11 +0800
Subject: [PATCH 02/43] Prepare Announcement Regex
---
.../Resource/Localization/SH.Designer.cs | 54 +++++++++++++++++++
.../Snap.Hutao/Resource/Localization/SH.resx | 18 +++++++
.../Announcement/AnnouncementContent.cs | 2 +-
.../Common/Announcement/AnnouncementRegex.cs | 19 +++++++
4 files changed, 92 insertions(+), 1 deletion(-)
create mode 100644 src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementRegex.cs
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
index de9dfcf7..75bafa99 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -5478,6 +5478,51 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 (?:〓活动时间〓|〓任务开放时间〓).*?\d\.\d版本更新(?:完成|)后永久开放 的本地化字符串。
+ ///
+ internal static string WebAnnouncementMatchPermanentActivityTime {
+ get {
+ return ResourceManager.GetString("WebAnnouncementMatchPermanentActivityTime", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 〓活动时间〓.*?\d\.\d版本期间持续开放 的本地化字符串。
+ ///
+ internal static string WebAnnouncementMatchPersistentActivityTime {
+ get {
+ return ResourceManager.GetString("WebAnnouncementMatchPersistentActivityTime", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)</t> 的本地化字符串。
+ ///
+ internal static string WebAnnouncementMatchTransientActivityTime {
+ get {
+ return ResourceManager.GetString("WebAnnouncementMatchTransientActivityTime", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 〓更新时间〓.+?<t class=\"t_(?:gl|lc)\".*?>(.*?)</t> 的本地化字符串。
+ ///
+ internal static string WebAnnouncementMatchVersionUpdateTime {
+ get {
+ return ResourceManager.GetString("WebAnnouncementMatchVersionUpdateTime", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 \d\.\d版本更新说明 的本地化字符串。
+ ///
+ internal static string WebAnnouncementMatchVersionUpdateTitle {
+ get {
+ return ResourceManager.GetString("WebAnnouncementMatchVersionUpdateTitle", resourceCulture);
+ }
+ }
+
///
/// 查找类似 {0} 天后开始 的本地化字符串。
///
@@ -5828,5 +5873,14 @@ namespace Snap.Hutao.Resource.Localization {
return ResourceManager.GetString("WebResponseRequestExceptionFormat", resourceCulture);
}
}
+
+ ///
+ /// 查找类似 (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)</t> 的本地化字符串。
+ ///
+ internal static string 活动时间祈愿时间上架时间DD版本更新后D4D2D2D2D2D2LtTClass {
+ get {
+ return ResourceManager.GetString("活动时间祈愿时间上架时间DD版本更新后D4D2D2D2D2D2LtTClass", resourceCulture);
+ }
+ }
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index a64d1819..dcd54d3e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -1979,6 +1979,21 @@
武器资料
+
+ (?:〓活动时间〓|〓任务开放时间〓).*?\d\.\d版本更新(?:完成|)后永久开放
+
+
+ 〓活动时间〓.*?\d\.\d版本期间持续开放
+
+
+ (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)</t>
+
+
+ 〓更新时间〓.+?<t class=\"t_(?:gl|lc)\".*?>(.*?)</t>
+
+
+ \d\.\d版本更新说明
+
{0} 天后开始
@@ -2096,4 +2111,7 @@
[{0}] 中的 [{1}] 网络请求异常,请稍后再试
+
+ (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)</t>
+
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementContent.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementContent.cs
index d668bfe0..c0c24cb3 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementContent.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementContent.cs
@@ -45,4 +45,4 @@ internal class AnnouncementContent
///
[JsonPropertyName("lang")]
public string Lang { get; set; } = default!;
-}
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementRegex.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementRegex.cs
new file mode 100644
index 00000000..a77d3741
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/AnnouncementRegex.cs
@@ -0,0 +1,19 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Text.RegularExpressions;
+
+namespace Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
+
+internal static class AnnouncementRegex
+{
+ public static readonly Regex VersionUpdateTitleRegex = new(SH.WebAnnouncementMatchVersionUpdateTitle, RegexOptions.Compiled);
+
+ public static readonly Regex VersionUpdateTimeRegex = new(SH.WebAnnouncementMatchVersionUpdateTime, RegexOptions.Compiled);
+
+ public static readonly Regex TransientActivityTimeRegex = new(SH.WebAnnouncementMatchTransientActivityTime, RegexOptions.Compiled);
+
+ public static readonly Regex PersistentActivityTimeRegex = new(SH.WebAnnouncementMatchPersistentActivityTime, RegexOptions.Compiled);
+
+ public static readonly Regex PermanentActivityTimeRegex = new(SH.WebAnnouncementMatchPermanentActivityTime, RegexOptions.Compiled);
+}
\ No newline at end of file
From 7e5a536119def412d6757aae528fffc60898b574 Mon Sep 17 00:00:00 2001
From: Lightczx <1686188646@qq.com>
Date: Fri, 18 Aug 2023 16:43:41 +0800
Subject: [PATCH 03/43] remove incorrect i18n resource
---
.../Snap.Hutao/Resource/Localization/SH.Designer.cs | 9 ---------
src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx | 3 ---
2 files changed, 12 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
index 75bafa99..e5e68acb 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -5873,14 +5873,5 @@ namespace Snap.Hutao.Resource.Localization {
return ResourceManager.GetString("WebResponseRequestExceptionFormat", resourceCulture);
}
}
-
- ///
- /// 查找类似 (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)</t> 的本地化字符串。
- ///
- internal static string 活动时间祈愿时间上架时间DD版本更新后D4D2D2D2D2D2LtTClass {
- get {
- return ResourceManager.GetString("活动时间祈愿时间上架时间DD版本更新后D4D2D2D2D2D2LtTClass", resourceCulture);
- }
- }
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index dcd54d3e..09b35f8a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -2111,7 +2111,4 @@
[{0}] 中的 [{1}] 网络请求异常,请稍后再试
-
- (?:〓活动时间〓|祈愿时间|【上架时间】).*?(\d\.\d版本更新后|\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?~.*?<t class="t_(?:gl|lc)".*?>(.*?)</t>
-
\ No newline at end of file
From 674002ee8d4625b0b36a5fa8a3d90a152b634a7b Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 16:40:22 +0800
Subject: [PATCH 04/43] fix #841
---
.../ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs
index 69c3cc1a..bdfe1195 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/SpiralAbyssRecordViewModel.cs
@@ -153,12 +153,16 @@ internal sealed partial class SpiralAbyssRecordViewModel : Abstraction.ViewModel
SimpleRecord? record = await spiralAbyssClient.GetPlayerRecordAsync(userAndUid).ConfigureAwait(false);
if (record is not null)
{
- Web.Response.Response response = await spiralAbyssClient.UploadRecordAsync(record).ConfigureAwait(false);
+ Web.Response.Response response = await spiralAbyssClient.UploadRecordAsync(record).ConfigureAwait(false);
- if (response.IsOk())
+ if (response is { ReturnCode: 0 })
{
infoBarService.Success(response.Message);
}
+ else
+ {
+ infoBarService.Warning(response.Message);
+ }
}
}
else
From 282eb228d912ec746e450c8e172a783ac119ae24 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 17:15:46 +0800
Subject: [PATCH 05/43] improve cachedimage performance
---
src/Snap.Hutao/Snap.Hutao/App.xaml | 79 +++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml
index d23235df..447b603c 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml
@@ -5,6 +5,7 @@
xmlns:cwcw="using:CommunityToolkit.WinUI.Controls"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
+ xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shmmc="using:Snap.Hutao.Model.Metadata.Converter"
xmlns:shvc="using:Snap.Hutao.View.Converter">
@@ -493,7 +494,83 @@
-
+
From cb06949e608a47aa190695aa66d4372276d4b185 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 18:16:42 +0800
Subject: [PATCH 06/43] fix gachalog refresh crash
---
.../Core/Threading/DispatcherQueueProgress.cs | 46 +++++++++++++++++++
...n.cs => DispatcherQueueSwitchOperation.cs} | 6 +--
.../Snap.Hutao/Core/Threading/ITaskContext.cs | 4 +-
.../Snap.Hutao/Core/Threading/TaskContext.cs | 12 +++--
.../Service/GachaLog/GachaLogFetchStatus.cs | 10 ++++
.../Dialog/GachaLogRefreshProgressDialog.xaml | 18 ++++----
.../GachaLogRefreshProgressDialog.xaml.cs | 27 ++---------
.../ViewModel/GachaLog/GachaLogViewModel.cs | 2 +-
8 files changed, 84 insertions(+), 41 deletions(-)
create mode 100644 src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueProgress.cs
rename src/Snap.Hutao/Snap.Hutao/Core/Threading/{DispatherQueueSwitchOperation.cs => DispatcherQueueSwitchOperation.cs} (83%)
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueProgress.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueProgress.cs
new file mode 100644
index 00000000..c4b9b1b1
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueProgress.cs
@@ -0,0 +1,46 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Core.Threading;
+
+internal class DispatcherQueueProgress : IProgress
+{
+ private readonly SynchronizationContext synchronizationContext;
+ private readonly Action? handler;
+ private readonly SendOrPostCallback invokeHandlers;
+
+ public DispatcherQueueProgress(Action handler, SynchronizationContext synchronizationContext)
+ {
+ this.synchronizationContext = synchronizationContext;
+ invokeHandlers = new SendOrPostCallback(InvokeHandlers);
+
+ ArgumentNullException.ThrowIfNull(handler);
+
+ this.handler = handler;
+ }
+
+ public event EventHandler? ProgressChanged;
+
+ [SuppressMessage("", "VSTHRD001")]
+ public void Report(T value)
+ {
+ Action? handler = this.handler;
+ EventHandler? changedEvent = ProgressChanged;
+ if (handler is not null || changedEvent is not null)
+ {
+ synchronizationContext.Post(invokeHandlers, value);
+ }
+ }
+
+ [SuppressMessage("", "SH007")]
+ private void InvokeHandlers(object? state)
+ {
+ T value = (T)state!;
+
+ Action? handler = this.handler;
+ EventHandler? changedEvent = ProgressChanged;
+
+ handler?.Invoke(value);
+ changedEvent?.Invoke(this, value);
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueSwitchOperation.cs
similarity index 83%
rename from src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs
rename to src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueSwitchOperation.cs
index f600a20d..0f68e4df 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueSwitchOperation.cs
@@ -11,7 +11,7 @@ namespace Snap.Hutao.Core.Threading;
/// 等待此类型对象后上下文会被切换至主线程
///
[HighQuality]
-internal readonly struct DispatherQueueSwitchOperation : IAwaitable, ICriticalAwaiter
+internal readonly struct DispatcherQueueSwitchOperation : IAwaitable, ICriticalAwaiter
{
private readonly DispatcherQueue dispatherQueue;
@@ -19,7 +19,7 @@ internal readonly struct DispatherQueueSwitchOperation : IAwaitable
/// 调度器队列
- public DispatherQueueSwitchOperation(DispatcherQueue dispatherQueue)
+ public DispatcherQueueSwitchOperation(DispatcherQueue dispatherQueue)
{
this.dispatherQueue = dispatherQueue;
}
@@ -31,7 +31,7 @@ internal readonly struct DispatherQueueSwitchOperation : IAwaitable
- public DispatherQueueSwitchOperation GetAwaiter()
+ public DispatcherQueueSwitchOperation GetAwaiter()
{
return this;
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs
index e2c7b8f0..ab389d0e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs
@@ -8,6 +8,8 @@ namespace Snap.Hutao.Core.Threading;
///
internal interface ITaskContext
{
+ IProgress CreateProgressForMainThread(Action handler);
+
///
/// 在主线程上同步等待执行操作
///
@@ -26,5 +28,5 @@ internal interface ITaskContext
///
/// 使用 异步切换到 后台线程
/// 等待体
- DispatherQueueSwitchOperation SwitchToMainThreadAsync();
+ DispatcherQueueSwitchOperation SwitchToMainThreadAsync();
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs
index 5ae43f2c..5462d81f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs
@@ -11,6 +11,7 @@ namespace Snap.Hutao.Core.Threading;
[Injection(InjectAs.Singleton, typeof(ITaskContext))]
internal sealed class TaskContext : ITaskContext
{
+ private readonly DispatcherQueueSynchronizationContext dispatcherQueueSynchronizationContext;
private readonly DispatcherQueue dispatcherQueue;
///
@@ -19,8 +20,8 @@ internal sealed class TaskContext : ITaskContext
public TaskContext()
{
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
- DispatcherQueueSynchronizationContext context = new(dispatcherQueue);
- SynchronizationContext.SetSynchronizationContext(context);
+ dispatcherQueueSynchronizationContext = new(dispatcherQueue);
+ SynchronizationContext.SetSynchronizationContext(dispatcherQueueSynchronizationContext);
}
///
@@ -30,7 +31,7 @@ internal sealed class TaskContext : ITaskContext
}
///
- public DispatherQueueSwitchOperation SwitchToMainThreadAsync()
+ public DispatcherQueueSwitchOperation SwitchToMainThreadAsync()
{
return new(dispatcherQueue);
}
@@ -47,4 +48,9 @@ internal sealed class TaskContext : ITaskContext
dispatcherQueue.Invoke(action);
}
}
+
+ public IProgress CreateProgressForMainThread(Action handler)
+ {
+ return new DispatcherQueueProgress(handler, dispatcherQueueSynchronizationContext);
+ }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs
index 118f5221..c77de33c 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs
@@ -34,4 +34,14 @@ internal sealed class GachaLogFetchStatus
/// 当前获取的物品
///
public List- Items { get; set; } = new(20);
+
+ public string Header
+ {
+ get
+ {
+ return AuthKeyTimeout
+ ? SH.ViewDialogGachaLogRefreshProgressAuthkeyTimeout
+ : SH.ViewDialogGachaLogRefreshProgressDescription.Format(ConfigType.GetLocalizedDescription());
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogRefreshProgressDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogRefreshProgressDialog.xaml
index 546a0bd0..7f552aac 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogRefreshProgressDialog.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogRefreshProgressDialog.xaml
@@ -7,27 +7,27 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shvc="using:Snap.Hutao.View.Control"
+ xmlns:shvh="using:Snap.Hutao.View.Helper"
Title="{shcm:ResourceString Name=ViewDialogGachaLogRefreshProgressTitle}"
Style="{StaticResource DefaultContentDialogStyle}"
mc:Ignorable="d">
-
-
-
+
+
+ ItemTemplate="{StaticResource GachaItemDataTemplate}"
+ ItemsSource="{x:Bind Status.Items, Mode=OneWay}">
/// 接收进度更新
///
- /// 状态
- public void OnReport(GachaLogFetchStatus state)
+ /// 状态
+ public void OnReport(GachaLogFetchStatus status)
{
- Status = state;
-
- // TODO: test new binding approach
- GachaItemsPresenter.Header = state.AuthKeyTimeout
- ? SH.ViewDialogGachaLogRefreshProgressAuthkeyTimeout
- : SH.ViewDialogGachaLogRefreshProgressDescription.Format(state.ConfigType.GetLocalizedDescription());
-
- // Binding not working here.
- GachaItemsPresenter.Items.Clear();
-
- // System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
- foreach (Item item in state.Items.ToList())
- {
- GachaItemsPresenter.Items.Add(new ItemIcon
- {
- Width = 60,
- Height = 60,
- Quality = item.Quality,
- Icon = item.Icon,
- Badge = item.Badge,
- });
- }
+ Status = status;
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs
index ceb29fbe..6eac70f1 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs
@@ -160,7 +160,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
GachaLogRefreshProgressDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false);
ContentDialogHideToken hideToken = await dialog.BlockAsync(taskContext).ConfigureAwait(false);
- Progress progress = new(dialog.OnReport);
+ IProgress progress = taskContext.CreateProgressForMainThread(dialog.OnReport);
bool authkeyValid;
try
From 79cf2839e611c1d9e931abb601781306584fefde Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 18:21:24 +0800
Subject: [PATCH 07/43] fix gachalog import crash
---
src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs
index 3716ee64..f63e4e66 100644
--- a/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs
@@ -68,12 +68,12 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory
where TContentDialog : ContentDialog
{
await taskContext.SwitchToMainThreadAsync();
- return serviceProvider.CreateInstance();
+ return serviceProvider.CreateInstance(parameters);
}
public TContentDialog CreateInstance(params object[] parameters)
where TContentDialog : ContentDialog
{
- return serviceProvider.CreateInstance();
+ return serviceProvider.CreateInstance(parameters);
}
}
\ No newline at end of file
From 75938c3edeb4b5e3ccf9da9398446e1a1fe054eb Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 20:07:02 +0800
Subject: [PATCH 08/43] fix gachalog initialization & improve loading speed
---
.../ViewModel/GachaLog/GachaLogViewModel.cs | 42 ++++++-------------
1 file changed, 12 insertions(+), 30 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs
index 6eac70f1..595fdd59 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs
@@ -54,7 +54,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
public GachaArchive? SelectedArchive
{
get => selectedArchive;
- set => SetSelectedArchiveAndUpdateStatistics(value);
+ set => SetSelectedArchiveAndUpdateStatisticsAsync(value).SafeForget();
}
///
@@ -103,9 +103,8 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
await taskContext.SwitchToMainThreadAsync();
Archives = archives;
- SetSelectedArchiveAndUpdateStatistics(Archives.SelectedOrDefault(), true);
-
HutaoCloudViewModel.RetrieveCommand = RetrieveFromCloudCommand;
+ await SetSelectedArchiveAndUpdateStatisticsAsync(Archives.SelectedOrDefault(), true).ConfigureAwait(false);
return true;
}
}
@@ -188,7 +187,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
await taskContext.SwitchToMainThreadAsync();
if (authkeyValid)
{
- SetSelectedArchiveAndUpdateStatistics(gachaLogService.CurrentArchive, true);
+ await SetSelectedArchiveAndUpdateStatisticsAsync(gachaLogService.CurrentArchive, true).ConfigureAwait(false);
await hideToken.DisposeAsync().ConfigureAwait(false);
}
else
@@ -276,7 +275,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
// reselect first archive
await taskContext.SwitchToMainThreadAsync();
- SelectedArchive = Archives.FirstOrDefault();
+ await SetSelectedArchiveAndUpdateStatisticsAsync(Archives.FirstOrDefault(), false).ConfigureAwait(false);
}
}
}
@@ -293,42 +292,25 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
{
await taskContext.SwitchToMainThreadAsync();
Archives?.AddIfNotContains(archive);
- SetSelectedArchiveAndUpdateStatistics(archive, true);
+ await SetSelectedArchiveAndUpdateStatisticsAsync(archive, true).ConfigureAwait(false);
}
}
}
- ///
- /// 设置当前的祈愿存档
- /// 需要从主线程调用
- ///
- /// 存档
- /// 强制刷新,即使Uid相同也刷新该 Uid 的记录
- private void SetSelectedArchiveAndUpdateStatistics(GachaArchive? archive, bool forceUpdate = false)
+ private async ValueTask SetSelectedArchiveAndUpdateStatisticsAsync(GachaArchive? archive, bool forceUpdate = false)
{
- bool changed = false;
- if (selectedArchive != archive)
- {
- selectedArchive = archive;
- changed = true;
- }
+ bool changed = SetProperty(ref selectedArchive, archive, nameof(SelectedArchive));
if (changed)
{
gachaLogService.CurrentArchive = archive;
- OnPropertyChanged(nameof(SelectedArchive));
}
if (forceUpdate || changed)
{
- if (archive is null)
+ if (archive is not null)
{
- // no gacha log
- IsInitialized = true;
- }
- else
- {
- UpdateStatisticsAsync(archive).SafeForget();
+ await UpdateStatisticsAsync(archive).ConfigureAwait(false);
}
}
}
@@ -337,10 +319,10 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
{
try
{
- GachaStatistics? temp = await gachaLogService.GetStatisticsAsync(archive).ConfigureAwait(false);
+ GachaStatistics? statistics = await gachaLogService.GetStatisticsAsync(archive).ConfigureAwait(false);
await taskContext.SwitchToMainThreadAsync();
- Statistics = temp;
+ Statistics = statistics;
IsInitialized = true;
}
catch (UserdataCorruptedException ex)
@@ -375,7 +357,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
infoBarService.Success(SH.ViewModelGachaLogImportComplete);
await taskContext.SwitchToMainThreadAsync();
- SetSelectedArchiveAndUpdateStatistics(gachaLogService.CurrentArchive, true);
+ await SetSelectedArchiveAndUpdateStatisticsAsync(gachaLogService.CurrentArchive, true).ConfigureAwait(false);
return true;
}
else
From 6f1c7b250e8679cc3cbc375fda400d42426304b0 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 20:23:30 +0800
Subject: [PATCH 09/43] fix achievement archive creation
---
.../Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs
index 76ef8dea..4ffa0ff2 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs
@@ -187,7 +187,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
[Command("AddArchiveCommand")]
private async Task AddArchiveAsync()
{
- if (Archives is null)
+ if (Archives is not null)
{
AchievementArchiveCreateDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false);
(bool isOk, string name) = await dialog.GetInputAsync().ConfigureAwait(false);
From baee72a2fa25088214a0fcf09b30460bb3faeaf4 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 20:33:32 +0800
Subject: [PATCH 10/43] fix gachastatistics pullprediction infobar spam
---
.../Snap.Hutao/Service/GachaLog/Factory/PullPrediction.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/PullPrediction.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/PullPrediction.cs
index dfe63e32..80df0613 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/PullPrediction.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/PullPrediction.cs
@@ -28,9 +28,9 @@ internal sealed class PullPrediction
await context.TaskContext.SwitchToBackgroundAsync();
Response response = await context.GetGachaDistributionAsync().ConfigureAwait(false);
- if (response.IsOk())
+ if (response is { ReturnCode: 0, Data: GachaDistribution data })
{
- PredictResult result = PredictCore(response.Data.Distribution, typedWishSummary);
+ PredictResult result = PredictCore(data.Distribution, typedWishSummary);
await barrier.SignalAndWaitAsync().ConfigureAwait(false);
await context.TaskContext.SwitchToMainThreadAsync();
From 368d0bfbd73fa17bbf718b3a1f333268e27eabad Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sat, 19 Aug 2023 20:56:27 +0800
Subject: [PATCH 11/43] fix avatarproperty ordering
---
src/Snap.Hutao/Snap.Hutao/App.xaml | 1 +
.../Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml
index 447b603c..1f3b166d 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml
@@ -52,6 +52,7 @@
180
+ 64
0.2
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs
index 955ff6ad..16428011 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs
@@ -38,7 +38,7 @@ internal sealed partial class SummaryFactory : ISummaryFactory
.Where(a => !AvatarIds.IsPlayer(a.AvatarId))
.Select(a => new SummaryAvatarFactory(metadataContext, a).Create())
.OrderByDescending(a => a.LevelNumber)
- .ThenByDescending(a => a.Name)
+ .ThenBy(a => a.Name)
.ToList(),
// .ThenByDescending(a => a.Quality)
From f2fea5a0e6a89cea7bf6cecff30f90b11ea08f22 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sun, 20 Aug 2023 21:50:39 +0800
Subject: [PATCH 12/43] fix game package convert
---
src/Snap.Hutao/Snap.Hutao/App.xaml | 8 +--
.../Snap.Hutao/Core/IO/DirectoryOperation.cs | 5 +-
.../Snap.Hutao/Core/RuntimeOptions.cs | 4 +-
.../Resource/Localization/SH.Designer.cs | 27 +++++++
.../Snap.Hutao/Resource/Localization/SH.resx | 9 +++
.../Snap.Hutao/Service/Game/GameService.cs | 4 +-
.../Service/Game/LaunchScheme.KnownSchemes.cs | 10 +++
.../Service/Game/Package/PackageConverter.cs | 70 +++++++++++--------
.../Game/Package/PackageReplaceStatus.cs | 33 +++++----
.../LaunchGamePackageConvertDialog.xaml | 21 ++++--
.../ViewModel/Game/LaunchGameViewModel.cs | 4 +-
11 files changed, 138 insertions(+), 57 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml
index 1f3b166d..fd4bf633 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml
@@ -44,14 +44,12 @@
0,6,6,0
0,0,6,6
2
-
- 212
-
- 304
+
288
+ 212
+ 304
180
-
64
0.2
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/DirectoryOperation.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/DirectoryOperation.cs
index c881bb77..39132ba2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/IO/DirectoryOperation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/DirectoryOperation.cs
@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
+using Microsoft.VisualBasic.FileIO;
using System.IO;
namespace Snap.Hutao.Core.IO;
@@ -14,7 +15,7 @@ internal static class DirectoryOperation
return false;
}
- Directory.Move(sourceDirName, destDirName);
+ FileSystem.MoveDirectory(sourceDirName, destDirName, true);
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs b/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs
index ad3a4916..30aa3f95 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs
@@ -131,15 +131,13 @@ internal sealed class RuntimeOptions : IOptions
private static bool GetElevated()
{
-#if DEBUG_AS_FAKE_ELEVATED
return true;
-#else
+
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
{
WindowsPrincipal principal = new(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
-#endif
}
private void DetectWebView2Environment(ref string webView2Version, ref bool isWebView2Supported)
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
index e5e68acb..368a76a5 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -1473,6 +1473,33 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 备份:{0} 的本地化字符串。
+ ///
+ internal static string ServiceGamePackageConvertMoveFileBackupFormat {
+ get {
+ return ResourceManager.GetString("ServiceGamePackageConvertMoveFileBackupFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 重命名:{0} 到:{1} 的本地化字符串。
+ ///
+ internal static string ServiceGamePackageConvertMoveFileRenameFormat {
+ get {
+ return ResourceManager.GetString("ServiceGamePackageConvertMoveFileRenameFormat", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 替换:{0} 的本地化字符串。
+ ///
+ internal static string ServiceGamePackageConvertMoveFileRestoreFormat {
+ get {
+ return ResourceManager.GetString("ServiceGamePackageConvertMoveFileRestoreFormat", resourceCulture);
+ }
+ }
+
///
/// 查找类似 重命名数据文件夹名称失败 的本地化字符串。
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index 09b35f8a..5f8b287a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -644,6 +644,15 @@
在 Unity 日志文件中找不到游戏路径
+
+ 备份:{0}
+
+
+ 重命名:{0} 到:{1}
+
+
+ 替换:{0}
+
重命名数据文件夹名称失败
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
index 2ce14a2f..8a0cea37 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
@@ -163,7 +163,7 @@ internal sealed partial class GameService : IGameService
}
}
- return changed;
+ return changed || !LaunchSchemeMatchesExecutable(scheme, Path.GetFileName(gamePath));
}
///
@@ -244,7 +244,7 @@ internal sealed partial class GameService : IGameService
}
string gamePath = appOptions.GamePath;
- ArgumentNullException.ThrowIfNullOrEmpty(gamePath);
+ ArgumentException.ThrowIfNullOrEmpty(gamePath);
using (Process game = ProcessInterop.InitializeGameProcess(launchOptions, gamePath))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchScheme.KnownSchemes.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchScheme.KnownSchemes.cs
index 99833640..4527cb62 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchScheme.KnownSchemes.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchScheme.KnownSchemes.cs
@@ -18,6 +18,15 @@ internal sealed partial class LaunchScheme
private const string SdkStaticLauncherBilibiliKey = "KAtdSsoQ";
private const string SdkStaticLauncherGlobalKey = "gcStgarh";
+ private static readonly LaunchScheme ServerChineseChannelOfficialSubChannelDefault = new()
+ {
+ LauncherId = SdkStaticLauncherChineseId,
+ Key = SdkStaticLauncherChineseKey,
+ Channel = ChannelType.Official,
+ SubChannel = SubChannelType.Default,
+ IsOversea = false,
+ };
+
private static readonly LaunchScheme ServerChineseChannelOfficialSubChannelOfficial = new()
{
LauncherId = SdkStaticLauncherChineseId,
@@ -81,6 +90,7 @@ internal sealed partial class LaunchScheme
return new List()
{
// 官服
+ ServerChineseChannelOfficialSubChannelDefault,
ServerChineseChannelOfficialSubChannelOfficial,
ServerChineseChannelOfficialSubChannelNoTapTap,
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs
index 7321a6f5..a01a8f22 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs
@@ -27,6 +27,7 @@ internal sealed partial class PackageConverter
private readonly JsonSerializerOptions options;
private readonly RuntimeOptions runtimeOptions;
private readonly HttpClient httpClient;
+ private readonly ILogger logger;
///
/// 异步检查替换游戏资源
@@ -253,7 +254,9 @@ internal sealed partial class PackageConverter
}
// Cache no matching item, download
- Directory.CreateDirectory(context.ServerCacheTargetFolder);
+ string? directory = Path.GetDirectoryName(cacheFile);
+ ArgumentException.ThrowIfNullOrEmpty(directory);
+ Directory.CreateDirectory(directory);
using (FileStream fileStream = File.Create(cacheFile))
{
string remoteUrl = context.GetScatteredFilesUrl(remoteName);
@@ -288,24 +291,10 @@ internal sealed partial class PackageConverter
private async ValueTask ReplaceGameResourceAsync(List operations, PackageConvertContext context, IProgress progress)
{
- // 重命名 _Data 目录
- try
- {
- DirectoryOperation.Move(context.FromDataFolder, context.ToDataFolder);
- }
- catch (IOException ex)
- {
- // Access to the path is denied.
- // When user install the game in special folder like 'Program Files'
- throw ThrowHelper.GameFileOperation(SH.ServiceGamePackageRenameDataFolderFailed, ex);
- }
-
// 执行下载与移动操作
foreach (ItemOperationInfo info in operations)
{
- progress.Report(new($"{info.Remote}"));
-
- (bool backup, bool target) = info.Type switch
+ (bool moveToBackup, bool moveToTarget) = info.Type switch
{
ItemOperationType.Backup => (true, false),
ItemOperationType.Replace => (true, true),
@@ -313,27 +302,52 @@ internal sealed partial class PackageConverter
_ => (false, false),
};
- if (backup)
+ // 先备份
+ if (moveToBackup)
{
- string localFileName = info.Local.RelativePath.Format(context.FromDataFolder);
+ string localFileName = info.Local.RelativePath.Format(context.FromDataFolderName);
+ progress.Report(new(SH.ServiceGamePackageConvertMoveFileBackupFormat.Format(localFileName)));
+
string localFilePath = context.GetGameFolderFilePath(localFileName);
- string? directory = Path.GetDirectoryName(localFilePath);
- ArgumentException.ThrowIfNullOrEmpty(directory);
- Directory.CreateDirectory(directory);
- File.Move(localFilePath, context.GetServerCacheBackupFilePath(localFileName), true);
+ string cacheFilePath = context.GetServerCacheBackupFilePath(localFileName);
+ string? cacheFileDirectory = Path.GetDirectoryName(cacheFilePath);
+ ArgumentException.ThrowIfNullOrEmpty(cacheFileDirectory);
+ Directory.CreateDirectory(cacheFileDirectory);
+
+ logger.LogInformation("Backing file from:{Src} to:{Dst}", localFilePath, cacheFilePath);
+ FileOperation.Move(localFilePath, cacheFilePath, true);
}
- if (target)
+ // 后替换
+ if (moveToTarget)
{
- string targetFileName = info.Remote.RelativePath.Format(context.ToDataFolder);
+ string targetFileName = info.Remote.RelativePath.Format(context.ToDataFolderName);
+ progress.Report(new(SH.ServiceGamePackageConvertMoveFileRestoreFormat.Format(targetFileName)));
+
string targetFilePath = context.GetGameFolderFilePath(targetFileName);
- string? directory = Path.GetDirectoryName(targetFilePath);
- ArgumentException.ThrowIfNullOrEmpty(directory);
- Directory.CreateDirectory(directory);
- File.Move(context.GetServerCacheTargetFilePath(targetFileName), targetFilePath, true);
+ string? targetFileDirectory = Path.GetDirectoryName(targetFilePath);
+ string cacheFilePath = context.GetServerCacheTargetFilePath(targetFileName);
+ ArgumentException.ThrowIfNullOrEmpty(targetFileDirectory);
+ Directory.CreateDirectory(targetFileDirectory);
+
+ logger.LogInformation("Restoring file from:{Src} to:{Dst}", cacheFilePath, targetFilePath);
+ FileOperation.Move(cacheFilePath, targetFilePath, true);
}
}
+ // 重命名 _Data 目录
+ try
+ {
+ progress.Report(new(SH.ServiceGamePackageConvertMoveFileRenameFormat.Format(context.FromDataFolderName, context.ToDataFolderName)));
+ DirectoryOperation.Move(context.FromDataFolder, context.ToDataFolder);
+ }
+ catch (IOException ex)
+ {
+ // Access to the path is denied.
+ // When user install the game in special folder like 'Program Files'
+ throw ThrowHelper.GameFileOperation(SH.ServiceGamePackageRenameDataFolderFailed, ex);
+ }
+
// 重新下载所有 *pkg_version 文件
await ReplacePackageVersionFilesAsync(context).ConfigureAwait(false);
return true;
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageReplaceStatus.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageReplaceStatus.cs
index 0e49cfa2..1998f152 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageReplaceStatus.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageReplaceStatus.cs
@@ -14,11 +14,11 @@ internal sealed class PackageReplaceStatus : ICloneable
///
/// 构造一个新的包更新状态
///
- /// 描述
- public PackageReplaceStatus(string description)
+ /// 描述
+ public PackageReplaceStatus(string name)
{
- Name = default!;
- Description = description;
+ Name = name;
+ Description = default!;
}
///
@@ -34,23 +34,27 @@ internal sealed class PackageReplaceStatus : ICloneable
Description = $"{Converters.ToFileSizeString(bytesRead)}/{Converters.ToFileSizeString(totalBytes)}";
}
- public string Name { get; set; }
+ private PackageReplaceStatus()
+ {
+ }
+
+ public string Name { get; set; } = default!;
///
/// 描述
///
- public string Description { get; set; }
-
- ///
- /// 是否有进度
- ///
- public bool IsIndeterminate { get => Percent < 0; }
+ public string Description { get; set; } = default!;
///
/// 进度
///
public double Percent { get; set; } = -1;
+ ///
+ /// 是否有进度
+ ///
+ public bool IsIndeterminate { get => Percent < 0; }
+
///
/// 克隆
///
@@ -58,6 +62,11 @@ internal sealed class PackageReplaceStatus : ICloneable
public PackageReplaceStatus Clone()
{
// 进度需要在主线程上创建
- return new(Description) { Percent = Percent };
+ return new()
+ {
+ Name = Name,
+ Description = Description,
+ Percent = Percent,
+ };
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGamePackageConvertDialog.xaml b/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGamePackageConvertDialog.xaml
index c8bca679..9118449b 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGamePackageConvertDialog.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGamePackageConvertDialog.xaml
@@ -21,9 +21,22 @@
IsIndeterminate="{Binding State.IsIndeterminate}"
Maximum="1"
Value="{Binding State.Percent}"/>
-
+
+
+
+
+
+
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs
index 6e6fb91d..85487db3 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs
@@ -10,6 +10,7 @@ using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Service;
using Snap.Hutao.Service.Game;
+using Snap.Hutao.Service.Game.Package;
using Snap.Hutao.Service.Navigation;
using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
@@ -188,7 +189,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
{
// Channel changed, we need to change local file.
LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false);
- Progress progress = new(state => dialog.State = state.Clone());
+ IProgress progress = taskContext.CreateProgressForMainThread(state => dialog.State = state/*.Clone()*/);
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
{
if (!await gameService.EnsureGameResourceAsync(SelectedScheme, progress).ConfigureAwait(false))
@@ -212,6 +213,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel
}
catch (Exception ex)
{
+ System.Diagnostics.Debug.WriteLine(ExceptionFormat.Format(ex));
infoBarService.Error(ex);
}
}
From e347694a0bb99efe6acb6473baaa90b2437aefc3 Mon Sep 17 00:00:00 2001
From: Lightczx <1686188646@qq.com>
Date: Mon, 21 Aug 2023 15:52:20 +0800
Subject: [PATCH 13/43] Update dependabot.yml
---
.github/dependabot.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index fc08c96d..15bf4c04 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -7,9 +7,10 @@ version: 2
updates:
- package-ecosystem: "nuget"
directory: "/src/Snap.Hutao" # Snap.Hutao.csproj
+ target-branch: "develop"
schedule:
interval: "weekly"
groups:
- main-dependencies:
+ packages:
patterns:
- "*"
\ No newline at end of file
From 23feb78f051334fc24e116b15d5551e9225c7eda Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Mon, 21 Aug 2023 22:51:33 +0800
Subject: [PATCH 14/43] fix user collection initialization race condition
---
.../Snap.Hutao/Control/BoxedValues.cs | 15 --------
.../Snap.Hutao/Core/RuntimeOptions.cs | 2 --
.../Snap.Hutao/Core/Threading/Throttler.cs | 19 ++++++++++
src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs | 11 ++++++
.../Snap.Hutao/Service/User/UserService.cs | 28 ++++++++-------
.../LaunchGamePackageConvertDialog.xaml | 5 +--
.../Web/Hutao/HomaGachaLogClient.cs | 36 ++++++++++---------
.../Web/Hutao/HomaPassportClient.cs | 4 +--
8 files changed, 68 insertions(+), 52 deletions(-)
create mode 100644 src/Snap.Hutao/Snap.Hutao/Core/Threading/Throttler.cs
diff --git a/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs b/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs
index f705497a..15e7d2ba 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs
@@ -9,21 +9,6 @@ namespace Snap.Hutao.Control;
[HighQuality]
internal static class BoxedValues
{
- ///
- /// 0
- ///
- public static readonly object DoubleZero = 0D;
-
- ///
- /// 1
- ///
- public static readonly object DoubleOne = 1D;
-
- ///
- /// 0
- ///
- public static readonly object Int32Zero = 0;
-
///
///
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs b/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs
index 30aa3f95..3ae76131 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/RuntimeOptions.cs
@@ -131,8 +131,6 @@ internal sealed class RuntimeOptions : IOptions
private static bool GetElevated()
{
- return true;
-
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
{
WindowsPrincipal principal = new(identity);
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Throttler.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Throttler.cs
new file mode 100644
index 00000000..1b12e79e
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Throttler.cs
@@ -0,0 +1,19 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Collections.Concurrent;
+using System.Runtime.CompilerServices;
+
+namespace Snap.Hutao.Core.Threading;
+
+internal sealed class Throttler
+{
+ private readonly ConcurrentDictionary methodSemaphoreMap = new();
+
+ public ValueTask ThrottleAsync(CancellationToken token = default, [CallerMemberName] string callerName = default!, [CallerLineNumber] int callerLine = 0)
+ {
+ string key = $"{callerName}L{callerLine}";
+ SemaphoreSlim semaphore = methodSemaphoreMap.GetOrAdd(key, name => new SemaphoreSlim(1));
+ return semaphore.EnterAsync(token);
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs b/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs
index 35186dab..a2be57a4 100644
--- a/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs
@@ -6,6 +6,7 @@ using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Core.Windowing;
using Snap.Hutao.Message;
+using Windows.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Snap.Hutao;
@@ -22,6 +23,8 @@ internal sealed partial class MainWindow : Window, IWindowOptionsSource, IRecipi
private const int MinHeight = 524;
private readonly WindowOptions windowOptions;
+ private readonly ILogger logger;
+ private readonly TypedEventHandler