diff --git a/src/Snap.Hutao/.editorconfig b/src/Snap.Hutao/.editorconfig index 7fb1d9f5..55caa86a 100644 --- a/src/Snap.Hutao/.editorconfig +++ b/src/Snap.Hutao/.editorconfig @@ -10,7 +10,7 @@ csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = false:silent csharp_style_expression_bodied_indexers = false:silent -csharp_style_expression_bodied_accessors = when_on_single_line:silent +csharp_style_expression_bodied_accessors = when_on_single_line:suggestion csharp_style_expression_bodied_lambdas = when_on_single_line:silent csharp_style_expression_bodied_local_functions = false:silent csharp_style_conditional_delegate_call = true:suggestion diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Animation/AnimationDurations.cs b/src/Snap.Hutao/Snap.Hutao/Control/Animation/AnimationDurations.cs new file mode 100644 index 00000000..2e025658 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Animation/AnimationDurations.cs @@ -0,0 +1,16 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Control.Animation; + +/// +/// 动画时长 +/// +[HighQuality] +internal static class AnimationDurations +{ + /// + /// 图片缩放动画 + /// + public static readonly TimeSpan ImageZoom = TimeSpan.FromSeconds(0.5); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomInAnimation.cs b/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomInAnimation.cs index fee5136e..06df2ce0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomInAnimation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomInAnimation.cs @@ -4,6 +4,7 @@ using CommunityToolkit.WinUI.UI; using CommunityToolkit.WinUI.UI.Animations; using Microsoft.UI.Composition; +using System.Diagnostics.Contracts; using System.Numerics; namespace Snap.Hutao.Control.Animation; @@ -11,17 +12,18 @@ namespace Snap.Hutao.Control.Animation; /// /// 图片放大动画 /// -internal class ImageZoomInAnimation : ImplicitAnimation +[HighQuality] +internal sealed class ImageZoomInAnimation : ImplicitAnimation { /// /// 构造一个新的图片放大动画 /// public ImageZoomInAnimation() { + Duration = AnimationDurations.ImageZoom; EasingMode = Microsoft.UI.Xaml.Media.Animation.EasingMode.EaseOut; EasingType = CommunityToolkit.WinUI.UI.Animations.EasingType.Circle; - To = "1.1"; - Duration = TimeSpan.FromSeconds(0.5); + To = Core.StringLiterals.OnePointOne; } /// @@ -35,4 +37,4 @@ internal class ImageZoomInAnimation : ImplicitAnimation { return (To?.ToVector3(), From?.ToVector3()); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomOutAnimation.cs b/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomOutAnimation.cs index 468af39d..ecb59e66 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomOutAnimation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Animation/ImageZoomOutAnimation.cs @@ -11,17 +11,18 @@ namespace Snap.Hutao.Control.Animation; /// /// 图片缩小动画 /// -internal class ImageZoomOutAnimation : ImplicitAnimation +[HighQuality] +internal sealed class ImageZoomOutAnimation : ImplicitAnimation { /// /// 构造一个新的图片缩小动画 /// public ImageZoomOutAnimation() { + Duration = AnimationDurations.ImageZoom; EasingMode = Microsoft.UI.Xaml.Media.Animation.EasingMode.EaseOut; EasingType = CommunityToolkit.WinUI.UI.Animations.EasingType.Circle; - To = "1"; - Duration = TimeSpan.FromSeconds(0.5); + To = Core.StringLiterals.One; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs index 047c68bd..1b30b9e9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoHeightBehavior.cs @@ -9,10 +9,11 @@ namespace Snap.Hutao.Control.Behavior; /// /// 按给定比例自动调整高度的行为 /// -internal class AutoHeightBehavior : BehaviorBase +[HighQuality] +internal sealed class AutoHeightBehavior : BehaviorBase { - private static readonly DependencyProperty TargetWidthProperty = Property.Depend(nameof(TargetWidth), 1080D); - private static readonly DependencyProperty TargetHeightProperty = Property.Depend(nameof(TargetHeight), 390D); + private static readonly DependencyProperty TargetWidthProperty = Property.DependBoxed(nameof(TargetWidth), BoxedValues.DoubleOne); + private static readonly DependencyProperty TargetHeightProperty = Property.DependBoxed(nameof(TargetHeight), BoxedValues.DoubleOne); /// /// 目标宽度 @@ -35,7 +36,7 @@ internal class AutoHeightBehavior : BehaviorBase /// protected override void OnAssociatedObjectLoaded() { - UpdateElementHeight(); + UpdateElement(); AssociatedObject.SizeChanged += OnSizeChanged; } @@ -48,11 +49,11 @@ internal class AutoHeightBehavior : BehaviorBase private void OnSizeChanged(object sender, SizeChangedEventArgs e) { - UpdateElementHeight(); + UpdateElement(); } - private void UpdateElementHeight() + private void UpdateElement() { AssociatedObject.Height = (double)AssociatedObject.ActualWidth * (TargetHeight / TargetWidth); } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs index 34a57a15..6837f71f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/AutoWidthBehavior.cs @@ -9,7 +9,8 @@ namespace Snap.Hutao.Control.Behavior; /// /// 按给定比例自动调整高度的行为 /// -internal class AutoWidthBehavior : BehaviorBase +[HighQuality] +internal sealed class AutoWidthBehavior : BehaviorBase { private static readonly DependencyProperty TargetWidthProperty = Property.Depend(nameof(TargetWidth), 320D); private static readonly DependencyProperty TargetHeightProperty = Property.Depend(nameof(TargetHeight), 1024D); @@ -35,7 +36,7 @@ internal class AutoWidthBehavior : BehaviorBase /// protected override void OnAssociatedObjectLoaded() { - UpdateElementWidth(); + UpdateElement(); AssociatedObject.SizeChanged += OnSizeChanged; } @@ -48,10 +49,10 @@ internal class AutoWidthBehavior : BehaviorBase private void OnSizeChanged(object sender, SizeChangedEventArgs e) { - UpdateElementWidth(); + UpdateElement(); } - private void UpdateElementWidth() + private void UpdateElement() { AssociatedObject.Width = (double)AssociatedObject.Height * (TargetWidth / TargetHeight); } diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs index eff38f95..39ceb65a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior.cs @@ -11,7 +11,7 @@ namespace Snap.Hutao.Control.Behavior; /// AppTitleBar Workaround /// https://github.com/microsoft/microsoft-ui-xaml/issues/7756 /// -internal class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : BehaviorBase +internal sealed class ComboBoxExtendsContentIntoTitleBarWorkaroundBehavior : BehaviorBase { private readonly IMessenger messenger; diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnLoadedBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnLoadedBehavior.cs index 4a274f26..33c61d85 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnLoadedBehavior.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnLoadedBehavior.cs @@ -9,7 +9,8 @@ namespace Snap.Hutao.Control.Behavior; /// /// 在元素加载完成后执行命令的行为 /// -internal class InvokeCommandOnLoadedBehavior : BehaviorBase +[HighQuality] +internal sealed class InvokeCommandOnLoadedBehavior : BehaviorBase { private static readonly DependencyProperty CommandProperty = Property.Depend(nameof(Command)); private static readonly DependencyProperty CommandParameterProperty = Property.Depend(nameof(CommandParameter)); @@ -38,7 +39,7 @@ internal class InvokeCommandOnLoadedBehavior : BehaviorBase { if (Command != null && Command.CanExecute(CommandParameter)) { - Command?.Execute(CommandParameter); + Command.Execute(CommandParameter); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnUnloadedBehavior.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnUnloadedBehavior.cs deleted file mode 100644 index 0603e64e..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/InvokeCommandOnUnloadedBehavior.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using CommunityToolkit.WinUI.UI.Behaviors; -using Microsoft.UI.Xaml; - -namespace Snap.Hutao.Control.Behavior; - -/// -/// 在元素卸载完成后执行命令的行为 -/// -internal class InvokeCommandOnUnloadedBehavior : BehaviorBase -{ - private static readonly DependencyProperty CommandProperty = Property.Depend(nameof(Command)); - - /// - /// 待执行的命令 - /// - public ICommand Command - { - get => (ICommand)GetValue(CommandProperty); - set => SetValue(CommandProperty, value); - } - - /// - protected override void OnDetaching() - { - // 由于卸载顺序问题,必须重写此方法才能正确触发命令 - if (Command != null && Command.CanExecute(null)) - { - Command.Execute(null); - } - - base.OnDetaching(); - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/OpenAttachedFlyoutAction.cs b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/OpenAttachedFlyoutAction.cs index 2f9d4fef..d8eb0670 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Behavior/OpenAttachedFlyoutAction.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Behavior/OpenAttachedFlyoutAction.cs @@ -10,7 +10,8 @@ namespace Snap.Hutao.Control.Behavior; /// /// 打开附着的浮出控件操作 /// -internal class OpenAttachedFlyoutAction : DependencyObject, IAction +[HighQuality] +internal sealed class OpenAttachedFlyoutAction : DependencyObject, IAction { /// public object Execute(object sender, object parameter) diff --git a/src/Snap.Hutao/Snap.Hutao/Control/BindingProxy.cs b/src/Snap.Hutao/Snap.Hutao/Control/BindingProxy.cs index 5e64644e..348ef545 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/BindingProxy.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/BindingProxy.cs @@ -11,6 +11,7 @@ namespace Snap.Hutao.Control; /// DependencyObject will dispose inner ReferenceTracker in any time /// when object is not used anymore. /// +[HighQuality] public class BindingProxy : DependencyObject { private static readonly DependencyProperty DataContextProperty = Property.Depend(nameof(DataContext)); diff --git a/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs b/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs new file mode 100644 index 00000000..d9182822 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/BoxedValues.cs @@ -0,0 +1,26 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Control; + +/// +/// 封装的值 +/// +[HighQuality] +internal static class BoxedValues +{ + /// + /// 0 + /// + public static readonly object DoubleZero = 0D; + + /// + /// 0 + /// + public static readonly object DoubleOne = 1D; + + /// + /// + /// + public static readonly object True = true; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Extension/ContentDialogExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Extension/ContentDialogExtension.cs index 3bac06ef..e75bb321 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Extension/ContentDialogExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Extension/ContentDialogExtension.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Control.Extension; /// /// 对话框扩展 /// +[HighQuality] internal static class ContentDialogExtension { /// @@ -15,7 +16,7 @@ internal static class ContentDialogExtension /// /// 对话框 /// 用于恢复用户交互 - public static async ValueTask BlockAsync(this ContentDialog contentDialog) + public static async ValueTask BlockAsync(this ContentDialog contentDialog) { await ThreadHelper.SwitchToMainThreadAsync(); contentDialog.ShowAsync().AsTask().SafeForget(); @@ -25,7 +26,7 @@ internal static class ContentDialogExtension return new ContentDialogHider(contentDialog); } - private readonly struct ContentDialogHider : IAsyncDisposable + private class ContentDialogHider : IDisposable { private readonly ContentDialog contentDialog; @@ -34,12 +35,10 @@ internal static class ContentDialogExtension this.contentDialog = contentDialog; } - public async ValueTask DisposeAsync() + public void Dispose() { - await ThreadHelper.SwitchToMainThreadAsync(); - // Hide() must be called on main thread. - contentDialog.Hide(); + ThreadHelper.InvokeOnMainThread(contentDialog.Hide); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs index ab14ff26..86ccb7a9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs @@ -13,7 +13,8 @@ namespace Snap.Hutao.Control.Image; /// /// 缓存图像 /// -public class CachedImage : ImageEx +[HighQuality] +internal sealed class CachedImage : ImageEx { /// /// 构造一个新的缓存图像 @@ -22,17 +23,20 @@ public class CachedImage : ImageEx { IsCacheEnabled = true; EnableLazyLoading = true; - LazyLoadingThreshold = 500; } /// protected override async Task ProvideCachedResourceAsync(Uri imageUri, CancellationToken token) { + // We can only use Ioc to retrive IImageCache, + // no IServiceProvider is available. IImageCache imageCache = Ioc.Default.GetRequiredService(); try { Verify.Operation(imageUri.Host != string.Empty, SH.ControlImageCachedImageInvalidResourceUri); + + // BitmapImage need to be created by main thread. string file = await imageCache.GetFileFromCacheAsync(imageUri).ConfigureAwait(true); // check token state to determine whether the operation should be canceled. diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs index 7c3037b5..a27ba5d9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionExtension.cs @@ -10,8 +10,14 @@ namespace Snap.Hutao.Control.Image; /// /// 合成扩展 /// +[HighQuality] internal static class CompositionExtension { + private const string Background = nameof(Background); + private const string Foreground = nameof(Foreground); + private const string Source = nameof(Source); + private const string AlphaMask = nameof(AlphaMask); + /// /// 创建拼合图视觉对象 /// @@ -41,15 +47,15 @@ internal static class CompositionExtension { BlendEffect effect = new() { - Background = new CompositionEffectSourceParameter("Background"), - Foreground = new CompositionEffectSourceParameter("Foreground"), + Background = new CompositionEffectSourceParameter(Background), + Foreground = new CompositionEffectSourceParameter(Foreground), Mode = blendEffectMode, }; CompositionEffectBrush brush = compositor.CreateEffectFactory(effect).CreateBrush(); - brush.SetSourceParameter("Background", background); - brush.SetSourceParameter("Foreground", foreground); + brush.SetSourceParameter(Background, background); + brush.SetSourceParameter(Foreground, foreground); return brush; } @@ -66,12 +72,12 @@ internal static class CompositionExtension { GrayscaleEffect effect = new() { - Source = new CompositionEffectSourceParameter("Source"), + Source = new CompositionEffectSourceParameter(Source), }; CompositionEffectBrush brush = compositor.CreateEffectFactory(effect).CreateBrush(); - brush.SetSourceParameter("Source", source); + brush.SetSourceParameter(Source, source); return brush; } @@ -88,12 +94,12 @@ internal static class CompositionExtension { LuminanceToAlphaEffect effect = new() { - Source = new CompositionEffectSourceParameter("Source"), + Source = new CompositionEffectSourceParameter(Source), }; CompositionEffectBrush brush = compositor.CreateEffectFactory(effect).CreateBrush(); - brush.SetSourceParameter("Source", sourceBrush); + brush.SetSourceParameter(Source, sourceBrush); return brush; } @@ -112,14 +118,14 @@ internal static class CompositionExtension { AlphaMaskEffect maskEffect = new() { - AlphaMask = new CompositionEffectSourceParameter("AlphaMask"), - Source = new CompositionEffectSourceParameter("Source"), + AlphaMask = new CompositionEffectSourceParameter(AlphaMask), + Source = new CompositionEffectSourceParameter(Source), }; CompositionEffectBrush brush = compositor.CreateEffectFactory(maskEffect).CreateBrush(); - brush.SetSourceParameter("AlphaMask", alphaMask); - brush.SetSourceParameter("Source", sourceBrush); + brush.SetSourceParameter(AlphaMask, alphaMask); + brush.SetSourceParameter(Source, sourceBrush); return brush; } @@ -172,25 +178,6 @@ internal static class CompositionExtension return brush; } - /// - /// 创建一个新的蒙版画刷 - /// - /// 合成器 - /// 源 - /// 蒙版 - /// 蒙版画刷 - public static CompositionMaskBrush CompositeMaskBrush( - this Compositor compositor, - CompositionBrush source, - CompositionBrush mask) - { - CompositionMaskBrush brush = compositor.CreateMaskBrush(); - brush.Source = source; - brush.Mask = mask; - - return brush; - } - private static Vector2 GetStartPointOfDirection(GradientDirection direction) { return direction switch @@ -216,6 +203,4 @@ internal static class CompositionExtension _ => Vector2.Zero, }; } - - public record struct GradientStop(float Offset, Windows.UI.Color Color); -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs index 5f038bf8..05c57578 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/CompositionImage.cs @@ -20,10 +20,11 @@ namespace Snap.Hutao.Control.Image; /// 合成图像控件 /// 为其他图像类控件提供基类 /// +[HighQuality] public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control { private static readonly DependencyProperty SourceProperty = Property.Depend(nameof(Source), default(Uri), OnSourceChanged); - private static readonly DependencyProperty EnableLazyLoadingProperty = Property.Depend(nameof(EnableLazyLoading), true); + private static readonly DependencyProperty EnableLazyLoadingProperty = Property.DependBoxed(nameof(EnableLazyLoading), BoxedValues.True); private static readonly ConcurrentCancellationTokenSource LoadingTokenSource = new(); private readonly IServiceProvider serviceProvider; @@ -62,8 +63,8 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control /// public bool EnableLazyLoading { - get { return (bool)GetValue(EnableLazyLoadingProperty); } - set { SetValue(EnableLazyLoadingProperty, value); } + get => (bool)GetValue(EnableLazyLoadingProperty); + set => SetValue(EnableLazyLoadingProperty, value); } /// @@ -98,7 +99,31 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control spriteVisual.Size = ActualSize; } - private static void OnApplyImageFailed(Uri? uri, Exception exception) + private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg) + { + CompositionImage image = (CompositionImage)sender; + CancellationToken token = LoadingTokenSource.Register(image); + IServiceProvider serviceProvider = image.serviceProvider; + ILogger logger = serviceProvider.GetRequiredService>(); + + // source is valid + if (arg.NewValue is Uri inner && !string.IsNullOrEmpty(inner.OriginalString)) + { + // value is different from old one + if (inner != (arg.OldValue as Uri)) + { + image + .ApplyImageAsync(inner, token) + .SafeForget(logger, ex => OnApplyImageFailed(serviceProvider, inner, ex)); + } + } + else + { + image.HideAsync(token).SafeForget(logger); + } + } + + private static void OnApplyImageFailed(IServiceProvider serviceProvider, Uri? uri, Exception exception) { IInfoBarService infoBarService = Ioc.Default.GetRequiredService(); @@ -116,36 +141,15 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control } } - private static void OnSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs arg) - { - CompositionImage image = (CompositionImage)sender; - CancellationToken token = LoadingTokenSource.Register(image); - ILogger logger = Ioc.Default.GetRequiredService>(); - - // source is valid - if (arg.NewValue is Uri inner && !string.IsNullOrEmpty(inner.Host)) - { - // value is different from old one - if (inner != (arg.OldValue as Uri)) - { - image.ApplyImageInternalAsync(inner, token).SafeForget(logger, ex => OnApplyImageFailed(inner, ex)); - } - } - else - { - image.HideAsync(token).SafeForget(logger); - } - } - - private async Task ApplyImageInternalAsync(Uri? uri, CancellationToken token) + private async Task ApplyImageAsync(Uri? uri, CancellationToken token) { await HideAsync(token).ConfigureAwait(true); - LoadedImageSurface? imageSurface = null; - Compositor compositor = ElementCompositionPreview.GetElementVisual(this).Compositor; - if (uri != null) { + LoadedImageSurface? imageSurface = null; + Compositor compositor = ElementCompositionPreview.GetElementVisual(this).Compositor; + IImageCache imageCache = serviceProvider.GetRequiredService(); string file = await imageCache.GetFileFromCacheAsync(uri).ConfigureAwait(true); @@ -177,6 +181,8 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control { if (!isShow) { + isShow = true; + if (EnableLazyLoading) { await AnimationBuilder.Create().Opacity(1d, 0d).StartAsync(this, token).ConfigureAwait(true); @@ -185,8 +191,6 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control { Opacity = 1; } - - isShow = true; } } @@ -194,6 +198,8 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control { if (isShow) { + isShow = false; + if (EnableLazyLoading) { await AnimationBuilder.Create().Opacity(0d, 1d).StartAsync(this, token).ConfigureAwait(true); @@ -202,8 +208,6 @@ public abstract class CompositionImage : Microsoft.UI.Xaml.Controls.Control { Opacity = 0; } - - isShow = false; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/Gradient.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/Gradient.cs index 51ef857a..9196d9d0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/Gradient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/Gradient.cs @@ -5,6 +5,7 @@ using Microsoft.UI; using Microsoft.UI.Composition; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; +using Snap.Hutao.Win32; using System.IO; using Windows.Graphics.Imaging; using Windows.Storage.Streams; @@ -12,9 +13,10 @@ using Windows.Storage.Streams; namespace Snap.Hutao.Control.Image; /// -/// 支持渐变的图像 +/// 渐变图像 /// -public class Gradient : CompositionImage +[HighQuality] +internal sealed class Gradient : CompositionImage { private static readonly DependencyProperty BackgroundDirectionProperty = Property.Depend(nameof(BackgroundDirection), GradientDirection.TopToBottom); private static readonly DependencyProperty ForegroundDirectionProperty = Property.Depend(nameof(ForegroundDirection), GradientDirection.TopToBottom); @@ -44,7 +46,7 @@ public class Gradient : CompositionImage { if (spriteVisual is not null) { - Height = (double)Math.Clamp(ActualWidth / imageAspectRatio, 0, MaxHeight); + Height = Math.Clamp(ActualWidth / imageAspectRatio, 0D, MaxHeight); spriteVisual.Size = ActualSize; } } @@ -52,19 +54,11 @@ public class Gradient : CompositionImage /// protected override async Task LoadImageSurfaceAsync(string file, CancellationToken token) { - using (FileStream fileStream = new(file, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (IRandomAccessStream imageStream = fileStream.AsRandomAccessStream()) - { - BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream); - imageAspectRatio = decoder.PixelWidth / (double)decoder.PixelHeight; - } - } - TaskCompletionSource loadCompleteTaskSource = new(); LoadedImageSurface surface = LoadedImageSurface.StartLoadFromUri(new(file)); surface.LoadCompleted += (s, e) => loadCompleteTaskSource.TrySetResult(); await loadCompleteTaskSource.Task.ConfigureAwait(true); + imageAspectRatio = surface.NaturalSize.AspectRatio(); return surface; } diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientDirection.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientDirection.cs index c7ec0777..97f19c9f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientDirection.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientDirection.cs @@ -6,7 +6,8 @@ namespace Snap.Hutao.Control.Image; /// /// 渐变方向 /// -public enum GradientDirection +[HighQuality] +internal enum GradientDirection { /// /// 下到上 diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientStop.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientStop.cs new file mode 100644 index 00000000..6c54967a --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/GradientStop.cs @@ -0,0 +1,34 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Control.Image; + +/// +/// 渐变锚点 +/// +/// 便宜 +/// 颜色 +[HighQuality] +internal struct GradientStop +{ + /// + /// 便宜 + /// + public float Offset; + + /// + /// 颜色 + /// + public Windows.UI.Color Color; + + /// + /// 构造一个新的渐变锚点 + /// + /// 偏移 + /// 颜色 + public GradientStop(float offset, Windows.UI.Color color) + { + Offset = offset; + Color = color; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Image/MonoChrome.cs b/src/Snap.Hutao/Snap.Hutao/Control/Image/MonoChrome.cs index e1760298..fc0157ab 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Image/MonoChrome.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Image/MonoChrome.cs @@ -13,7 +13,8 @@ namespace Snap.Hutao.Control.Image; /// /// 支持单色的图像 /// -public class MonoChrome : CompositionImage +[HighQuality] +internal sealed class MonoChrome : CompositionImage { private CompositionColorBrush? backgroundBrush; @@ -56,7 +57,7 @@ public class MonoChrome : CompositionImage { ApplicationTheme.Light => Colors.Black, ApplicationTheme.Dark => Colors.White, - _ => throw Must.NeverHappen(), + _ => Colors.Transparent, }; } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Markup/BitmapIconExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Markup/BitmapIconExtension.cs index a96baba0..b8751a52 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Markup/BitmapIconExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Markup/BitmapIconExtension.cs @@ -9,8 +9,9 @@ namespace Snap.Hutao.Control.Markup; /// /// Custom which can provide values. /// +[HighQuality] [MarkupExtensionReturnType(ReturnType = typeof(BitmapIcon))] -public sealed class BitmapIconExtension : MarkupExtension +internal sealed class BitmapIconExtension : MarkupExtension { /// /// Gets or sets the representing the image to display. diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconExtension.cs index 54a566ce..ae46d329 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconExtension.cs @@ -9,8 +9,9 @@ namespace Snap.Hutao.Control.Markup; /// /// Custom which can provide values. /// +[HighQuality] [MarkupExtensionReturnType(ReturnType = typeof(FontIcon))] -internal class FontIconExtension : MarkupExtension +internal sealed class FontIconExtension : MarkupExtension { /// /// Gets or sets the value representing the icon to display. diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconSourceExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconSourceExtension.cs deleted file mode 100644 index 03949938..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Control/Markup/FontIconSourceExtension.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Markup; - -namespace Snap.Hutao.Control.Markup; - -/// -/// Custom which can provide values. -/// -[MarkupExtensionReturnType(ReturnType = typeof(FontIcon))] -internal class FontIconSourceExtension : MarkupExtension -{ - /// - /// Gets or sets the value representing the icon to display. - /// - public string Glyph { get; set; } = default!; - - /// - protected override object ProvideValue() - { - return new FontIconSource() - { - Glyph = Glyph, - }; - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs index c7a7ca36..2e71149d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Markup/ResourceStringExtension.cs @@ -8,29 +8,18 @@ namespace Snap.Hutao.Control.Markup; /// /// Xaml extension to return a value from resource file associated with a resource key /// +[HighQuality] [MarkupExtensionReturnType(ReturnType = typeof(string))] -public sealed class ResourceStringExtension : MarkupExtension +internal sealed class ResourceStringExtension : MarkupExtension { /// /// Gets or sets associated ID from resource strings. /// public string? Name { get; set; } - /// - /// Gets a string value from resource file associated with a resource key. - /// - /// Resource key name. - /// A string value from resource file associated with a resource key. - public static string GetValue(string name) - { - // This function is needed to accomodate compiled function usage without second paramater, - // which doesn't work with optional values. - return SH.ResourceManager.GetString(name)!; - } - /// protected override object ProvideValue() { - return GetValue(Name ?? string.Empty); + return SH.ResourceManager.GetString(Name ?? string.Empty) ?? Name ?? string.Empty; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Media/Bgra8.cs b/src/Snap.Hutao/Snap.Hutao/Control/Media/Bgra8.cs index da772d90..3c1fa3b8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Media/Bgra8.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Media/Bgra8.cs @@ -9,8 +9,9 @@ namespace Snap.Hutao.Control.Media; /// /// BGRA8 结构 /// +[HighQuality] [StructLayout(LayoutKind.Explicit)] -public struct Bgra8 +internal struct Bgra8 { /// /// B diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Media/Rgba8.cs b/src/Snap.Hutao/Snap.Hutao/Control/Media/Rgba8.cs index 3507c455..85aa84c8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Media/Rgba8.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Media/Rgba8.cs @@ -12,8 +12,9 @@ namespace Snap.Hutao.Control.Media; /// /// RGBA 颜色 /// +[HighQuality] [StructLayout(LayoutKind.Explicit)] -public struct Rgba8 +internal struct Rgba8 { /// /// R @@ -48,7 +49,6 @@ public struct Rgba8 /// 色值字符串 public Rgba8(ReadOnlySpan hex) { - Must.Argument(hex.Length == 8, "色值长度不为8"); R = 0; G = 0; B = 0; diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Media/SoftwareBitmapExtension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Media/SoftwareBitmapExtension.cs index 3c5e02c8..df16eec0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Media/SoftwareBitmapExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Media/SoftwareBitmapExtension.cs @@ -12,7 +12,8 @@ namespace Snap.Hutao.Control.Media; /// /// 软件位图拓展 /// -public static class SoftwareBitmapExtension +[HighQuality] +internal static class SoftwareBitmapExtension { /// /// 混合模式 正常 diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs b/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs index b77d4be3..5666d646 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/AspectRatio.cs @@ -9,12 +9,13 @@ namespace Snap.Hutao.Control.Panel; /// /// 纵横比控件 /// +[HighQuality] internal class AspectRatio : Microsoft.UI.Xaml.Controls.Control { private const double Epsilon = 2.2204460492503131e-016; - private static readonly DependencyProperty TargetWidthProperty = Property.Depend(nameof(TargetWidth), 1D); - private static readonly DependencyProperty TargetHeightProperty = Property.Depend(nameof(TargetHeight), 1D); + private static readonly DependencyProperty TargetWidthProperty = Property.DependBoxed(nameof(TargetWidth), BoxedValues.DoubleOne); + private static readonly DependencyProperty TargetHeightProperty = Property.DependBoxed(nameof(TargetHeight), BoxedValues.DoubleOne); /// /// 目标宽度 diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml b/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml index 0cf5046b..1725dee1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml @@ -1,33 +1,31 @@ - - - - - - - - - - - - - + + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml.cs b/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml.cs index 839e524f..c2028e10 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml.cs @@ -9,9 +9,12 @@ namespace Snap.Hutao.Control.Panel; /// /// 面板选择器 /// -public sealed partial class PanelSelector : UserControl +[HighQuality] +internal sealed partial class PanelSelector : SplitButton { - private static readonly DependencyProperty CurrentProperty = Property.Depend(nameof(Current), "List", OnCurrentChanged); + private const string List = nameof(List); + + private static readonly DependencyProperty CurrentProperty = Property.Depend(nameof(Current), List, OnCurrentChanged); /// /// 构造一个新的面板选择器 diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Property.cs b/src/Snap.Hutao/Snap.Hutao/Control/Property.cs index 5f275dd9..113981e3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Property.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Property.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Control; /// 快速创建 /// /// 所有者的类型 +[HighQuality] internal static class Property { /// @@ -34,6 +35,18 @@ internal static class Property return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new(defaultValue)); } + /// + /// 注册依赖属性 + /// + /// 属性的类型 + /// 属性名称 + /// 封装的默认值 + /// 注册的依赖属性 + public static DependencyProperty DependBoxed(string name, object defaultValue) + { + return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new(defaultValue)); + } + /// /// 注册依赖属性 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs index b2ef6480..4f7c10e0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/ScopedPage.cs @@ -13,8 +13,9 @@ namespace Snap.Hutao.Control; /// 表示支持取消加载的异步页面 /// 在被导航到其他页面前触发取消异步通知 /// +[HighQuality] [SuppressMessage("", "CA1001")] -public class ScopedPage : Page +internal class ScopedPage : Page { // Allow GC to Collect the IServiceScope private static readonly WeakReference PreviousScopeReference = new(null!); diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs index 35d69c02..9e902e34 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs @@ -1,7 +1,5 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -// Some part of this file came from: -// https://github.com/xunkong/desktop/tree/main/src/Desktop/Desktop/Pages/CharacterInfoPage.xaml.cs using CommunityToolkit.WinUI; using Microsoft.UI.Xaml; @@ -16,8 +14,11 @@ namespace Snap.Hutao.Control.Text; /// /// 专用于呈现描述文本的文本块 +/// Some part of this file came from: +/// https://github.com/xunkong/desktop/tree/main/src/Desktop/Desktop/Pages/CharacterInfoPage.xaml.cs /// -public class DescriptionTextBlock : ContentControl +[HighQuality] +internal sealed class DescriptionTextBlock : ContentControl { private static readonly DependencyProperty DescriptionProperty = Property.Depend(nameof(Description), string.Empty, OnDescriptionChanged); @@ -33,6 +34,7 @@ public class DescriptionTextBlock : ContentControl public DescriptionTextBlock() { IsTabStop = false; + Content = new TextBlock() { TextWrapping = TextWrapping.Wrap, diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Theme/ThemeHelper.cs b/src/Snap.Hutao/Snap.Hutao/Control/Theme/ThemeHelper.cs index d750f6f6..3d17f18b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Theme/ThemeHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Theme/ThemeHelper.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Control.Theme; /// /// 主题帮助工具类 /// +[HighQuality] public static class ThemeHelper { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Control/ValueConverter.cs b/src/Snap.Hutao/Snap.Hutao/Control/ValueConverter.cs index 17166826..6f185773 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/ValueConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/ValueConverter.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Control; /// /// 源类型 /// 目标类型 -public abstract class ValueConverter : IValueConverter +internal abstract class ValueConverter : IValueConverter { /// public object? Convert(object value, Type targetType, object parameter, string language) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/DisposableObject.cs b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/DisposableObject.cs index ff706ff5..a2268b7a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/DisposableObject.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/DisposableObject.cs @@ -3,8 +3,9 @@ namespace Snap.Hutao.Core.Abstraction; +[HighQuality] [SuppressMessage("", "SA1600")] -public abstract class DisposableObject : IDisposable +internal abstract class DisposableObject : IDisposable { public bool IsDisposed { get; private set; } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/IDeconstructable.cs b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/IDeconstructable.cs index 17250e3b..51841cad 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/IDeconstructable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/IDeconstructable.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.Abstraction; /// /// 元组的第一个类型 /// 元组的第二个类型 +[HighQuality] internal interface IDeconstructable { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/INamed.cs b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/INamedService.cs similarity index 86% rename from src/Snap.Hutao/Snap.Hutao/Core/Abstraction/INamed.cs rename to src/Snap.Hutao/Snap.Hutao/Core/Abstraction/INamedService.cs index dbc094d8..191b02c6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/INamed.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Abstraction/INamedService.cs @@ -7,7 +7,8 @@ namespace Snap.Hutao.Core.Abstraction; /// 有名称的对象 /// 指示该对象可通过名称区分 /// -internal interface INamed +[HighQuality] +internal interface INamedService { /// /// 名称 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs b/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs new file mode 100644 index 00000000..31036982 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/Annotation/HighQualityAttribute.cs @@ -0,0 +1,12 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Core.Annotation; + +/// +/// 高质量代码 +/// +[AttributeUsage(AttributeTargets.All)] +internal class HighQualityAttribute : Attribute +{ +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Annotation/LocalizationKeyAttribute.cs b/src/Snap.Hutao/Snap.Hutao/Core/Annotation/LocalizationKeyAttribute.cs index bcda0ccf..08370927 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Annotation/LocalizationKeyAttribute.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Annotation/LocalizationKeyAttribute.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.Annotation; /// /// 本地化键 /// +[HighQuality] [AttributeUsage(AttributeTargets.Field)] internal class LocalizationKeyAttribute : Attribute { @@ -22,4 +23,4 @@ internal class LocalizationKeyAttribute : Attribute /// 键 /// public string Key { get; } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs index 420a0ccc..f500af98 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCache.cs @@ -7,6 +7,7 @@ namespace Snap.Hutao.Core.Caching; /// 为图像缓存提供抽象 /// /// 缓存类型 +[HighQuality] internal interface IImageCache { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCacheFilePathOperation.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCacheFilePathOperation.cs index 02c3f75f..f6faa5d2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCacheFilePathOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/IImageCacheFilePathOperation.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.Caching; /// /// 图像缓存 文件路径操作 /// +[HighQuality] internal interface IImageCacheFilePathOperation { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs index 41e47120..c64f3ebf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs @@ -2,9 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; -using Snap.Hutao.Core.Logging; using System.Collections.Concurrent; -using System.Collections.Immutable; using System.IO; using System.Net; using System.Net.Http; @@ -18,10 +16,11 @@ namespace Snap.Hutao.Core.Caching; /// Provides methods and tools to cache files in a folder /// The class's name will become the cache folder's name /// +[HighQuality] [Injection(InjectAs.Singleton, typeof(IImageCache))] [HttpClient(HttpClientConfigration.Default)] [PrimaryHttpMessageHandler(MaxConnectionsPerServer = 8)] -public class ImageCache : IImageCache, IImageCacheFilePathOperation +public sealed class ImageCache : IImageCache, IImageCacheFilePathOperation { private const string CacheFolderName = nameof(ImageCache); @@ -89,7 +88,7 @@ public class ImageCache : IImageCache, IImageCacheFilePathOperation foreach (Uri uri in uriForCachedItems) { string filePath = Path.Combine(folder, GetCacheFileName(uri)); - if (files.Contains(filePath)) + if (Array.IndexOf(files, filePath) >= 0) { filesToDelete.Add(filePath); } @@ -113,13 +112,12 @@ public class ImageCache : IImageCache, IImageCacheFilePathOperation { await DownloadFileAsync(uri, filePath).ConfigureAwait(false); } - else + else if (concurrentTasks.TryGetValue(fileName, out Task? task)) { - if (concurrentTasks.TryGetValue(fileName, out Task? task)) - { - await task.ConfigureAwait(false); - } + await task.ConfigureAwait(false); } + + concurrentTasks.TryRemove(fileName, out _); } finally { @@ -173,7 +171,7 @@ public class ImageCache : IImageCache, IImageCacheFilePathOperation private async Task DownloadFileAsync(Uri uri, string baseFile) { - logger.LogInformation(EventIds.FileCaching, "Begin downloading for {uri}", uri); + logger.LogInformation("Begin downloading for {uri}", uri); int retryCount = 0; while (retryCount < 6) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs index 3eac4031..3d81aa7d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/CommandLineBuilder.cs @@ -8,7 +8,8 @@ namespace Snap.Hutao.Core; /// /// 命令行建造器 /// -public class CommandLineBuilder +[HighQuality] +internal sealed class CommandLineBuilder { private const char WhiteSpace = ' '; private readonly Dictionary options = new(); @@ -56,6 +57,7 @@ public class CommandLineBuilder { s.Append(WhiteSpace); s.Append(key); + if (!string.IsNullOrEmpty(value)) { s.Append(WhiteSpace); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Convert.cs b/src/Snap.Hutao/Snap.Hutao/Core/Convert.cs index 3842e83d..a9dc770f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Convert.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Convert.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core; /// /// 支持Md5转换 /// +[HighQuality] internal static class Convert { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs index 845c79c7..48a60bc9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/CoreEnvironment.cs @@ -17,6 +17,7 @@ namespace Snap.Hutao.Core; /// /// 核心环境参数 /// +[HighQuality] internal static class CoreEnvironment { /// @@ -27,7 +28,7 @@ internal static class CoreEnvironment /// /// 米游社移动端请求UA /// - public const string HoyolabMobileUA = $"Mozilla/5.0 (Linux; Android 12) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/106.0.5249.126 Mobile Safari/537.36 miHoYoBBS/{HoyolabXrpcVersion}"; + public const string HoyolabMobileUA = $"Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/{HoyolabXrpcVersion}"; /// /// 米游社 Rpc 版本 @@ -38,7 +39,7 @@ internal static class CoreEnvironment /// 盐 /// // https://github.com/UIGF-org/Hoyolab.Salt - public static readonly ImmutableDictionary DynamicSecrets = new Dictionary() + public static readonly ImmutableDictionary DynamicSecretSalts = new Dictionary() { [SaltType.K2] = "dZAwGk4e9aC0MXXItkwnHamjA1x30IYw", [SaltType.LK2] = "IEIZiKYaput2OCKQprNuGsog1NZc1FkS", @@ -47,41 +48,6 @@ internal static class CoreEnvironment [SaltType.PROD] = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS", }.ToImmutableDictionary(); - /// - /// 标准UA - /// - public static readonly string CommonUA; - - /// - /// 当前版本 - /// - public static readonly Version Version; - - /// - /// 米游社设备Id - /// - public static readonly string HoyolabDeviceId; - - /// - /// 胡桃设备Id - /// - public static readonly string HutaoDeviceId; - - /// - /// 包家族名称 - /// - public static readonly string FamilyName; - - /// - /// 安装位置 - /// - public static readonly string InstalledLocation; - - /// - /// 数据文件夹 - /// - public static readonly string DataFolder; - /// /// 默认的Json序列化选项 /// @@ -100,6 +66,41 @@ internal static class CoreEnvironment }, }; + /// + /// 当前版本 + /// + public static readonly Version Version; + + /// + /// 标准UA + /// + public static readonly string CommonUA; + + /// + /// 数据文件夹 + /// + public static readonly string DataFolder; + + /// + /// 包家族名称 + /// + public static readonly string FamilyName; + + /// + /// 米游社设备Id + /// + public static readonly string HoyolabDeviceId; + + /// + /// 胡桃设备Id + /// + public static readonly string HutaoDeviceId; + + /// + /// 安装位置 + /// + public static readonly string InstalledLocation; + private const string CryptographyKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\"; private const string MachineGuidValue = "MachineGuid"; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs index ad22f519..5959f5ad 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbCurrent.cs @@ -12,7 +12,8 @@ namespace Snap.Hutao.Core.Database; /// /// 实体的类型 /// 消息的类型 -internal class DbCurrent +[HighQuality] +internal sealed class DbCurrent where TEntity : class, ISelectable where TMessage : Message.ValueChangedMessage, new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs index 0ad3729b..f4b080ec 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/DbSetExtension.cs @@ -3,12 +3,14 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using System.Runtime.CompilerServices; namespace Snap.Hutao.Core.Database; /// /// 数据库集合扩展 /// +[HighQuality] public static class DbSetExtension { /// @@ -17,6 +19,7 @@ public static class DbSetExtension /// 实体类型 /// 数据库集 /// 对应的数据库上下文 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DbContext Context(this DbSet dbSet) where TEntity : class { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/EnumerableExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/EnumerableExtension.cs index 696de653..c7e27b18 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/EnumerableExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/EnumerableExtension.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.Database; /// /// 可枚举扩展 /// +[HighQuality] public static class EnumerableExtension { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/ISelectable.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/ISelectable.cs index 78a31204..e0701239 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/ISelectable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/ISelectable.cs @@ -5,8 +5,11 @@ namespace Snap.Hutao.Core.Database; /// /// 可选择的项 -/// 若要使用 必须实现该接口 +/// 若要使用 +/// 或 +/// 必须实现该接口 /// +[HighQuality] public interface ISelectable { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/QueryableExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/QueryableExtension.cs index 88826a69..e4e530f5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/QueryableExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/QueryableExtension.cs @@ -3,12 +3,14 @@ using Microsoft.EntityFrameworkCore; using System.Linq.Expressions; +using System.Runtime.CompilerServices; namespace Snap.Hutao.Core.Database; /// /// 可查询扩展 /// +[HighQuality] public static class QueryableExtension { /// @@ -19,6 +21,7 @@ public static class QueryableExtension /// 条件 /// 取消令牌 /// SQL返回个数 + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task ExecuteDeleteWhereAsync(this IQueryable source, Expression> predicate, CancellationToken token = default) { return source.Where(predicate).ExecuteDeleteAsync(token); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs index 88bb02b6..29199713 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/ScopedDbCurrent.cs @@ -13,12 +13,12 @@ namespace Snap.Hutao.Core.Database; /// /// 实体的类型 /// 消息的类型 -internal class ScopedDbCurrent +internal sealed class ScopedDbCurrent where TEntity : class, ISelectable where TMessage : Message.ValueChangedMessage, new() { private readonly IServiceScopeFactory scopeFactory; - private readonly Func> dbSetFunc; + private readonly Func> dbSetSelector; private readonly IMessenger messenger; private TEntity? current; @@ -27,12 +27,12 @@ internal class ScopedDbCurrent /// 构造一个新的数据库当前项 /// /// 范围工厂 - /// 数据集 + /// 数据集选择器 /// 消息器 - public ScopedDbCurrent(IServiceScopeFactory scopeFactory, Func> dbSetFunc, IMessenger messenger) + public ScopedDbCurrent(IServiceScopeFactory scopeFactory, Func> dbSetSelector, IMessenger messenger) { this.scopeFactory = scopeFactory; - this.dbSetFunc = dbSetFunc; + this.dbSetSelector = dbSetSelector; this.messenger = messenger; } @@ -52,7 +52,7 @@ internal class ScopedDbCurrent using (IServiceScope scope = scopeFactory.CreateScope()) { - DbSet dbSet = dbSetFunc(scope.ServiceProvider); + DbSet dbSet = dbSetSelector(scope.ServiceProvider); // only update when not processing a deletion if (value != null) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Database/SettingEntryHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/Database/SettingEntryExtension.cs similarity index 87% rename from src/Snap.Hutao/Snap.Hutao/Core/Database/SettingEntryHelper.cs rename to src/Snap.Hutao/Snap.Hutao/Core/Database/SettingEntryExtension.cs index 15137101..308c9944 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Database/SettingEntryHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Database/SettingEntryExtension.cs @@ -9,18 +9,9 @@ namespace Snap.Hutao.Core.Database; /// /// 设置帮助类 /// -public static class SettingEntryHelper +[HighQuality] +public static class SettingEntryExtension { - /// - /// "True" - /// - public static readonly string TrueString = true.ToString(); - - /// - /// "False" - /// - public static readonly string FalseString = false.ToString(); - /// /// 获取或添加一个对应的设置 /// @@ -35,8 +26,7 @@ public static class SettingEntryHelper if (entry == null) { entry = new(key, value); - dbSet.Add(entry); - dbSet.Context().SaveChanges(); + dbSet.AddAndSave(entry); } return entry; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs index 67ad19d0..98ac6470 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocConfiguration.cs @@ -11,6 +11,7 @@ namespace Snap.Hutao.Core.DependencyInjection; /// /// 配置 /// +[HighQuality] internal static class IocConfiguration { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs index e492b648..1a532ad2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core.DependencyInjection; /// /// 配置 /// +[HighQuality] internal static partial class IocHttpClientConfiguration { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceCollectionExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceCollectionExtension.cs index 75c79460..4ebcf5ae 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceCollectionExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceCollectionExtension.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core.DependencyInjection; /// 服务管理器 /// 依赖注入的核心管理类 /// +[HighQuality] internal static partial class ServiceCollectionExtension { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs index a524a9a7..06b90bc2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionRecorder.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml; -using Snap.Hutao.Core.Logging; using System.Collections; using System.Text; @@ -11,7 +10,8 @@ namespace Snap.Hutao.Core.ExceptionService; /// /// 异常记录器 /// -internal class ExceptionRecorder +[HighQuality] +internal sealed class ExceptionRecorder { private readonly ILogger logger; @@ -49,6 +49,6 @@ internal class ExceptionRecorder private void OnXamlBindingFailed(object? sender, BindingFailedEventArgs e) { - logger.LogCritical(EventIds.XamlBindingError, "XAML绑定失败: {message}", e.Message); + logger.LogCritical("XAML绑定失败: {message}", e.Message); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/RuntimeEnvironmentException.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/RuntimeEnvironmentException.cs index 79fad0eb..e56eb72e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/RuntimeEnvironmentException.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/RuntimeEnvironmentException.cs @@ -7,7 +7,8 @@ namespace Snap.Hutao.Core.ExceptionService; /// 运行环境异常 /// 用户的计算机中的某些设置不符合要求 /// -internal class RuntimeEnvironmentException : Exception +[HighQuality] +internal sealed class RuntimeEnvironmentException : Exception { /// /// 构造一个新的运行环境异常 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ThrowHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ThrowHelper.cs index 607ed062..7bf5d25a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ThrowHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ThrowHelper.cs @@ -10,6 +10,7 @@ namespace Snap.Hutao.Core.ExceptionService; /// /// 帮助更好的抛出异常 /// +[HighQuality] [System.Diagnostics.StackTraceHidden] internal static class ThrowHelper { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs index 217b3af7..d0860313 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs @@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.ExceptionService; /// /// 用户数据损坏异常 /// -internal class UserdataCorruptedException : Exception +[HighQuality] +internal sealed class UserdataCorruptedException : Exception { /// /// 构造一个新的用户数据损坏异常 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExpressionService/CastTo.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExpressionService/CastTo.cs index 393e3ab5..11a95fc9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExpressionService/CastTo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExpressionService/CastTo.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core.ExpressionService; /// Class to cast to type /// /// Target type +[HighQuality] public static class CastTo { /// 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 660b59cf..1707ef26 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsJob.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsJob.cs @@ -14,15 +14,16 @@ namespace Snap.Hutao.Core.IO.Bits; /// /// BITS Job /// +[HighQuality] [SuppressMessage("", "SA1600")] -internal class BitsJob : DisposableObject, IBackgroundCopyCallback +internal sealed class BitsJob : DisposableObject, IBackgroundCopyCallback { /// /// 任务名称前缀 /// public const string JobNamePrefix = "SnapHutaoBitsJob"; - private const uint Timeout = 44; + private const uint Timeout = 29; private const int MaxResumeAttempts = 3; private readonly string displayName; @@ -47,26 +48,26 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback public static BitsJob CreateJob(IServiceProvider serviceProvider, IBackgroundCopyManager backgroundCopyManager, Uri uri, string filePath) { - ILogger service = serviceProvider.GetRequiredService>(); - string text = $"{JobNamePrefix} - {uri}"; - IBackgroundCopyJob ppJob; + ILogger logger = serviceProvider.GetRequiredService>(); + string jobName = $"{JobNamePrefix} - {uri}"; + IBackgroundCopyJob job; try { - backgroundCopyManager.CreateJob(text, BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out Guid _, out ppJob); + backgroundCopyManager.CreateJob(jobName, BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out Guid _, out job); // BG_NOTIFY_JOB_TRANSFERRED & BG_NOTIFY_JOB_ERROR & BG_NOTIFY_JOB_MODIFICATION - ppJob.SetNotifyFlags(0b1011); - 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); + job.SetNotifyFlags(0B1011); + job.SetNoProgressTimeout(Timeout); + job.SetPriority(BG_JOB_PRIORITY.BG_JOB_PRIORITY_FOREGROUND); + job.SetProxySettings(BG_JOB_PROXY_USAGE.BG_JOB_PROXY_USAGE_AUTODETECT, default, default); } catch (COMException ex) { - service.LogInformation("Failed to create job. {message}", ex.Message); + logger.LogInformation("Failed to create job. {message}", ex.Message); throw; } - BitsJob bitsJob = new(serviceProvider, text, ppJob); + BitsJob bitsJob = new(serviceProvider, jobName, job); bitsJob.InitJob(uri.AbsoluteUri, filePath); return bitsJob; } @@ -115,7 +116,9 @@ internal class BitsJob : DisposableObject, IBackgroundCopyCallback if (state == BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR) { HRESULT errorCode = GetErrorCode(job); - if (errorCode == -2145844944) + + // BG_E_HTTP_ERROR_304 + if (errorCode == 0x80190130) { ErrorCode = errorCode; CompleteOrCancel(); 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 fbac1d48..d2c3f8b5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsManager.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/BitsManager.cs @@ -12,6 +12,7 @@ namespace Snap.Hutao.Core.IO.Bits; /// /// BITS 管理器 /// +[HighQuality] [Injection(InjectAs.Singleton)] internal class BitsManager { @@ -25,8 +26,8 @@ internal class BitsManager /// 服务提供器 public BitsManager(IServiceProvider serviceProvider) { - this.serviceProvider = serviceProvider; logger = serviceProvider.GetRequiredService>(); + this.serviceProvider = serviceProvider; } /// @@ -69,10 +70,14 @@ internal class BitsManager { uint actualFetched = 0; pJobs.Next(1, out IBackgroundCopyJob pJob, ref actualFetched); - pJob.GetDisplayName(out PWSTR name); - if (name.AsSpan().StartsWith(BitsJob.JobNamePrefix)) + + if (actualFetched != 0) { - jobsToCancel.Add(pJob); + pJob.GetDisplayName(out PWSTR name); + if (name.AsSpan().StartsWith(BitsJob.JobNamePrefix)) + { + jobsToCancel.Add(pJob); + } } } @@ -89,7 +94,7 @@ internal class BitsManager } catch (Exception ex) { - logger?.LogWarning("BITS download engine not supported: {message}", ex.Message); + logger.LogWarning("BITS download engine not supported: {message}", ex.Message); return false; } @@ -103,7 +108,7 @@ internal class BitsManager } catch (Exception ex) { - logger?.LogWarning(ex, "BITS download failed:"); + logger.LogWarning(ex, "BITS download failed:"); return false; } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/ProgressUpdateStatus.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/ProgressUpdateStatus.cs index f8ab9af3..b3893cde 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/ProgressUpdateStatus.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Bits/ProgressUpdateStatus.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.IO.Bits; /// /// 进度更新状态 /// +[HighQuality] [DebuggerDisplay("{BytesRead}/{TotalBytes}")] public class ProgressUpdateStatus { 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 70cec621..0c6b7f1c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/DataTransfer/Clipboard.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/DataTransfer/Clipboard.cs @@ -7,8 +7,9 @@ using Windows.Storage.Streams; namespace Snap.Hutao.Core.IO.DataTransfer; /// -/// 剪贴板 +/// 剪贴板 在主线程使用 /// +[HighQuality] internal static class Clipboard { /// @@ -23,6 +24,7 @@ internal static class Clipboard 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/IO/Digest.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Digest.cs index 28bbd29c..1cb59b3a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Digest.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Digest.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core.IO; /// /// 摘要 /// +[HighQuality] internal static class Digest { /// @@ -17,11 +18,11 @@ internal static class Digest /// 文件路径 /// 取消令牌 /// 文件 Md5 摘要 - public static async Task GetFileMd5Async(string filePath, CancellationToken token = default) + public static async Task GetFileMD5Async(string filePath, CancellationToken token = default) { using (FileStream stream = File.OpenRead(filePath)) { - return await GetStreamMd5Async(stream, token).ConfigureAwait(false); + return await GetStreamMD5Async(stream, token).ConfigureAwait(false); } } @@ -31,7 +32,7 @@ internal static class Digest /// 流 /// 取消令牌 /// 流 Md5 摘要 - public static async Task GetStreamMd5Async(Stream stream, CancellationToken token = default) + public static async Task GetStreamMD5Async(Stream stream, CancellationToken token = default) { using (MD5 md5 = MD5.Create()) { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/FileOperation.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/FileOperation.cs index bc8c261f..f0a90f3e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/FileOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/FileOperation.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.IO; /// /// 文件操作 /// +[HighQuality] internal static class FileOperation { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniComment.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniComment.cs index 22e78fd5..379c2c0e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniComment.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniComment.cs @@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.IO.Ini; /// /// Ini 注释 /// -internal class IniComment : IniElement +[HighQuality] +internal sealed class IniComment : IniElement { /// /// 构造一个新的 Ini 注释 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniElement.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniElement.cs index ae79b116..c98899b3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniElement.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniElement.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.IO.Ini; /// /// Ini 元素 /// +[HighQuality] internal abstract class IniElement { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniParameter.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniParameter.cs index 83dfe0cf..f6678d20 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniParameter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniParameter.cs @@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.IO.Ini; /// /// Ini 参数 /// -internal class IniParameter : IniElement +[HighQuality] +internal sealed class IniParameter : IniElement { /// /// Ini 参数 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSection.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSection.cs index 62075949..884b2fd7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSection.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSection.cs @@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.IO.Ini; /// /// Ini 节 /// -internal class IniSection : IniElement +[HighQuality] +internal sealed class IniSection : IniElement { /// /// 构造一个新的Ini 节 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs index bcbb8dc5..49efe952 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.IO.Ini; /// /// Ini 序列化器 /// +[HighQuality] internal static class IniSerializer { /// @@ -17,7 +18,7 @@ internal static class IniSerializer /// Ini 元素集合 public static IEnumerable Deserialize(FileStream fileStream) { - using (TextReader reader = new StreamReader(fileStream)) + using (StreamReader reader = new(fileStream)) { while (reader.ReadLine() is string line) { @@ -52,7 +53,7 @@ internal static class IniSerializer /// 元素 public static void Serialize(FileStream fileStream, IEnumerable elements) { - using (TextWriter writer = new StreamWriter(fileStream)) + using (StreamWriter writer = new(fileStream)) { foreach (IniElement element in elements) { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/TempFile.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/TempFile.cs index cd3774a2..3579ceb0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/TempFile.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/TempFile.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core.IO; /// /// 封装一个临时文件 /// +[HighQuality] internal sealed class TempFile : IDisposable { /// @@ -23,7 +24,7 @@ internal sealed class TempFile : IDisposable } catch (UnauthorizedAccessException ex) { - throw ThrowHelper.RuntimeEnvironment(SH.CoreIOTempFileCreateFail, ex); + ThrowHelper.RuntimeEnvironment(SH.CoreIOTempFileCreateFail, ex); } if (delete) @@ -42,7 +43,7 @@ internal sealed class TempFile : IDisposable /// /// 源文件 /// 临时文件 - public static TempFile? CreateFromFileCopy(string file) + public static TempFile? CreateCopyFrom(string file) { TempFile temporaryFile = new(); try diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/ConfigurableEnumConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/ConfigurableEnumConverter.cs index be099c96..b3d7c2f3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/ConfigurableEnumConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/ConfigurableEnumConverter.cs @@ -10,7 +10,8 @@ namespace Snap.Hutao.Core.Json.Converter; /// 枚举转换器 /// /// 枚举的类型 -internal class ConfigurableEnumConverter : JsonConverter +[HighQuality] +internal sealed class ConfigurableEnumConverter : JsonConverter where TEnum : struct, Enum { private readonly JsonSerializeType readAs; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs index a170d9f9..3c9a2782 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/DateTimeOffsetConverter.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.Json.Converter; /// /// 实现日期的转换 /// +[HighQuality] internal class DateTimeOffsetConverter : JsonConverter { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs index 5ddfcc75..248ee056 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/SeparatorCommaInt32EnumerableConverter.cs @@ -1,24 +1,41 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Microsoft.Extensions.Primitives; +using Snap.Hutao.Extension; + namespace Snap.Hutao.Core.Json.Converter; /// /// 逗号分隔列表转换器 /// -internal class SeparatorCommaInt32EnumerableConverter : JsonConverter> +[HighQuality] +internal sealed class SeparatorCommaInt32EnumerableConverter : JsonConverter> { + private const char Comma = ','; + /// public override IEnumerable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - string? source = reader.GetString(); - IEnumerable? ids = source?.Split(',').Select(int.Parse); - return ids ?? Enumerable.Empty(); + if (reader.GetString() is string source) + { + return EnumerateNumbers(source); + } + + return Enumerable.Empty(); } /// public override void Write(Utf8JsonWriter writer, IEnumerable value, JsonSerializerOptions options) { - writer.WriteStringValue(string.Join(',', value)); + writer.WriteStringValue(string.Join(Comma, value)); + } + + private static IEnumerable EnumerateNumbers(string source) + { + foreach (StringSegment id in new StringTokenizer(source, Comma.Enumerate().ToArray())) + { + yield return int.Parse(id.AsSpan()); + } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/StringEnumKeyDictionaryConverter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/StringEnumKeyDictionaryConverter.cs index 94701c99..8336bb16 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/StringEnumKeyDictionaryConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/Converter/StringEnumKeyDictionaryConverter.cs @@ -4,10 +4,13 @@ namespace Snap.Hutao.Core.Json.Converter; /// -/// Json字典转换器 +/// Json枚举键字典转换器 /// -public class StringEnumKeyDictionaryConverter : JsonConverterFactory +[HighQuality] +internal sealed class StringEnumKeyDictionaryConverter : JsonConverterFactory { + private readonly Type converterType = typeof(StringEnumDictionaryConverterInner<,>); + /// public override bool CanConvert(Type typeToConvert) { @@ -27,11 +30,7 @@ public class StringEnumKeyDictionaryConverter : JsonConverterFactory /// public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) { - Type[] arguments = type.GetGenericArguments(); - Type keyType = arguments[0]; - Type valueType = arguments[1]; - - Type innerConverterType = typeof(StringEnumDictionaryConverterInner<,>).MakeGenericType(keyType, valueType); + Type innerConverterType = converterType.MakeGenericType(type.GetGenericArguments()); JsonConverter converter = (JsonConverter)Activator.CreateInstance(innerConverterType)!; return converter; } @@ -71,7 +70,7 @@ public class StringEnumKeyDictionaryConverter : JsonConverterFactory string? propertyName = reader.GetString(); - if (!Enum.TryParse(propertyName, ignoreCase: false, out TKey key) && !Enum.TryParse(propertyName, ignoreCase: true, out key)) + if (!Enum.TryParse(propertyName, false, out TKey key) && !Enum.TryParse(propertyName, true, out key)) { throw new JsonException($"Unable to convert \"{propertyName}\" to Enum \"{keyType}\"."); } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs deleted file mode 100644 index 584e86d5..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTextEncoder.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using System.Text.Encodings.Web; - -namespace Snap.Hutao.Core.Json; - -/// -/// 替换 = -/// -internal class JsonTextEncoder : JavaScriptEncoder -{ - private static readonly string BackSlashDoubleQuote = "\\\""; - - /// - public override int MaxOutputCharactersPerInputCharacter { get => 6; } - - /// - public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) - { - Span textSpan = new(text, textLength); - return textSpan.IndexOf('='); - } - - /// - public override unsafe bool TryEncodeUnicodeScalar(int unicodeScalar, char* buffer, int bufferLength, out int numberOfCharactersWritten) - { - // " => \" - if (unicodeScalar == '"') - { - numberOfCharactersWritten = 2; - return BackSlashDoubleQuote.AsSpan().TryCopyTo(new Span(buffer, bufferLength)); - } - - string encoded = $"\\u{(uint)unicodeScalar:x4}"; - numberOfCharactersWritten = (encoded.Length <= (uint)bufferLength) ? encoded.Length : 0; - return encoded.AsSpan().TryCopyTo(new Span(buffer, bufferLength)); - } - - /// - public override bool WillEncode(int unicodeScalar) - { - return unicodeScalar == '='; - } -} diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTypeInfoResolvers.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTypeInfoResolvers.cs index 95849256..c371d98a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTypeInfoResolvers.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonTypeInfoResolvers.cs @@ -9,6 +9,7 @@ namespace Snap.Hutao.Core.Json; /// /// Json 类型信息解析器 /// +[HighQuality] internal static class JsonTypeInfoResolvers { private static readonly Type JsonEnumAttributeType = typeof(JsonEnumAttribute); @@ -16,22 +17,28 @@ internal static class JsonTypeInfoResolvers /// /// 解析枚举类型 /// - /// Json 类型信息 - public static void ResolveEnumType(JsonTypeInfo ti) + /// Json 类型信息 + public static void ResolveEnumType(JsonTypeInfo typeInfo) { - if (ti.Kind != JsonTypeInfoKind.Object) + if (typeInfo.Kind != JsonTypeInfoKind.Object) { return; } - IEnumerable enumProperties = ti.Properties - .Where(p => p.PropertyType.IsEnum && (p.AttributeProvider?.IsDefined(JsonEnumAttributeType, false) ?? false)); - - foreach (JsonPropertyInfo enumProperty in enumProperties) + foreach (JsonPropertyInfo property in typeInfo.Properties) { - JsonEnumAttribute attr = enumProperty.AttributeProvider!.GetCustomAttributes(false).OfType().Single(); - - enumProperty.CustomConverter = attr.CreateConverter(enumProperty); + if (property.PropertyType.IsEnum) + { + if (property.AttributeProvider is System.Reflection.ICustomAttributeProvider provider) + { + object[] attributes = provider.GetCustomAttributes(JsonEnumAttributeType, false); + if (attributes.Length == 1) + { + JsonEnumAttribute attr = (JsonEnumAttribute)attributes[0]; + property.CustomConverter = attr.CreateConverter(property); + } + } + } } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs index f14a1daa..a66a53cf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/JumpListHelper.cs @@ -9,7 +9,8 @@ namespace Snap.Hutao.Core; /// /// 跳转列表帮助类 /// -public static class JumpListHelper +[HighQuality] +internal static class JumpListHelper { /// /// 异步配置跳转列表 @@ -24,7 +25,6 @@ public static class JumpListHelper list.Items.Clear(); JumpListItem launchGameItem = JumpListItem.CreateWithArguments(Activation.LaunchGame, SH.CoreJumpListHelperLaunchGameItemDisplayName); - launchGameItem.GroupName = SH.CoreJumpListHelperLaunchGameItemGroupName; launchGameItem.Logo = new("ms-appx:///Resource/Icon/UI_GuideIcon_PlayMethod.png"); list.Items.Add(launchGameItem); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs index 6dcd3e29..8bb38bb0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs @@ -18,8 +18,24 @@ namespace Snap.Hutao.Core.LifeCycle; /// /// 激活处理器 /// +[HighQuality] internal static class Activation { + /// + /// 操作 + /// + public const string Action = nameof(Action); + + /// + /// 无操作 + /// + public const string NoAction = ""; + + /// + /// Uid + /// + public const string Uid = nameof(Uid); + /// /// 启动游戏启动参数 /// @@ -30,6 +46,10 @@ internal static class Activation /// public const string ImportUIAFFromClipBoard = "ImportUIAFFromClipBoard"; + private const string CategoryAchievement = "achievement"; + private const string CategoryDailyNote = "dailynote"; + private const string UrlActionImport = "/import"; + private const string UrlActionRefresh = "/refresh"; private static readonly SemaphoreSlim ActivateSemaphore = new(1); /// @@ -38,7 +58,7 @@ internal static class Activation /// 是否提升了权限 public static bool GetElevated() { - if (System.Diagnostics.Debugger.IsAttached) + if (Debugger.IsAttached) { return true; } @@ -86,13 +106,12 @@ internal static class Activation public static void NotificationActivate(ToastNotificationActivatedEventArgsCompat args) { ToastArguments toastArgs = ToastArguments.Parse(args.Argument); - _ = toastArgs; - if (toastArgs.TryGetValue("Action", out string? action)) + if (toastArgs.TryGetValue(Action, out string? action)) { if (action == LaunchGame) { - _ = toastArgs.TryGetValue("Uid", out string? uid); + _ = toastArgs.TryGetValue(Uid, out string? uid); HandleLaunchGameActionAsync(uid).SafeForget(); } } @@ -128,7 +147,7 @@ internal static class Activation { switch (arguments) { - case "": + case NoAction: { // Increase launch times LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1); @@ -170,14 +189,14 @@ internal static class Activation switch (category) { - case "achievement": + case CategoryAchievement: { await WaitMainWindowAsync().ConfigureAwait(false); await HandleAchievementActionAsync(action, parameter, isRedirected).ConfigureAwait(false); break; } - case "dailynote": + case CategoryDailyNote: { await HandleDailyNoteActionAsync(action, parameter, isRedirected).ConfigureAwait(false); break; @@ -191,7 +210,7 @@ internal static class Activation _ = isRedirected; switch (action) { - case "/import": + case UrlActionImport: { await ThreadHelper.SwitchToMainThreadAsync(); @@ -210,7 +229,7 @@ internal static class Activation _ = parameter; switch (action) { - case "/refresh": + case UrlActionRefresh: { await Ioc.Default .GetRequiredService() @@ -242,7 +261,8 @@ internal static class Activation { await Ioc.Default .GetRequiredService() - .NavigateAsync(INavigationAwaiter.Default, true).ConfigureAwait(false); + .NavigateAsync(INavigationAwaiter.Default, true) + .ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs index 0c42c783..4a0a3999 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs @@ -9,7 +9,8 @@ namespace Snap.Hutao.Core.LifeCycle; /// /// 扩展 /// -public static class AppActivationArgumentsExtensions +[HighQuality] +internal static class AppActivationArgumentsExtensions { /// /// 尝试获取协议启动的Uri diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppInstanceExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppInstanceExtension.cs index 1cdb6f4f..0141aea0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppInstanceExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppInstanceExtension.cs @@ -12,6 +12,7 @@ namespace Snap.Hutao.Core.LifeCycle; /// /// App 实例拓展 /// +[HighQuality] internal static class AppInstanceExtension { // Hold the reference here to prevent memory corruption. @@ -23,11 +24,12 @@ internal static class AppInstanceExtension /// app实例 /// 参数 [SuppressMessage("", "VSTHRD002")] - [SuppressMessage("", "VSTHRD110")] public static unsafe void RedirectActivationTo(this AppInstance appInstance, AppActivationArguments args) { redirectEventHandle = CreateEvent(default(SECURITY_ATTRIBUTES*), true, false, null); - Task.Run(() => + + // use ThreadPool.UnsafeQueueUserWorkItem to cancel stacktrace + ThreadPool.UnsafeQueueUserWorkItem(new(RunAction), () => { appInstance.RedirectActivationToAsync(args).AsTask().Wait(); SetEvent(redirectEventHandle); @@ -36,4 +38,9 @@ internal static class AppInstanceExtension ReadOnlySpan handles = new(in redirectEventHandle); CoWaitForMultipleObjects((uint)CWMO_FLAGS.CWMO_DEFAULT, INFINITE, handles, out uint _); } + + private static void RunAction(object? state) + { + ((Action)state!)(); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Logging/EventIds.cs b/src/Snap.Hutao/Snap.Hutao/Core/Logging/EventIds.cs deleted file mode 100644 index 5a5d8fb3..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Core/Logging/EventIds.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Core.Logging; - -/// -/// 事件Id定义 -/// -[SuppressMessage("", "SA1124")] -internal static class EventIds -{ - #region 异常 - - /// - /// 未经处理的异常 - /// - public static readonly EventId UnhandledException = 100000; - - /// - /// Forget任务执行异常 - /// - public static readonly EventId TaskException = 100001; - - /// - /// 异步命令执行异常 - /// - public static readonly EventId AsyncCommandException = 100002; - - /// - /// WebView2环境异常 - /// - public static readonly EventId WebView2EnvironmentException = 100003; - - /// - /// 缓存异常 - /// - public static readonly EventId CacheException = 100004; - - /// - /// Xaml绑定错误 - /// - public static readonly EventId XamlBindingError = 100005; - - /// - /// Xaml绑定错误 - /// - public static readonly EventId UnobservedTaskException = 100006; - - /// - /// Xaml绑定错误 - /// - public static readonly EventId HttpException = 100007; - #endregion - - #region 服务 - - /// - /// 导航历史 - /// - public static readonly EventId NavigationHistory = 100100; - - /// - /// 导航失败 - /// - public static readonly EventId NavigationFailed = 100101; - - /// - /// 元数据初始化过程 - /// - public static readonly EventId MetadataInitialization = 100110; - - /// - /// 元数据文件MD5检查 - /// - public static readonly EventId MetadataFileMD5Check = 100111; - - /// - /// 文件缓存 - /// - public static readonly EventId FileCaching = 100120; - - /// - /// 删除缓存文件 - /// - public static readonly EventId CacheRemoveFile = 100121; - - /// - /// 成就 - /// - public static readonly EventId Achievement = 100130; - - /// - /// 祈愿统计生成 - /// - public static readonly EventId GachaStatisticGeneration = 100140; - - /// - /// 祈愿统计生成 - /// - public static readonly EventId AvatarInfoGeneration = 100150; - #endregion - - #region 杂项 - - /// - /// 杂项Log - /// - public static readonly EventId CommonLog = 200000; - - /// - /// 背景状态 - /// - public static readonly EventId BackdropState = 200001; - - /// - /// 子类控制 - /// - public static readonly EventId SubClassing = 200002; - - /// - /// 窗口状态 - /// - public static readonly EventId WindowState = 200003; - #endregion -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs b/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs index 44062767..0f0db2bb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ScheduleTaskHelper.cs @@ -12,6 +12,7 @@ namespace Snap.Hutao.Core; /// /// 任务计划器服务 /// +[HighQuality] internal static class ScheduleTaskHelper { private const string DailyNoteRefreshTaskName = "SnapHutaoDailyNoteRefreshTask"; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs index d1b60676..3c621586 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.Setting; /// /// 本地设置 /// +[HighQuality] internal static class LocalSetting { private static readonly ApplicationDataContainer Container; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs index 1f7fed0a..b55885c1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.Setting; /// /// 设置键 /// +[HighQuality] internal static class SettingKeys { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/StaticResource.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/StaticResource.cs index 3e0dd7ad..56c2201b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/StaticResource.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/StaticResource.cs @@ -6,6 +6,7 @@ namespace Snap.Hutao.Core.Setting; /// /// 静态资源 /// +[HighQuality] internal static class StaticResource { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/StringLiterals.cs b/src/Snap.Hutao/Snap.Hutao/Core/StringLiterals.cs new file mode 100644 index 00000000..da733821 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/StringLiterals.cs @@ -0,0 +1,31 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Core; + +/// +/// 字符串字面量 +/// +[HighQuality] +internal static class StringLiterals +{ + /// + /// 1 + /// + public const string One = "1"; + + /// + /// 1.1 + /// + public const string OnePointOne = "1.1"; + + /// + /// True + /// + public const string True = "True"; + + /// + /// False + /// + public const string False = "False"; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaitable.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaitable.cs index 959aaa72..5803865c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaitable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaitable.cs @@ -7,7 +7,7 @@ namespace Snap.Hutao.Core.Threading.Abstraction; /// 表示一个可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 异步等待。 /// /// 用于给 await 确定返回时机的 IAwaiter 的实例。 -public interface IAwaitable +internal interface IAwaitable where TAwaiter : IAwaiter { /// @@ -23,7 +23,7 @@ public interface IAwaitable /// /// 用于给 await 确定返回时机的 的实例。 /// 异步返回的返回值类型。 -public interface IAwaitable +internal interface IAwaitable where TAwaiter : IAwaiter { /// diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaiter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaiter.cs index 427821bf..209cf34d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaiter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/IAwaiter.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.Core.Threading.Abstraction; /// /// 用于给 await 确定异步返回的时机。 /// -public interface IAwaiter : INotifyCompletion +internal interface IAwaiter : INotifyCompletion { /// /// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。 @@ -26,7 +26,7 @@ public interface IAwaiter : INotifyCompletion /// 用于给 await 确定异步返回的时机,并获取到返回值。 /// /// 异步返回的返回值类型。 -public interface IAwaiter : INotifyCompletion +internal interface IAwaiter : INotifyCompletion { /// /// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/ICriticalAwaiter.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/ICriticalAwaiter.cs index 4d0b04f2..c620b4a6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/ICriticalAwaiter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/Abstraction/ICriticalAwaiter.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.Core.Threading.Abstraction; /// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时, /// 用于给 await 确定异步返回的时机。 /// -public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion +internal interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion { } @@ -18,6 +18,6 @@ public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion /// 用于给 await 确定异步返回的时机,并获取到返回值。 /// /// 异步返回的返回值类型。 -public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion +internal interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion { } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ConcurrentCancellationTokenSource.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ConcurrentCancellationTokenSource.cs index f2faf66c..78059b0e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ConcurrentCancellationTokenSource.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ConcurrentCancellationTokenSource.cs @@ -8,6 +8,7 @@ namespace Snap.Hutao.Core.Threading; /// /// 无区分项的并发 /// +[HighQuality] [SuppressMessage("", "CA1001")] internal class ConcurrentCancellationTokenSource { @@ -29,6 +30,7 @@ internal class ConcurrentCancellationTokenSource /// 有区分项的并发 /// /// 项类型 +[HighQuality] [SuppressMessage("", "SA1402")] internal class ConcurrentCancellationTokenSource where TItem : notnull diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs index 07d4e850..9bfa00f4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatcherQueueExtension.cs @@ -8,7 +8,8 @@ namespace Snap.Hutao.Core.Threading; /// /// 调度器队列拓展 /// -public static class DispatcherQueueExtension +[HighQuality] +internal static class DispatcherQueueExtension { /// /// 在调度器队列同步调用,直到执行结束,会持续阻塞当前线程 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs index cdb43cbb..7824e608 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/DispatherQueueSwitchOperation.cs @@ -10,7 +10,8 @@ namespace Snap.Hutao.Core.Threading; /// 调度器队列切换操作 /// 等待此类型对象后上下文会被切换至主线程 /// -public readonly struct DispatherQueueSwitchOperation : IAwaitable, IAwaiter +[HighQuality] +internal readonly struct DispatherQueueSwitchOperation : IAwaitable, IAwaiter { private readonly DispatcherQueue dispatherQueue; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/SemaphoreSlimExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/SemaphoreSlimExtension.cs index 82cd2ef0..2edd7af9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/SemaphoreSlimExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/SemaphoreSlimExtension.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.Core.Threading; /// /// 信号量扩展 /// -public static class SemaphoreSlimExtension +internal static class SemaphoreSlimExtension { /// /// 异步进入信号量 @@ -16,7 +16,7 @@ public static class SemaphoreSlimExtension /// 信号量 /// 取消令牌 /// 可释放的对象,用于释放信号量 - public static async Task EnterAsync(this SemaphoreSlim semaphoreSlim, CancellationToken token = default) + public static async ValueTask EnterAsync(this SemaphoreSlim semaphoreSlim, CancellationToken token = default) { try { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskExtensions.cs index 0185acc3..c9640d2a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskExtensions.cs @@ -1,16 +1,15 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Core.Logging; - namespace Snap.Hutao.Core.Threading; /// /// 任务扩展 /// +[HighQuality] [SuppressMessage("", "VSTHRD003")] [SuppressMessage("", "VSTHRD100")] -public static class TaskExtensions +internal static class TaskExtensions { /// /// 安全的触发任务 @@ -22,10 +21,20 @@ public static class TaskExtensions { await task.ConfigureAwait(false); } +#if DEBUG catch (Exception ex) { - System.Diagnostics.Debug.WriteLine(ex); + if (System.Diagnostics.Debugger.IsAttached) + { + _ = ex; + System.Diagnostics.Debugger.Break(); + } } +#else + catch (Exception) + { + } +#endif } /// @@ -45,7 +54,7 @@ public static class TaskExtensions } catch (Exception e) { - logger?.LogError(EventIds.TaskException, e, "{caller}:\r\n{exception}", nameof(SafeForget), e.GetBaseException()); + logger?.LogError(e, "{caller}:\r\n{exception}", nameof(SafeForget), e.GetBaseException()); } } @@ -67,7 +76,7 @@ public static class TaskExtensions } catch (Exception e) { - logger?.LogError(EventIds.TaskException, e, "{caller}:\r\n{exception}", nameof(SafeForget), e.GetBaseException()); + logger?.LogError(e, "{caller}:\r\n{exception}", nameof(SafeForget), e.GetBaseException()); onException?.Invoke(e); } } @@ -91,7 +100,7 @@ public static class TaskExtensions } catch (Exception e) { - logger?.LogError(EventIds.TaskException, e, "{caller}:\r\n{exception}", nameof(SafeForget), e.GetBaseException()); + logger?.LogError(e, "{caller}:\r\n{exception}", nameof(SafeForget), e.GetBaseException()); onException?.Invoke(e); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadPoolSwitchOperation.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadPoolSwitchOperation.cs index cf2551c2..0ad09184 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadPoolSwitchOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ThreadPoolSwitchOperation.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.Core.Threading; /// 线程池切换操作 /// 等待此类型对象后上下文会被切换至线程池线程 /// -public readonly struct ThreadPoolSwitchOperation : IAwaitable, IAwaiter, ICriticalAwaiter +internal readonly struct ThreadPoolSwitchOperation : IAwaitable, IAwaiter, ICriticalAwaiter { private static readonly WaitCallback WaitCallbackRunAction = RunAction; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ValueResult.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ValueResult.cs index e61f565d..db5e455c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ValueResult.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ValueResult.cs @@ -11,7 +11,7 @@ namespace Snap.Hutao.Core.Threading; /// /// 结果类型 /// 值类型 -public readonly struct ValueResult : IDeconstructable +internal readonly struct ValueResult : IDeconstructable { /// /// 是否成功 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs index 9fa90389..0c8047d7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Validation/Must.cs @@ -8,7 +8,8 @@ namespace Snap.Hutao.Core.Validation; /// /// 封装验证方法,简化微软验证 /// -public static class Must +[HighQuality] +internal static class Must { /// /// Throws an if a condition does not evaluate to true. @@ -16,6 +17,7 @@ public static class Must /// The condition to check. /// message /// The name of the parameter to blame in the exception, if thrown. + [MethodImpl(MethodImplOptions.NoInlining)] public static void Argument([DoesNotReturnIf(false)] bool condition, string? message, [CallerArgumentExpression("condition")] string? parameterName = null) { if (!condition) @@ -30,6 +32,7 @@ public static class Must /// The condition to check. /// message /// The name of the parameter to blame in the exception, if thrown. + [MethodImpl(MethodImplOptions.NoInlining)] public static void Range([DoesNotReturnIf(false)] bool condition, string? message, [CallerArgumentExpression("condition")] string? parameterName = null) { if (!condition) @@ -44,6 +47,7 @@ public static class Must /// 上下文 /// Nothing. This method always throws. [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] public static Exception NeverHappen(string? context = null) { throw new NotSupportedException(context); @@ -57,6 +61,7 @@ public static class Must /// The name of the parameter to include in any thrown exception. /// The value of the parameter. /// Thrown if is null. + [MethodImpl(MethodImplOptions.NoInlining)] public static T NotNull([NotNull] T value, [CallerArgumentExpression("value")] string? parameterName = null) where T : class // ensures value-types aren't passed to a null checking method { diff --git a/src/Snap.Hutao/Snap.Hutao/Core/WebView2Helper.cs b/src/Snap.Hutao/Snap.Hutao/Core/WebView2Helper.cs index bca6f18d..bb6c6436 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/WebView2Helper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/WebView2Helper.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using Microsoft.Web.WebView2.Core; -using Snap.Hutao.Core.Logging; using System.IO; namespace Snap.Hutao.Core; @@ -12,6 +11,7 @@ namespace Snap.Hutao.Core; /// 不再使用注册表检查方式 /// 必须为抽象类才能使用泛型日志器 /// +[HighQuality] internal abstract class WebView2Helper { private static bool hasEverDetected; @@ -36,7 +36,7 @@ internal abstract class WebView2Helper catch (FileNotFoundException ex) { ILogger logger = Ioc.Default.GetRequiredService>(); - logger.LogError(EventIds.WebView2EnvironmentException, ex, "WebView2 Runtime not installed."); + logger.LogError(ex, "WebView2 Runtime not installed."); isSupported = false; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/AppWindowExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/AppWindowExtension.cs index f540d473..8c09ad43 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/AppWindowExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/AppWindowExtension.cs @@ -10,7 +10,8 @@ namespace Snap.Hutao.Core.Windowing; /// /// 扩展 /// -public static class AppWindowExtension +[HighQuality] +internal static class AppWindowExtension { /// /// 获取当前 的呈现矩形 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs index e4c575ad..be74e082 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/BackdropType.cs @@ -6,7 +6,8 @@ namespace Snap.Hutao.Core.Windowing; /// /// 背景类型 /// -public enum BackdropType +[HighQuality] +internal enum BackdropType { /// /// 无 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs index 957ae450..c998b871 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs @@ -2,10 +2,10 @@ // Licensed under the MIT license. using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.DependencyInjection; using Microsoft.UI; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; -using Snap.Hutao.Core.Logging; using Snap.Hutao.Extension; using Snap.Hutao.Message; using Snap.Hutao.Win32; @@ -25,12 +25,13 @@ namespace Snap.Hutao.Core.Windowing; internal sealed class ExtendedWindow : IRecipient, IRecipient where TWindow : Window, IExtendedWindowSource { - private readonly HWND handle; + private readonly HWND hwnd; private readonly AppWindow appWindow; private readonly TWindow window; private readonly FrameworkElement titleBar; + private readonly IServiceProvider serviceProvider; private readonly ILogger> logger; private readonly WindowSubclassManager subclassManager; @@ -38,24 +39,19 @@ internal sealed class ExtendedWindow : IRecipient - /// 构造一个新的扩展窗口 - /// - /// 窗口 - /// 充当标题栏的元素 - private ExtendedWindow(TWindow window, FrameworkElement titleBar) + private ExtendedWindow(TWindow window, FrameworkElement titleBar, IServiceProvider serviceProvider) { this.window = window; this.titleBar = titleBar; - logger = Ioc.Default.GetRequiredService>>(); + logger = serviceProvider.GetRequiredService>>(); + this.serviceProvider = serviceProvider; - handle = (HWND)WindowNative.GetWindowHandle(window); - - WindowId windowId = Win32Interop.GetWindowIdFromWindow(handle); + hwnd = (HWND)WindowNative.GetWindowHandle(window); + WindowId windowId = Win32Interop.GetWindowIdFromWindow(hwnd); appWindow = AppWindow.GetFromWindowId(windowId); useLegacyDragBar = !AppWindowTitleBar.IsCustomizationSupported(); - subclassManager = new(window, handle, useLegacyDragBar); + subclassManager = new(window, hwnd, useLegacyDragBar); InitializeWindow(); } @@ -64,10 +60,11 @@ internal sealed class ExtendedWindow : IRecipient /// 窗口 + /// 服务提供器 /// 实例 - public static ExtendedWindow Initialize(TWindow window) + public static ExtendedWindow Initialize(TWindow window, IServiceProvider serviceProvider) { - return new(window, window.TitleBar); + return new(window, window.TitleBar, serviceProvider); } /// @@ -77,7 +74,7 @@ internal sealed class ExtendedWindow : IRecipient : IRecipient(); - - Color systemBaseLowColor = (Color)app.Resources["SystemBaseLowColor"]; - appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor; - - Color systemBaseMediumLowColor = (Color)app.Resources["SystemBaseMediumLowColor"]; - appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor; - - // The Foreground doesn't accept Alpha channel. So we translate it to gray. - byte light = (byte)((systemBaseMediumLowColor.R + systemBaseMediumLowColor.G + systemBaseMediumLowColor.B) / 3); - byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light); - appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result); - - Color systemBaseHighColor = (Color)app.Resources["SystemBaseHighColor"]; - appTitleBar.ButtonForegroundColor = systemBaseHighColor; - appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor; - appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor; - } - private static (string PosString, string SizeString) GetPostionAndSize(AppWindow appWindow) { PointInt32 pos = appWindow.Position; @@ -131,7 +104,7 @@ internal sealed class ExtendedWindow : IRecipient : IRecipient), subClassApplied ? "succeed" : "failed"); + logger.LogInformation("Apply {name} : {result}", nameof(WindowSubclassManager), subClassApplied ? "succeed" : "failed"); IMessenger messenger = Ioc.Default.GetRequiredService(); messenger.Register(this); @@ -177,11 +150,35 @@ internal sealed class ExtendedWindow : IRecipient UpdateDragRectangles(appTitleBar); titleBar.ActualThemeChanged += (s, e) => UpdateTitleButtonColor(appTitleBar); + titleBar.SizeChanged += (s, e) => UpdateDragRectangles(appTitleBar); } } + private void UpdateTitleButtonColor(AppWindowTitleBar appTitleBar) + { + appTitleBar.ButtonBackgroundColor = Colors.Transparent; + appTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; + + App app = serviceProvider.GetRequiredService(); + + Color systemBaseLowColor = (Color)app.Resources["SystemBaseLowColor"]; + appTitleBar.ButtonHoverBackgroundColor = systemBaseLowColor; + + Color systemBaseMediumLowColor = (Color)app.Resources["SystemBaseMediumLowColor"]; + appTitleBar.ButtonPressedBackgroundColor = systemBaseMediumLowColor; + + // The Foreground doesn't accept Alpha channel. So we translate it to gray. + byte light = (byte)((systemBaseMediumLowColor.R + systemBaseMediumLowColor.G + systemBaseMediumLowColor.B) / 3); + byte result = (byte)((systemBaseMediumLowColor.A / 255.0) * light); + appTitleBar.ButtonInactiveForegroundColor = Color.FromArgb(0xFF, result, result, result); + + Color systemBaseHighColor = (Color)app.Resources["SystemBaseHighColor"]; + appTitleBar.ButtonForegroundColor = systemBaseHighColor; + appTitleBar.ButtonHoverForegroundColor = systemBaseHighColor; + appTitleBar.ButtonPressedForegroundColor = systemBaseHighColor; + } + private void UpdateDragRectangles(AppWindowTitleBar appTitleBar, bool isFlyoutOpened = false) { if (isFlyoutOpened) @@ -191,7 +188,7 @@ internal sealed class ExtendedWindow : IRecipient /// 窗体持久化 /// +[HighQuality] internal static class Persistence { /// @@ -40,7 +41,7 @@ internal static class Persistence } } - TransformToCenterScreen(&rect); + TransformToCenterScreen(ref rect); appWindow.MoveAndResize(rect); } @@ -78,13 +79,13 @@ internal static class Persistence return new((int)(size.Width * scale), (int)(size.Height * scale)); } - private static unsafe void TransformToCenterScreen(RectInt32* rect) + private static void TransformToCenterScreen(ref RectInt32 rect) { - DisplayArea displayArea = DisplayArea.GetFromRect(*rect, DisplayAreaFallback.Primary); + DisplayArea displayArea = DisplayArea.GetFromRect(rect, DisplayAreaFallback.Primary); RectInt32 workAreaRect = displayArea.WorkArea; - rect->X = workAreaRect.X + ((workAreaRect.Width - rect->Width) / 2); - rect->Y = workAreaRect.Y + ((workAreaRect.Height - rect->Height) / 2); + rect.X = workAreaRect.X + ((workAreaRect.Width - rect.Width) / 2); + rect.Y = workAreaRect.Y + ((workAreaRect.Height - rect.Height) / 2); } [StructLayout(LayoutKind.Explicit)] diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/SystemBackdrop.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/SystemBackdrop.cs index 51f1693d..237172dd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/SystemBackdrop.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/SystemBackdrop.cs @@ -18,7 +18,7 @@ namespace Snap.Hutao.Core.Windowing; /// /// 系统背景帮助类 /// -public class SystemBackdrop +internal sealed class SystemBackdrop { private readonly Window window; diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs index 43443f26..4fd2ec38 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs @@ -13,7 +13,8 @@ namespace Snap.Hutao.Core.Windowing; /// 窗体子类管理器 /// /// 窗体类型 -internal class WindowSubclassManager : IDisposable +[HighQuality] +internal sealed class WindowSubclassManager : IDisposable where TWindow : Window, IExtendedWindowSource { private const int WindowSubclassId = 101; diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/StringBuilderExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Extension/StringBuilderExtensions.cs index dfa068fb..1e565ffb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/StringBuilderExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/StringBuilderExtensions.cs @@ -33,4 +33,4 @@ public static class StringBuilderExtensions { return condition ? sb.Append(value) : sb; } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/GlobalUsing.cs b/src/Snap.Hutao/Snap.Hutao/GlobalUsing.cs index 0d09504f..ac60a663 100644 --- a/src/Snap.Hutao/Snap.Hutao/GlobalUsing.cs +++ b/src/Snap.Hutao/Snap.Hutao/GlobalUsing.cs @@ -9,6 +9,7 @@ global using Microsoft; global using Microsoft.Extensions.Logging; // Snap.Hutao +global using Snap.Hutao.Core.Annotation; global using Snap.Hutao.Core.DependencyInjection; global using Snap.Hutao.Core.DependencyInjection.Annotation; global using Snap.Hutao.Core.Threading; diff --git a/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs index 0000ae2a..b4e10849 100644 --- a/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/LaunchGameWindow.xaml.cs @@ -31,9 +31,9 @@ public sealed partial class LaunchGameWindow : Window, IDisposable, IExtendedWin public LaunchGameWindow(IServiceScopeFactory scopeFactory) { InitializeComponent(); - ExtendedWindow.Initialize(this); scope = scopeFactory.CreateScope(); + ExtendedWindow.Initialize(this, scope.ServiceProvider); RootGrid.DataContext = scope.ServiceProvider.GetRequiredService(); Closed += (s, e) => Dispose(); } diff --git a/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs b/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs index 17a18be0..babcbd8b 100644 --- a/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/MainWindow.xaml.cs @@ -24,10 +24,11 @@ public sealed partial class MainWindow : Window, IExtendedWindowSource, IRecipie /// /// 构造一个新的主窗体 /// - public MainWindow() + /// 服务提供器 + public MainWindow(IServiceProvider serviceProvider) { InitializeComponent(); - ExtendedWindow.Initialize(this); + ExtendedWindow.Initialize(this, serviceProvider); IsPresent = true; Closed += (s, e) => IsPresent = false; diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index 2b1ec29f..e22f8897 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="1.4.15.0" /> Snap Hutao diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs index a74cbd80..6c873d2c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using Snap.Hutao.Core.Diagnostics; -using Snap.Hutao.Core.Logging; using Snap.Hutao.Model.Binding.AvatarProperty; using Snap.Hutao.Model.Binding.User; using Snap.Hutao.Model.Entity.Database; @@ -120,7 +119,7 @@ internal class AvatarInfoService : IAvatarInfoService { ValueStopwatch stopwatch = ValueStopwatch.StartNew(); Summary summary = await summaryFactory.CreateAsync(info, avatarInfos, token).ConfigureAwait(false); - logger.LogInformation(EventIds.AvatarInfoGeneration, "AvatarInfoSummary Generation toke {time} ms.", stopwatch.GetElapsedTime().TotalMilliseconds); + logger.LogInformation("AvatarInfoSummary Generation toke {time} ms.", stopwatch.GetElapsedTime().TotalMilliseconds); return summary; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs index ec667d64..cd6c6d57 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotifier.cs @@ -173,7 +173,7 @@ internal class DailyNoteNotifier .AddArgument("Uid", entry.Uid)) .AddButton(new ToastButtonDismiss(SH.ServiceDailyNoteNotifierActionLaunchGameDismiss)); - if (appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, SettingEntryHelper.FalseString).GetBoolean()) + if (appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, Core.StringLiterals.False).GetBoolean()) { builder.SetToastScenario(ToastScenario.Reminder); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs index d11f0d21..113564dc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteService.cs @@ -112,7 +112,7 @@ internal class DailyNoteService : IDailyNoteService, IRecipient(); bool isSilentMode = appDbContext.Settings - .SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, SettingEntryHelper.FalseString) + .SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, Core.StringLiterals.False) .GetBoolean(); bool isGameRunning = scope.ServiceProvider.GetRequiredService().IsGameRunning(); if (isSilentMode && isGameRunning) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs index 34ff18f1..0d640338 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs @@ -50,7 +50,7 @@ internal class GachaStatisticsFactory : IGachaStatisticsFactory List historyWishBuilders = gachaevents.Select(g => new HistoryWishBuilder(g, nameAvatarMap, nameWeaponMap)).ToList(); SettingEntry entry = await appDbContext.Settings - .SingleOrAddAsync(SettingEntry.IsEmptyHistoryWishVisible, SettingEntryHelper.TrueString) + .SingleOrAddAsync(SettingEntry.IsEmptyHistoryWishVisible, Core.StringLiterals.True) .ConfigureAwait(false); bool isEmptyHistoryWishVisible = entry.GetBoolean(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs index 38acef09..c92dc05c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs @@ -7,7 +7,6 @@ using Microsoft.EntityFrameworkCore; using Snap.Hutao.Core.Database; using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.ExceptionService; -using Snap.Hutao.Core.Logging; using Snap.Hutao.Extension; using Snap.Hutao.Model.Binding.Gacha; using Snap.Hutao.Model.Binding.Gacha.Abstraction; @@ -164,7 +163,7 @@ internal class GachaLogService : IGachaLogService GachaStatistics statistics = await gachaStatisticsFactory.CreateAsync(items).ConfigureAwait(false); - logger.LogInformation(EventIds.GachaStatisticGeneration, "GachaStatistic Generation toke {time} ms.", stopwatch.GetElapsedTime().TotalMilliseconds); + logger.LogInformation("GachaStatistic Generation toke {time} ms.", stopwatch.GetElapsedTime().TotalMilliseconds); return statistics; } else diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryWebCacheProvider.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryWebCacheProvider.cs index 5c285a2c..0f6da2e9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryWebCacheProvider.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryWebCacheProvider.cs @@ -52,7 +52,7 @@ internal class GachaLogQueryWebCacheProvider : IGachaLogQueryProvider { string cacheFile = GetCacheFile(path); - using (TempFile? tempFile = TempFile.CreateFromFileCopy(cacheFile)) + using (TempFile? tempFile = TempFile.CreateCopyFrom(cacheFile)) { if (tempFile == null) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/IGachaLogQueryProvider.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/IGachaLogQueryProvider.cs index 8e2cf63a..8b32983b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/IGachaLogQueryProvider.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/IGachaLogQueryProvider.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider; /// /// 祈愿记录Url提供器 /// -internal interface IGachaLogQueryProvider : INamed +internal interface IGachaLogQueryProvider : INamedService { /// /// 异步获取包含验证密钥的查询语句 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/IGameLocator.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/IGameLocator.cs index a37671c8..943655c6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/IGameLocator.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/IGameLocator.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.Service.Game.Locator; /// /// 游戏位置定位器 /// -internal interface IGameLocator : INamed +internal interface IGameLocator : INamedService { /// /// 异步获取游戏位置 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/UnityLogGameLocator.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/UnityLogGameLocator.cs index 3a3a8293..ad70be1e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/UnityLogGameLocator.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/UnityLogGameLocator.cs @@ -28,7 +28,7 @@ internal partial class UnityLogGameLocator : IGameLocator // We need to fallback the the cn server rather than os server. string logFilePathFinal = File.Exists(logFilePathOvsesea) ? logFilePathOvsesea : logFilePathChinese; - using (TempFile? tempFile = TempFile.CreateFromFileCopy(logFilePathFinal)) + using (TempFile? tempFile = TempFile.CreateCopyFrom(logFilePathFinal)) { if (tempFile != null) { 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 a67c05bf..bc901517 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs @@ -287,7 +287,7 @@ internal class PackageConverter { if (File.Exists(cacheFilePath)) { - string remoteMd5 = await Digest.GetFileMd5Async(cacheFilePath).ConfigureAwait(false); + string remoteMd5 = await Digest.GetFileMD5Async(cacheFilePath).ConfigureAwait(false); if (info.Md5 == remoteMd5.ToLowerInvariant() && new FileInfo(cacheFilePath).Length == info.TotalBytes) { // Valid, move it to target path @@ -316,7 +316,7 @@ internal class PackageConverter { await CopyToWithProgressAsync(webStream, fileStream, info.Target, totalBytes, progress).ConfigureAwait(false); fileStream.Seek(0, SeekOrigin.Begin); - string remoteMd5 = await Digest.GetStreamMd5Async(fileStream).ConfigureAwait(false); + string remoteMd5 = await Digest.GetStreamMD5Async(fileStream).ConfigureAwait(false); if (info.Md5 == remoteMd5.ToLowerInvariant()) { return; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs index 9974c5f3..2b37aded 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs @@ -6,7 +6,6 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.IO; -using Snap.Hutao.Core.Logging; using Snap.Hutao.Extension; using Snap.Hutao.Service.Abstraction; using System.IO; @@ -73,13 +72,18 @@ internal partial class MetadataService : IMetadataService, IMetadataServiceIniti /// public async Task InitializeInternalAsync(CancellationToken token = default) { + if (isInitialized) + { + return; + } + ValueStopwatch stopwatch = ValueStopwatch.StartNew(); - logger.LogInformation(EventIds.MetadataInitialization, "Metadata initializaion begin"); + logger.LogInformation("Metadata initializaion begin"); isInitialized = await TryUpdateMetadataAsync(token).ConfigureAwait(false); initializeCompletionSource.TrySetResult(); - logger.LogInformation(EventIds.MetadataInitialization, "Metadata initializaion completed in {time}ms", stopwatch.GetElapsedTime().TotalMilliseconds); + logger.LogInformation("Metadata initializaion completed in {time}ms", stopwatch.GetElapsedTime().TotalMilliseconds); } private async Task TryUpdateMetadataAsync(CancellationToken token) @@ -135,7 +139,7 @@ internal partial class MetadataService : IMetadataService, IMetadataServiceIniti string fileFullPath = Path.Combine(metadataFolderPath, fileFullName); if (File.Exists(fileFullPath)) { - skip = md5 == await Digest.GetFileMd5Async(fileFullPath, token).ConfigureAwait(false); + skip = md5 == await Digest.GetFileMD5Async(fileFullPath, token).ConfigureAwait(false); } if (!skip) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs index 3fb67243..61fb12ce 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/User/IUserService.cs @@ -11,7 +11,7 @@ namespace Snap.Hutao.Service.User; /// /// 用户服务 /// -public interface IUserService +internal interface IUserService { /// /// 获取或设置当前用户 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementArchiveCreateDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementArchiveCreateDialog.xaml.cs index 95ca9702..9b1aadee 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementArchiveCreateDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementArchiveCreateDialog.xaml.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.View.Dialog; /// /// 成就存档创建对话框 /// -public sealed partial class AchievementArchiveCreateDialog : ContentDialog +internal sealed partial class AchievementArchiveCreateDialog : ContentDialog { /// /// 构造一个新的成就存档创建对话框 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementImportDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementImportDialog.xaml.cs index 3ccea45b..21f9ccf0 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementImportDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/AchievementImportDialog.xaml.cs @@ -12,7 +12,7 @@ namespace Snap.Hutao.View.Dialog; /// /// 成就对话框 /// -public sealed partial class AchievementImportDialog : ContentDialog +internal sealed partial class AchievementImportDialog : ContentDialog { private static readonly DependencyProperty UIAFProperty = Property.Depend(nameof(UIAF), default(UIAF)); diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivateProjectDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivateProjectDialog.xaml.cs index 3c02e24a..d17d7e72 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivateProjectDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivateProjectDialog.xaml.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.View.Dialog; /// /// ɼƻԻ /// -public sealed partial class CultivateProjectDialog : ContentDialog +internal sealed partial class CultivateProjectDialog : ContentDialog { /// /// һµɼƻԻ diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml.cs index 53fa5415..f1ced5e4 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/CultivatePromotionDeltaDialog.xaml.cs @@ -11,7 +11,7 @@ namespace Snap.Hutao.View.Dialog; /// /// ɼԻ /// -public sealed partial class CultivatePromotionDeltaDialog : ContentDialog +internal sealed partial class CultivatePromotionDeltaDialog : ContentDialog { private static readonly DependencyProperty AvatarProperty = Property.Depend(nameof(Avatar)); private static readonly DependencyProperty WeaponProperty = Property.Depend(nameof(Weapon)); diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs index 7efd9db3..f9de79ec 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/GachaLogUrlDialog.xaml.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.View.Dialog; /// /// 祈愿记录Url对话框 /// -public sealed partial class GachaLogUrlDialog : ContentDialog +internal sealed partial class GachaLogUrlDialog : ContentDialog { /// /// 初始化一个新的祈愿记录Url对话框 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGameAccountNameDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGameAccountNameDialog.xaml.cs index f4bba16b..83083137 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGameAccountNameDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/LaunchGameAccountNameDialog.xaml.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.View.Dialog; /// /// 游戏账号命名对话框 /// -public sealed partial class LaunchGameAccountNameDialog : ContentDialog +internal sealed partial class LaunchGameAccountNameDialog : ContentDialog { /// /// 构造一个新的游戏账号命名对话框 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserDialog.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserDialog.xaml.cs index 8fa0a41d..fda3338d 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserDialog.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Dialog/UserDialog.xaml.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.View.Dialog; /// /// 添加用户对话框 /// -public sealed partial class UserDialog : ContentDialog +internal sealed partial class UserDialog : ContentDialog { /// /// 构造一个新的添加用户对话框 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml.cs index e80d6330..fc53e3cc 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 成就页面 /// -public sealed partial class AchievementPage : ScopedPage +internal sealed partial class AchievementPage : ScopedPage { /// /// 构造一个新的成就页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml.cs index 3303fb0b..c5a230ab 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AnnouncementPage.xaml.cs @@ -11,7 +11,7 @@ namespace Snap.Hutao.View.Page; /// /// 公告页面 /// -public sealed partial class AnnouncementPage : ScopedPage +internal sealed partial class AnnouncementPage : ScopedPage { /// /// 构造一个新的公告页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml.cs index b7c5b05c..225cb047 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 角色属性页 /// -public sealed partial class AvatarPropertyPage : ScopedPage +internal sealed partial class AvatarPropertyPage : ScopedPage { /// /// 初始化一个新的角色属性页 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml.cs index 6ee32d28..d330df96 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/CultivationPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// ҳ /// -public sealed partial class CultivationPage : ScopedPage +internal sealed partial class CultivationPage : ScopedPage { /// /// һµҳ diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml.cs index 50e230e1..d407c0c0 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 实时便笺页面 /// -public sealed partial class DailyNotePage : ScopedPage +internal sealed partial class DailyNotePage : ScopedPage { /// /// 构造一个新的实时便笺页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml.cs index 2f4e462e..6fcdc4a4 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/GachaLogPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 祈愿记录页面 /// -public sealed partial class GachaLogPage : ScopedPage +internal sealed partial class GachaLogPage : ScopedPage { /// /// 构造一个新的祈愿记录页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs index ef29fdb6..f8774b6a 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 胡桃数据库页面 /// -public sealed partial class HutaoDatabasePage : ScopedPage +internal sealed partial class HutaoDatabasePage : ScopedPage { /// /// 构造一个新的胡桃数据库页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml index 65dd9ccb..1f2e5bae 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml @@ -2,6 +2,7 @@ x:Class="Snap.Hutao.View.Page.LaunchGamePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:cwub="using:CommunityToolkit.WinUI.UI.Behaviors" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mxi="using:Microsoft.Xaml.Interactivity" @@ -266,6 +267,10 @@ + + + + -public sealed partial class LaunchGamePage : ScopedPage +internal sealed partial class LaunchGamePage : ScopedPage { /// /// 构造一个新的启动游戏页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LoginMihoyoUserPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/LoginMihoyoUserPage.xaml.cs index ea65fa0e..25f53196 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/LoginMihoyoUserPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LoginMihoyoUserPage.xaml.cs @@ -16,7 +16,7 @@ namespace Snap.Hutao.View.Page; /// /// 登录米哈游通行证页面 /// -public sealed partial class LoginMihoyoUserPage : Microsoft.UI.Xaml.Controls.Page +internal sealed partial class LoginMihoyoUserPage : Microsoft.UI.Xaml.Controls.Page { /// /// 构造一个新的登录米哈游通行证页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml.cs index 5444cf72..7b6a50cd 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 设置页面 /// -public sealed partial class SettingPage : ScopedPage +internal sealed partial class SettingPage : ScopedPage { /// /// 构造新的设置页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/SpiralAbyssRecordPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/SpiralAbyssRecordPage.xaml.cs index a71602e3..0a0f234c 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/SpiralAbyssRecordPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/SpiralAbyssRecordPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 深渊记录页面 /// -public sealed partial class SpiralAbyssRecordPage : ScopedPage +internal sealed partial class SpiralAbyssRecordPage : ScopedPage { /// /// 构造一个新的深渊记录页面 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/TestPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/TestPage.xaml.cs index 8a6ed07f..0b9eabbc 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/TestPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/TestPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// ҳ /// -public sealed partial class TestPage : ScopedPage +internal sealed partial class TestPage : ScopedPage { /// /// һµIJҳ diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml.cs index 84d4a9f9..c68f2a15 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// 角色资料页 /// -public sealed partial class WikiAvatarPage : ScopedPage +internal sealed partial class WikiAvatarPage : ScopedPage { /// /// 构造一个新的角色资料页 diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml.cs index a31f7351..8f5ada2e 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiWeaponPage.xaml.cs @@ -9,7 +9,7 @@ namespace Snap.Hutao.View.Page; /// /// ҳ /// -public sealed partial class WikiWeaponPage : ScopedPage +internal sealed partial class WikiWeaponPage : ScopedPage { /// /// һµҳ diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs index 53785195..9d295ffe 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs @@ -128,7 +128,7 @@ internal class AchievementImporter .CreateForIndeterminateProgressAsync(SH.ViewModelAchievementImportProgress) .ConfigureAwait(false); - await using (await dialog.BlockAsync().ConfigureAwait(false)) + using (await dialog.BlockAsync().ConfigureAwait(false)) { result = await achievementService.ImportFromUIAFAsync(archive, uiaf.List, strategy).ConfigureAwait(false); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs index f4ef7cfc..028174b9 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarPropertyViewModel.cs @@ -155,8 +155,7 @@ internal class AvatarPropertyViewModel : Abstraction.ViewModel .CreateForIndeterminateProgressAsync(SH.ViewModelAvatarPropertyFetch) .ConfigureAwait(false); - await ThreadHelper.SwitchToMainThreadAsync(); - await using (await dialog.BlockAsync().ConfigureAwait(false)) + using (await dialog.BlockAsync().ConfigureAwait(false)) { summaryResult = await serviceProvider .GetRequiredService() diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs index 917d1284..9f185fc7 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs @@ -193,11 +193,11 @@ internal class DailyNoteViewModel : Abstraction.ViewModel OnPropertyChanged(nameof(SelectedRefreshTime)); ScheduleTaskHelper.RegisterForDailyNoteRefresh(refreshSeconds); - reminderNotifyEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, SettingEntryHelper.FalseString); + reminderNotifyEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, Core.StringLiterals.False); isReminderNotification = reminderNotifyEntry.GetBoolean(); OnPropertyChanged(nameof(IsReminderNotification)); - silentModeEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, SettingEntryHelper.FalseString); + silentModeEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, Core.StringLiterals.False); isSilentWhenPlayingGame = silentModeEntry.GetBoolean(); OnPropertyChanged(nameof(IsSilentWhenPlayingGame)); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs index a55b7919..7e203818 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLogViewModel.cs @@ -195,7 +195,7 @@ internal class GachaLogViewModel : Abstraction.ViewModel // ContentDialog must be created by main thread. await ThreadHelper.SwitchToMainThreadAsync(); GachaLogRefreshProgressDialog dialog = new(); - IAsyncDisposable dialogHider = await dialog.BlockAsync().ConfigureAwait(false); + IDisposable dialogHider = await dialog.BlockAsync().ConfigureAwait(false); Progress progress = new(dialog.OnReport); bool authkeyValid; @@ -225,7 +225,7 @@ internal class GachaLogViewModel : Abstraction.ViewModel if (authkeyValid) { SetSelectedArchiveAndUpdateStatistics(gachaLogService.CurrentArchive, true); - await dialogHider.DisposeAsync().ConfigureAwait(false); + dialogHider.Dispose(); } else { @@ -369,7 +369,7 @@ internal class GachaLogViewModel : Abstraction.ViewModel if (uigf.IsValidList()) { ContentDialog dialog = await contentDialogFactory.CreateForIndeterminateProgressAsync(SH.ViewModelGachaLogImportProgress).ConfigureAwait(true); - await using (await dialog.BlockAsync().ConfigureAwait(false)) + using (await dialog.BlockAsync().ConfigureAwait(false)) { await gachaLogService.ImportFromUIGFAsync(uigf.List, uigf.Info.Uid).ConfigureAwait(false); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs index 7bd7fc35..b91b494e 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs @@ -22,7 +22,6 @@ using Snap.Hutao.Web.Hoyolab.Takumi.Binding; using System.Collections.ObjectModel; using System.IO; using Windows.Graphics; -using static Snap.Hutao.Core.Database.SettingEntryHelper; namespace Snap.Hutao.ViewModel; @@ -250,10 +249,10 @@ internal class LaunchGameViewModel : Abstraction.ViewModel { DbSet settings = appDbContext.Settings; - isFullScreen = settings.SingleOrAdd(SettingEntry.LaunchIsFullScreen, TrueString).GetBoolean(); + isFullScreen = settings.SingleOrAdd(SettingEntry.LaunchIsFullScreen, Core.StringLiterals.True).GetBoolean(); OnPropertyChanged(nameof(IsFullScreen)); - isBorderless = settings.SingleOrAdd(SettingEntry.LaunchIsBorderless, FalseString).GetBoolean(); + isBorderless = settings.SingleOrAdd(SettingEntry.LaunchIsBorderless, Core.StringLiterals.False).GetBoolean(); OnPropertyChanged(nameof(IsBorderless)); RectInt32 primaryRect = DisplayArea.Primary.OuterBounds; @@ -264,7 +263,7 @@ internal class LaunchGameViewModel : Abstraction.ViewModel screenHeight = settings.SingleOrAdd(SettingEntry.LaunchScreenHeight, $"{primaryRect.Height}").GetInt32(); OnPropertyChanged(nameof(ScreenHeight)); - unlockFps = settings.SingleOrAdd(SettingEntry.LaunchUnlockFps, FalseString).GetBoolean(); + unlockFps = settings.SingleOrAdd(SettingEntry.LaunchUnlockFps, Core.StringLiterals.False).GetBoolean(); OnPropertyChanged(nameof(UnlockFps)); targetFps = settings.SingleOrAdd(SettingEntry.LaunchTargetFps, "60").GetInt32(); @@ -274,12 +273,12 @@ internal class LaunchGameViewModel : Abstraction.ViewModel private void SaveSetting() { DbSet settings = appDbContext.Settings; - settings.SingleOrAdd(SettingEntry.LaunchIsExclusive, FalseString).SetBoolean(IsExclusive); - settings.SingleOrAdd(SettingEntry.LaunchIsFullScreen, FalseString).SetBoolean(IsFullScreen); - settings.SingleOrAdd(SettingEntry.LaunchIsBorderless, FalseString).SetBoolean(IsBorderless); + settings.SingleOrAdd(SettingEntry.LaunchIsExclusive, Core.StringLiterals.False).SetBoolean(IsExclusive); + settings.SingleOrAdd(SettingEntry.LaunchIsFullScreen, Core.StringLiterals.False).SetBoolean(IsFullScreen); + settings.SingleOrAdd(SettingEntry.LaunchIsBorderless, Core.StringLiterals.False).SetBoolean(IsBorderless); settings.SingleOrAdd(SettingEntry.LaunchScreenWidth, "1920").SetInt32(ScreenWidth); settings.SingleOrAdd(SettingEntry.LaunchScreenHeight, "1080").SetInt32(ScreenHeight); - settings.SingleOrAdd(SettingEntry.LaunchUnlockFps, FalseString).SetBoolean(UnlockFps); + settings.SingleOrAdd(SettingEntry.LaunchUnlockFps, Core.StringLiterals.False).SetBoolean(UnlockFps); settings.SingleOrAdd(SettingEntry.LaunchTargetFps, "60").SetInt32(TargetFps); appDbContext.SaveChanges(); } @@ -303,7 +302,7 @@ internal class LaunchGameViewModel : Abstraction.ViewModel await ThreadHelper.SwitchToMainThreadAsync(); LaunchGamePackageConvertDialog dialog = new(); Progress progress = new(state => dialog.State = state.Clone()); - await using (await dialog.BlockAsync().ConfigureAwait(false)) + using (await dialog.BlockAsync().ConfigureAwait(false)) { if (!await gameService.EnsureGameResourceAsync(SelectedScheme, progress).ConfigureAwait(false)) { diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs index b211a6db..a41c72aa 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs @@ -57,7 +57,7 @@ internal class SettingViewModel : Abstraction.ViewModel Experimental = serviceProvider.GetRequiredService(); this.serviceProvider = serviceProvider; - isEmptyHistoryWishVisibleEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.IsEmptyHistoryWishVisible, SettingEntryHelper.TrueString); + isEmptyHistoryWishVisibleEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.IsEmptyHistoryWishVisible, Core.StringLiterals.False); IsEmptyHistoryWishVisible = bool.Parse(isEmptyHistoryWishVisibleEntry.Value!); selectedBackdropTypeEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.SystemBackdropType, BackdropType.Mica.ToString()); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs index 41218a0f..ff39ea7a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/MiHoYoJSInterface.cs @@ -122,7 +122,7 @@ public class MiHoYoJSInterface /// 响应 public virtual JsResult> GetDynamicSecrectV1(JsParam param) { - string salt = Core.CoreEnvironment.DynamicSecrets[SaltType.LK2]; + string salt = Core.CoreEnvironment.DynamicSecretSalts[SaltType.LK2]; long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); string r = GetRandomString(); string check = Core.Convert.ToMd5HexString($"salt={salt}&t={t}&r={r}").ToLowerInvariant(); @@ -152,7 +152,7 @@ public class MiHoYoJSInterface /// 响应 public virtual JsResult> GetDynamicSecrectV2(JsParam param) { - string salt = Core.CoreEnvironment.DynamicSecrets[SaltType.X4]; + string salt = Core.CoreEnvironment.DynamicSecretSalts[SaltType.X4]; long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); int r = GetRandom(); string b = param.Payload.Body; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs index 9fd7a1cc..c13e7110 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/DynamicSecretHandler.cs @@ -27,7 +27,7 @@ public class DynamicSecretHandler : DelegatingHandler private static async Task ProcessRequestWithOptionsAsync(HttpRequestMessage request, DynamicSecretCreationOptions options, CancellationToken token) { - string salt = Core.CoreEnvironment.DynamicSecrets[options.SaltType]; + string salt = Core.CoreEnvironment.DynamicSecretSalts[options.SaltType]; long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabHttpClientExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabHttpClientExtensions.cs index 9b29cb43..6cb7bfd3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabHttpClientExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HoyolabHttpClientExtensions.cs @@ -25,17 +25,17 @@ internal static class HoyolabHttpClientExtensions httpClient.DefaultRequestHeaders.Remove("Cookie"); StringBuilder stringBuilder = new(); - if ((cookie & CookieType.CookieToken) == CookieType.CookieToken) + if (cookie.HasFlag(CookieType.CookieToken)) { stringBuilder.Append(user.CookieToken).AppendIf(user.CookieToken != null, ';'); } - if ((cookie & CookieType.Ltoken) == CookieType.Ltoken) + if (cookie.HasFlag(CookieType.Ltoken)) { stringBuilder.Append(user.Ltoken).AppendIf(user.Ltoken != null, ';'); } - if ((cookie & CookieType.Stoken) == CookieType.Stoken) + if (cookie.HasFlag(CookieType.Stoken)) { stringBuilder.Append(user.Stoken).AppendIf(user.Stoken != null, ';'); } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtensions.cs index 61aecb37..544b29f5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/HttpClientExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Core.Logging; using System.IO; using System.Net.Http; using System.Net.Http.Json; @@ -12,8 +11,11 @@ namespace Snap.Hutao.Web; /// /// 扩展 /// +[HighQuality] internal static class HttpClientExtensions { + private const string RequestErrorMessage = "请求异常已忽略"; + /// internal static async Task TryCatchGetFromJsonAsync(this HttpClient httpClient, string requestUri, JsonSerializerOptions options, ILogger logger, CancellationToken token = default) where T : class @@ -24,22 +26,22 @@ internal static class HttpClientExtensions } catch (HttpRequestException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } catch (IOException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } catch (JsonException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } catch (SocketException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } } @@ -55,22 +57,22 @@ internal static class HttpClientExtensions } catch (HttpRequestException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } catch (IOException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } catch (JsonException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } catch (SocketException ex) { - logger.LogWarning(EventIds.HttpException, ex, "请求异常已忽略"); + logger.LogWarning(ex, RequestErrorMessage); return null; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/StructExtension.cs b/src/Snap.Hutao/Snap.Hutao/Win32/StructExtension.cs index 1fa785da..194be857 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/StructExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/StructExtension.cs @@ -10,6 +10,16 @@ namespace Snap.Hutao.Win32; /// internal static class StructExtension { + /// + /// 转换到宽高比 + /// + /// 尺寸 + /// 宽高比 + public static double AspectRatio(this Windows.Foundation.Size size) + { + return size.Width / size.Height; + } + /// /// 比例缩放 ///