mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
#impl 1096
This commit is contained in:
@@ -18,4 +18,23 @@ public sealed class UnsafeRuntimeBehaviorTest
|
||||
Assert.AreEqual(uint.MaxValue, *(uint*)pBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public sealed class NewModifierRuntimeBehaviorTest
|
||||
{
|
||||
private interface IBase
|
||||
{
|
||||
int GetValue();
|
||||
}
|
||||
|
||||
private interface IBaseImpl : IBase
|
||||
{
|
||||
new int GetValue();
|
||||
}
|
||||
|
||||
private sealed class Impl : IBaseImpl
|
||||
{
|
||||
public int GetValue() => 1;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/microsoft/CsWin32/main/src/Microsoft.Windows.CsWin32/settings.schema.json",
|
||||
"allowMarshaling": true,
|
||||
"useSafeHandles": false
|
||||
"useSafeHandles": false,
|
||||
"comInterop": {
|
||||
"preserveSigMethods": [
|
||||
"IFileOpenDialog.Show",
|
||||
"IFileSaveDialog.Show"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,9 @@ WriteProcessMemory
|
||||
CoCreateInstance
|
||||
CoWaitForMultipleObjects
|
||||
|
||||
// SHELL32
|
||||
SHCreateItemFromParsingName
|
||||
|
||||
// USER32
|
||||
AttachThreadInput
|
||||
FindWindowExW
|
||||
@@ -47,18 +50,21 @@ SetForegroundWindow
|
||||
UnregisterHotKey
|
||||
|
||||
// COM
|
||||
FileOpenDialog
|
||||
FileSaveDialog
|
||||
IFileOpenDialog
|
||||
IFileSaveDialog
|
||||
IPersistFile
|
||||
IShellLinkW
|
||||
ShellLink
|
||||
SHELL_LINK_DATA_FLAGS
|
||||
FileOpenDialog
|
||||
IFileOpenDialog
|
||||
|
||||
// WinRT
|
||||
IMemoryBufferByteAccess
|
||||
|
||||
// Const value
|
||||
INFINITE
|
||||
MAX_PATH
|
||||
WM_GETMINMAXINFO
|
||||
WM_HOTKEY
|
||||
WM_NCRBUTTONDOWN
|
||||
@@ -66,6 +72,8 @@ WM_NCRBUTTONUP
|
||||
WM_NULL
|
||||
|
||||
// Type & Enum definition
|
||||
HRESULT_FROM_WIN32
|
||||
SLGP_FLAGS
|
||||
|
||||
// System.Threading
|
||||
LPTHREAD_START_ROUTINE
|
||||
|
||||
@@ -8,8 +8,7 @@ internal static partial class PInvoke
|
||||
{
|
||||
/// <inheritdoc cref="CoCreateInstance(Guid*, object, CLSCTX, Guid*, out object)"/>
|
||||
internal static unsafe HRESULT CoCreateInstance<TClass, TInterface>(object? pUnkOuter, CLSCTX dwClsContext, out TInterface ppv)
|
||||
where TInterface : class
|
||||
|
||||
where TInterface : class
|
||||
{
|
||||
HRESULT hr = CoCreateInstance(typeof(TClass).GUID, pUnkOuter, dwClsContext, typeof(TInterface).GUID, out object o);
|
||||
ppv = (TInterface)o;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/NumericValue.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/PageOverride.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/PivotOverride.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/ScrollViewer.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/SettingsStyle.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/TransitionCollection.xaml"/>
|
||||
<ResourceDictionary Source="ms-appx:///Control/Theme/Uri.xaml"/>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Helper;
|
||||
|
||||
[SuppressMessage("", "SH001")]
|
||||
[DependencyProperty("LeftPanelMaxWidth", typeof(double), IsAttached = true, AttachedType = typeof(ScrollViewer))]
|
||||
[DependencyProperty("RightPanel", typeof(UIElement), IsAttached = true, AttachedType = typeof(ScrollViewer))]
|
||||
public sealed partial class ScrollViewerHelper
|
||||
{
|
||||
}
|
||||
287
src/Snap.Hutao/Snap.Hutao/Control/Theme/ScrollViewer.xaml
Normal file
287
src/Snap.Hutao/Snap.Hutao/Control/Theme/ScrollViewer.xaml
Normal file
@@ -0,0 +1,287 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:shch="using:Snap.Hutao.Control.Helper">
|
||||
<Style x:Key="TwoPanelScrollViewerStyle" TargetType="ScrollViewer">
|
||||
<Setter Property="HorizontalScrollMode" Value="Auto"/>
|
||||
<Setter Property="VerticalScrollMode" Value="Auto"/>
|
||||
<Setter Property="IsHorizontalRailEnabled" Value="True"/>
|
||||
<Setter Property="IsVerticalRailEnabled" Value="True"/>
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="ZoomMode" Value="Disabled"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Top"/>
|
||||
<Setter Property="VerticalScrollBarVisibility" Value="Visible"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ScrollViewer">
|
||||
<Border
|
||||
x:Name="Root"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Grid Background="{TemplateBinding Background}">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
Grid.RowSpan="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{TemplateBinding Padding}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" MaxWidth="{Binding Path=(shch:ScrollViewerHelper.LeftPanelMaxWidth), RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollContentPresenter x:Name="ScrollContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}"/>
|
||||
<ContentPresenter Grid.Column="1" Content="{Binding Path=(shch:ScrollViewerHelper.RightPanel), RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.RowSpan="2" Grid.ColumnSpan="2"/>
|
||||
<Grid
|
||||
Grid.Column="1"
|
||||
Padding="{ThemeResource ScrollViewerScrollBarMargin}"
|
||||
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}">
|
||||
<ScrollBar
|
||||
x:Name="VerticalScrollBar"
|
||||
HorizontalAlignment="Right"
|
||||
IsTabStop="False"
|
||||
Maximum="{TemplateBinding ScrollableHeight}"
|
||||
Orientation="Vertical"
|
||||
ViewportSize="{TemplateBinding ViewportHeight}"
|
||||
Value="{TemplateBinding VerticalOffset}"/>
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Padding="{ThemeResource ScrollViewerScrollBarMargin}"
|
||||
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}">
|
||||
<ScrollBar
|
||||
x:Name="HorizontalScrollBar"
|
||||
IsTabStop="False"
|
||||
Maximum="{TemplateBinding ScrollableWidth}"
|
||||
Orientation="Horizontal"
|
||||
ViewportSize="{TemplateBinding ViewportWidth}"
|
||||
Value="{TemplateBinding HorizontalOffset}"/>
|
||||
</Grid>
|
||||
<Border
|
||||
x:Name="ScrollBarSeparator"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Background="{ThemeResource ScrollViewerScrollBarSeparatorBackground}"
|
||||
Opacity="0"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="ScrollingIndicatorStates">
|
||||
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition From="MouseIndicator" To="NoIndicator">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollViewerSeparatorContractDelay}">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollViewerSeparatorContractDelay}">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="MouseIndicatorFull" To="NoIndicator">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollViewerSeparatorContractDelay}">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollViewerSeparatorContractDelay}">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="MouseIndicatorFull" To="MouseIndicator">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollViewerSeparatorContractDelay}">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollViewerSeparatorContractDelay}">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
<VisualTransition From="TouchIndicator" To="NoIndicator">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="NoIndicator"/>
|
||||
<VisualState x:Name="TouchIndicator">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MouseIndicator">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MouseIndicatorFull">
|
||||
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ScrollBarSeparatorStates">
|
||||
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition From="ScrollBarSeparatorExpanded" To="ScrollBarSeparatorCollapsed">
|
||||
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="{ThemeResource ScrollViewerSeparatorContractBeginTime}"
|
||||
Storyboard.TargetName="ScrollBarSeparator"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="{ThemeResource ScrollViewerSeparatorContractDuration}"/>
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="ScrollBarSeparatorCollapsed"/>
|
||||
<VisualState x:Name="ScrollBarSeparatorExpanded">
|
||||
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="{ThemeResource ScrollViewerSeparatorExpandBeginTime}"
|
||||
Storyboard.TargetName="ScrollBarSeparator"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1"
|
||||
Duration="{ThemeResource ScrollViewerSeparatorExpandDuration}"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="ScrollBarSeparatorExpandedWithoutAnimation">
|
||||
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="{ThemeResource ScrollViewerSeparatorExpandBeginTime}"
|
||||
Storyboard.TargetName="ScrollBarSeparator"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1"
|
||||
Duration="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="ScrollBarSeparatorCollapsedWithoutAnimation">
|
||||
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="{ThemeResource ScrollViewerSeparatorContractBeginTime}"
|
||||
Storyboard.TargetName="ScrollBarSeparator"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -9,11 +9,6 @@ namespace Snap.Hutao.Core.Windowing;
|
||||
[HighQuality]
|
||||
internal enum BackdropType
|
||||
{
|
||||
/// <summary>
|
||||
/// 透明
|
||||
/// </summary>
|
||||
Transparent = -1,
|
||||
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.Shell.Common;
|
||||
using static Windows.Win32.PInvoke;
|
||||
|
||||
namespace Snap.Hutao.Factory.Picker;
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Transient, typeof(IFileSystemPickerInteraction))]
|
||||
internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInteraction
|
||||
{
|
||||
private readonly ICurrentWindowReference currentWindowReference;
|
||||
|
||||
public unsafe ValueResult<bool, ValueFile> PickFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters)
|
||||
{
|
||||
CoCreateInstance<FileOpenDialog, IFileOpenDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileOpenDialog dialog).ThrowOnFailure();
|
||||
|
||||
FILEOPENDIALOGOPTIONS options =
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOTESTFILECREATE |
|
||||
FILEOPENDIALOGOPTIONS.FOS_FORCEFILESYSTEM |
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR;
|
||||
|
||||
dialog.SetOptions(options);
|
||||
SetDesktopAsStartupFolder(dialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
dialog.SetTitle(title);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(defaultFileName))
|
||||
{
|
||||
dialog.SetFileName(defaultFileName);
|
||||
}
|
||||
|
||||
if (filters is { Length: > 0 })
|
||||
{
|
||||
SetFileTypes(dialog, filters);
|
||||
}
|
||||
|
||||
HRESULT res = dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
if (res == HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED))
|
||||
{
|
||||
return new(false, default);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(res);
|
||||
}
|
||||
|
||||
dialog.GetResult(out IShellItem item);
|
||||
|
||||
PWSTR displayName = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new((char*)displayName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)displayName.Value);
|
||||
}
|
||||
|
||||
return new(true, file);
|
||||
}
|
||||
|
||||
public unsafe ValueResult<bool, ValueFile> SaveFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters)
|
||||
{
|
||||
CoCreateInstance<FileSaveDialog, IFileSaveDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileSaveDialog dialog).ThrowOnFailure();
|
||||
|
||||
FILEOPENDIALOGOPTIONS options =
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOTESTFILECREATE |
|
||||
FILEOPENDIALOGOPTIONS.FOS_FORCEFILESYSTEM |
|
||||
FILEOPENDIALOGOPTIONS.FOS_STRICTFILETYPES |
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR;
|
||||
|
||||
dialog.SetOptions(options);
|
||||
SetDesktopAsStartupFolder(dialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
dialog.SetTitle(title);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(defaultFileName))
|
||||
{
|
||||
dialog.SetFileName(defaultFileName);
|
||||
}
|
||||
|
||||
if (filters is { Length: > 0 })
|
||||
{
|
||||
SetFileTypes(dialog, filters);
|
||||
}
|
||||
|
||||
HRESULT res = dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
if (res == HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED))
|
||||
{
|
||||
return new(false, default);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(res);
|
||||
}
|
||||
|
||||
dialog.GetResult(out IShellItem item);
|
||||
|
||||
PWSTR displayName = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new((char*)displayName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)displayName.Value);
|
||||
}
|
||||
|
||||
return new(true, file);
|
||||
}
|
||||
|
||||
public unsafe ValueResult<bool, string> PickFolder(string? title)
|
||||
{
|
||||
CoCreateInstance<FileOpenDialog, IFileOpenDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileOpenDialog dialog).ThrowOnFailure();
|
||||
|
||||
FILEOPENDIALOGOPTIONS options =
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOTESTFILECREATE |
|
||||
FILEOPENDIALOGOPTIONS.FOS_FORCEFILESYSTEM |
|
||||
FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS |
|
||||
FILEOPENDIALOGOPTIONS.FOS_NOCHANGEDIR;
|
||||
|
||||
dialog.SetOptions(options);
|
||||
SetDesktopAsStartupFolder(dialog);
|
||||
|
||||
if (!string.IsNullOrEmpty(title))
|
||||
{
|
||||
dialog.SetTitle(title);
|
||||
}
|
||||
|
||||
HRESULT res = dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
if (res == HRESULT_FROM_WIN32(WIN32_ERROR.ERROR_CANCELLED))
|
||||
{
|
||||
return new(false, default!);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(res);
|
||||
}
|
||||
|
||||
dialog.GetResult(out IShellItem item);
|
||||
|
||||
PWSTR displayName = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out displayName);
|
||||
file = new((char*)displayName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)displayName.Value);
|
||||
}
|
||||
|
||||
return new(true, file);
|
||||
}
|
||||
|
||||
private static unsafe void SetFileTypes<TDialog>(TDialog dialog, (string Name, string Type)[] filters)
|
||||
where TDialog : IFileDialog
|
||||
{
|
||||
List<nint> unmanagedStringPtrs = new(filters.Length * 2);
|
||||
List<COMDLG_FILTERSPEC> filterSpecs = new(filters.Length);
|
||||
foreach ((string name, string type) in filters)
|
||||
{
|
||||
nint pName = Marshal.StringToHGlobalUni(name);
|
||||
nint pType = Marshal.StringToHGlobalUni(type);
|
||||
unmanagedStringPtrs.Add(pName);
|
||||
unmanagedStringPtrs.Add(pType);
|
||||
COMDLG_FILTERSPEC spec = default;
|
||||
spec.pszName = *(PCWSTR*)&pName;
|
||||
spec.pszSpec = *(PCWSTR*)&pType;
|
||||
filterSpecs.Add(spec);
|
||||
}
|
||||
|
||||
fixed (COMDLG_FILTERSPEC* ptr = CollectionsMarshal.AsSpan(filterSpecs))
|
||||
{
|
||||
dialog.SetFileTypes((uint)filterSpecs.Count, ptr);
|
||||
}
|
||||
|
||||
foreach (ref readonly nint ptr in CollectionsMarshal.AsSpan(unmanagedStringPtrs))
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void SetDesktopAsStartupFolder<TDialog>(TDialog dialog)
|
||||
where TDialog : IFileDialog
|
||||
{
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
SHCreateItemFromParsingName(desktopPath, default, typeof(IShellItem).GUID, out object shellItem).ThrowOnFailure();
|
||||
dialog.SetFolder((IShellItem)shellItem);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.IO;
|
||||
|
||||
namespace Snap.Hutao.Factory.Picker;
|
||||
|
||||
internal static class FileSystemPickerInteractionExtension
|
||||
{
|
||||
public static ValueResult<bool, ValueFile> PickFile(this IFileSystemPickerInteraction interaction, string? title, (string Name, string Type)[]? filters)
|
||||
{
|
||||
return interaction.PickFile(title, null, filters);
|
||||
}
|
||||
|
||||
public static ValueResult<bool, string> PickFolder(this IFileSystemPickerInteraction interaction)
|
||||
{
|
||||
return interaction.PickFolder(null);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,15 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using Snap.Hutao.Core.IO;
|
||||
|
||||
namespace Snap.Hutao.Factory.Picker;
|
||||
|
||||
internal interface IFileSystemPickerInteraction
|
||||
{
|
||||
}
|
||||
ValueResult<bool, ValueFile> PickFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters);
|
||||
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Transient, typeof(IFileSystemPickerInteraction))]
|
||||
internal sealed partial class FileSystemPickerInteraction : IFileSystemPickerInteraction
|
||||
{
|
||||
private readonly ICurrentWindowReference currentWindowReference;
|
||||
ValueResult<bool, string> PickFolder(string? title);
|
||||
|
||||
public unsafe string PickFile()
|
||||
{
|
||||
HRESULT result = CoCreateInstance<FileOpenDialog, IFileOpenDialog>(default, CLSCTX.CLSCTX_INPROC_SERVER, out IFileOpenDialog dialog);
|
||||
Marshal.ThrowExceptionForHR(result);
|
||||
|
||||
dialog.Show(currentWindowReference.GetWindowHandle());
|
||||
dialog.GetResult(out IShellItem item);
|
||||
PWSTR name = default;
|
||||
string file;
|
||||
try
|
||||
{
|
||||
item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out name);
|
||||
file = new((char*)name);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeCoTaskMem((nint)name.Value);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
ValueResult<bool, ValueFile> SaveFile(string? title, string? defaultFileName, (string Name, string Type)[]? filters);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Windows.Storage.Pickers;
|
||||
|
||||
namespace Snap.Hutao.Factory.Picker;
|
||||
|
||||
/// <summary>
|
||||
/// 文件选择器工厂
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal interface IPickerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取 经过初始化的 <see cref="FileOpenPicker"/>
|
||||
/// </summary>
|
||||
/// <param name="location">初始位置</param>
|
||||
/// <param name="commitButton">提交按钮文本</param>
|
||||
/// <param name="fileTypes">文件类型</param>
|
||||
/// <returns>经过初始化的 <see cref="FileOpenPicker"/></returns>
|
||||
FileOpenPicker GetFileOpenPicker(PickerLocationId location, string commitButton, params string[] fileTypes);
|
||||
|
||||
/// <summary>
|
||||
/// 获取 经过初始化的 <see cref="FileSavePicker"/>
|
||||
/// </summary>
|
||||
/// <param name="location">初始位置</param>
|
||||
/// <param name="fileName">文件名</param>
|
||||
/// <param name="commitButton">提交按钮文本</param>
|
||||
/// <param name="fileTypes">文件类型</param>
|
||||
/// <returns>经过初始化的 <see cref="FileSavePicker"/></returns>
|
||||
FileSavePicker GetFileSavePicker(PickerLocationId location, string fileName, string commitButton, IDictionary<string, IList<string>> fileTypes);
|
||||
|
||||
/// <summary>
|
||||
/// 获取 经过初始化的 <see cref="FolderPicker"/>
|
||||
/// </summary>
|
||||
/// <returns>经过初始化的 <see cref="FolderPicker"/></returns>
|
||||
FolderPicker GetFolderPicker();
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.Win32.Foundation;
|
||||
using WinRT.Interop;
|
||||
|
||||
namespace Snap.Hutao.Factory.Picker;
|
||||
|
||||
/// <inheritdoc cref="IPickerFactory"/>
|
||||
[HighQuality]
|
||||
[ConstructorGenerated]
|
||||
[Injection(InjectAs.Transient, typeof(IPickerFactory))]
|
||||
internal sealed partial class PickerFactory : IPickerFactory
|
||||
{
|
||||
private const string AnyType = "*";
|
||||
|
||||
private readonly ICurrentWindowReference currentWindowReference;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FileOpenPicker GetFileOpenPicker(PickerLocationId location, string commitButton, params string[] fileTypes)
|
||||
{
|
||||
FileOpenPicker picker = GetInitializedPicker<FileOpenPicker>();
|
||||
|
||||
picker.SuggestedStartLocation = location;
|
||||
picker.CommitButtonText = commitButton;
|
||||
|
||||
foreach (string type in fileTypes)
|
||||
{
|
||||
picker.FileTypeFilter.Add(type);
|
||||
}
|
||||
|
||||
// below Windows 11
|
||||
if (!UniversalApiContract.IsPresent(WindowsVersion.Windows11))
|
||||
{
|
||||
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
||||
picker.FileTypeFilter.Add(AnyType);
|
||||
}
|
||||
|
||||
return picker;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FileSavePicker GetFileSavePicker(PickerLocationId location, string fileName, string commitButton, IDictionary<string, IList<string>> fileTypes)
|
||||
{
|
||||
FileSavePicker picker = GetInitializedPicker<FileSavePicker>();
|
||||
|
||||
picker.SuggestedStartLocation = location;
|
||||
picker.SuggestedFileName = fileName;
|
||||
picker.CommitButtonText = commitButton;
|
||||
|
||||
foreach (KeyValuePair<string, IList<string>> kvp in fileTypes)
|
||||
{
|
||||
picker.FileTypeChoices.Add(kvp);
|
||||
}
|
||||
|
||||
return picker;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FolderPicker GetFolderPicker()
|
||||
{
|
||||
FolderPicker picker = GetInitializedPicker<FolderPicker>();
|
||||
|
||||
// below Windows 11
|
||||
if (!UniversalApiContract.IsPresent(WindowsVersion.Windows11))
|
||||
{
|
||||
// https://github.com/microsoft/WindowsAppSDK/issues/2931
|
||||
picker.FileTypeFilter.Add(AnyType);
|
||||
}
|
||||
|
||||
return picker;
|
||||
}
|
||||
|
||||
private T GetInitializedPicker<T>()
|
||||
where T : new()
|
||||
{
|
||||
// Create a folder picker.
|
||||
T picker = new();
|
||||
|
||||
HWND hwnd = currentWindowReference.GetWindowHandle();
|
||||
InitializeWithWindow.Initialize(picker, hwnd);
|
||||
|
||||
return picker;
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ namespace Snap.Hutao;
|
||||
[SuppressMessage("", "CA1001")]
|
||||
internal sealed partial class MainWindow : Window, IWindowOptionsSource, IMinMaxInfoHandler
|
||||
{
|
||||
private const int MinWidth = 848;
|
||||
private const int MinHeight = 524;
|
||||
private const int MinWidth = 1200;
|
||||
private const int MinHeight = 750;
|
||||
|
||||
private readonly WindowOptions windowOptions;
|
||||
private readonly ILogger<MainWindow> logger;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<Identity
|
||||
Name="60568DGPStudio.SnapHutao"
|
||||
Publisher="CN=35C8E923-85DF-49A7-9172-B39DC6312C52"
|
||||
Version="1.7.18.0" />
|
||||
Version="1.7.19.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Snap Hutao</DisplayName>
|
||||
|
||||
@@ -599,6 +599,12 @@
|
||||
<data name="ServiceAchievementImportResultFormat" xml:space="preserve">
|
||||
<value>新增:{0} 个成就 | 更新:{1} 个成就 | 删除:{2} 个成就</value>
|
||||
</data>
|
||||
<data name="ServiceAchievementUIAFImportPickerFilterText" xml:space="preserve">
|
||||
<value>UIAF Json 文件</value>
|
||||
</data>
|
||||
<data name="ServiceAchievementUIAFImportPickerTitile" xml:space="preserve">
|
||||
<value>打开 UIAF Json 文件</value>
|
||||
</data>
|
||||
<data name="ServiceAchievementUserdataCorruptedInnerIdNotUnique" xml:space="preserve">
|
||||
<value>单个成就存档内发现多个相同的成就 Id</value>
|
||||
</data>
|
||||
@@ -869,6 +875,9 @@
|
||||
<data name="ServiceGameLocatorFileOpenPickerCommitText" xml:space="preserve">
|
||||
<value>选择游戏本体</value>
|
||||
</data>
|
||||
<data name="ServiceGameLocatorPickerFilterText" xml:space="preserve">
|
||||
<value>游戏本体</value>
|
||||
</data>
|
||||
<data name="ServiceGameLocatorUnityLogFileNotFound" xml:space="preserve">
|
||||
<value>找不到 Unity 日志文件</value>
|
||||
</data>
|
||||
@@ -1334,6 +1343,9 @@
|
||||
<data name="ViewModelAchievementRemoveArchiveTitle" xml:space="preserve">
|
||||
<value>确定要删除存档 {0} 吗?</value>
|
||||
</data>
|
||||
<data name="ViewModelAchievementUIAFExportPickerTitle" xml:space="preserve">
|
||||
<value>导出 UIAF Json 文件到指定路径</value>
|
||||
</data>
|
||||
<data name="ViewModelAvatarPropertyBatchCultivateProgressTitle" xml:space="preserve">
|
||||
<value>获取培养材料中,请稍候...</value>
|
||||
</data>
|
||||
@@ -1460,9 +1472,15 @@
|
||||
<data name="ViewModelGachaLogRetrieveFromHutaoCloudProgress" xml:space="preserve">
|
||||
<value>从胡桃云服务同步祈愿记录</value>
|
||||
</data>
|
||||
<data name="ViewModelGachaLogUIGFExportPickerTitle" xml:space="preserve">
|
||||
<value>导出 UIGF Json 文件到指定路径</value>
|
||||
</data>
|
||||
<data name="ViewModelGachaLogUploadToHutaoCloudProgress" xml:space="preserve">
|
||||
<value>正在上传到胡桃云服务</value>
|
||||
</data>
|
||||
<data name="ViewModelGachaUIGFImportPickerTitile" xml:space="preserve">
|
||||
<value>导入 UIGF Json 文件</value>
|
||||
</data>
|
||||
<data name="ViewModelGuideActionAgreement" xml:space="preserve">
|
||||
<value>我已阅读并同意上方的条款</value>
|
||||
</data>
|
||||
|
||||
@@ -44,21 +44,18 @@ internal sealed class GameRecordCharacterAvatarInfoTransformer : IAvatarInfoTran
|
||||
|
||||
Equip equip = avatarInfo.EquipList.Last();
|
||||
|
||||
if (equip.ItemId != source.Weapon.Id)
|
||||
// 切换了武器
|
||||
equip.ItemId = source.Weapon.Id;
|
||||
equip.Weapon = new()
|
||||
{
|
||||
// 切换了武器
|
||||
equip.ItemId = source.Weapon.Id;
|
||||
equip.Weapon = new()
|
||||
Level = source.Weapon.Level,
|
||||
AffixMap = new()
|
||||
{
|
||||
Level = source.Weapon.Level,
|
||||
AffixMap = new()
|
||||
{
|
||||
[100000 + source.Weapon.Id] = source.Weapon.AffixLevel - 1,
|
||||
},
|
||||
};
|
||||
[100000U + source.Weapon.Id] = source.Weapon.AffixLevel - 1,
|
||||
},
|
||||
};
|
||||
|
||||
// Special case here, don't set EQUIP_WEAPON
|
||||
equip.Flat = new() { ItemType = ItemType.ITEM_WEAPON, };
|
||||
}
|
||||
// Special case here, don't set EQUIP_WEAPON
|
||||
equip.Flat = new() { ItemType = ItemType.ITEM_WEAPON, };
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Factory.Picker;
|
||||
using Windows.Storage.Pickers;
|
||||
|
||||
namespace Snap.Hutao.Service.Game.Locator;
|
||||
|
||||
@@ -15,30 +14,24 @@ namespace Snap.Hutao.Service.Game.Locator;
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal sealed partial class ManualGameLocator : IGameLocator
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IPickerFactory pickerFactory;
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<ValueResult<bool, string>> LocateGamePathAsync()
|
||||
public ValueTask<ValueResult<bool, string>> LocateGamePathAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
|
||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker(
|
||||
PickerLocationId.Desktop,
|
||||
(bool isPickerOk, ValueFile file) = fileSystemPickerInteraction.PickFile(
|
||||
SH.ServiceGameLocatorFileOpenPickerCommitText,
|
||||
".exe");
|
||||
|
||||
(bool isPickerOk, ValueFile file) = await picker.TryPickSingleFileAsync().ConfigureAwait(false);
|
||||
[(SH.ServiceGameLocatorPickerFilterText, $"{GameConstants.YuanShenFileName};{GameConstants.GenshinImpactFileName}")]);
|
||||
|
||||
if (isPickerOk)
|
||||
{
|
||||
string fileName = System.IO.Path.GetFileName(file);
|
||||
if (fileName is GameConstants.YuanShenFileName or GameConstants.GenshinImpactFileName)
|
||||
{
|
||||
return new(true, file);
|
||||
return ValueTask.FromResult<ValueResult<bool, string>>(new(true, file));
|
||||
}
|
||||
}
|
||||
|
||||
return new(false, default!);
|
||||
return ValueTask.FromResult<ValueResult<bool, string>>(new(false, default!));
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@
|
||||
<UseRidGraph>true</UseRidGraph>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
|
||||
<PublishProfile>win10-$(Platform).pubxml</PublishProfile>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<UseWPF>False</UseWPF>
|
||||
<UseWindowsForms>False</UseWindowsForms>
|
||||
@@ -89,6 +88,7 @@
|
||||
<None Remove="Control\Theme\NumericValue.xaml" />
|
||||
<None Remove="Control\Theme\PageOverride.xaml" />
|
||||
<None Remove="Control\Theme\PivotOverride.xaml" />
|
||||
<None Remove="Control\Theme\ScrollViewer.xaml" />
|
||||
<None Remove="Control\Theme\SettingsStyle.xaml" />
|
||||
<None Remove="Control\Theme\TransitionCollection.xaml" />
|
||||
<None Remove="Control\Theme\Uri.xaml" />
|
||||
@@ -282,6 +282,7 @@
|
||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.8.8" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231115000" />
|
||||
<PackageReference Include="Snap.Discord.GameSDK" Version="1.1.0" />
|
||||
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.507">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@@ -316,6 +317,12 @@
|
||||
<AdditionalFiles Include="Resource\Localization\SH.zh-Hant.resx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Control\Theme\ScrollViewer.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Control\Theme\FlyoutStyle.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -121,7 +121,10 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Inner.Title}"/>
|
||||
<TextBlock
|
||||
Text="{Binding Inner.Title}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
<Border
|
||||
Margin="4,0,0,0"
|
||||
Padding="4,1"
|
||||
@@ -144,7 +147,8 @@
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding Inner.Description}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -7,77 +7,89 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shc="using:Snap.Hutao.Control"
|
||||
xmlns:shch="using:Snap.Hutao.Control.Helper"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvs="using:Snap.Hutao.ViewModel.Setting"
|
||||
d:DataContext="{d:DesignInstance shvs:SettingViewModel}"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition MaxWidth="1000"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Margin="16,16,16,16" Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<ScrollViewer shch:ScrollViewerHelper.LeftPanelMaxWidth="800" Style="{StaticResource TwoPanelScrollViewerStyle}">
|
||||
<shch:ScrollViewerHelper.RightPanel>
|
||||
<StackPanel Width="360" Margin="0,16,16,16">
|
||||
<Border cw:Effects.Shadow="{ThemeResource CompatCardShadow}">
|
||||
<Grid Height="280" Style="{ThemeResource GridCardStyle}">
|
||||
<Border CornerRadius="{ThemeResource ControlCornerRadius}">
|
||||
<Image
|
||||
VerticalAlignment="Center"
|
||||
Source="ms-appx:///Resource/BlurBackground.png"
|
||||
Stretch="Fill"/>
|
||||
<Grid Style="{ThemeResource GridCardStyle}">
|
||||
<Border
|
||||
VerticalAlignment="Stretch"
|
||||
cw:UIElementExtensions.ClipToBounds="True"
|
||||
CornerRadius="{ThemeResource ControlCornerRadius}">
|
||||
<Image Source="ms-appx:///Resource/BlurBackground.png" Stretch="Fill"/>
|
||||
</Border>
|
||||
|
||||
<Grid Background="{ThemeResource SystemControlBackgroundAltMediumBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Margin="48"
|
||||
MaxWidth="120"
|
||||
MaxHeight="120"
|
||||
Margin="48,48"
|
||||
Source="ms-appx:///Assets/Square44x44Logo.targetsize-256.png"/>
|
||||
<StackPanel
|
||||
<cwc:UniformGrid
|
||||
Grid.Row="1"
|
||||
Margin="8"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Bottom"
|
||||
Orientation="Horizontal">
|
||||
ColumnSpacing="8"
|
||||
Columns="2"
|
||||
RowSpacing="8">
|
||||
<HyperlinkButton
|
||||
Margin="0,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Command="{Binding UpdateCheckCommand}"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingUpdateCheckAction}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Command="{Binding StoreReviewCommand}"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingStoreReviewNavigate}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingOfficialSiteNavigate}"
|
||||
NavigateUri="{StaticResource DocumentLink_Home}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingFeedbackNavigate}"
|
||||
NavigateUri="{StaticResource DocumentLink_BugReport}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingTranslateNavigate}"
|
||||
NavigateUri="{StaticResource DocumentLink_Translate}"/>
|
||||
<HyperlinkButton
|
||||
Margin="12,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Content="{shcm:ResourceString Name=ViewPageSettingSponsorNavigate}"
|
||||
NavigateUri="{StaticResource Sponsor_Afadian}"/>
|
||||
</StackPanel>
|
||||
</cwc:UniformGrid>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="8"
|
||||
HorizontalAlignment="Center"
|
||||
Opacity="0.7"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="Copyright © 2022 - 2024 DGP Studio. All Rights Reserved."
|
||||
TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="0,4"
|
||||
Text="Copyright © 2022 - 2024 DGP Studio. All Rights Reserved."
|
||||
TextWrapping="Wrap"/>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingAboutHeader}"/>
|
||||
</StackPanel>
|
||||
</shch:ScrollViewerHelper.RightPanel>
|
||||
<Grid Padding="16" HorizontalAlignment="Left">
|
||||
<StackPanel Grid.Column="0" Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<cwc:SettingsExpander
|
||||
Description="{Binding HutaoOptions.Version}"
|
||||
Header="{shcm:ResourceString Name=AppName}"
|
||||
@@ -200,28 +212,36 @@
|
||||
Description="{shcm:ResourceString Name=ViewPageSettingKeyShortcutAutoClickingDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingKeyShortcutAutoClickingHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="16">
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Win"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasWindows, Mode=TwoWay}"/>
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Ctrl"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasControl, Mode=TwoWay}"/>
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Shift"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasShift, Mode=TwoWay}"/>
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Alt"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasAlt, Mode=TwoWay}"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<cwc:UniformGrid
|
||||
Margin="16,-12"
|
||||
ColumnSpacing="16"
|
||||
Columns="2"
|
||||
Orientation="Horizontal"
|
||||
RowSpacing="0">
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Win"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasWindows, Mode=TwoWay}"/>
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Ctrl"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasControl, Mode=TwoWay}"/>
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Shift"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasShift, Mode=TwoWay}"/>
|
||||
<CheckBox
|
||||
MinWidth="64"
|
||||
VerticalAlignment="Center"
|
||||
Content="Alt"
|
||||
IsChecked="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.ModifierHasAlt, Mode=TwoWay}"/>
|
||||
</cwc:UniformGrid>
|
||||
<ComboBox
|
||||
MinWidth="120"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="Name"
|
||||
ItemsSource="{Binding HotKeyOptions.VirtualKeys}"
|
||||
@@ -233,6 +253,7 @@
|
||||
IsOn="{Binding HotKeyOptions.MouseClickRepeatForeverKeyCombination.IsEnabled, Mode=TwoWay}"/>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</cwc:SettingsCard>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewpageSettingHomeHeader}"/>
|
||||
|
||||
@@ -11,7 +11,6 @@ using Snap.Hutao.Model.InterChange.Achievement;
|
||||
using Snap.Hutao.Service.Achievement;
|
||||
using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using Windows.Storage.Pickers;
|
||||
using EntityAchievementArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Achievement;
|
||||
@@ -24,11 +23,11 @@ namespace Snap.Hutao.ViewModel.Achievement;
|
||||
[Injection(InjectAs.Scoped)]
|
||||
internal sealed partial class AchievementImporter
|
||||
{
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IClipboardProvider clipboardInterop;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly IPickerFactory pickerFactory;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
@@ -65,10 +64,9 @@ internal sealed partial class AchievementImporter
|
||||
{
|
||||
if (achievementService.CurrentArchive is { } archive)
|
||||
{
|
||||
ValueResult<bool, ValueFile> pickerResult = await pickerFactory
|
||||
.GetFileOpenPicker(PickerLocationId.Desktop, SH.FilePickerImportCommit, ".json")
|
||||
.TryPickSingleFileAsync()
|
||||
.ConfigureAwait(false);
|
||||
ValueResult<bool, ValueFile> pickerResult = fileSystemPickerInteraction.PickFile(
|
||||
SH.ServiceAchievementUIAFImportPickerTitile,
|
||||
[(SH.ServiceAchievementUIAFImportPickerFilterText, ".json")]);
|
||||
|
||||
if (pickerResult.TryGetValue(out ValueFile file))
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using Windows.Storage.Pickers;
|
||||
using EntityAchievementArchive = Snap.Hutao.Model.Entity.AchievementArchive;
|
||||
using MetadataAchievement = Snap.Hutao.Model.Metadata.Achievement.Achievement;
|
||||
using MetadataAchievementGoal = Snap.Hutao.Model.Metadata.Achievement.AchievementGoal;
|
||||
@@ -33,8 +32,8 @@ 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 IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IPickerFactory pickerFactory;
|
||||
private readonly AchievementImporter achievementImporter;
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IMetadataService metadataService;
|
||||
@@ -257,17 +256,12 @@ internal sealed partial class AchievementViewModel : Abstraction.ViewModel, INav
|
||||
{
|
||||
if (SelectedArchive is not null && Achievements is not null)
|
||||
{
|
||||
string fileName = $"{achievementService.CurrentArchive?.Name}.json";
|
||||
Dictionary<string, IList<string>> fileTypes = new()
|
||||
{
|
||||
[SH.ViewModelAchievementExportFileType] = [".json"],
|
||||
};
|
||||
(bool isOk, ValueFile file) = fileSystemPickerInteraction.SaveFile(
|
||||
SH.ViewModelAchievementUIAFExportPickerTitle,
|
||||
$"{achievementService.CurrentArchive?.Name}.json",
|
||||
[(SH.ViewModelAchievementExportFileType, "*.json")]);
|
||||
|
||||
FileSavePicker picker = pickerFactory
|
||||
.GetFileSavePicker(PickerLocationId.Desktop, fileName, SH.FilePickerExportCommit, fileTypes);
|
||||
|
||||
(bool isPickerOk, ValueFile file) = await picker.TryPickSaveFileAsync().ConfigureAwait(false);
|
||||
if (isPickerOk)
|
||||
if (isOk)
|
||||
{
|
||||
UIAF uiaf = await achievementService.ExportToUIAFAsync(SelectedArchive).ConfigureAwait(false);
|
||||
if (await file.SerializeToJsonAsync(uiaf, options).ConfigureAwait(false))
|
||||
|
||||
@@ -17,7 +17,6 @@ using Snap.Hutao.Service.Notification;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage.Pickers;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.GachaLog;
|
||||
|
||||
@@ -31,13 +30,13 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
{
|
||||
private readonly HutaoCloudStatisticsViewModel hutaoCloudStatisticsViewModel;
|
||||
private readonly IGachaLogQueryProviderFactory gachaLogQueryProviderFactory;
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly HutaoCloudViewModel hutaoCloudViewModel;
|
||||
private readonly IProgressFactory progressFactory;
|
||||
private readonly IGachaLogService gachaLogService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly IPickerFactory pickerFactory;
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
private ObservableCollection<GachaArchive>? archives;
|
||||
@@ -215,52 +214,52 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
|
||||
[Command("ImportFromUIGFJsonCommand")]
|
||||
private async Task ImportFromUIGFJsonAsync()
|
||||
{
|
||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker(PickerLocationId.Desktop, SH.FilePickerImportCommit, ".json");
|
||||
(bool isPickerOk, ValueFile file) = await picker.TryPickSingleFileAsync().ConfigureAwait(false);
|
||||
if (isPickerOk)
|
||||
(bool isOk, ValueFile file) = fileSystemPickerInteraction.PickFile(
|
||||
SH.ViewModelGachaUIGFImportPickerTitile,
|
||||
[(SH.ViewModelGachaLogExportFileType, "*.json")]);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
ValueResult<bool, UIGF?> result = await file.DeserializeFromJsonAsync<UIGF>(options).ConfigureAwait(false);
|
||||
if (result.TryGetValue(out UIGF? uigf))
|
||||
{
|
||||
await TryImportUIGFInternalAsync(uigf).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Error(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ValueResult<bool, UIGF?> result = await file.DeserializeFromJsonAsync<UIGF>(options).ConfigureAwait(false);
|
||||
if (result.TryGetValue(out UIGF? uigf))
|
||||
{
|
||||
await TryImportUIGFInternalAsync(uigf).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Error(SH.ViewModelImportWarningTitle, SH.ViewModelImportWarningMessage);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("ExportToUIGFJsonCommand")]
|
||||
private async Task ExportToUIGFJsonAsync()
|
||||
{
|
||||
if (SelectedArchive is not null)
|
||||
if (SelectedArchive is null)
|
||||
{
|
||||
Dictionary<string, IList<string>> fileTypes = new()
|
||||
{
|
||||
[SH.ViewModelGachaLogExportFileType] = [".json"],
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
FileSavePicker picker = pickerFactory.GetFileSavePicker(
|
||||
PickerLocationId.Desktop,
|
||||
$"{SelectedArchive.Uid}.json",
|
||||
SH.FilePickerExportCommit,
|
||||
fileTypes);
|
||||
(bool isOk, ValueFile file) = fileSystemPickerInteraction.SaveFile(
|
||||
SH.ViewModelGachaLogUIGFExportPickerTitle,
|
||||
$"{SelectedArchive.Uid}.json",
|
||||
[(SH.ViewModelGachaLogExportFileType, "*.json")]);
|
||||
|
||||
(bool isPickerOk, ValueFile file) = await picker.TryPickSaveFileAsync().ConfigureAwait(false);
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPickerOk)
|
||||
{
|
||||
UIGF uigf = await gachaLogService.ExportToUIGFAsync(SelectedArchive).ConfigureAwait(false);
|
||||
if (await file.SerializeToJsonAsync(uigf, options).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelExportSuccessTitle, SH.ViewModelExportSuccessMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelExportWarningTitle, SH.ViewModelExportWarningMessage);
|
||||
}
|
||||
}
|
||||
UIGF uigf = await gachaLogService.ExportToUIGFAsync(SelectedArchive).ConfigureAwait(false);
|
||||
if (await file.SerializeToJsonAsync(uigf, options).ConfigureAwait(false))
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelExportSuccessTitle, SH.ViewModelExportSuccessMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelExportWarningTitle, SH.ViewModelExportWarningMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ using Snap.Hutao.ViewModel.Guide;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.System;
|
||||
|
||||
namespace Snap.Hutao.ViewModel.Setting;
|
||||
@@ -41,6 +40,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
{
|
||||
private readonly HomeCardOptions homeCardOptions = new();
|
||||
|
||||
private readonly IFileSystemPickerInteraction fileSystemPickerInteraction;
|
||||
private readonly HutaoPassportViewModel hutaoPassportViewModel;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly IGameLocatorFactory gameLocatorFactory;
|
||||
@@ -50,7 +50,6 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
private readonly HutaoUserOptions hutaoUserOptions;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
private readonly IPickerFactory pickerFactory;
|
||||
private readonly HotKeyOptions hotKeyOptions;
|
||||
private readonly IUserService userService;
|
||||
private readonly ITaskContext taskContext;
|
||||
@@ -143,8 +142,7 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
[Command("SetPowerShellPathCommand")]
|
||||
private async Task SetPowerShellPathAsync()
|
||||
{
|
||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker(PickerLocationId.DocumentsLibrary, SH.FilePickerPowerShellCommit, ".exe");
|
||||
(bool isOk, ValueFile file) = await picker.TryPickSingleFileAsync().ConfigureAwait(false);
|
||||
(bool isOk, ValueFile file) = fileSystemPickerInteraction.PickFile(SH.FilePickerPowerShellCommit, [("PowerShell", "powershell.exe")]);
|
||||
|
||||
if (isOk && Path.GetFileNameWithoutExtension(file).Equals("POWERSHELL", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -200,12 +198,9 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel
|
||||
}
|
||||
|
||||
[Command("SetDataFolderCommand")]
|
||||
private async Task SetDataFolderAsync()
|
||||
private void SetDataFolder()
|
||||
{
|
||||
(bool isOk, string folder) = await pickerFactory
|
||||
.GetFolderPicker()
|
||||
.TryPickSingleFolderAsync()
|
||||
.ConfigureAwait(false);
|
||||
(bool isOk, string folder) = fileSystemPickerInteraction.PickFolder();
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user