mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Settings folder size display
This commit is contained in:
@@ -23,6 +23,18 @@ public sealed class UnsafeRuntimeBehaviorTest
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public unsafe void UInt32LayoutIsLittleEndian()
|
||||
{
|
||||
ulong testValue = 0x1234567887654321;
|
||||
ref BuildVersion version = ref Unsafe.As<ulong, BuildVersion>(ref testValue);
|
||||
|
||||
Assert.AreEqual(0x1234, version.Major);
|
||||
Assert.AreEqual(0x5678, version.Minor);
|
||||
Assert.AreEqual(0x8765, version.Patch);
|
||||
Assert.AreEqual(0x4321, version.Build);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public unsafe void ReadOnlyStructCanBeModifiedInCtor()
|
||||
{
|
||||
@@ -34,6 +46,8 @@ public sealed class UnsafeRuntimeBehaviorTest
|
||||
Assert.AreEqual(1212, testStruct.Value4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private readonly struct TestStruct
|
||||
{
|
||||
public readonly int Value1;
|
||||
@@ -46,4 +60,12 @@ public sealed class UnsafeRuntimeBehaviorTest
|
||||
CollectionsMarshal.AsSpan(list).CopyTo(MemoryMarshal.CreateSpan(ref Unsafe.As<TestStruct, int>(ref this), 4));
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct BuildVersion
|
||||
{
|
||||
public readonly ushort Build;
|
||||
public readonly ushort Patch;
|
||||
public readonly ushort Minor;
|
||||
public readonly ushort Major;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
<SolidColorBrush x:Key="PurpleColorBrush" Color="{ThemeResource PurpleColor}"/>
|
||||
<SolidColorBrush x:Key="OrangeColorBrush" Color="{ThemeResource OrangeColor}"/>
|
||||
|
||||
<SolidColorBrush x:Key="GuaranteePullCoolorBrush" Color="{ThemeResource GuaranteePullColor}"/>
|
||||
<SolidColorBrush x:Key="GuaranteePullColorBrush" Color="{ThemeResource GuaranteePullColor}"/>
|
||||
<SolidColorBrush x:Key="UpPullColorBrush" Color="{ThemeResource UpPullColor}"/>
|
||||
|
||||
<SolidColorBrush x:Key="DarkOnlyOverlayMaskColorBrush" Color="{ThemeResource DarkOnlyOverlayMaskColor}"/>
|
||||
|
||||
@@ -18,41 +18,30 @@ namespace Snap.Hutao.Core.Caching;
|
||||
/// The class's name will become the cache folder's name
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Singleton, typeof(IImageCache))]
|
||||
[HttpClient(HttpClientConfiguration.Default)]
|
||||
[PrimaryHttpMessageHandler(MaxConnectionsPerServer = 8)]
|
||||
internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
internal sealed partial class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
{
|
||||
private const string CacheFolderName = nameof(ImageCache);
|
||||
|
||||
private static readonly FrozenDictionary<int, TimeSpan> RetryCountToDelay = new Dictionary<int, TimeSpan>()
|
||||
private readonly FrozenDictionary<int, TimeSpan> retryCountToDelay = new Dictionary<int, TimeSpan>()
|
||||
{
|
||||
[0] = TimeSpan.FromSeconds(4),
|
||||
[1] = TimeSpan.FromSeconds(16),
|
||||
[2] = TimeSpan.FromSeconds(64),
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
||||
|
||||
private readonly IHttpClientFactory httpClientFactory;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ILogger<ImageCache> logger;
|
||||
|
||||
private readonly ConcurrentDictionary<string, Task> concurrentTasks = new();
|
||||
|
||||
private string? baseFolder;
|
||||
private string? cacheFolder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageCache"/> class.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
public ImageCache(IServiceProvider serviceProvider)
|
||||
{
|
||||
logger = serviceProvider.GetRequiredService<ILogger<ImageCache>>();
|
||||
httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();
|
||||
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveInvalid()
|
||||
{
|
||||
@@ -62,7 +51,7 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
/// <inheritdoc/>
|
||||
public void Remove(Uri uriForCachedItem)
|
||||
{
|
||||
Remove(new ReadOnlySpan<Uri>(ref uriForCachedItem));
|
||||
Remove([uriForCachedItem]);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -191,7 +180,7 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
|
||||
case HttpStatusCode.TooManyRequests:
|
||||
{
|
||||
retryCount++;
|
||||
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? RetryCountToDelay[retryCount];
|
||||
TimeSpan delay = message.Headers.RetryAfter?.Delta ?? retryCountToDelay[retryCount];
|
||||
logger.LogInformation("Retry {Uri} after {Delay}.", uri, delay);
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
@@ -34,6 +34,8 @@ internal sealed class Material : DisplayItem
|
||||
/// <returns>是否为物品栏物品</returns>
|
||||
public bool IsInventoryItem()
|
||||
{
|
||||
// TODO: Add a pre-filtered metadata set to check if it's an inventory item
|
||||
|
||||
// 原质
|
||||
if (Id == 112001U)
|
||||
{
|
||||
|
||||
@@ -1565,6 +1565,9 @@
|
||||
<data name="ViewModelSettingCreateDesktopShortcutFailed" xml:space="preserve">
|
||||
<value>创建桌面快捷方式失败</value>
|
||||
</data>
|
||||
<data name="ViewModelSettingFolderSizeDescription" xml:space="preserve">
|
||||
<value>已使用磁盘空间:{0}</value>
|
||||
</data>
|
||||
<data name="ViewModelSettingGeetestCustomUrlSucceed" xml:space="preserve">
|
||||
<value>无感验证复合 Url 配置成功</value>
|
||||
</data>
|
||||
@@ -2205,7 +2208,7 @@
|
||||
<value>图片缓存 在此处存放</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCacheFolderHeader" xml:space="preserve">
|
||||
<value>打开 缓存 文件夹</value>
|
||||
<value>缓存 文件夹</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingCopyDeviceIdAction" xml:space="preserve">
|
||||
<value>复制</value>
|
||||
@@ -2232,7 +2235,7 @@
|
||||
<value>用户数据/元数据 在此处存放</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingDataFolderHeader" xml:space="preserve">
|
||||
<value>打开 数据 文件夹</value>
|
||||
<value>数据 文件夹</value>
|
||||
</data>
|
||||
<data name="ViewPageSettingDeleteCacheAction" xml:space="preserve">
|
||||
<value>删除</value>
|
||||
@@ -2525,6 +2528,9 @@
|
||||
<data name="ViewServiceHutaoUserLoginOrRegisterHint" xml:space="preserve">
|
||||
<value>立即登录或注册</value>
|
||||
</data>
|
||||
<data name="ViewSettingFolderViewOpenFolderAction" xml:space="preserve">
|
||||
<value>打开文件夹</value>
|
||||
</data>
|
||||
<data name="ViewSpiralAbyssAvatarAppearanceRankDescription" xml:space="preserve">
|
||||
<value>角色出场率 = 本层上阵该角色次数(层内重复出现只记一次)/ 深渊记录总数</value>
|
||||
</data>
|
||||
|
||||
@@ -29,7 +29,7 @@ internal sealed partial class UnityLogGameLocator : IGameLocator
|
||||
// Fallback to the CN server.
|
||||
string logFilePathFinal = File.Exists(logFilePathOversea) ? logFilePathOversea : logFilePathChinese;
|
||||
|
||||
if (TempFile.CopyFrom(logFilePathFinal) is TempFile file)
|
||||
if (TempFile.CopyFrom(logFilePathFinal) is { } file)
|
||||
{
|
||||
using (file)
|
||||
{
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<TextBlock
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource GuaranteePullCoolorBrush}"
|
||||
Foreground="{StaticResource GuaranteePullColorBrush}"
|
||||
Text="{shcm:ResourceString Name=ViewControlStatisticsCardGuaranteeText}"
|
||||
Visibility="{Binding IsGuarantee, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
<TextBlock
|
||||
|
||||
@@ -151,7 +151,12 @@
|
||||
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportMaintainerHeader}"
|
||||
Visibility="{Binding UserOptions.IsMaintainer, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
Visibility="{Binding UserOptions.IsMaintainer, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Button
|
||||
Command="{Binding OpenTestPageCommand}"
|
||||
Content="TEST"
|
||||
Style="{ThemeResource SettingButtonStyle}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Description="{Binding UserOptions.GachaLogExpireAtSlim}" Header="{shcm:ResourceString Name=ViewPageSettingHutaoPassportGachaLogExpiredAtHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
Command="{Binding Passport.OpenRedeemWebsiteCommand}"
|
||||
@@ -351,38 +356,47 @@
|
||||
</cwc:SettingsCard>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingStorageHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingStorageOpenAction}"
|
||||
Command="{Binding OpenDataFolderCommand}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingDataFolderDescription}"
|
||||
<cwc:SettingsExpander
|
||||
Description="{Binding DataFolderView.Size}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingDataFolderHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingStorageSetAction}"
|
||||
Command="{Binding SetDataFolderCommand}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingSetDataFolderDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetDataFolderHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingStorageOpenAction}"
|
||||
Command="{Binding OpenCacheFolderCommand}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingCacheFolderDescription}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<cwc:SettingsExpander.Content>
|
||||
<Button
|
||||
Command="{Binding DataFolderView.OpenFolderCommand}"
|
||||
Content="{shcm:ResourceString Name=ViewSettingFolderViewOpenFolderAction}"
|
||||
Style="{ThemeResource SettingButtonStyle}"/>
|
||||
</cwc:SettingsExpander.Content>
|
||||
<cwc:SettingsExpander.Items>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingStorageSetAction}"
|
||||
Command="{Binding SetDataFolderCommand}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingSetDataFolderDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingSetDataFolderHeader}"
|
||||
IsClickEnabled="True"/>
|
||||
</cwc:SettingsExpander.Items>
|
||||
</cwc:SettingsExpander>
|
||||
|
||||
<cwc:SettingsExpander
|
||||
Description="{Binding CacheFolderView.Size}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingCacheFolderHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingResetAction}"
|
||||
Command="{Binding ResetStaticResourceCommand}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingResetStaticResourceDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingResetStaticResourceHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<cwc:SettingsExpander.Content>
|
||||
<Button
|
||||
Command="{Binding CacheFolderView.OpenFolderCommand}"
|
||||
Content="{shcm:ResourceString Name=ViewSettingFolderViewOpenFolderAction}"
|
||||
Style="{ThemeResource SettingButtonStyle}"/>
|
||||
</cwc:SettingsExpander.Content>
|
||||
<cwc:SettingsExpander.Items>
|
||||
<cwc:SettingsCard
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingResetAction}"
|
||||
Command="{Binding ResetStaticResourceCommand}"
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingResetStaticResourceDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingResetStaticResourceHeader}"
|
||||
IsClickEnabled="True"/>
|
||||
</cwc:SettingsExpander.Items>
|
||||
</cwc:SettingsExpander>
|
||||
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource SystemFillColorCriticalBrush}"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Common;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.IO;
|
||||
using Windows.System;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Setting;
|
||||
|
||||
internal sealed partial class FolderViewModel : ObservableObject
|
||||
{
|
||||
private readonly string folder;
|
||||
private string? size;
|
||||
|
||||
public FolderViewModel(ITaskContext taskContext, string folder)
|
||||
{
|
||||
this.folder = folder;
|
||||
|
||||
SetFolderSizeAsync().SafeForget();
|
||||
|
||||
async ValueTask SetFolderSizeAsync()
|
||||
{
|
||||
long totalSize = 0;
|
||||
|
||||
foreach (string file in Directory.EnumerateFiles(folder, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
totalSize += new FileInfo(file).Length;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
Size = SH.FormatViewModelSettingFolderSizeDescription(Converters.ToFileSizeString(totalSize));
|
||||
}
|
||||
}
|
||||
|
||||
public string Folder { get => folder; }
|
||||
|
||||
public string? Size { get => size; set => SetProperty(ref size, value); }
|
||||
|
||||
[Command("OpenFolderCommand")]
|
||||
private async Task OpenDataFolderAsync()
|
||||
{
|
||||
await Launcher.LaunchFolderPathAsync(folder);
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,8 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
private NameValue<BackdropType>? selectedBackdropType;
|
||||
private NameValue<CultureInfo>? selectedCulture;
|
||||
private IPInformation? ipInformation;
|
||||
private FolderViewModel? cacheFolderView;
|
||||
private FolderViewModel? dataFolderView;
|
||||
|
||||
public AppOptions AppOptions { get => appOptions; }
|
||||
|
||||
@@ -99,10 +101,17 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
public FolderViewModel? CacheFolderView { get => cacheFolderView; set => SetProperty(ref cacheFolderView, value); }
|
||||
|
||||
public FolderViewModel? DataFolderView { get => dataFolderView; set => SetProperty(ref dataFolderView, value); }
|
||||
|
||||
public IPInformation? IPInformation { get => ipInformation; private set => SetProperty(ref ipInformation, value); }
|
||||
|
||||
protected override async ValueTask<bool> InitializeUIAsync()
|
||||
{
|
||||
CacheFolderView = new(taskContext, runtimeOptions.LocalCache);
|
||||
DataFolderView = new(taskContext, runtimeOptions.DataFolder);
|
||||
|
||||
Response<IPInformation> resp = await hutaoInfrastructureClient.GetIPInformationAsync().ConfigureAwait(false);
|
||||
IPInformation info;
|
||||
|
||||
@@ -125,7 +134,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
private static void ResetStaticResource()
|
||||
{
|
||||
StaticResource.FailAll();
|
||||
LocalSetting.Set(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.StaticResourceBegin);
|
||||
UnsafeLocalSetting.Set(SettingKeys.Major1Minor7Revision0GuideState, GuideState.StaticResourceBegin);
|
||||
AppInstance.Restart(string.Empty);
|
||||
}
|
||||
|
||||
@@ -135,6 +144,12 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
await Launcher.LaunchUriAsync(new("ms-windows-store://review/?ProductId=9PH4NXJ2JN52"));
|
||||
}
|
||||
|
||||
[Command("UpdateCheckCommand")]
|
||||
private static async Task CheckUpdateAsync()
|
||||
{
|
||||
await Launcher.LaunchUriAsync(new("ms-windows-store://pdp/?productid=9PH4NXJ2JN52"));
|
||||
}
|
||||
|
||||
[Command("SetGamePathCommand")]
|
||||
private async Task SetGamePathAsync()
|
||||
{
|
||||
@@ -199,19 +214,12 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
[Command("UpdateCheckCommand")]
|
||||
private async Task CheckUpdateAsync()
|
||||
[Command("OpenTestPageCommand")]
|
||||
private async Task OpenTestPageAsync()
|
||||
{
|
||||
if (hutaoUserOptions.IsMaintainer)
|
||||
{
|
||||
await navigationService
|
||||
.NavigateAsync<View.Page.TestPage>(INavigationAwaiter.Default)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Launcher.LaunchUriAsync(new("ms-windows-store://pdp/?productid=9PH4NXJ2JN52"));
|
||||
}
|
||||
await navigationService
|
||||
.NavigateAsync<View.Page.TestPage>(INavigationAwaiter.Default)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Command("SetDataFolderCommand")]
|
||||
@@ -240,18 +248,6 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
[Command("OpenCacheFolderCommand")]
|
||||
private async Task OpenCacheFolderAsync()
|
||||
{
|
||||
await Launcher.LaunchFolderPathAsync(runtimeOptions.LocalCache);
|
||||
}
|
||||
|
||||
[Command("OpenDataFolderCommand")]
|
||||
private async Task OpenDataFolderAsync()
|
||||
{
|
||||
await Launcher.LaunchFolderPathAsync(runtimeOptions.DataFolder);
|
||||
}
|
||||
|
||||
[Command("DeleteUsersCommand")]
|
||||
private async Task DangerousDeleteUsersAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user