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}"/> - - - + + + + +