diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/CoreWebView2Extension.cs b/src/Snap.Hutao/Snap.Hutao/Control/Extension/WebView2Extension.cs similarity index 83% rename from src/Snap.Hutao/Snap.Hutao/Web/Bridge/CoreWebView2Extension.cs rename to src/Snap.Hutao/Snap.Hutao/Control/Extension/WebView2Extension.cs index 52e972d2..9d28ef31 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/CoreWebView2Extension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Extension/WebView2Extension.cs @@ -1,16 +1,17 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Microsoft.UI.Xaml.Controls; using Microsoft.Web.WebView2.Core; using System.Diagnostics; -namespace Snap.Hutao.Web.Bridge; +namespace Snap.Hutao.Control.Extension; /// /// Bridge 拓展 /// [HighQuality] -internal static class CoreWebView2Extension +internal static class WebView2Extension { [Conditional("RELEASE")] public static void DisableDevToolsForReleaseBuild(this CoreWebView2 webView) @@ -37,4 +38,9 @@ internal static class CoreWebView2Extension manager.DeleteCookie(item); } } + + public static bool IsDisposed(this WebView2 webView2) + { + return WinRTExtension.IsDisposed(webView2); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs b/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs index 46c03ce5..94150ea4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Caching/ImageCache.cs @@ -25,7 +25,6 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation { private const string CacheFolderName = nameof(ImageCache); - // TODO: use FrozenDictionary private static readonly FrozenDictionary RetryCountToDelay = new Dictionary() { [0] = TimeSpan.FromSeconds(4), diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Abstraction/OverseaSupportFactory.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Abstraction/OverseaSupportFactory.cs index 1d3ef60d..49d10903 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Abstraction/OverseaSupportFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/Abstraction/OverseaSupportFactory.cs @@ -3,6 +3,12 @@ namespace Snap.Hutao.Core.DependencyInjection.Abstraction; +/// +/// 由于 AddHttpClient 不支持 KeyedService, 所以使用工厂模式 +/// +/// 抽象类型 +/// 官服/米游社类型 +/// 国际/HoYoLAB类型 internal abstract class OverseaSupportFactory : IOverseaSupportFactory where TClientCN : notnull, TClient where TClientOS : notnull, TClient diff --git a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceProviderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceProviderExtension.cs index 7850ffb9..bdaafd82 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceProviderExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/ServiceProviderExtension.cs @@ -22,7 +22,7 @@ internal static class ServiceProviderExtension { if (serviceProvider is null) { - return false; + return true; } return serviceProvider.GetType().GetField("_disposed")?.GetValue(serviceProvider) is true; diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/StructExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/StructExtension.cs index c8b7f949..3d19fe1a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/StructExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/StructExtension.cs @@ -67,4 +67,4 @@ internal static class StructExtension { return size.Width * size.Height; } -} \ No newline at end of file +} diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs new file mode 100644 index 00000000..d88586a0 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs @@ -0,0 +1,19 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.Runtime.CompilerServices; +using WinRT; + +namespace Snap.Hutao.Extension; + +internal static class WinRTExtension +{ + public static bool IsDisposed(this IWinRTObject obj) + { + return GetDisposed(obj.NativeObject); + } + + // protected bool disposed; + [UnsafeAccessor(UnsafeAccessorKind.Field, Name ="disposed")] + private static extern ref bool GetDisposed(IObjectReference objRef); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs index f6b0c259..64dddd00 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs @@ -84,7 +84,6 @@ internal sealed partial class MetadataService Dictionary displays = await FromCacheAsDictionaryAsync(FileNameDisplayItem, a => a.Id, token).ConfigureAwait(false); Dictionary materials = await GetIdToMaterialMapAsync(token).ConfigureAwait(false); - // TODO: Cache this Dictionary results = new(displays); foreach ((MaterialId id, DisplayItem material) in materials) diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs index 159074db..afa1d250 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/AnnouncementContentViewer.xaml.cs @@ -4,8 +4,8 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.Web.WebView2.Core; +using Snap.Hutao.Control.Extension; using Snap.Hutao.Control.Theme; -using Snap.Hutao.Web.Bridge; using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement; using System.Text; using System.Text.RegularExpressions; diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs index 1f53bba9..26a63db1 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/WebViewer.xaml.cs @@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.Messaging; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.Web.WebView2.Core; +using Snap.Hutao.Control.Extension; using Snap.Hutao.Message; using Snap.Hutao.Service.Notification; using Snap.Hutao.Service.User; @@ -94,53 +95,52 @@ internal partial class WebViewer : UserControl, IRecipient return; } - // TODO: replace with .NET 8 UnsafeAccessor - try + if (WebView.IsDisposed()) { - CoreWebView2? coreWebView2 = WebView?.CoreWebView2; - - if (coreWebView2 is null) - { - return; - } - - if (SourceProvider is not null) - { - if (UserAndUid.TryFromUser(user, out UserAndUid? userAndUid)) - { - string source = SourceProvider.GetSource(userAndUid); - if (!string.IsNullOrEmpty(source)) - { - try - { - await coreWebView2.Profile.ClearBrowsingDataAsync(); - } - catch (InvalidCastException) - { - infoBarService.Warning(SH.ViewControlWebViewerCoreWebView2ProfileQueryInterfaceFailed); - await coreWebView2.DeleteCookiesAsync(userAndUid.IsOversea).ConfigureAwait(true); - } - - CoreWebView2Navigator navigator = new(coreWebView2); - await navigator.NavigateAsync("about:blank").ConfigureAwait(true); - - coreWebView2 - .SetCookie(user.CookieToken, user.LToken, userAndUid.IsOversea) - .SetMobileUserAgent(userAndUid.IsOversea); - jsBridge?.Detach(); - jsBridge = SourceProvider.CreateJSBridge(serviceProvider, coreWebView2, userAndUid); - - await navigator.NavigateAsync(source).ConfigureAwait(true); - } - } - else - { - infoBarService.Warning(SH.MustSelectUserAndUid); - } - } + return; } - catch (ObjectDisposedException) + + CoreWebView2? coreWebView2 = WebView?.CoreWebView2; + + if (coreWebView2 is null) { + return; + } + + if (SourceProvider is null) + { + return; + } + + if (!UserAndUid.TryFromUser(user, out UserAndUid? userAndUid)) + { + infoBarService.Warning(SH.MustSelectUserAndUid); + return; + } + + string source = SourceProvider.GetSource(userAndUid); + if (!string.IsNullOrEmpty(source)) + { + try + { + await coreWebView2.Profile.ClearBrowsingDataAsync(); + } + catch (InvalidCastException) + { + infoBarService.Warning(SH.ViewControlWebViewerCoreWebView2ProfileQueryInterfaceFailed); + await coreWebView2.DeleteCookiesAsync(userAndUid.IsOversea).ConfigureAwait(true); + } + + CoreWebView2Navigator navigator = new(coreWebView2); + await navigator.NavigateAsync("about:blank").ConfigureAwait(true); + + coreWebView2 + .SetCookie(user.CookieToken, user.LToken, userAndUid.IsOversea) + .SetMobileUserAgent(userAndUid.IsOversea); + jsBridge?.Detach(); + jsBridge = SourceProvider.CreateJSBridge(serviceProvider, coreWebView2, userAndUid); + + await navigator.NavigateAsync(source).ConfigureAwait(true); } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/ISupportLoginByWebView.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/ISupportLoginByWebView.cs index 203ca5a1..a6101a73 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/ISupportLoginByWebView.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/ISupportLoginByWebView.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control.Extension; using Snap.Hutao.Service.Navigation; using Snap.Hutao.Service.Notification; using Snap.Hutao.Service.User; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarProperty.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarProperty.cs index fd4ad553..6c35eba6 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarProperty.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarProperty.cs @@ -6,6 +6,7 @@ using Microsoft.UI.Xaml.Media; using Snap.Hutao.Control.Collection.Alternating; using Snap.Hutao.Model; using Snap.Hutao.Model.Intrinsic; +using System.Collections.Frozen; using System.Collections.Immutable; namespace Snap.Hutao.ViewModel.AvatarProperty; @@ -16,8 +17,7 @@ namespace Snap.Hutao.ViewModel.AvatarProperty; [HighQuality] internal sealed class AvatarProperty : ObservableObject, INameIcon, IAlternatingItem { - // TODO: use FrozenDictionary - private static readonly ImmutableDictionary PropertyIcons = new Dictionary() + private static readonly FrozenDictionary PropertyIcons = new Dictionary() { [FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_CDReduce.png").ToUri(), [FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_ChargeEfficiency.png").ToUri(), @@ -37,7 +37,7 @@ internal sealed class AvatarProperty : ObservableObject, INameIcon, IAlternating [FightProperty.FIGHT_PROP_MAX_HP] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_MaxHp.png").ToUri(), [FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_PhysicalAttackUp.png").ToUri(), [FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO] = Web.HutaoEndpoints.StaticFile("Property", "UI_Icon_ShieldCostMinus.png").ToUri(), - }.ToImmutableDictionary(); + }.ToFrozenDictionary(); private Brush? background; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/HoyolabCoreWebView2Extension.cs b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/HoyolabCoreWebView2Extension.cs index 7131fdcc..a9d97c86 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Bridge/HoyolabCoreWebView2Extension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Bridge/HoyolabCoreWebView2Extension.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.Web.WebView2.Core; +using Snap.Hutao.Control.Extension; using Snap.Hutao.Web.Hoyolab; namespace Snap.Hutao.Web.Bridge; diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/Announcement.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/Announcement.cs index cc3429fd..e9b03136 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/Announcement.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Common/Announcement/Announcement.cs @@ -70,7 +70,7 @@ internal sealed class Announcement : AnnouncementContent { // TODO: validate correctness // UTC+8 - DateTimeOffset currentTime = DateTimeOffset.UtcNow.AddHours(8); + DateTimeOffset currentTime = DateTimeOffset.Now; TimeSpan current = currentTime - StartTime; TimeSpan total = EndTime - StartTime; return current / total;