diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs
similarity index 99%
rename from src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtensions.cs
rename to src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs
index 62a023db..7c3037b5 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtensions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Control.Image;
///
/// 合成扩展
///
-internal static class CompositionExtensions
+internal static class CompositionExtension
{
///
/// 创建拼合图视觉对象
diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs
index 1c4c8d45..1e5cf33f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs
@@ -99,7 +99,11 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control
}
else
{
- infoBarService.Error(exception.GetBaseException(), SH.ControlImageCompositionImageSystemException);
+ Exception baseException = exception.GetBaseException();
+ if (baseException is not COMException)
+ {
+ infoBarService.Error(baseException, SH.ControlImageCompositionImageSystemException);
+ }
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsJob.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsJob.cs
index 6c12019b..660b59cf 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsJob.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsJob.cs
@@ -22,16 +22,16 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
///
public const string JobNamePrefix = "SnapHutaoBitsJob";
- private const uint BitsEngineNoProgressTimeout = 30;
- private const int MaxResumeAttempts = 10;
+ private const uint Timeout = 44;
+ private const int MaxResumeAttempts = 3;
private readonly string displayName;
- private readonly ILogger log;
- private readonly object lockObj = new();
+ private readonly ILogger logger;
+ private readonly object syncRoot = new();
private IBackgroundCopyJob? nativeJob;
private Exception? jobException;
- private BG_JOB_PROGRESS progress;
+ private BG_JOB_PROGRESS jobProgress;
private BG_JOB_STATE state;
private bool isJobComplete;
private int resumeAttempts;
@@ -40,7 +40,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
{
this.displayName = displayName;
nativeJob = job;
- log = serviceProvider.GetRequiredService>();
+ logger = serviceProvider.GetRequiredService>();
}
public HRESULT ErrorCode { get; private set; }
@@ -56,7 +56,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
// BG_NOTIFY_JOB_TRANSFERRED & BG_NOTIFY_JOB_ERROR & BG_NOTIFY_JOB_MODIFICATION
ppJob.SetNotifyFlags(0b1011);
- ppJob.SetNoProgressTimeout(BitsEngineNoProgressTimeout);
+ ppJob.SetNoProgressTimeout(Timeout);
ppJob.SetPriority(BG_JOB_PRIORITY.BG_JOB_PRIORITY_FOREGROUND);
ppJob.SetProxySettings(BG_JOB_PROXY_USAGE.BG_JOB_PROXY_USAGE_AUTODETECT, null, null);
}
@@ -81,7 +81,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
}
catch (Exception ex)
{
- log.LogInformation("Failed to job transfer: {message}", ex.Message);
+ logger.LogInformation("Failed to job transfer: {message}", ex.Message);
}
}
@@ -90,7 +90,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
IBackgroundCopyError error2 = error;
try
{
- log.LogInformation("Failed job: {message}", displayName);
+ logger.LogInformation("Failed job: {message}", displayName);
UpdateJobState();
BG_ERROR_CONTEXT errorContext = BG_ERROR_CONTEXT.BG_ERROR_CONTEXT_NONE;
HRESULT returnCode = new(0);
@@ -99,11 +99,11 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
ErrorCode = returnCode;
jobException = new IOException(string.Format("Error context: {0}, Error code: {1}", errorContext, returnCode));
CompleteOrCancel();
- log.LogInformation(jobException, "Job Exception:");
+ logger.LogInformation(jobException, "Job Exception:");
}
catch (Exception ex)
{
- log?.LogInformation("Failed to handle job error: {message}", ex.Message);
+ logger?.LogInformation("Failed to handle job error: {message}", ex.Message);
}
}
@@ -129,7 +129,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
return;
}
- log.LogInformation("Max resume attempts for job '{name}' exceeded. Canceling.", displayName);
+ logger.LogInformation("Max resume attempts for job '{name}' exceeded. Canceling.", displayName);
CompleteOrCancel();
}
else if (IsProgressingState(state))
@@ -143,14 +143,14 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
}
catch (Exception ex)
{
- log.LogInformation(ex, "message");
+ logger.LogInformation(ex, "message");
}
}
public void Cancel()
{
- log.LogInformation("Canceling job {name}", displayName);
- lock (lockObj)
+ logger.LogInformation("Canceling job {name}", displayName);
+ lock (syncRoot)
{
if (!isJobComplete)
{
@@ -161,16 +161,18 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
}
}
- public void WaitForCompletion(Action callback, CancellationToken cancellationToken)
+ public void WaitForCompletion(IProgress progress, CancellationToken cancellationToken)
{
CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.Register(Cancel);
int noProgressSeconds = 0;
+ int noTransferSeconds = 0;
+ ulong previousTransferred = 0;
try
{
UpdateJobState();
while (IsProgressingState(state) || state == BG_JOB_STATE.BG_JOB_STATE_QUEUED)
{
- if (noProgressSeconds > BitsEngineNoProgressTimeout)
+ if (noProgressSeconds > Timeout || noTransferSeconds > Timeout)
{
jobException = new TimeoutException($"Timeout reached for job {displayName} whilst in state {state}");
break;
@@ -183,7 +185,18 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
if (state is BG_JOB_STATE.BG_JOB_STATE_TRANSFERRING or BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED or BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED)
{
noProgressSeconds = 0;
- callback(new ProgressUpdateStatus((long)progress.BytesTransferred, (long)progress.BytesTotal));
+ if (jobProgress.BytesTransferred > previousTransferred)
+ {
+ previousTransferred = jobProgress.BytesTransferred;
+ noTransferSeconds = 0;
+ logger.LogInformation("{job}: {read} / {total}", displayName, jobProgress.BytesTransferred, jobProgress.BytesTotal);
+ progress.Report(new ProgressUpdateStatus((long)jobProgress.BytesTransferred, (long)jobProgress.BytesTotal));
+ }
+ else
+ {
+ ++noTransferSeconds;
+ logger.LogInformation("{job} no transfer for {x} seconds", displayName, noTransferSeconds);
+ }
}
// Refresh every seconds.
@@ -229,7 +242,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
return;
}
- lock (lockObj)
+ lock (syncRoot)
{
if (isJobComplete)
{
@@ -238,7 +251,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
if (state == BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED)
{
- log.LogInformation("Completing job '{name}'.", displayName);
+ logger.LogInformation("Completing job '{name}'.", displayName);
Invoke(() => nativeJob?.Complete(), "Bits Complete");
while (state == BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED)
{
@@ -248,7 +261,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
}
else
{
- log.LogInformation("Canceling job '{name}'.", displayName);
+ logger.LogInformation("Canceling job '{name}'.", displayName);
Invoke(() => nativeJob?.Cancel(), "Bits Cancel");
}
@@ -268,7 +281,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
{
if (!isJobComplete)
{
- Invoke(() => nativeJob?.GetProgress(out progress), "GetProgress");
+ Invoke(() => nativeJob?.GetProgress(out jobProgress), "GetProgress");
}
}
@@ -285,7 +298,7 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback
}
catch (Exception ex)
{
- log.LogInformation("{name} failed. {exception}", displayName, ex);
+ logger.LogInformation("{name} failed. {exception}", displayName, ex);
if (throwOnFailure)
{
throw;
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsManager.cs
index af8c2ba7..fbac1d48 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsManager.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsManager.cs
@@ -40,7 +40,7 @@ internal class BitsManager
{
TempFile tempFile = new(true);
await ThreadHelper.SwitchToBackgroundAsync();
- bool result = DownloadCore(uri, tempFile.Path, progress.Report, token);
+ bool result = DownloadCore(uri, tempFile.Path, progress, token);
return new(result, tempFile);
}
@@ -79,7 +79,7 @@ internal class BitsManager
jobsToCancel.ForEach(job => job.Cancel());
}
- private bool DownloadCore(Uri uri, string tempFile, Action progress, CancellationToken token)
+ private bool DownloadCore(Uri uri, string tempFile, IProgress progress, CancellationToken token)
{
IBackgroundCopyManager value;
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/DataTransfer/Clipboard.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/DataTransfer/Clipboard.cs
index ab54c4c5..70cec621 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/IO/DataTransfer/Clipboard.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/DataTransfer/Clipboard.cs
@@ -20,8 +20,10 @@ internal static class Clipboard
public static async Task DeserializeTextAsync(JsonSerializerOptions options)
where T : class
{
+ await ThreadHelper.SwitchToMainThreadAsync();
DataPackageView view = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
string json = await view.GetTextAsync();
+ await ThreadHelper.SwitchToBackgroundAsync();
return JsonSerializer.Deserialize(json, options);
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs
index 172de3c2..7245cfb2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs
@@ -109,7 +109,7 @@ internal static class Activation
private static async Task HandleActivationCoreAsync(AppActivationArguments args, bool isRedirected)
{
- if (args.Kind == ExtendedActivationKind.Protocol)
+ if (args.Kind == ExtendedActivationKind.Protocol)
{
if (args.TryGetProtocolActivatedUri(out Uri? uri))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs
index 08877585..e14a4ff8 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs
@@ -111,10 +111,13 @@ internal class DailyNoteService : IDailyNoteService, IRecipient();
GameRecordClient gameRecordClient = scope.ServiceProvider.GetRequiredService();
- if (appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, SettingEntryHelper.FalseString).GetBoolean()
- && scope.ServiceProvider.GetRequiredService().IsGameRunning())
+ bool isSilentMode = appDbContext.Settings
+ .SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, SettingEntryHelper.FalseString)
+ .GetBoolean();
+ bool isGameRunning = scope.ServiceProvider.GetRequiredService().IsGameRunning();
+ if (isSilentMode && isGameRunning)
{
- // Prevent notify when we are in silent mode.
+ // Prevent notify when we are in game && silent mode.
notify = false;
}
@@ -140,15 +143,18 @@ internal class DailyNoteService : IDailyNoteService, IRecipient().Warning(dailyNoteResponse.ToString());
- }
else
{
- scope.ServiceProvider.GetRequiredService().Error(dailyNoteResponse.ToString());
+ IInfoBarService infoBarService = scope.ServiceProvider.GetRequiredService();
+ // special retcode handling for dailynote
+ if (dailyNoteResponse.ReturnCode == (int)Web.Response.KnownReturnCode.CODE1034)
+ {
+ infoBarService.Warning(dailyNoteResponse.ToString());
+ }
+ else
+ {
+ infoBarService.Error(dailyNoteResponse.ToString());
+ }
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/WelcomeView.xaml b/src/Snap.Hutao/Snap.Hutao/View/WelcomeView.xaml
index b61505ab..5b7e314e 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/WelcomeView.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/WelcomeView.xaml
@@ -34,9 +34,11 @@
Text="{shcm:ResourceString Name=ViewWelcomeBody}"/>
-
-
-
+
+
+
+
+