ValueResult struct & new Icon

This commit is contained in:
DismissedLight
2022-09-06 22:21:45 +08:00
parent 4b544b7ee4
commit 7e5c26cf63
22 changed files with 240 additions and 24 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 KiB

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -0,0 +1,19 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Core.Abstraction;
/// <summary>
/// 指示该类可以解构为元组
/// </summary>
/// <typeparam name="T1">元组的第一个类型</typeparam>
/// <typeparam name="T2">元组的第二个类型</typeparam>
internal interface IDeconstructable<T1, T2>
{
/// <summary>
/// 解构
/// </summary>
/// <param name="t1">第一个元素</param>
/// <param name="t2">第二个元素</param>
void Deconstruct(out T1 t1, out T2 t2);
}

View File

@@ -13,4 +13,4 @@ internal interface ISupportValidation
/// </summary>
/// <returns>当前数据是否有效</returns>
public bool Validate();
}
}

View File

@@ -66,7 +66,7 @@ internal sealed partial class DatebaseLogger : ILogger
/// <summary>
/// An empty scope without any logic
/// </summary>
private class NullScope : IDisposable
private struct NullScope : IDisposable
{
public NullScope()
{

View File

@@ -1,38 +1,41 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Abstraction;
namespace Snap.Hutao.Core.Threading;
/// <summary>
/// 用于包装异步操作的结果
/// 结构类型,在栈上分配
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <typeparam name="TValue"></typeparam>
public record Result<TResult, TValue>
/// <typeparam name="TResult">结果类型</typeparam>
/// <typeparam name="TValue">值类型</typeparam>
public readonly struct ValueResult<TResult, TValue> : IDeconstructable<TResult, TValue>
where TResult : notnull
where TValue : notnull
{
/// <summary>
/// 是否成功
/// </summary>
public readonly TResult IsOk;
/// <summary>
/// 值
/// </summary>
public readonly TValue Value;
/// <summary>
/// 构造一个新的结果
/// </summary>
/// <param name="isOk">是否成功</param>
/// <param name="value">值</param>
public Result(TResult isOk, TValue value)
public ValueResult(TResult isOk, TValue value)
{
IsOk = isOk;
Value = value;
}
/// <summary>
/// 是否成功
/// </summary>
public TResult IsOk { get; }
/// <summary>
/// 值
/// </summary>
public TValue Value { get; }
/// <summary>
/// 用于元组析构
/// </summary>
@@ -43,4 +46,4 @@ public record Result<TResult, TValue>
isOk = IsOk;
value = Value;
}
}
}

View File

@@ -9,7 +9,7 @@
<Identity
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
Publisher="CN=DGP Studio"
Version="1.0.31.0" />
Version="1.0.32.0" />
<Properties>
<DisplayName>胡桃</DisplayName>

View File

@@ -9,4 +9,4 @@ namespace Snap.Hutao.Service.GachaLog;
internal class GachaLogService
{
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Threading;
namespace Snap.Hutao.Service.GachaLog;
/// <summary>
/// 浏览器缓存方法
/// </summary>
[Injection(InjectAs.Transient, typeof(IGachaLogUrlProvider))]
internal class GachaLogUrlWebCacheProvider : IGachaLogUrlProvider
{
/// <inheritdoc/>
public async Task<ValueResult<bool, string>> GetQueryAsync()
{
throw Must.NeverHappen();
}
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Threading;
namespace Snap.Hutao.Service.GachaLog;
/// <summary>
/// 祈愿记录Url提供器
/// </summary>
public interface IGachaLogUrlProvider
{
/// <summary>
/// 异步获取包含验证密钥的查询语句
/// </summary>
/// <returns>包含验证密钥的查询语句</returns>
Task<ValueResult<bool, string>> GetQueryAsync();
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Threading;
namespace Snap.Hutao.Service.Game.Locator;
/// <summary>
/// 游戏位置定位器
/// </summary>
internal interface IGameLocator
{
/// <summary>
/// 异步获取游戏位置
/// 路径应当包含游戏文件名称
/// </summary>
/// <returns>游戏位置</returns>
Task<ValueResult<bool, string>> LocateGamePathAsync();
/// <summary>
/// 异步获取游戏启动器位置
/// 路径应当包含启动器文件名称
/// </summary>
/// <returns>游戏启动器位置</returns>
Task<ValueResult<bool, string>> LocateLauncherPathAsync();
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core.Threading;
using Snap.Hutao.Factory.Abstraction;
using Windows.Storage;
using Windows.Storage.Pickers;
namespace Snap.Hutao.Service.Game.Locator;
/// <summary>
/// 手动模式
/// </summary>
internal class ManualGameLocator : IGameLocator
{
private readonly IPickerFactory pickerFactory;
/// <summary>
/// 构造一个新的手动模式提供器
/// </summary>
/// <param name="pickerFactory">选择器工厂</param>
public ManualGameLocator(IPickerFactory pickerFactory)
{
this.pickerFactory = pickerFactory;
}
/// <inheritdoc/>
public Task<ValueResult<bool, string>> LocateGamePathAsync()
{
return LocateInternalAsync("YuanShen.exe");
}
/// <inheritdoc/>
public Task<ValueResult<bool, string>> LocateLauncherPathAsync()
{
return LocateInternalAsync("launcher.exe");
}
private async Task<ValueResult<bool, string>> LocateInternalAsync(string fileName)
{
FileOpenPicker picker = pickerFactory.GetFileOpenPicker();
picker.FileTypeFilter.Add(".exe");
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
if (await picker.PickSingleFileAsync() is StorageFile file)
{
string path = file.Path;
if (path.Contains(fileName))
{
return new(true, path);
}
}
return new(false, null!);
}
}

View File

@@ -0,0 +1,51 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Win32;
using Snap.Hutao.Core.Threading;
using System.IO;
namespace Snap.Hutao.Service.Game.Locator;
/// <summary>
/// 注册表启动器位置定位器
/// </summary>
internal class RegistryLauncherLocator : IGameLocator
{
/// <inheritdoc/>
public Task<ValueResult<bool, string>> LocateGamePathAsync()
{
return Task.FromResult(LocateInternal("InstallPath", "YuanShen.exe"));
}
/// <inheritdoc/>
public Task<ValueResult<bool, string>> LocateLauncherPathAsync()
{
return Task.FromResult(LocateInternal("DisplayIcon"));
}
private static ValueResult<bool, string> LocateInternal(string key, string? combine = null)
{
RegistryKey? uninstallKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神");
if (uninstallKey != null)
{
if (uninstallKey.GetValue(key) is string path)
{
if (!string.IsNullOrEmpty(combine))
{
path = Path.Combine(combine);
}
return new(true, path);
}
else
{
return new(false, null!);
}
}
else
{
return new(false, null!);
}
}
}

View File

@@ -26,7 +26,7 @@ public sealed partial class AchievementArchiveCreateDialog : ContentDialog
/// 获取输入的字符串
/// </summary>
/// <returns>输入的结果</returns>
public async Task<Result<bool, string>> GetInputAsync()
public async Task<ValueResult<bool, string>> GetInputAsync()
{
ContentDialogResult result = await ShowAsync();
string text = InputText.Text ?? string.Empty;

View File

@@ -42,11 +42,11 @@ public sealed partial class AchievementImportDialog : ContentDialog
/// 异步获取导入选项
/// </summary>
/// <returns>导入选项</returns>
public async Task<Result<bool, ImportOption>> GetImportOptionAsync()
public async Task<ValueResult<bool, ImportOption>> GetImportOptionAsync()
{
ContentDialogResult result = await ShowAsync();
ImportOption option = (ImportOption)ImportModeSelector.SelectedIndex;
return new Result<bool, ImportOption>(result == ContentDialogResult.Primary, option);
return new(result == ContentDialogResult.Primary, option);
}
}

View File

@@ -26,7 +26,7 @@ public sealed partial class UserDialog : ContentDialog
/// 获取输入的Cookie
/// </summary>
/// <returns>输入的结果</returns>
public async Task<Result<bool, string>> GetInputCookieAsync()
public async Task<ValueResult<bool, string>> GetInputCookieAsync()
{
ContentDialogResult result = await ShowAsync();
string cookie = InputText.Text;

View File

@@ -19,8 +19,32 @@
</Page.Resources>
<ScrollViewer>
<StackPanel Margin="32,0,24,0">
<sc:SettingsGroup Header="关于 胡桃">
<Grid Margin="0,4,0,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Width="80"
Source="ms-appx:///Assets/Square150x150Logo.scale-200.png"/>
<Grid
Margin="16,0,0,0"
Grid.Column="1">
<TextBlock TextWrapping="Wrap">
<Run>胡桃 图标由 </Run>
<Hyperlink NavigateUri="https://dieqi32894.lofter.com/post/4b58ce16_2b6b2d365">LOFTER@夙夜</Hyperlink>
<Run>纸绘,并由 </Run>
<Hyperlink NavigateUri="https://github.com/DGP-Studio">DGP Studio</Hyperlink>
<Run> 后期处理后,授权使用。</Run>
</TextBlock>
<TextBlock
VerticalAlignment="Bottom"
Text="Copyright © 2022 DGP Studio. All Rights Reserved."/>
</Grid>
</Grid>
<sc:Setting
Icon="&#xECAA;"
Header="胡桃"