mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
1 Commits
feat/IFile
...
feat/fix_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2874ce291 |
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Control.Builder.ButtonBase;
|
||||
|
||||
internal class ButtonBaseBuilder<TButton> : IButtonBaseBuilder<TButton>
|
||||
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase, new()
|
||||
{
|
||||
public TButton Button { get; } = new();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
|
||||
namespace Snap.Hutao.Control.Builder.ButtonBase;
|
||||
|
||||
internal static class ButtonBaseBuilderExtension
|
||||
{
|
||||
public static TBuilder SetContent<TBuilder, TButton>(this TBuilder builder, object? content)
|
||||
where TBuilder : IButtonBaseBuilder<TButton>
|
||||
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase
|
||||
{
|
||||
builder.Configure(builder => builder.Button.Content = content);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static TBuilder SetCommand<TBuilder, TButton>(this TBuilder builder, ICommand command)
|
||||
where TBuilder : IButtonBaseBuilder<TButton>
|
||||
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase
|
||||
{
|
||||
builder.Configure(builder => builder.Button.Command = command);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Builder.ButtonBase;
|
||||
|
||||
internal sealed class ButtonBuilder : ButtonBaseBuilder<Button>;
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Builder.ButtonBase;
|
||||
|
||||
internal static class ButtonBuilderExtension
|
||||
{
|
||||
public static ButtonBuilder SetContent(this ButtonBuilder builder, object? content)
|
||||
{
|
||||
return builder.SetContent<ButtonBuilder, Button>(content);
|
||||
}
|
||||
|
||||
public static ButtonBuilder SetCommand(this ButtonBuilder builder, ICommand command)
|
||||
{
|
||||
return builder.SetCommand<ButtonBuilder, Button>(command);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Control.Builder.ButtonBase;
|
||||
|
||||
internal interface IButtonBaseBuilder<TButton> : IBuilder
|
||||
where TButton : Microsoft.UI.Xaml.Controls.Primitives.ButtonBase
|
||||
{
|
||||
TButton Button { get; }
|
||||
}
|
||||
@@ -40,23 +40,15 @@ internal sealed class HutaoException : Exception
|
||||
}
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
public static HutaoException ServiceTypeCastFailed<TFrom, TTo>(string name, Exception? innerException = default)
|
||||
{
|
||||
string message = $"This instance of '{typeof(TFrom).FullName}' '{name}' doesn't implement '{typeof(TTo).FullName}'";
|
||||
throw new HutaoException(HutaoExceptionKind.ServiceTypeCastFailed, message, innerException);
|
||||
}
|
||||
|
||||
public static HutaoException GachaStatisticsInvalidItemId(uint id, Exception? innerException = default)
|
||||
{
|
||||
string message = SH.FormatServiceGachaStatisticsFactoryItemIdInvalid(id);
|
||||
throw new HutaoException(HutaoExceptionKind.GachaStatisticsInvalidItemId, message, innerException);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
public static InvalidCastException InvalidCast<TFrom, TTo>(string name, Exception? innerException = default)
|
||||
{
|
||||
string message = $"This instance of '{typeof(TFrom).FullName}' '{name}' doesn't implement '{typeof(TTo).FullName}'";
|
||||
throw new InvalidCastException(message, innerException);
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
public static OperationCanceledException OperationCanceled(string message, Exception? innerException = default)
|
||||
{
|
||||
return new OperationCanceledException(message, innerException);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ internal enum HutaoExceptionKind
|
||||
None,
|
||||
|
||||
// Foundation
|
||||
ServiceTypeCastFailed,
|
||||
ImageCacheInvalidUri,
|
||||
|
||||
// IO
|
||||
|
||||
@@ -1334,6 +1334,9 @@
|
||||
<data name="ViewDialogLaunchGameAccountTitle" xml:space="preserve">
|
||||
<value>为账号命名</value>
|
||||
</data>
|
||||
<data name="ViewDialogLaunchGameConfigurationFixDialogTitle" xml:space="preserve">
|
||||
<value>正在修复配置文件</value>
|
||||
</data>
|
||||
<data name="ViewDialogLaunchGamePackageConvertHint" xml:space="preserve">
|
||||
<value>转换可能需要花费一段时间,请勿关闭胡桃</value>
|
||||
</data>
|
||||
@@ -1625,6 +1628,12 @@
|
||||
<data name="ViewModelLaunchGameEnsureGameResourceFail" xml:space="preserve">
|
||||
<value>切换服务器失败</value>
|
||||
</data>
|
||||
<data name="ViewModelLaunchGameFixConfigurationFileButtonText" xml:space="preserve">
|
||||
<value>修复配置文件</value>
|
||||
</data>
|
||||
<data name="ViewModelLaunchGameFixConfigurationFileSuccess" xml:space="preserve">
|
||||
<value>修复完成</value>
|
||||
</data>
|
||||
<data name="ViewModelLaunchGameIdentifyMonitorsAction" xml:space="preserve">
|
||||
<value>识别显示器</value>
|
||||
</data>
|
||||
@@ -1637,6 +1646,9 @@
|
||||
<data name="ViewModelLaunchGameSchemeNotSelected" xml:space="preserve">
|
||||
<value>尚未选择任何服务器</value>
|
||||
</data>
|
||||
<data name="ViewModelLaunchGameSetGamePathButtonText" xml:space="preserve">
|
||||
<value>设置游戏目录</value>
|
||||
</data>
|
||||
<data name="ViewModelLaunchGameSwitchGameAccountFail" xml:space="preserve">
|
||||
<value>切换账号失败</value>
|
||||
</data>
|
||||
|
||||
@@ -178,16 +178,7 @@ internal sealed class LaunchOptions : DbStoreOptions
|
||||
[AllowNull]
|
||||
public NameValue<int> Monitor
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetOption(ref monitor, SettingEntry.LaunchMonitor, index => Monitors[RestrictIndex(Monitors, index)], Monitors[0]);
|
||||
|
||||
static int RestrictIndex(List<NameValue<int>> monitors, string index)
|
||||
{
|
||||
return Math.Clamp(int.Parse(index, CultureInfo.InvariantCulture) - 1, 0, monitors.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
get => GetOption(ref monitor, SettingEntry.LaunchMonitor, index => Monitors[int.Parse(index, CultureInfo.InvariantCulture) - 1], Monitors[0]);
|
||||
set
|
||||
{
|
||||
if (value is not null)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
internal interface IInfoBarOptionsBuilder : IBuilder
|
||||
{
|
||||
public InfoBarOptions Options { get; }
|
||||
}
|
||||
@@ -11,5 +11,5 @@ internal interface IInfoBarService
|
||||
{
|
||||
ObservableCollection<InfoBar> Collection { get; }
|
||||
|
||||
void PrepareInfoBarAndShow(Action<IInfoBarOptionsBuilder> configure);
|
||||
void PrepareInfoBarAndShow(InfoBarSeverity severity, string? title, string? message, int delay, string? buttonContent, ICommand? buttonCommand);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
internal sealed class InfoBarOptions
|
||||
{
|
||||
public InfoBarSeverity Severity { get; set; }
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string? Message { get; set; }
|
||||
|
||||
public object? Content { get; set; }
|
||||
|
||||
public ButtonBase? ActionButton { get; set; }
|
||||
|
||||
public int MilliSecondsDelay { get; set; }
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
internal sealed class InfoBarOptionsBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
public InfoBarOptions Options { get; } = new();
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Snap.Hutao.Control.Builder.ButtonBase;
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
internal static class InfoBarOptionsBuilderExtension
|
||||
{
|
||||
public static TBuilder SetSeverity<TBuilder>(this TBuilder builder, InfoBarSeverity severity)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
builder.Configure(builder => builder.Options.Severity = severity);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static TBuilder SetTitle<TBuilder>(this TBuilder builder, string? title)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
builder.Configure(builder => builder.Options.Title = title);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IInfoBarOptionsBuilder SetMessage<TBuilder>(this TBuilder builder, string? message)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
builder.Configure(builder => builder.Options.Message = message);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IInfoBarOptionsBuilder SetContent<TBuilder>(this TBuilder builder, object? content)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
builder.Configure(builder => builder.Options.Content = content);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IInfoBarOptionsBuilder SetActionButton<TBuilder, TButton>(this TBuilder builder, Action<ButtonBaseBuilder<TButton>> configureButton)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
where TButton : ButtonBase, new()
|
||||
{
|
||||
ButtonBaseBuilder<TButton> buttonBaseBuilder = new ButtonBaseBuilder<TButton>().Configure(configureButton);
|
||||
builder.Configure(builder => builder.Options.ActionButton = buttonBaseBuilder.Button);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IInfoBarOptionsBuilder SetDelay<TBuilder>(this TBuilder builder, int milliSeconds)
|
||||
where TBuilder : IInfoBarOptionsBuilder
|
||||
{
|
||||
builder.Configure(builder => builder.Options.MilliSecondsDelay = milliSeconds);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
using System.Collections.ObjectModel;
|
||||
using Windows.Foundation;
|
||||
|
||||
@@ -35,30 +34,37 @@ internal sealed class InfoBarService : IInfoBarService
|
||||
get => collection ??= [];
|
||||
}
|
||||
|
||||
public void PrepareInfoBarAndShow(Action<IInfoBarOptionsBuilder> configure)
|
||||
public void PrepareInfoBarAndShow(InfoBarSeverity severity, string? title, string? message, int delay, string? buttonContent = default, ICommand? buttonCommand = default)
|
||||
{
|
||||
if (collection is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PrepareInfoBarAndShowCoreAsync(configure).SafeForget(logger);
|
||||
PrepareInfoBarAndShowCoreAsync(severity, title, message, delay, buttonContent, buttonCommand).SafeForget(logger);
|
||||
}
|
||||
|
||||
private async ValueTask PrepareInfoBarAndShowCoreAsync(Action<IInfoBarOptionsBuilder> configure)
|
||||
private async ValueTask PrepareInfoBarAndShowCoreAsync(InfoBarSeverity severity, string? title, string? message, int delay, string? buttonContent, ICommand? buttonCommand)
|
||||
{
|
||||
IInfoBarOptionsBuilder builder = new InfoBarOptionsBuilder().Configure(configure);
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
Button? actionButton = default;
|
||||
if (buttonContent is not null)
|
||||
{
|
||||
actionButton = new()
|
||||
{
|
||||
Content = buttonContent,
|
||||
Command = buttonCommand,
|
||||
};
|
||||
}
|
||||
|
||||
InfoBar infoBar = new()
|
||||
{
|
||||
Severity = builder.Options.Severity,
|
||||
Title = builder.Options.Title,
|
||||
Message = builder.Options.Message,
|
||||
Content = builder.Options.Content,
|
||||
ActionButton = actionButton,
|
||||
Severity = severity,
|
||||
Title = title,
|
||||
Message = message,
|
||||
IsOpen = true,
|
||||
ActionButton = builder.Options.ActionButton,
|
||||
Transitions = [new AddDeleteThemeTransition()],
|
||||
};
|
||||
|
||||
@@ -66,9 +72,9 @@ internal sealed class InfoBarService : IInfoBarService
|
||||
ArgumentNullException.ThrowIfNull(collection);
|
||||
collection.Add(infoBar);
|
||||
|
||||
if (builder.Options.MilliSecondsDelay > 0)
|
||||
if (delay > 0)
|
||||
{
|
||||
await Delay.FromMilliSeconds(builder.Options.MilliSecondsDelay).ConfigureAwait(true);
|
||||
await Delay.FromMilliSeconds(delay).ConfigureAwait(true);
|
||||
collection.Remove(infoBar);
|
||||
infoBar.IsOpen = false;
|
||||
}
|
||||
|
||||
@@ -2,79 +2,108 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
|
||||
namespace Snap.Hutao.Service.Notification;
|
||||
|
||||
internal static class InfoBarServiceExtension
|
||||
{
|
||||
public static void Information(this IInfoBarService infoBarService, string message, int milliSeconds = 5000)
|
||||
public static void Information(this IInfoBarService infoBarService, string message, int delay = 5000)
|
||||
{
|
||||
infoBarService.Information(builder => builder.SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Informational, null, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Information(this IInfoBarService infoBarService, string title, string message, int milliSeconds = 5000)
|
||||
public static void Information(this IInfoBarService infoBarService, string title, string message, int delay = 5000)
|
||||
{
|
||||
infoBarService.Information(builder => builder.SetTitle(title).SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Informational, title, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Information(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
public static void Information(this IInfoBarService infoBarService, string title, string message, string buttonContent, int delay = 5000)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(builder => builder.SetSeverity(InfoBarSeverity.Informational).Configure(configure));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Informational, title, message, delay, buttonContent, null);
|
||||
}
|
||||
|
||||
public static void Success(this IInfoBarService infoBarService, string message, int milliSeconds = 5000)
|
||||
public static void Information(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int delay = 5000)
|
||||
{
|
||||
infoBarService.Success(builder => builder.SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Informational, title, message, delay, buttonContent, buttonCommand);
|
||||
}
|
||||
|
||||
public static void Success(this IInfoBarService infoBarService, string title, string message, int milliSeconds = 5000)
|
||||
public static void Success(this IInfoBarService infoBarService, string message, int delay = 5000)
|
||||
{
|
||||
infoBarService.Success(builder => builder.SetTitle(title).SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Success, null, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Success(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
public static void Success(this IInfoBarService infoBarService, string title, string message, int delay = 5000)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(builder => builder.SetSeverity(InfoBarSeverity.Success).Configure(configure));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Success, title, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Warning(this IInfoBarService infoBarService, string message, int milliSeconds = 30000)
|
||||
public static void Success(this IInfoBarService infoBarService, string title, string message, string buttonContent, int delay = 5000)
|
||||
{
|
||||
infoBarService.Warning(builder => builder.SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Success, title, message, delay, buttonContent, null);
|
||||
}
|
||||
|
||||
public static void Warning(this IInfoBarService infoBarService, string title, string message, int milliSeconds = 30000)
|
||||
public static void Success(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int delay = 5000)
|
||||
{
|
||||
infoBarService.Warning(builder => builder.SetTitle(title).SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Success, title, message, delay, buttonContent, buttonCommand);
|
||||
}
|
||||
|
||||
public static void Warning(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
public static void Warning(this IInfoBarService infoBarService, string message, int delay = 30000)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(builder => builder.SetSeverity(InfoBarSeverity.Warning).Configure(configure));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Warning, null, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, string message, int milliSeconds = 0)
|
||||
public static void Warning(this IInfoBarService infoBarService, string title, string message, int delay = 30000)
|
||||
{
|
||||
infoBarService.Error(builder => builder.SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Warning, title, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, string title, string message, int milliSeconds = 0)
|
||||
public static void Warning(this IInfoBarService infoBarService, string title, string message, string buttonContent, int delay = 30000)
|
||||
{
|
||||
infoBarService.Error(builder => builder.SetTitle(title).SetMessage(message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Warning, title, message, delay, buttonContent, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, int milliSeconds = 0)
|
||||
public static void Warning(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int delay = 30000)
|
||||
{
|
||||
infoBarService.Error(builder => builder.SetTitle(ex.GetType().Name).SetMessage(ex.Message).SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Warning, title, message, delay, buttonContent, buttonCommand);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, string subtitle, int milliSeconds = 0)
|
||||
public static void Error(this IInfoBarService infoBarService, string message, int delay = 0)
|
||||
{
|
||||
infoBarService.Error(builder => builder.SetTitle(ex.GetType().Name).SetMessage($"{subtitle}\n{ex.Message}").SetDelay(milliSeconds));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, null, message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Action<IInfoBarOptionsBuilder> configure)
|
||||
public static void Error(this IInfoBarService infoBarService, string title, string message, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(builder => builder.SetSeverity(InfoBarSeverity.Error).Configure(configure));
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, title, message, delay, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, string title, string message, string buttonContent, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, title, message, delay, buttonContent, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, string title, string message, string buttonContent, ICommand buttonCommand, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, title, message, delay, buttonContent, buttonCommand);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, ex.GetType().Name, ex.Message, delay, null, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, string title, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, ex.GetType().Name, $"{title}\n{ex.Message}", delay, null, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, string title, string buttonContent, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, ex.GetType().Name, $"{title}\n{ex.Message}", delay, buttonContent, null);
|
||||
}
|
||||
|
||||
public static void Error(this IInfoBarService infoBarService, Exception ex, string title, string buttonContent, ICommand buttonCommand, int delay = 0)
|
||||
{
|
||||
infoBarService.PrepareInfoBarAndShow(InfoBarSeverity.Error, ex.GetType().Name, $"{title}\n{ex.Message}", delay, buttonContent, buttonCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@
|
||||
<None Remove="View\Dialog\HutaoPassportResetPasswordDialog.xaml" />
|
||||
<None Remove="View\Dialog\HutaoPassportUnregisterDialog.xaml" />
|
||||
<None Remove="View\Dialog\LaunchGameAccountNameDialog.xaml" />
|
||||
<None Remove="View\Dialog\LaunchGameConfigurationFixDialog.xaml" />
|
||||
<None Remove="View\Dialog\LaunchGamePackageConvertDialog.xaml" />
|
||||
<None Remove="View\Dialog\ReconfirmDialog.xaml" />
|
||||
<None Remove="View\Dialog\UserDialog.xaml" />
|
||||
@@ -349,6 +350,11 @@
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\LaunchGameConfigurationFixDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Control\Theme\SegmentedOverride.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.LaunchGameConfigurationFixDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shccs="using:Snap.Hutao.Control.Collection.Selector"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvd="using:Snap.Hutao.View.Dialog"
|
||||
Title="{shcm:ResourceString Name=ViewDialogLaunchGameConfigurationFixDialogTitle}"
|
||||
d:DataContext="{d:DesignInstance shvd:LaunchGameConfigurationFixDialog}"
|
||||
CloseButtonText="{shcm:ResourceString Name=ContentDialogCancelCloseButtonText}"
|
||||
PrimaryButtonText="{shcm:ResourceString Name=ContentDialogConfirmPrimaryButtonText}"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<shccs:ComboBox2
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="DisplayName"
|
||||
EnableMemberPath="IsNotCompatOnly"
|
||||
ItemsSource="{x:Bind KnownSchemes}"
|
||||
SelectedItem="{x:Bind SelectedScheme, Mode=TwoWay}"
|
||||
Style="{StaticResource DefaultComboBoxStyle}"/>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Service.Game.Scheme;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
[DependencyProperty("KnownSchemes", typeof(IEnumerable<LaunchScheme>))]
|
||||
[DependencyProperty("SelectedScheme", typeof(LaunchScheme))]
|
||||
internal sealed partial class LaunchGameConfigurationFixDialog : ContentDialog
|
||||
{
|
||||
public LaunchGameConfigurationFixDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public async ValueTask<ValueResult<bool, LaunchScheme?>> GetLaunchSchemeAsync()
|
||||
{
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
|
||||
return new(result == ContentDialogResult.Primary, SelectedScheme);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ namespace Snap.Hutao.ViewModel.Abstraction;
|
||||
/// 视图模型抽象类
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[SuppressMessage("", "SA1124")]
|
||||
internal abstract partial class ViewModel : ObservableObject, IViewModel
|
||||
{
|
||||
private bool isInitialized;
|
||||
@@ -29,15 +28,9 @@ internal abstract partial class ViewModel : ObservableObject, IViewModel
|
||||
[Command("OpenUICommand")]
|
||||
protected virtual async Task OpenUIAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// ConfigureAwait(true) sets value on UI thread
|
||||
IsInitialized = await InitializeUIAsync().ConfigureAwait(true);
|
||||
Initialization.TrySetResult(IsInitialized);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
// Set value on UI thread
|
||||
IsInitialized = await InitializeUIAsync().ConfigureAwait(true);
|
||||
Initialization.TrySetResult(IsInitialized);
|
||||
}
|
||||
|
||||
protected virtual ValueTask<bool> InitializeUIAsync()
|
||||
@@ -53,8 +46,6 @@ internal abstract partial class ViewModel : ObservableObject, IViewModel
|
||||
return disposable;
|
||||
}
|
||||
|
||||
#region SetProperty
|
||||
|
||||
protected new bool SetProperty<T>([NotNullIfNotNull(nameof(newValue))] ref T field, T newValue, [CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
return !IsViewDisposed && base.SetProperty(ref field, newValue, propertyName);
|
||||
@@ -108,13 +99,12 @@ internal abstract partial class ViewModel : ObservableObject, IViewModel
|
||||
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void ThrowIfViewDisposed()
|
||||
{
|
||||
if (IsViewDisposed)
|
||||
{
|
||||
HutaoException.OperationCanceled(SH.ViewModelViewDisposedOperationCancel);
|
||||
ThrowHelper.OperationCanceled(SH.ViewModelViewDisposedOperationCancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -34,18 +33,19 @@ internal static class AchievementFinishPercent
|
||||
|
||||
if (achievements.SourceCollection is not List<AchievementView> list)
|
||||
{
|
||||
throw HutaoException.InvalidCast<IEnumerable<AchievementView>, List<AchievementView>>("AchievementViewModel.Achievements.SourceCollection");
|
||||
// Fast path
|
||||
throw Must.NeverHappen("AchievementViewModel.Achievements.SourceCollection 应为 List<AchievementView>");
|
||||
}
|
||||
|
||||
Dictionary<AchievementGoalId, AchievementGoalStatistics> counter = achievementGoals.ToDictionary(x => x.Id, AchievementGoalStatistics.From);
|
||||
|
||||
foreach (ref readonly AchievementView achievementView in CollectionsMarshal.AsSpan(list))
|
||||
foreach (ref readonly AchievementView achievement in CollectionsMarshal.AsSpan(list))
|
||||
{
|
||||
ref AchievementGoalStatistics goalStat = ref CollectionsMarshal.GetValueRefOrNullRef(counter, achievementView.Inner.Goal);
|
||||
ref AchievementGoalStatistics goalStat = ref CollectionsMarshal.GetValueRefOrNullRef(counter, achievement.Inner.Goal);
|
||||
|
||||
goalStat.TotalCount += 1;
|
||||
totalCount += 1;
|
||||
if (achievementView.IsChecked)
|
||||
if (achievement.IsChecked)
|
||||
{
|
||||
goalStat.Finished += 1;
|
||||
totalFinished += 1;
|
||||
|
||||
@@ -15,99 +15,123 @@ using EntityAchievementArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就导入器
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class AchievementImporter
|
||||
{
|
||||
private readonly AchievementImporterDependencies dependencies;
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IClipboardProvider clipboardInterop;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
/// <summary>
|
||||
/// 从剪贴板导入
|
||||
/// </summary>
|
||||
/// <returns>是否导入成功</returns>
|
||||
public async ValueTask<bool> FromClipboardAsync()
|
||||
{
|
||||
if (dependencies.AchievementService.CurrentArchive is not { } archive)
|
||||
if (achievementService.CurrentArchive is { } archive)
|
||||
{
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage2);
|
||||
return false;
|
||||
if (await TryCatchGetUIAFFromClipboardAsync().ConfigureAwait(false) is { } uiaf)
|
||||
{
|
||||
return await TryImportAsync(archive, uiaf).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage2);
|
||||
}
|
||||
|
||||
if (await TryCatchGetUIAFFromClipboardAsync().ConfigureAwait(false) is not { } uiaf)
|
||||
{
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
return await TryImportAsync(archive, uiaf).ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文件导入
|
||||
/// </summary>
|
||||
/// <returns>是否导入成功</returns>
|
||||
public async ValueTask<bool> FromFileAsync()
|
||||
{
|
||||
if (dependencies.AchievementService.CurrentArchive is not { } archive)
|
||||
if (achievementService.CurrentArchive is { } archive)
|
||||
{
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage2);
|
||||
return false;
|
||||
ValueResult<bool, ValueFile> pickerResult = fileSystemPickerInteraction.PickFile(
|
||||
SH.ServiceAchievementUIAFImportPickerTitile,
|
||||
[(SH.ServiceAchievementUIAFImportPickerFilterText, "*.json")]);
|
||||
|
||||
if (pickerResult.TryGetValue(out ValueFile file))
|
||||
{
|
||||
ValueResult<bool, UIAF?> uiafResult = await file.DeserializeFromJsonAsync<UIAF>(options).ConfigureAwait(false);
|
||||
|
||||
if (uiafResult.TryGetValue(out UIAF? uiaf))
|
||||
{
|
||||
return await TryImportAsync(archive, uiaf).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage2);
|
||||
}
|
||||
|
||||
ValueResult<bool, ValueFile> pickerResult = dependencies.FileSystemPickerInteraction.PickFile(
|
||||
SH.ServiceAchievementUIAFImportPickerTitile,
|
||||
[(SH.ServiceAchievementUIAFImportPickerFilterText, "*.json")]);
|
||||
|
||||
if (!pickerResult.TryGetValue(out ValueFile file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ValueResult<bool, UIAF?> uiafResult = await file.DeserializeFromJsonAsync<UIAF>(dependencies.JsonSerializerOptions).ConfigureAwait(false);
|
||||
|
||||
if (!uiafResult.TryGetValue(out UIAF? uiaf))
|
||||
{
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
return await TryImportAsync(archive, uiaf).ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
private async ValueTask<UIAF?> TryCatchGetUIAFFromClipboardAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await dependencies.ClipboardProvider.DeserializeFromJsonAsync<UIAF>().ConfigureAwait(false);
|
||||
return await clipboardInterop.DeserializeFromJsonAsync<UIAF>().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
dependencies.InfoBarService.Error(ex, SH.ViewModelImportFromClipboardErrorTitle);
|
||||
infoBarService?.Error(ex, SH.ViewModelImportFromClipboardErrorTitle);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<bool> TryImportAsync(EntityAchievementArchive archive, UIAF uiaf)
|
||||
{
|
||||
if (!uiaf.IsCurrentVersionSupported())
|
||||
if (uiaf.IsCurrentVersionSupported())
|
||||
{
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelAchievementImportWarningMessage);
|
||||
return false;
|
||||
AchievementImportDialog importDialog = await contentDialogFactory.CreateInstanceAsync<AchievementImportDialog>(uiaf).ConfigureAwait(false);
|
||||
(bool isOk, ImportStrategy strategy) = await importDialog.GetImportStrategyAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ContentDialog dialog = await contentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelAchievementImportProgress)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
ImportResult result;
|
||||
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
{
|
||||
result = await achievementService.ImportFromUIAFAsync(archive, uiaf.List, strategy).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
infoBarService.Success($"{result}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelImportWarningTitle, SH.ViewModelAchievementImportWarningMessage);
|
||||
}
|
||||
|
||||
AchievementImportDialog importDialog = await dependencies.ContentDialogFactory
|
||||
.CreateInstanceAsync<AchievementImportDialog>(uiaf).ConfigureAwait(false);
|
||||
(bool isOk, ImportStrategy strategy) = await importDialog.GetImportStrategyAsync().ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
await dependencies.TaskContext.SwitchToMainThreadAsync();
|
||||
ContentDialog dialog = await dependencies.ContentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelAchievementImportProgress)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
ImportResult result;
|
||||
using (await dialog.BlockAsync(dependencies.TaskContext).ConfigureAwait(false))
|
||||
{
|
||||
result = await dependencies.AchievementService.ImportFromUIAFAsync(archive, uiaf.List, strategy).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
dependencies.InfoBarService.Success($"{result}");
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.IO.DataTransfer;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Factory.Picker;
|
||||
using Snap.Hutao.Service.Achievement;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class AchievementImporterDependencies
|
||||
{
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly JsonSerializerOptions jsonSerializerOptions;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IClipboardProvider clipboardProvider;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public IFileSystemPickerInteraction FileSystemPickerInteraction { get => fileSystemPickerInteraction; }
|
||||
|
||||
public JsonSerializerOptions JsonSerializerOptions { get => jsonSerializerOptions; }
|
||||
|
||||
public IContentDialogFactory ContentDialogFactory { get => contentDialogFactory; }
|
||||
|
||||
public IAchievementService AchievementService { get => achievementService; }
|
||||
|
||||
public IClipboardProvider ClipboardProvider { get => clipboardProvider; }
|
||||
|
||||
public IInfoBarService InfoBarService { get => infoBarService; }
|
||||
|
||||
public ITaskContext TaskContext { get => taskContext; }
|
||||
}
|
||||
@@ -5,6 +5,8 @@ using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control.Collection.AdvancedCollectionView;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Factory.Picker;
|
||||
using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Service.Achievement;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
@@ -21,6 +23,9 @@ using SortDirection = CommunityToolkit.WinUI.Collections.SortDirection;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就视图模型
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped)]
|
||||
@@ -29,7 +34,14 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
private readonly SortDescription uncompletedItemsFirstSortDescription = new(nameof(AchievementView.IsChecked), SortDirection.Ascending);
|
||||
private readonly SortDescription completionTimeSortDescription = new(nameof(AchievementView.Time), SortDirection.Descending);
|
||||
|
||||
private readonly AchievementViewModelDependencies dependencies;
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly AchievementImporter achievementImporter;
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private AdvancedCollectionView<AchievementView>? achievements;
|
||||
private List<AchievementGoalView>? achievementGoals;
|
||||
@@ -40,12 +52,18 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
private string searchText = string.Empty;
|
||||
private string? finishDescription;
|
||||
|
||||
/// <summary>
|
||||
/// 成就存档集合
|
||||
/// </summary>
|
||||
public ObservableCollection<EntityAchievementArchive>? Archives
|
||||
{
|
||||
get => archives;
|
||||
set => SetProperty(ref archives, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中的成就存档
|
||||
/// </summary>
|
||||
public EntityAchievementArchive? SelectedArchive
|
||||
{
|
||||
get => selectedArchive;
|
||||
@@ -53,24 +71,38 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
if (SetProperty(ref selectedArchive, value))
|
||||
{
|
||||
dependencies.AchievementService.CurrentArchive = value;
|
||||
if (IsViewDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
achievementService.CurrentArchive = value;
|
||||
UpdateAchievementsAsync(value).SafeForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 成就视图
|
||||
/// </summary>
|
||||
public AdvancedCollectionView<AchievementView>? Achievements
|
||||
{
|
||||
get => achievements;
|
||||
set => SetProperty(ref achievements, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 成就分类
|
||||
/// </summary>
|
||||
public List<AchievementGoalView>? AchievementGoals
|
||||
{
|
||||
get => achievementGoals;
|
||||
set => SetProperty(ref achievementGoals, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中的成就分类
|
||||
/// </summary>
|
||||
public AchievementGoalView? SelectedAchievementGoal
|
||||
{
|
||||
get => selectedAchievementGoal;
|
||||
@@ -84,18 +116,27 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
public string SearchText
|
||||
{
|
||||
get => searchText;
|
||||
set => SetProperty(ref searchText, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 未完成优先
|
||||
/// </summary>
|
||||
public bool IsUncompletedItemsFirst
|
||||
{
|
||||
get => isUncompletedItemsFirst;
|
||||
set => SetProperty(ref isUncompletedItemsFirst, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 完成进度描述
|
||||
/// </summary>
|
||||
public string? FinishDescription
|
||||
{
|
||||
get => finishDescription;
|
||||
@@ -119,30 +160,36 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
|
||||
protected override async ValueTask<bool> InitializeUIAsync()
|
||||
{
|
||||
if (!await dependencies.MetadataService.InitializeAsync().ConfigureAwait(false))
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
return false;
|
||||
try
|
||||
{
|
||||
List<AchievementGoalView> sortedGoals;
|
||||
ObservableCollection<EntityAchievementArchive> archives;
|
||||
|
||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
||||
{
|
||||
List<MetadataAchievementGoal> goals = await metadataService
|
||||
.GetAchievementGoalListAsync(CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
sortedGoals = goals.SortBy(goal => goal.Order).SelectList(AchievementGoalView.From);
|
||||
archives = achievementService.ArchiveCollection;
|
||||
}
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
AchievementGoals = sortedGoals;
|
||||
Archives = archives;
|
||||
SelectedArchive = achievementService.CurrentArchive;
|
||||
return true;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
List<AchievementGoalView> sortedGoals;
|
||||
ObservableCollection<EntityAchievementArchive> archives;
|
||||
|
||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
||||
{
|
||||
List<MetadataAchievementGoal> goals = await dependencies.MetadataService
|
||||
.GetAchievementGoalListAsync(CancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
sortedGoals = goals.SortBy(goal => goal.Order).SelectList(AchievementGoalView.From);
|
||||
archives = dependencies.AchievementService.ArchiveCollection;
|
||||
}
|
||||
|
||||
await dependencies.TaskContext.SwitchToMainThreadAsync();
|
||||
|
||||
AchievementGoals = sortedGoals;
|
||||
Archives = archives;
|
||||
SelectedArchive = dependencies.AchievementService.CurrentArchive;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
[GeneratedRegex("\\d\\.\\d")]
|
||||
@@ -153,25 +200,25 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
if (Archives is not null)
|
||||
{
|
||||
AchievementArchiveCreateDialog dialog = await dependencies.ContentDialogFactory.CreateInstanceAsync<AchievementArchiveCreateDialog>().ConfigureAwait(false);
|
||||
AchievementArchiveCreateDialog dialog = await contentDialogFactory.CreateInstanceAsync<AchievementArchiveCreateDialog>().ConfigureAwait(false);
|
||||
(bool isOk, string name) = await dialog.GetInputAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
ArchiveAddResult result = await dependencies.AchievementService.AddArchiveAsync(EntityAchievementArchive.From(name)).ConfigureAwait(false);
|
||||
ArchiveAddResult result = await achievementService.AddArchiveAsync(EntityAchievementArchive.From(name)).ConfigureAwait(false);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case ArchiveAddResult.Added:
|
||||
await dependencies.TaskContext.SwitchToMainThreadAsync();
|
||||
SelectedArchive = dependencies.AchievementService.CurrentArchive;
|
||||
dependencies.InfoBarService.Success(SH.FormatViewModelAchievementArchiveAdded(name));
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
SelectedArchive = achievementService.CurrentArchive;
|
||||
infoBarService.Success(SH.FormatViewModelAchievementArchiveAdded(name));
|
||||
break;
|
||||
case ArchiveAddResult.InvalidName:
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelAchievementArchiveInvalidName);
|
||||
infoBarService.Warning(SH.ViewModelAchievementArchiveInvalidName);
|
||||
break;
|
||||
case ArchiveAddResult.AlreadyExists:
|
||||
dependencies.InfoBarService.Warning(SH.FormatViewModelAchievementArchiveAlreadyExists(name));
|
||||
infoBarService.Warning(SH.FormatViewModelAchievementArchiveAlreadyExists(name));
|
||||
break;
|
||||
default:
|
||||
throw Must.NeverHappen();
|
||||
@@ -187,7 +234,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
string title = SH.FormatViewModelAchievementRemoveArchiveTitle(SelectedArchive.Name);
|
||||
string content = SH.ViewModelAchievementRemoveArchiveContent;
|
||||
ContentDialogResult result = await dependencies.ContentDialogFactory
|
||||
ContentDialogResult result = await contentDialogFactory
|
||||
.CreateForConfirmCancelAsync(title, content)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -197,11 +244,11 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
||||
{
|
||||
await dependencies.AchievementService.RemoveArchiveAsync(SelectedArchive).ConfigureAwait(false);
|
||||
await achievementService.RemoveArchiveAsync(SelectedArchive).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Re-select first archive
|
||||
await dependencies.TaskContext.SwitchToMainThreadAsync();
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
SelectedArchive = Archives.FirstOrDefault();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -216,21 +263,21 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
if (SelectedArchive is not null && Achievements is not null)
|
||||
{
|
||||
(bool isOk, ValueFile file) = dependencies.FileSystemPickerInteraction.SaveFile(
|
||||
(bool isOk, ValueFile file) = fileSystemPickerInteraction.SaveFile(
|
||||
SH.ViewModelAchievementUIAFExportPickerTitle,
|
||||
$"{dependencies.AchievementService.CurrentArchive?.Name}.json",
|
||||
$"{achievementService.CurrentArchive?.Name}.json",
|
||||
[(SH.ViewModelAchievementExportFileType, "*.json")]);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
UIAF uiaf = await dependencies.AchievementService.ExportToUIAFAsync(SelectedArchive).ConfigureAwait(false);
|
||||
if (await file.SerializeToJsonAsync(uiaf, dependencies.JsonSerializerOptions).ConfigureAwait(false))
|
||||
UIAF uiaf = await achievementService.ExportToUIAFAsync(SelectedArchive).ConfigureAwait(false);
|
||||
if (await file.SerializeToJsonAsync(uiaf, options).ConfigureAwait(false))
|
||||
{
|
||||
dependencies.InfoBarService.Success(SH.ViewModelExportSuccessTitle, SH.ViewModelExportSuccessMessage);
|
||||
infoBarService.Success(SH.ViewModelExportSuccessTitle, SH.ViewModelExportSuccessMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
dependencies.InfoBarService.Warning(SH.ViewModelExportWarningTitle, SH.ViewModelExportWarningMessage);
|
||||
infoBarService.Warning(SH.ViewModelExportWarningTitle, SH.ViewModelExportWarningMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,20 +286,20 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
[Command("ImportUIAFFromClipboardCommand")]
|
||||
private async Task ImportUIAFFromClipboardAsync()
|
||||
{
|
||||
if (await dependencies.AchievementImporter.FromClipboardAsync().ConfigureAwait(false))
|
||||
if (await achievementImporter.FromClipboardAsync().ConfigureAwait(false))
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dependencies.AchievementService.CurrentArchive);
|
||||
await UpdateAchievementsAsync(dependencies.AchievementService.CurrentArchive).ConfigureAwait(false);
|
||||
ArgumentNullException.ThrowIfNull(achievementService.CurrentArchive);
|
||||
await UpdateAchievementsAsync(achievementService.CurrentArchive).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("ImportUIAFFromFileCommand")]
|
||||
private async Task ImportUIAFFromFileAsync()
|
||||
{
|
||||
if (await dependencies.AchievementImporter.FromFileAsync().ConfigureAwait(false))
|
||||
if (await achievementImporter.FromFileAsync().ConfigureAwait(false))
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dependencies.AchievementService.CurrentArchive);
|
||||
await UpdateAchievementsAsync(dependencies.AchievementService.CurrentArchive).ConfigureAwait(false);
|
||||
ArgumentNullException.ThrowIfNull(achievementService.CurrentArchive);
|
||||
await UpdateAchievementsAsync(achievementService.CurrentArchive).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,11 +311,11 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
return;
|
||||
}
|
||||
|
||||
List<MetadataAchievement> achievements = await dependencies.MetadataService.GetAchievementListAsync(CancellationToken).ConfigureAwait(false);
|
||||
List<MetadataAchievement> achievements = await metadataService.GetAchievementListAsync(CancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (TryGetAchievements(archive, achievements, out List<AchievementView>? combined))
|
||||
{
|
||||
await dependencies.TaskContext.SwitchToMainThreadAsync();
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
Achievements = new(combined, true);
|
||||
UpdateAchievementsFinishPercent();
|
||||
@@ -281,12 +328,12 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
try
|
||||
{
|
||||
combined = dependencies.AchievementService.GetAchievementViewList(archive, achievements);
|
||||
combined = achievementService.GetAchievementViewList(archive, achievements);
|
||||
return true;
|
||||
}
|
||||
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
||||
{
|
||||
dependencies.InfoBarService.Error(ex);
|
||||
infoBarService.Error(ex);
|
||||
combined = default;
|
||||
return false;
|
||||
}
|
||||
@@ -371,7 +418,7 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
if (achievement is not null)
|
||||
{
|
||||
dependencies.AchievementService.SaveAchievement(achievement);
|
||||
achievementService.SaveAchievement(achievement);
|
||||
UpdateAchievementsFinishPercent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Factory.Picker;
|
||||
using Snap.Hutao.Service.Achievement;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class AchievementViewModelDependencies
|
||||
{
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly AchievementImporter achievementImporter;
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly JsonSerializerOptions jsonSerializerOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public IFileSystemPickerInteraction FileSystemPickerInteraction { get => fileSystemPickerInteraction; }
|
||||
|
||||
public JsonSerializerOptions JsonSerializerOptions { get => jsonSerializerOptions; }
|
||||
|
||||
public IContentDialogFactory ContentDialogFactory { get => contentDialogFactory; }
|
||||
|
||||
public AchievementImporter AchievementImporter { get => achievementImporter; }
|
||||
|
||||
public IAchievementService AchievementService { get => achievementService; }
|
||||
|
||||
public IMetadataService MetadataService { get => metadataService; }
|
||||
|
||||
public IInfoBarService InfoBarService { get => infoBarService; }
|
||||
|
||||
public ITaskContext TaskContext { get => taskContext; }
|
||||
}
|
||||
@@ -2,39 +2,98 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.ExceptionService;
|
||||
using Snap.Hutao.Factory.ContentDialog;
|
||||
using Snap.Hutao.Service.Game;
|
||||
using Snap.Hutao.Service.Game.Configuration;
|
||||
using Snap.Hutao.Service.Game.Scheme;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using Snap.Hutao.View.Page;
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Game;
|
||||
|
||||
internal static class LaunchGameShared
|
||||
[Injection(InjectAs.Transient)]
|
||||
[ConstructorGenerated]
|
||||
internal sealed partial class LaunchGameShared
|
||||
{
|
||||
public static LaunchScheme? GetCurrentLaunchSchemeFromConfigFile(IGameServiceFacade gameService, IInfoBarService infoBarService)
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly INavigationService navigationService;
|
||||
private readonly IGameServiceFacade gameService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly LaunchOptions launchOptions;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public LaunchScheme? GetCurrentLaunchSchemeFromConfigFile(IGameServiceFacade gameService, IInfoBarService infoBarService)
|
||||
{
|
||||
ChannelOptions options = gameService.GetChannelOptions();
|
||||
|
||||
if (options.ErrorKind is ChannelOptionsErrorKind.None)
|
||||
switch (options.ErrorKind)
|
||||
{
|
||||
try
|
||||
{
|
||||
return KnownLaunchSchemes.Get().Single(scheme => scheme.Equals(options));
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
if (!IgnoredInvalidChannelOptions.Contains(options))
|
||||
case ChannelOptionsErrorKind.None:
|
||||
try
|
||||
{
|
||||
// 后台收集
|
||||
throw ThrowHelper.NotSupported($"不支持的 MultiChannel: {options}");
|
||||
return KnownLaunchSchemes.Get().Single(scheme => scheme.Equals(options));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning($"{options.ErrorKind}", SH.FormatViewModelLaunchGameMultiChannelReadFail(options.FilePath));
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
if (!IgnoredInvalidChannelOptions.Contains(options))
|
||||
{
|
||||
// 后台收集
|
||||
throw ThrowHelper.NotSupported($"不支持的 MultiChannel: {options}");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case ChannelOptionsErrorKind.ConfigurationFileNotFound:
|
||||
infoBarService.Warning($"{options.ErrorKind}", SH.FormatViewModelLaunchGameMultiChannelReadFail(options.FilePath), SH.ViewModelLaunchGameFixConfigurationFileButtonText, HandleConfigurationFileNotFoundCommand);
|
||||
break;
|
||||
case ChannelOptionsErrorKind.GamePathNullOrEmpty:
|
||||
infoBarService.Warning($"{options.ErrorKind}", SH.FormatViewModelLaunchGameMultiChannelReadFail(options.FilePath), SH.ViewModelLaunchGameSetGamePathButtonText, HandleGamePathNullOrEmptyCommand);
|
||||
break;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
[Command("HandleConfigurationFileNotFoundCommand")]
|
||||
private async void HandleConfigurationFileNotFoundAsync()
|
||||
{
|
||||
launchOptions.TryGetGameFileSystem(out GameFileSystem? gameFileSystem);
|
||||
ArgumentNullException.ThrowIfNull(gameFileSystem);
|
||||
bool isOversea = LaunchScheme.ExecutableIsOversea(gameFileSystem.GameFileName);
|
||||
string version = await File.ReadAllTextAsync(Path.Combine(gameFileSystem.GameDirectory, isOversea ? GameConstants.GenshinImpactData : GameConstants.YuanShenData, "Persistent", "ScriptVersion")).ConfigureAwait(false);
|
||||
|
||||
LaunchGameConfigurationFixDialog dialog = await contentDialogFactory.CreateInstanceAsync<LaunchGameConfigurationFixDialog>().ConfigureAwait(false);
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
dialog.KnownSchemes = KnownLaunchSchemes.Get().Where(scheme => scheme.IsOversea == isOversea);
|
||||
dialog.SelectedScheme = dialog.KnownSchemes.First(scheme => scheme.IsNotCompatOnly);
|
||||
(bool isOk, LaunchScheme? launchScheme) = await dialog.GetLaunchSchemeAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(launchScheme);
|
||||
|
||||
string content = $"""
|
||||
[General]
|
||||
channel={(int)launchScheme.Channel}
|
||||
cps=mihoyo
|
||||
game_version={version}
|
||||
sub_channel={(int)launchScheme.SubChannel}
|
||||
sdk_version=
|
||||
game_biz=hk4e_{(launchScheme.IsOversea ? "global" : "cn")}
|
||||
""";
|
||||
|
||||
await File.WriteAllTextAsync(gameFileSystem.GameConfigFilePath, content).ConfigureAwait(false);
|
||||
infoBarService.Success(SH.ViewModelLaunchGameFixConfigurationFileSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("HandleGamePathNullOrEmptyCommand")]
|
||||
private void HandleGamePathNullOrEmpty()
|
||||
{
|
||||
navigationService.Navigate<LaunchGamePage>(INavigationAwaiter.Default);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
private readonly LaunchStatusOptions launchStatusOptions;
|
||||
private readonly IGameLocatorFactory gameLocatorFactory;
|
||||
private readonly ILogger<LaunchGameViewModel> logger;
|
||||
private readonly LaunchGameShared launchGameShared;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ResourceClient resourceClient;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
@@ -99,7 +100,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel, IView
|
||||
{
|
||||
using (await EnterCriticalExecutionAsync().ConfigureAwait(false))
|
||||
{
|
||||
LaunchScheme? scheme = LaunchGameShared.GetCurrentLaunchSchemeFromConfigFile(gameService, infoBarService);
|
||||
LaunchScheme? scheme = launchGameShared.GetCurrentLaunchSchemeFromConfigFile(gameService, infoBarService);
|
||||
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
await SetSelectedSchemeAsync(scheme).ConfigureAwait(true);
|
||||
|
||||
@@ -23,6 +23,7 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
|
||||
{
|
||||
private readonly LaunchStatusOptions launchStatusOptions;
|
||||
private readonly ILogger<LaunchGameViewModelSlim> logger;
|
||||
private readonly LaunchGameShared launchGameShared;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly IGameServiceFacade gameService;
|
||||
private readonly ITaskContext taskContext;
|
||||
@@ -47,7 +48,7 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OpenUIAsync()
|
||||
{
|
||||
LaunchScheme? scheme = LaunchGameShared.GetCurrentLaunchSchemeFromConfigFile(gameService, infoBarService);
|
||||
LaunchScheme? scheme = launchGameShared.GetCurrentLaunchSchemeFromConfigFile(gameService, infoBarService);
|
||||
ObservableCollection<GameAccount> accounts = gameService.GameAccountCollection;
|
||||
|
||||
try
|
||||
@@ -76,7 +77,7 @@ internal sealed partial class LaunchGameViewModelSlim : Abstraction.ViewModelSli
|
||||
private async Task LaunchAsync()
|
||||
{
|
||||
IInfoBarService infoBarService = ServiceProvider.GetRequiredService<IInfoBarService>();
|
||||
LaunchScheme? scheme = LaunchGameShared.GetCurrentLaunchSchemeFromConfigFile(gameService, infoBarService);
|
||||
LaunchScheme? scheme = launchGameShared.GetCurrentLaunchSchemeFromConfigFile(gameService, infoBarService);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -121,7 +121,7 @@ internal sealed class DownloadSummary : ObservableObject
|
||||
{
|
||||
if (imageCache is not IImageCacheFilePathOperation imageCacheFilePathOperation)
|
||||
{
|
||||
throw HutaoException.InvalidCast<IImageCache, IImageCacheFilePathOperation>(nameof(imageCache));
|
||||
throw HutaoException.ServiceTypeCastFailed<IImageCache, IImageCacheFilePathOperation>(nameof(imageCache));
|
||||
}
|
||||
|
||||
using (ZipArchive archive = new(stream))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.Abstraction;
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
internal interface IBuilder;
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Net.Http;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Net.Http.Headers;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Net.Http;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
internal interface IHttpProtocolVersionBuilder : IBuilder
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Net.Http;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Net.Http;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
|
||||
internal interface IRequestUriBuilder : IBuilder
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Snap.Hutao.Core.Abstraction.Extension;
|
||||
namespace Snap.Hutao.Web.Request.Builder;
|
||||
|
||||
internal static class BuilderExtension
|
||||
{
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Abstraction.Extension;
|
||||
using Snap.Hutao.Web.Request.Builder.Abstraction;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.Foundation;
|
||||
|
||||
[SuppressMessage("", "SA1201")]
|
||||
[SuppressMessage("", "SA1300")]
|
||||
[SuppressMessage("", "SA1307")]
|
||||
internal struct DECIMAL
|
||||
{
|
||||
public ushort wReserved;
|
||||
|
||||
public byte scale;
|
||||
|
||||
public byte sign;
|
||||
|
||||
public unsafe ushort signscale
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (DECIMAL* pThis = &this)
|
||||
{
|
||||
return *(ushort*)&pThis->scale;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
fixed (DECIMAL* pThis = &this)
|
||||
{
|
||||
*(ushort*)&pThis->scale = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint Hi32;
|
||||
|
||||
public uint Lo32;
|
||||
|
||||
public uint Mid32;
|
||||
|
||||
public unsafe ulong Lo64
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (DECIMAL* pThis = &this)
|
||||
{
|
||||
return *(ulong*)&pThis->Lo32;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
fixed (DECIMAL* pThis = &this)
|
||||
{
|
||||
*(ulong*)&pThis->Lo32 = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Variant;
|
||||
|
||||
namespace Snap.Hutao.Win32.System.Com.StructuredStorage;
|
||||
|
||||
[SuppressMessage("", "IDE1006")]
|
||||
[SuppressMessage("", "SA1300")]
|
||||
[SuppressMessage("", "SA1307")]
|
||||
internal struct PROPVARIANT
|
||||
{
|
||||
public VARENUM vt;
|
||||
public ushort wReserved1;
|
||||
public ushort wReserved2;
|
||||
public ushort wReserved3;
|
||||
public nint Value;
|
||||
|
||||
// https://learn.microsoft.com/zh-cn/windows/win32/api/propidlbase/ns-propidlbase-propvariant
|
||||
public unsafe DECIMAL decVal
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (PROPVARIANT* pThis = &this)
|
||||
{
|
||||
return *(DECIMAL*)pThis;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
fixed (PROPVARIANT* pThis = &this)
|
||||
{
|
||||
*(DECIMAL*)pThis = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.System.Variant;
|
||||
|
||||
internal enum VARENUM : ushort
|
||||
{
|
||||
VT_EMPTY = 0,
|
||||
VT_NULL = 1,
|
||||
VT_I2 = 2,
|
||||
VT_I4 = 3,
|
||||
VT_R4 = 4,
|
||||
VT_R8 = 5,
|
||||
VT_CY = 6,
|
||||
VT_DATE = 7,
|
||||
VT_BSTR = 8,
|
||||
VT_DISPATCH = 9,
|
||||
VT_ERROR = 10,
|
||||
VT_BOOL = 11,
|
||||
VT_VARIANT = 12,
|
||||
VT_UNKNOWN = 13,
|
||||
VT_DECIMAL = 14,
|
||||
VT_I1 = 16,
|
||||
VT_UI1 = 17,
|
||||
VT_UI2 = 18,
|
||||
VT_UI4 = 19,
|
||||
VT_I8 = 20,
|
||||
VT_UI8 = 21,
|
||||
VT_INT = 22,
|
||||
VT_UINT = 23,
|
||||
VT_VOID = 24,
|
||||
VT_HRESULT = 25,
|
||||
VT_PTR = 26,
|
||||
VT_SAFEARRAY = 27,
|
||||
VT_CARRAY = 28,
|
||||
VT_USERDEFINED = 29,
|
||||
VT_LPSTR = 30,
|
||||
VT_LPWSTR = 31,
|
||||
VT_RECORD = 36,
|
||||
VT_INT_PTR = 37,
|
||||
VT_UINT_PTR = 38,
|
||||
VT_FILETIME = 64,
|
||||
VT_BLOB = 65,
|
||||
VT_STREAM = 66,
|
||||
VT_STORAGE = 67,
|
||||
VT_STREAMED_OBJECT = 68,
|
||||
VT_STORED_OBJECT = 69,
|
||||
VT_BLOB_OBJECT = 70,
|
||||
VT_CF = 71,
|
||||
VT_CLSID = 72,
|
||||
VT_VERSIONED_STREAM = 73,
|
||||
VT_BSTR_BLOB = 4095,
|
||||
VT_VECTOR = 4096,
|
||||
VT_ARRAY = 8192,
|
||||
VT_BYREF = 16384,
|
||||
VT_RESERVED = 32768,
|
||||
VT_ILLEGAL = 65535,
|
||||
VT_ILLEGALMASKED = 4095,
|
||||
VT_TYPEMASK = 4095,
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell;
|
||||
|
||||
[Flags]
|
||||
internal enum FILEOPERATION_FLAGS : uint
|
||||
{
|
||||
FOFX_NOSKIPJUNCTIONS = 0x00010000,
|
||||
FOFX_PREFERHARDLINK = 0x00020000,
|
||||
FOFX_SHOWELEVATIONPROMPT = 0x00040000,
|
||||
FOFX_RECYCLEONDELETE = 0x00080000,
|
||||
FOFX_EARLYFAILURE = 0x00100000,
|
||||
FOFX_PRESERVEFILEEXTENSIONS = 0x00200000,
|
||||
FOFX_KEEPNEWERFILE = 0x00400000,
|
||||
FOFX_NOCOPYHOOKS = 0x00800000,
|
||||
FOFX_NOMINIMIZEBOX = 0x01000000,
|
||||
FOFX_MOVEACLSACROSSVOLUMES = 0x02000000,
|
||||
FOFX_DONTDISPLAYSOURCEPATH = 0x04000000,
|
||||
FOFX_DONTDISPLAYDESTPATH = 0x08000000,
|
||||
FOFX_REQUIREELEVATION = 0x10000000,
|
||||
FOFX_ADDUNDORECORD = 0x20000000,
|
||||
FOFX_COPYASDOWNLOAD = 0x40000000,
|
||||
FOFX_DONTDISPLAYLOCATIONS = 0x80000000,
|
||||
FOF_MULTIDESTFILES = 0x00000001,
|
||||
FOF_CONFIRMMOUSE = 0x00000002,
|
||||
FOF_SILENT = 0x00000004,
|
||||
FOF_RENAMEONCOLLISION = 0x00000008,
|
||||
FOF_NOCONFIRMATION = 0x00000010,
|
||||
FOF_WANTMAPPINGHANDLE = 0x00000020,
|
||||
FOF_ALLOWUNDO = 0x00000040,
|
||||
FOF_FILESONLY = 0x00000080,
|
||||
FOF_SIMPLEPROGRESS = 0x00000100,
|
||||
FOF_NOCONFIRMMKDIR = 0x00000200,
|
||||
FOF_NOERRORUI = 0x00000400,
|
||||
FOF_NOCOPYSECURITYATTRIBS = 0x00000800,
|
||||
FOF_NORECURSION = 0x00001000,
|
||||
FOF_NO_CONNECTED_ELEMENTS = 0x00002000,
|
||||
FOF_WANTNUKEWARNING = 0x00004000,
|
||||
FOF_NORECURSEREPARSE = 0x00008000,
|
||||
FOF_NO_UI = 0x00000614,
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell;
|
||||
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
[Guid("947AAB5F-0A5C-4C13-B4D6-4BF7836FC9F8")]
|
||||
internal unsafe struct IFileOperation
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
internal static unsafe ref readonly Guid IID
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlySpan<byte> data = [0x5F, 0xAB, 0x7A, 0x94, 0x5C, 0x0A, 0x13, 0x4C, 0xB4, 0xD6, 0x4B, 0xF7, 0x83, 0x6F, 0xC9, 0xF8];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe HRESULT QueryInterface<TInterface>(ref readonly Guid riid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.QueryInterface((IUnknown*)Unsafe.AsPointer(ref this), riid2, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint AddRef()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.AddRef((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
public uint Release()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.Release((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IUnknown.Vftbl IUnknownVftbl;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IFileOperationProgressSink*, uint*, HRESULT> Advise;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, uint, HRESULT> Unadvise;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, FILEOPERATION_FLAGS, HRESULT> SetOperationFlags;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, PCWSTR, HRESULT> SetProgressMessage;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IOperationsProgressDialog*, HRESULT> SetProgressDialog;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IPropertyChangeArray*, HRESULT> SetProperties;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, HWND, HRESULT> SetOwnerWindow;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IShellItem*, HRESULT> ApplyPropertiesToItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IUnknown*, HRESULT> ApplyPropertiesToItems;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IShellItem*, PCWSTR, IFileOperationProgressSink*, HRESULT> RenameItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IUnknown*, PCWSTR, HRESULT> RenameItems;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IShellItem*, IShellItem*, PCWSTR, IFileOperationProgressSink*, HRESULT> MoveItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IUnknown*, IShellItem*, HRESULT> MoveItems;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IShellItem*, IShellItem*, PCWSTR, IFileOperationProgressSink*, HRESULT> CopyItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IUnknown*, IShellItem*, HRESULT> CopyItems;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IShellItem*, IFileOperationProgressSink*, HRESULT> DeleteItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IUnknown*, HRESULT> DeleteItems;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, IShellItem*, uint, PCWSTR, PCWSTR, IFileOperationProgressSink*, HRESULT> NewItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, HRESULT> PerformOperations;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperation*, BOOL*, HRESULT> GetAnyOperationsAborted;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell;
|
||||
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
[Guid("04B0F1A7-9490-44BC-96E1-4296A31252E2")]
|
||||
internal unsafe struct IFileOperationProgressSink
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
internal static unsafe ref readonly Guid IID
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlySpan<byte> data = [0xA7, 0xF1, 0xB0, 0x04, 0x90, 0x94, 0xBC, 0x44, 0x96, 0xE1, 0x42, 0x96, 0xA3, 0x12, 0x52, 0xE2];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe HRESULT QueryInterface<TInterface>(ref readonly Guid riid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.QueryInterface((IUnknown*)Unsafe.AsPointer(ref this), riid2, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint AddRef()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.AddRef((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
public uint Release()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.Release((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IUnknown.Vftbl IUnknownVftbl;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, HRESULT> StartOperations;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, HRESULT, HRESULT> FinishOperations;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, PCWSTR, HRESULT> PreRenameItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, PCWSTR, HRESULT, IShellItem*, HRESULT> PostRenameItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, IShellItem*, PCWSTR, HRESULT> PreMoveItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, IShellItem*, PCWSTR, HRESULT, IShellItem*, HRESULT> PostMoveItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, IShellItem*, PCWSTR, HRESULT> PreCopyItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, IShellItem*, PCWSTR, HRESULT, IShellItem*, HRESULT> PostCopyItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, HRESULT> PreDeleteItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, HRESULT, IShellItem*, HRESULT> PostDeleteItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, PCWSTR, HRESULT> PreNewItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, IShellItem*, PCWSTR, PCWSTR, uint, HRESULT, IShellItem*, HRESULT> PostNewItem;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, uint, uint, HRESULT> UpdateProgress;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, HRESULT> ResetTimer;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, HRESULT> PauseTimer;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IFileOperationProgressSink*, HRESULT> ResumeTimer;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell;
|
||||
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
[Guid("0C9FB851-E5C9-43EB-A370-F0677B13874C")]
|
||||
internal unsafe struct IOperationsProgressDialog
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
internal static unsafe ref readonly Guid IID
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlySpan<byte> data = [0x51, 0xB8, 0x9F, 0x0C, 0xC9, 0xE5, 0xEB, 0x43, 0xA3, 0x70, 0xF0, 0x67, 0x7B, 0x13, 0x87, 0x4C];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe HRESULT QueryInterface<TInterface>(ref readonly Guid riid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.QueryInterface((IUnknown*)Unsafe.AsPointer(ref this), riid2, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint AddRef()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.AddRef((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
public uint Release()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.Release((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IUnknown.Vftbl IUnknownVftbl;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, HWND, uint, HRESULT> StartProgressDialog;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, HRESULT> StopProgressDialog;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, SPACTION, HRESULT> SetOperation;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, uint, HRESULT> SetMode;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, ulong, ulong, ulong, ulong, ulong, ulong, HRESULT> UpdateProgress;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, IShellItem*, IShellItem*, IShellItem*, HRESULT> UpdateLocations;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, HRESULT> ResetTimer;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, HRESULT> PauseTimer;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, HRESULT> ResumeTimer;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, ulong*, ulong*, HRESULT> GetMilliseconds;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IOperationsProgressDialog*, PDOPSTATUS*, HRESULT> GetOperationStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
[Guid("FC0CA0A7-C316-4FD2-9031-3E628E6D4F23")]
|
||||
internal unsafe struct IObjectWithPropertyKey
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
internal static unsafe ref readonly Guid IID
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlySpan<byte> data = [0xA7, 0xA0, 0x0C, 0xFC, 0x16, 0xC3, 0xD2, 0x4F, 0x90, 0x31, 0x3E, 0x62, 0x8E, 0x6D, 0x4F, 0x23];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe HRESULT QueryInterface<TInterface>(ref readonly Guid riid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.QueryInterface((IUnknown*)Unsafe.AsPointer(ref this), riid2, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint AddRef()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.AddRef((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
public uint Release()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.Release((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IUnknown.Vftbl IUnknownVftbl;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IObjectWithPropertyKey*, PROPERTYKEY*, HRESULT> SetPropertyKey;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IObjectWithPropertyKey*, PROPERTYKEY*, HRESULT> GetPropertyKey;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using Snap.Hutao.Win32.System.Com.StructuredStorage;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
[Guid("F917BC8A-1BBA-4478-A245-1BDE03EB9431")]
|
||||
internal unsafe struct IPropertyChange
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
internal static unsafe ref readonly Guid IID
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlySpan<byte> data = [0x8A, 0xBC, 0x17, 0xF9, 0xBA, 0x1B, 0x78, 0x44, 0xA2, 0x45, 0x1B, 0xDE, 0x03, 0xEB, 0x94, 0x31];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe HRESULT QueryInterface<TInterface>(ref readonly Guid riid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ThisPtr->IObjectWithPropertyKeyVftbl.IUnknownVftbl.QueryInterface((IUnknown*)Unsafe.AsPointer(ref this), riid2, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint AddRef()
|
||||
{
|
||||
return ThisPtr->IObjectWithPropertyKeyVftbl.IUnknownVftbl.AddRef((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
public uint Release()
|
||||
{
|
||||
return ThisPtr->IObjectWithPropertyKeyVftbl.IUnknownVftbl.Release((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IObjectWithPropertyKey.Vftbl IObjectWithPropertyKeyVftbl;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChange*, PROPVARIANT*, PROPVARIANT*, HRESULT> ApplyToPropVariant;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Win32.Foundation;
|
||||
using Snap.Hutao.Win32.System.Com;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
[SupportedOSPlatform("windows6.0.6000")]
|
||||
[Guid("380F5CAD-1B5E-42F2-805D-637FD392D31E")]
|
||||
internal unsafe struct IPropertyChangeArray
|
||||
{
|
||||
public readonly Vftbl* ThisPtr;
|
||||
|
||||
internal static unsafe ref readonly Guid IID
|
||||
{
|
||||
get
|
||||
{
|
||||
ReadOnlySpan<byte> data = [0xAD, 0x5C, 0x0F, 0x38, 0x5E, 0x1B, 0xF2, 0x42, 0x80, 0x5D, 0x63, 0x7F, 0xD3, 0x92, 0xD3, 0x1E];
|
||||
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe HRESULT QueryInterface<TInterface>(ref readonly Guid riid, out TInterface* pvObject)
|
||||
where TInterface : unmanaged
|
||||
{
|
||||
fixed (Guid* riid2 = &riid)
|
||||
{
|
||||
fixed (TInterface** ppvObject = &pvObject)
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.QueryInterface((IUnknown*)Unsafe.AsPointer(ref this), riid2, (void**)ppvObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint AddRef()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.AddRef((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
public uint Release()
|
||||
{
|
||||
return ThisPtr->IUnknownVftbl.Release((IUnknown*)Unsafe.AsPointer(ref this));
|
||||
}
|
||||
|
||||
internal readonly struct Vftbl
|
||||
{
|
||||
internal readonly IUnknown.Vftbl IUnknownVftbl;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, uint*, HRESULT> GetCount;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, uint, Guid*, void**, HRESULT> GetAt;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, uint, IPropertyChange*, HRESULT> InsertAt;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, IPropertyChange*, HRESULT> Append;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, IPropertyChange*, HRESULT> AppendOrReplace;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, uint, HRESULT> RemoveAt;
|
||||
internal readonly delegate* unmanaged[Stdcall]<IPropertyChangeArray*, PROPERTYKEY*, HRESULT> IsKeyInArray;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
internal enum PDOPSTATUS
|
||||
{
|
||||
PDOPS_RUNNING = 1,
|
||||
PDOPS_PAUSED = 2,
|
||||
PDOPS_CANCELLED = 3,
|
||||
PDOPS_STOPPED = 4,
|
||||
PDOPS_ERRORS = 5,
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
[SuppressMessage("", "SA1307")]
|
||||
internal struct PROPERTYKEY
|
||||
{
|
||||
public Guid fmtid;
|
||||
public uint pid;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Win32.UI.Shell;
|
||||
|
||||
internal enum SPACTION
|
||||
{
|
||||
SPACTION_NONE = 0,
|
||||
SPACTION_MOVING = 1,
|
||||
SPACTION_COPYING = 2,
|
||||
SPACTION_RECYCLING = 3,
|
||||
SPACTION_APPLYINGATTRIBS = 4,
|
||||
SPACTION_DOWNLOADING = 5,
|
||||
SPACTION_SEARCHING_INTERNET = 6,
|
||||
SPACTION_CALCULATING = 7,
|
||||
SPACTION_UPLOADING = 8,
|
||||
SPACTION_SEARCHING_FILES = 9,
|
||||
SPACTION_DELETING = 10,
|
||||
SPACTION_RENAMING = 11,
|
||||
SPACTION_FORMATTING = 12,
|
||||
SPACTION_COPY_MOVING = 13,
|
||||
}
|
||||
Reference in New Issue
Block a user