mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
UnsafeAccessor
This commit is contained in:
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Bridge 拓展
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
{
|
||||
private const string CacheFolderName = nameof(ImageCache);
|
||||
|
||||
// TODO: use FrozenDictionary
|
||||
private static readonly FrozenDictionary<int, TimeSpan> RetryCountToDelay = new Dictionary<int, TimeSpan>()
|
||||
{
|
||||
[0] = TimeSpan.FromSeconds(4),
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
namespace Snap.Hutao.Core.DependencyInjection.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// 由于 AddHttpClient 不支持 KeyedService, 所以使用工厂模式
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient">抽象类型</typeparam>
|
||||
/// <typeparam name="TClientCN">官服/米游社类型</typeparam>
|
||||
/// <typeparam name="TClientOS">国际/HoYoLAB类型</typeparam>
|
||||
internal abstract class OverseaSupportFactory<TClient, TClientCN, TClientOS> : IOverseaSupportFactory<TClient>
|
||||
where TClientCN : notnull, TClient
|
||||
where TClientOS : notnull, TClient
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -67,4 +67,4 @@ internal static class StructExtension
|
||||
{
|
||||
return size.Width * size.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs
Normal file
19
src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs
Normal file
@@ -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);
|
||||
}
|
||||
@@ -84,7 +84,6 @@ internal sealed partial class MetadataService
|
||||
Dictionary<MaterialId, DisplayItem> displays = await FromCacheAsDictionaryAsync<MaterialId, DisplayItem>(FileNameDisplayItem, a => a.Id, token).ConfigureAwait(false);
|
||||
Dictionary<MaterialId, Material> materials = await GetIdToMaterialMapAsync(token).ConfigureAwait(false);
|
||||
|
||||
// TODO: Cache this
|
||||
Dictionary<MaterialId, DisplayItem> results = new(displays);
|
||||
|
||||
foreach ((MaterialId id, DisplayItem material) in materials)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<UserChangedMessage>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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<FightProperty, Uri> PropertyIcons = new Dictionary<FightProperty, Uri>()
|
||||
private static readonly FrozenDictionary<FightProperty, Uri> PropertyIcons = new Dictionary<FightProperty, Uri>()
|
||||
{
|
||||
[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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user