Settings folder size display

This commit is contained in:
Lightczx
2023-12-08 16:19:38 +08:00
parent 859492e580
commit 3cc17375f0
10 changed files with 153 additions and 79 deletions

View File

@@ -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;
}
}

View File

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

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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>

View File

@@ -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)
{

View 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

View File

@@ -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=&#xE76C;}"
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=&#xEC25;}"
IsClickEnabled="True"/>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE76C;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingStorageSetAction}"
Command="{Binding SetDataFolderCommand}"
Description="{shcm:ResourceString Name=ViewPageSettingSetDataFolderDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingSetDataFolderHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE8DE;}"
IsClickEnabled="True"/>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE76C;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingStorageOpenAction}"
Command="{Binding OpenCacheFolderCommand}"
Description="{shcm:ResourceString Name=ViewPageSettingCacheFolderDescription}"
HeaderIcon="{shcm:FontIcon Glyph=&#xEC25;}">
<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=&#xE76C;}"
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=&#xE8B7;}"
IsClickEnabled="True"/>
<cwc:SettingsCard
ActionIcon="{shcm:FontIcon Glyph=&#xE76C;}"
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingResetAction}"
Command="{Binding ResetStaticResourceCommand}"
Description="{shcm:ResourceString Name=ViewPageSettingResetStaticResourceDescription}"
Header="{shcm:ResourceString Name=ViewPageSettingResetStaticResourceHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xEBC4;}"
IsClickEnabled="True"/>
HeaderIcon="{shcm:FontIcon Glyph=&#xE8B7;}">
<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=&#xE76C;}"
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}"

View File

@@ -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);
}
}

View File

@@ -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()
{