mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331cc14532 | ||
|
|
c0ddb24825 | ||
|
|
e925c5909c |
@@ -6,7 +6,9 @@
|
||||
## 安装
|
||||
|
||||
* 前往 [下载页面](https://go.hut.ao/archive) 下载最新版本的 `胡桃` 安装包
|
||||
* 完全解压后,使用 powershell 运行 `install.ps1` 文件
|
||||
* (曾启用的可以跳过此步骤)在系统设置中打开 **开发者选项** 界面,勾选 `开发人员模式` 和 `允许 PowerShell 脚本`
|
||||
* 完全解压后,右键使用 powershell 运行 `install.ps1` 文件
|
||||
* 安装完成后可以关闭 `允许 PowerShell 脚本`
|
||||
|
||||
## 特别感谢
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Snap.Hutao.Core.Caching;
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton, typeof(IImageCache))]
|
||||
[HttpClient(HttpClientConfigration.Default)]
|
||||
[PrimaryHttpMessageHandler(MaxConnectionsPerServer = 20)]
|
||||
[PrimaryHttpMessageHandler(MaxConnectionsPerServer = 16)]
|
||||
public class ImageCache : CacheBase<BitmapImage>, IImageCache
|
||||
{
|
||||
private const string DateAccessedProperty = "System.DateAccessed";
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Win32;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Graphics;
|
||||
using Windows.Win32.Foundation;
|
||||
@@ -25,11 +26,15 @@ internal static class Persistence
|
||||
// Set first launch size.
|
||||
HWND hwnd = (HWND)Win32Interop.GetWindowFromWindowId(appWindow.Id);
|
||||
SizeInt32 size = TransformSizeForWindow(new(1200, 741), hwnd);
|
||||
RectInt32 rect = new(0, 0, size.Width, size.Height);
|
||||
RectInt32 rect = StructMarshal.RectInt32(size);
|
||||
|
||||
// Make it centralized
|
||||
TransformToCenterScreen(ref rect);
|
||||
RectInt32 target = (CompactRect)LocalSetting.Get(SettingKeys.WindowRect, (ulong)(CompactRect)rect);
|
||||
if (target.Width * target.Height < 848 * 524)
|
||||
{
|
||||
target = rect;
|
||||
}
|
||||
|
||||
TransformToCenterScreen(ref target);
|
||||
appWindow.MoveAndResize(target);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class User : Observable
|
||||
/// </summary>
|
||||
/// <param name="cookie">cookie的字符串形式</param>
|
||||
/// <returns>包含cookie信息的字典</returns>
|
||||
public static IDictionary<string, string> ParseCookie(string cookie)
|
||||
public static IDictionary<string, string> MapCookie(string cookie)
|
||||
{
|
||||
SortedDictionary<string, string> cookieDictionary = new();
|
||||
|
||||
@@ -142,9 +142,9 @@ public class User : Observable
|
||||
/// <param name="authClient">验证客户端</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>是否升级成功</returns>
|
||||
internal async Task<bool> TryUpgradeAsync(IDictionary<string, string> addition, AuthClient authClient, CancellationToken token)
|
||||
internal async Task<bool> TryUpgradeByLoginTicketAsync(IDictionary<string, string> addition, AuthClient authClient, CancellationToken token)
|
||||
{
|
||||
IDictionary<string, string> cookie = ParseCookie(Cookie!);
|
||||
IDictionary<string, string> cookie = MapCookie(Cookie!);
|
||||
if (addition.TryGetValue(CookieKeys.LOGIN_TICKET, out string? loginTicket))
|
||||
{
|
||||
cookie[CookieKeys.LOGIN_TICKET] = loginTicket;
|
||||
@@ -155,7 +155,7 @@ public class User : Observable
|
||||
cookie[CookieKeys.LOGIN_UID] = loginUid;
|
||||
}
|
||||
|
||||
bool result = await TryAddStokenToCookieAsync(cookie, authClient, token).ConfigureAwait(false);
|
||||
bool result = await TryRequestStokenAndAddToCookieAsync(cookie, authClient, token).ConfigureAwait(false);
|
||||
|
||||
if (result)
|
||||
{
|
||||
@@ -165,12 +165,31 @@ public class User : Observable
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加 Stoken
|
||||
/// </summary>
|
||||
/// <param name="addition">额外的cookie</param>
|
||||
internal void AddStoken(IDictionary<string, string> addition)
|
||||
{
|
||||
IDictionary<string, string> cookie = MapCookie(Cookie!);
|
||||
|
||||
if (addition.TryGetValue(CookieKeys.STOKEN, out string? stoken))
|
||||
{
|
||||
cookie[CookieKeys.STOKEN] = stoken;
|
||||
}
|
||||
|
||||
if (addition.TryGetValue(CookieKeys.STUID, out string? stuid))
|
||||
{
|
||||
cookie[CookieKeys.STUID] = stuid;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ToCookieString(IDictionary<string, string> cookie)
|
||||
{
|
||||
return string.Join(';', cookie.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
||||
}
|
||||
|
||||
private static async Task<bool> TryAddStokenToCookieAsync(IDictionary<string, string> cookie, AuthClient authClient, CancellationToken token)
|
||||
private static async Task<bool> TryRequestStokenAndAddToCookieAsync(IDictionary<string, string> cookie, AuthClient authClient, CancellationToken token)
|
||||
{
|
||||
if (cookie.TryGetValue(CookieKeys.LOGIN_TICKET, out string? loginTicket))
|
||||
{
|
||||
@@ -225,7 +244,7 @@ public class User : Observable
|
||||
return true;
|
||||
}
|
||||
|
||||
if (await TryAddStokenToCookieAsync(cookie, authClient, token).ConfigureAwait(false))
|
||||
if (await TryRequestStokenAndAddToCookieAsync(cookie, authClient, token).ConfigureAwait(false))
|
||||
{
|
||||
Cookie = ToCookieString(cookie);
|
||||
}
|
||||
|
||||
@@ -13,12 +13,10 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
||||
internal sealed class DescParamDescriptor : ValueConverterBase<DescParam, IList<LevelParam<string, ParameterInfo>>>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override IList<LevelParam<string, ParameterInfo>> Convert(DescParam rawDescParam)
|
||||
public override IList<LevelParam<string, ParameterInfo>> Convert(DescParam from)
|
||||
{
|
||||
IList<LevelParam<string, ParameterInfo>> parameters = rawDescParam.Parameters
|
||||
.Select(param => new LevelParam<string, ParameterInfo>(
|
||||
param.Level.ToString(),
|
||||
GetParameterInfos(rawDescParam, param.Parameters)))
|
||||
IList<LevelParam<string, ParameterInfo>> parameters = from.Parameters
|
||||
.Select(param => new LevelParam<string, ParameterInfo>(param.Level.ToString(), GetParameterInfos(from, param.Parameters)))
|
||||
.ToList();
|
||||
|
||||
return parameters;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.1.3.0" />
|
||||
Version="1.1.4.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
@@ -91,19 +91,18 @@ internal class InfoBarService : IInfoBarService
|
||||
PrepareInfoBarAndShow(InfoBarSeverity.Error, ex.GetType().Name, $"{title}\n{ex.Message}", delay);
|
||||
}
|
||||
|
||||
[SuppressMessage("", "VSTHRD100")]
|
||||
private async void PrepareInfoBarAndShow(InfoBarSeverity severity, string? title, string? message, int delay)
|
||||
private void PrepareInfoBarAndShow(InfoBarSeverity severity, string? title, string? message, int delay)
|
||||
{
|
||||
if (infoBarStack is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await PrepareInfoBarAndShowInternalAsync(severity, title, message, delay).ConfigureAwait(false);
|
||||
PrepareInfoBarAndShowInternalAsync(severity, title, message, delay).SafeForget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 此方法应在主线程上运行
|
||||
/// 准备信息条并显示
|
||||
/// </summary>
|
||||
/// <param name="severity">严重程度</param>
|
||||
/// <param name="title">标题</param>
|
||||
@@ -122,11 +121,12 @@ internal class InfoBarService : IInfoBarService
|
||||
};
|
||||
|
||||
infoBar.Closed += OnInfoBarClosed;
|
||||
Must.NotNull(infoBarStack!).Children.Add(infoBar);
|
||||
infoBarStack!.Children.Add(infoBar);
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
await Task.Delay(delay);
|
||||
await Task.Delay(delay).ConfigureAwait(true);
|
||||
infoBarStack.Children.Remove(infoBar);
|
||||
infoBar.IsOpen = false;
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ internal class InfoBarService : IInfoBarService
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
|
||||
Must.NotNull(infoBarStack!).Children.Remove(sender);
|
||||
infoBarStack!.Children.Remove(sender);
|
||||
sender.Closed -= OnInfoBarClosed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,17 @@ public interface IUserService
|
||||
/// <summary>
|
||||
/// 尝试使用 login_ticket 升级用户
|
||||
/// </summary>
|
||||
/// <param name="cookie">额外的Cookie</param>
|
||||
/// <param name="addiition">额外的Cookie</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>是否升级成功</returns>
|
||||
Task<ValueResult<bool, string>> TryUpgradeUserAsync(IDictionary<string, string> addiition, CancellationToken token = default);
|
||||
Task<ValueResult<bool, string>> TryUpgradeUserByLoginTicketAsync(IDictionary<string, string> addiition, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 尝试使用 Stoken 升级用户
|
||||
/// </summary>
|
||||
/// <param name="stoken">stoken</param>
|
||||
/// <returns>是否升级成功</returns>
|
||||
Task<ValueResult<bool, string>> TryUpgradeUserByStokenAsync(IDictionary<string, string> stoken);
|
||||
|
||||
/// <summary>
|
||||
/// 异步移除用户
|
||||
|
||||
@@ -118,6 +118,7 @@ internal class UserService : IUserService
|
||||
Verify.Operation(newUser.IsInitialized, "该用户尚未初始化");
|
||||
|
||||
// Sync cache
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
userCollection.Add(newUser);
|
||||
|
||||
// Sync database
|
||||
@@ -180,7 +181,7 @@ internal class UserService : IUserService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ValueResult<bool, string>> TryUpgradeUserAsync(IDictionary<string, string> addition, CancellationToken token = default)
|
||||
public async Task<ValueResult<bool, string>> TryUpgradeUserByLoginTicketAsync(IDictionary<string, string> addition, CancellationToken token = default)
|
||||
{
|
||||
Must.NotNull(userCollection!);
|
||||
if (addition.TryGetValue(CookieKeys.LOGIN_UID, out string? uid))
|
||||
@@ -189,15 +190,36 @@ internal class UserService : IUserService
|
||||
if (userCollection.SingleOrDefault(u => u.UserInfo!.Uid == uid) is BindingUser userWithSameUid)
|
||||
{
|
||||
// Update user cookie here.
|
||||
if (await userWithSameUid.TryUpgradeAsync(addition, authClient, token))
|
||||
if (await userWithSameUid.TryUpgradeByLoginTicketAsync(addition, authClient, token))
|
||||
{
|
||||
appDbContext.Users.Update(userWithSameUid.Entity);
|
||||
await appDbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
return new(true, uid);
|
||||
return new(true, userWithSameUid.UserInfo?.Nickname ?? string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new(false, string.Empty);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ValueResult<bool, string>> TryUpgradeUserByStokenAsync(IDictionary<string, string> stoken)
|
||||
{
|
||||
Must.NotNull(userCollection!);
|
||||
if (stoken.TryGetValue(CookieKeys.STUID, out string? uid))
|
||||
{
|
||||
// 查找是否有相同的uid
|
||||
if (userCollection.SingleOrDefault(u => u.UserInfo!.Uid == uid) is BindingUser userWithSameUid)
|
||||
{
|
||||
// Update user cookie here.
|
||||
userWithSameUid.AddStoken(stoken);
|
||||
|
||||
appDbContext.Users.Update(userWithSameUid.Entity);
|
||||
await appDbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
return new(true, userWithSameUid.UserInfo?.Nickname ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
return new(false, string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,14 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition/>
|
||||
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Margin="0,0,0,8"
|
||||
Text="请在 成功登录米哈游通行证 后点击 [继续] 按钮"/>
|
||||
<TextBlock
|
||||
Text="在下方登录"
|
||||
Grid.Row="0"/>
|
||||
<WebView2
|
||||
Grid.Row="1"
|
||||
Grid.Row="2"
|
||||
Margin="0,12,0,0"
|
||||
Width="640"
|
||||
Height="400"
|
||||
x:Name="WebView"/>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Snap.Hutao.View.Dialog;
|
||||
/// </summary>
|
||||
public sealed partial class UserAutoCookieDialog : ContentDialog
|
||||
{
|
||||
private IDictionary<string, string>? cookieString;
|
||||
private IDictionary<string, string>? cookie;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的用户自动Cookie对话框
|
||||
@@ -32,7 +32,7 @@ public sealed partial class UserAutoCookieDialog : ContentDialog
|
||||
public async Task<ValueResult<bool, IDictionary<string, string>>> GetInputCookieAsync()
|
||||
{
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
return new(result == ContentDialogResult.Primary && cookieString != null, cookieString!);
|
||||
return new(result == ContentDialogResult.Primary && cookie != null, cookie!);
|
||||
}
|
||||
|
||||
[SuppressMessage("", "VSTHRD100")]
|
||||
@@ -62,8 +62,7 @@ public sealed partial class UserAutoCookieDialog : ContentDialog
|
||||
{
|
||||
CoreWebView2CookieManager manager = WebView.CoreWebView2.CookieManager;
|
||||
IReadOnlyList<CoreWebView2Cookie> cookies = await manager.GetCookiesAsync("https://user.mihoyo.com");
|
||||
cookieString = cookies.ToDictionary(c => c.Name, c => c.Value);
|
||||
|
||||
cookie = cookies.ToDictionary(c => c.Name, c => c.Value);
|
||||
WebView.CoreWebView2.SourceChanged -= OnCoreWebView2SourceChanged;
|
||||
}
|
||||
catch (Exception)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:shc="using:Snap.Hutao.Control"
|
||||
xmlns:shvm="using:Snap.Hutao.ViewModel"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance shvm:UserViewModel}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
@@ -199,11 +200,11 @@
|
||||
Text="Cookie"/>
|
||||
<CommandBar DefaultLabelPosition="Right">
|
||||
<AppBarButton
|
||||
Icon="Add"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="升级Stoken"
|
||||
Command="{Binding UpgradeToStokenCommand}"/>
|
||||
<AppBarButton
|
||||
Icon="Add"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="手动添加"
|
||||
Command="{Binding AddUserCommand}"/>
|
||||
</CommandBar>
|
||||
|
||||
@@ -10,7 +10,6 @@ using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.View.Dialog;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Net;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
@@ -21,8 +20,6 @@ namespace Snap.Hutao.ViewModel;
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class UserViewModel : ObservableObject
|
||||
{
|
||||
private const string AccountIdKey = "account_id";
|
||||
|
||||
private readonly IUserService userService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
|
||||
@@ -42,7 +39,7 @@ internal class UserViewModel : ObservableObject
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
AddUserCommand = asyncRelayCommandFactory.Create(AddUserAsync);
|
||||
UpgradeToStokenCommand = asyncRelayCommandFactory.Create(UpgradeToStokenAsync);
|
||||
UpgradeToStokenCommand = asyncRelayCommandFactory.Create(UpgradeByLoginTicketAsync);
|
||||
RemoveUserCommand = asyncRelayCommandFactory.Create<User>(RemoveUserAsync);
|
||||
CopyCookieCommand = new RelayCommand<User>(CopyCookie);
|
||||
}
|
||||
@@ -92,35 +89,45 @@ internal class UserViewModel : ObservableObject
|
||||
/// </summary>
|
||||
public ICommand CopyCookieCommand { get; }
|
||||
|
||||
private static bool TryValidateCookie(IDictionary<string, string> map, [NotNullWhen(true)] out IDictionary<string, string>? filteredCookie)
|
||||
private static (bool Valid, bool Upgrade) TryValidateCookie(IDictionary<string, string> map, out IDictionary<string, string> cookie)
|
||||
{
|
||||
int validFlag = 4;
|
||||
int stokenFlag = 2;
|
||||
|
||||
SortedDictionary<string, string> filter = new();
|
||||
cookie = new SortedDictionary<string, string>();
|
||||
|
||||
foreach ((string key, string value) in map)
|
||||
{
|
||||
if (key == CookieKeys.COOKIE_TOKEN || key == CookieKeys.ACCOUNT_ID || key == CookieKeys.LTOKEN || key == CookieKeys.LTUID)
|
||||
switch (key)
|
||||
{
|
||||
validFlag--;
|
||||
filter.Add(key, value);
|
||||
}
|
||||
else if (key == CookieKeys.STOKEN || key == CookieKeys.STUID || key == CookieKeys.LOGIN_TICKET || key == CookieKeys.LOGIN_UID)
|
||||
{
|
||||
filter.Add(key, value);
|
||||
case CookieKeys.COOKIE_TOKEN:
|
||||
case CookieKeys.ACCOUNT_ID:
|
||||
case CookieKeys.LTOKEN:
|
||||
case CookieKeys.LTUID:
|
||||
{
|
||||
validFlag--;
|
||||
cookie.Add(key, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CookieKeys.STOKEN:
|
||||
case CookieKeys.STUID:
|
||||
{
|
||||
stokenFlag--;
|
||||
cookie.Add(key, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case CookieKeys.LOGIN_TICKET:
|
||||
case CookieKeys.LOGIN_UID:
|
||||
{
|
||||
cookie.Add(key, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validFlag == 0)
|
||||
{
|
||||
filteredCookie = filter;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
filteredCookie = null;
|
||||
return false;
|
||||
}
|
||||
return (validFlag == 0, stokenFlag == 0);
|
||||
}
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
@@ -138,11 +145,12 @@ internal class UserViewModel : ObservableObject
|
||||
// User confirms the input
|
||||
if (result.IsOk)
|
||||
{
|
||||
if (TryValidateCookie(User.ParseCookie(result.Value), out IDictionary<string, string>? filteredCookie))
|
||||
(bool valid, bool upgradable) = TryValidateCookie(User.MapCookie(result.Value), out IDictionary<string, string> cookie);
|
||||
if (valid)
|
||||
{
|
||||
if (await userService.CreateUserAsync(filteredCookie).ConfigureAwait(false) is User user)
|
||||
if (await userService.CreateUserAsync(cookie).ConfigureAwait(false) is User user)
|
||||
{
|
||||
switch (await userService.TryAddUserAsync(user, filteredCookie[AccountIdKey]).ConfigureAwait(false))
|
||||
switch (await userService.TryAddUserAsync(user, cookie[CookieKeys.ACCOUNT_ID]).ConfigureAwait(false))
|
||||
{
|
||||
case UserAddResult.Added:
|
||||
infoBarService.Success($"用户 [{user.UserInfo!.Nickname}] 添加成功");
|
||||
@@ -164,12 +172,28 @@ internal class UserViewModel : ObservableObject
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning("提供的文本不是正确的 Cookie ,请重新输入");
|
||||
if (upgradable)
|
||||
{
|
||||
(bool success, string nickname) = await userService.TryUpgradeUserByStokenAsync(cookie).ConfigureAwait(false);
|
||||
|
||||
if (success)
|
||||
{
|
||||
infoBarService.Information($"用户 [{nickname}] 的 Stoken 更新成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning($"未找到匹配的可升级用户");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning("提供的文本不是正确的 Cookie ,请重新输入");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpgradeToStokenAsync()
|
||||
private async Task UpgradeByLoginTicketAsync()
|
||||
{
|
||||
// Get cookie from user input
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
@@ -178,10 +202,10 @@ internal class UserViewModel : ObservableObject
|
||||
// User confirms the input
|
||||
if (isOk)
|
||||
{
|
||||
(bool isUpgradeSucceed, string uid) = await userService.TryUpgradeUserAsync(addition).ConfigureAwait(false);
|
||||
if (isUpgradeSucceed)
|
||||
(bool isUpgraded, string nickname) = await userService.TryUpgradeUserByLoginTicketAsync(addition).ConfigureAwait(false);
|
||||
if (isUpgraded)
|
||||
{
|
||||
infoBarService.Information($"用户 [{uid}] 的 Cookie 已成功添加 Stoken");
|
||||
infoBarService.Information($"用户 [{nickname}] 的 Cookie 已成功添加 Stoken");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI.UI;
|
||||
using Snap.Hutao.Core.Threading;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
@@ -143,13 +144,14 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
if (await metadataService.InitializeAsync())
|
||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||
{
|
||||
IList<Avatar> avatars = await metadataService.GetAvatarsAsync();
|
||||
IList<Avatar> avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false);
|
||||
IOrderedEnumerable<Avatar> sorted = avatars
|
||||
.OrderBy(avatar => avatar.BeginTime)
|
||||
.ThenBy(avatar => avatar.Sort);
|
||||
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
Avatars = new AdvancedCollectionView(sorted.ToList(), true);
|
||||
Avatars.MoveCurrentToFirst();
|
||||
}
|
||||
@@ -174,7 +176,7 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
.Select(e => e.Value.Value)
|
||||
.ToList();
|
||||
|
||||
List<ItemQuality> targeQualities = FilterQualityInfos
|
||||
List<ItemQuality> targetQualities = FilterQualityInfos
|
||||
.Where(e => e.IsSelected)
|
||||
.Select(e => e.Value.Value)
|
||||
.ToList();
|
||||
@@ -188,7 +190,7 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
&& targetElements.Contains(avatar.FetterInfo.VisionBefore)
|
||||
&& targetAssociations.Contains(avatar.FetterInfo.Association)
|
||||
&& targetWeaponTypes.Contains(avatar.Weapon)
|
||||
&& targeQualities.Contains(avatar.Quality)
|
||||
&& targetQualities.Contains(avatar.Quality)
|
||||
&& targetBodies.Contains(avatar.Body);
|
||||
|
||||
if (!Avatars.Contains(Selected))
|
||||
|
||||
@@ -12,7 +12,7 @@ public class DetailedCertification : Certification
|
||||
/// Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
public string Id { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 认证Id
|
||||
|
||||
@@ -7,7 +7,7 @@ using Windows.Win32.System.Diagnostics.ToolHelp;
|
||||
namespace Snap.Hutao.Win32;
|
||||
|
||||
/// <summary>
|
||||
/// 内存拓展
|
||||
/// 内存拓展 for <see cref="Memory{T}"/> <see cref="Span{T}"/>
|
||||
/// </summary>
|
||||
internal static class MemoryExtensions
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Windows.Graphics;
|
||||
using Windows.Win32.System.Diagnostics.ToolHelp;
|
||||
|
||||
namespace Snap.Hutao.Win32;
|
||||
@@ -19,6 +20,16 @@ internal static class StructMarshal
|
||||
return new() { dwSize = (uint)sizeof(MODULEENTRY32) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的<see cref="Windows.Graphics.RectInt32"/>
|
||||
/// </summary>
|
||||
/// <param name="size">尺寸</param>
|
||||
/// <returns>新的实例</returns>
|
||||
public static RectInt32 RectInt32(SizeInt32 size)
|
||||
{
|
||||
return new(0, 0, size.Width, size.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断结构实例是否为默认结构
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user