From 98b3f2d202e5ed39310ab868cbec3d55dfc57bba Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Wed, 29 Mar 2023 17:35:43 +0800
Subject: [PATCH] add hutao passport
---
src/Snap.Hutao/Snap.Hutao/App.xaml | 1 +
.../Snap.Hutao/Control/BoxedValues.cs | 5 +
.../Snap.Hutao/Core/LifeCycle/Activation.cs | 15 +-
.../Resource/Localization/SH.Designer.cs | 63 ++++++
.../Snap.Hutao/Resource/Localization/SH.resx | 21 ++
.../Service/Hutao/HutaoUserOptions.cs | 30 +++
.../Service/Hutao/HutaoUserService.cs | 30 ++-
src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 7 +
.../EmptyObjectToVisibilityRevertConverter.cs | 2 +-
.../View/Converter/StringBoolConverter.cs | 22 ++
.../View/Page/HutaoPassportPage.xaml | 105 ++++++++++
.../View/Page/HutaoPassportPage.xaml.cs | 22 ++
.../Snap.Hutao/View/Page/SettingPage.xaml | 6 +-
.../ViewModel/HutaoPassportViewModel.cs | 196 ++++++++++++++++++
.../Snap.Hutao/ViewModel/SettingViewModel.cs | 26 ++-
15 files changed, 527 insertions(+), 24 deletions(-)
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/View/Converter/StringBoolConverter.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml
create mode 100644 src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoPassportViewModel.cs
diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml
index a47b389b..cac03244 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml
@@ -102,6 +102,7 @@
+
///
public static readonly object True = true;
+
+ ///
+ ///
+ ///
+ public static readonly object False = false;
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs
index f87b7472..d8f34df4 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs
@@ -7,6 +7,7 @@ using Microsoft.Windows.AppLifecycle;
using Snap.Hutao.Core.Setting;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.DailyNote;
+using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.Navigation;
using System.Diagnostics;
@@ -182,15 +183,23 @@ internal static class Activation
private static async Task WaitMainWindowAsync()
{
await ThreadHelper.SwitchToMainThreadAsync();
- Ioc.Default.GetRequiredService().Activate();
+ IServiceProvider serviceProvider = Ioc.Default;
- await Ioc.Default.GetRequiredService().WaitInitializationAsync().ConfigureAwait(false);
+ serviceProvider.GetRequiredService().Activate();
- Ioc.Default
+ await serviceProvider.GetRequiredService().WaitInitializationAsync().ConfigureAwait(false);
+
+ serviceProvider
.GetRequiredService()
.As()?
.InitializeInternalAsync()
.SafeForget();
+
+ serviceProvider
+ .GetRequiredService()
+ .As()?
+ .InitializeInternalAsync()
+ .SafeForget();
}
private static async Task HandleUrlActivationAsync(Uri uri, bool isRedirected)
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
index fc94a76d..5b287d1e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -3606,6 +3606,69 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 登录 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportLoginHeader {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportLoginHeader", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请输入密码 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportPasswordHint {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportPasswordHint", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 注册 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportRegisterHeader {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportRegisterHeader", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 重置密码 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportResetPasswordHeader {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportResetPasswordHeader", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请输入邮箱 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportUserNameHint {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportUserNameHint", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 获取验证码 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportVerifyCodeAction {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportVerifyCodeAction", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 请输入验证码 的本地化字符串。
+ ///
+ internal static string ViewPageHutaoPassportVerifyCodeHint {
+ get {
+ return ResourceManager.GetString("ViewPageHutaoPassportVerifyCodeHint", resourceCulture);
+ }
+ }
+
///
/// 查找类似 启动游戏 的本地化字符串。
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index 58934a7b..8c094015 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -1821,4 +1821,25 @@
HoYoLab
+
+ 登录
+
+
+ 请输入密码
+
+
+ 注册
+
+
+ 重置密码
+
+
+ 请输入邮箱
+
+
+ 获取验证码
+
+
+ 请输入验证码
+
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
new file mode 100644
index 00000000..c8a72465
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserOptions.cs
@@ -0,0 +1,30 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using CommunityToolkit.Mvvm.ComponentModel;
+using Microsoft.Extensions.Options;
+
+namespace Snap.Hutao.Service.Hutao;
+
+///
+/// 胡桃用户选项
+///
+[Injection(InjectAs.Singleton)]
+internal sealed class HutaoUserOptions : ObservableObject, IOptions
+{
+ private string? userName;
+ private string? token;
+
+ ///
+ /// 用户名
+ ///
+ public string? UserName { get => userName; set => SetProperty(ref userName, value); }
+
+ ///
+ /// 访问令牌
+ ///
+ public string? Token { get => token; set => SetProperty(ref token, value); }
+
+ ///
+ public HutaoUserOptions Value { get => this; }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserService.cs
index 8de4fd32..9e6d1736 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoUserService.cs
@@ -12,30 +12,24 @@ namespace Snap.Hutao.Service.Hutao;
[Injection(InjectAs.Singleton, typeof(IHutaoUserService))]
internal sealed class HutaoUserService : IHutaoUserService, IHutaoUserServiceInitialization
{
- private readonly HomaPassportClient passportClient;
private readonly TaskCompletionSource initializeCompletionSource = new();
+ private readonly HomaPassportClient passportClient;
+ private readonly HutaoUserOptions options;
+
private bool isInitialized;
///
/// 构造一个新的胡桃用户服务
///
/// 通行证客户端
- public HutaoUserService(HomaPassportClient passportClient)
+ /// 选项
+ public HutaoUserService(HomaPassportClient passportClient, HutaoUserOptions options)
{
this.passportClient = passportClient;
+ this.options = options;
}
- ///
- /// 用户名
- ///
- public string? UserName { get; private set; }
-
- ///
- /// 访问令牌
- ///
- public string? Token { get; private set; }
-
///
/// 异步初始化
///
@@ -52,26 +46,30 @@ internal sealed class HutaoUserService : IHutaoUserService, IHutaoUserServiceIni
string userName = LocalSetting.Get(SettingKeys.PassportUserName, string.Empty);
string passport = LocalSetting.Get(SettingKeys.PassportPassword, string.Empty);
+ string? accessToken = null;
+
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(passport))
{
Web.Response.Response response = await passportClient.LoginAsync(userName, passport, token).ConfigureAwait(false);
if (response.IsOk())
{
- Token = response.Data;
- UserName = userName;
isInitialized = true;
}
else
{
- UserName = SH.ViewServiceHutaoUserLoginFailHint;
+ userName = SH.ViewServiceHutaoUserLoginFailHint;
}
}
else
{
- UserName = SH.ViewServiceHutaoUserLoginOrRegisterHint;
+ userName = SH.ViewServiceHutaoUserLoginOrRegisterHint;
}
+ await ThreadHelper.SwitchToMainThreadAsync();
+ options.Token = accessToken;
+ options.UserName = userName;
+
initializeCompletionSource.TrySetResult();
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
index c118bc0a..7bf4d553 100644
--- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
+++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
@@ -136,6 +136,7 @@
+
@@ -287,6 +288,12 @@
SH.Designer.cs
+
+
+
+ MSBuild:Compile
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Converter/EmptyObjectToVisibilityRevertConverter.cs b/src/Snap.Hutao/Snap.Hutao/View/Converter/EmptyObjectToVisibilityRevertConverter.cs
index 7f029174..29b76368 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Converter/EmptyObjectToVisibilityRevertConverter.cs
+++ b/src/Snap.Hutao/Snap.Hutao/View/Converter/EmptyObjectToVisibilityRevertConverter.cs
@@ -20,4 +20,4 @@ internal sealed class EmptyObjectToVisibilityRevertConverter : EmptyObjectToObje
EmptyValue = Visibility.Visible;
NotEmptyValue = Visibility.Collapsed;
}
-}
\ No newline at end of file
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Converter/StringBoolConverter.cs b/src/Snap.Hutao/Snap.Hutao/View/Converter/StringBoolConverter.cs
new file mode 100644
index 00000000..ddd0830e
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Converter/StringBoolConverter.cs
@@ -0,0 +1,22 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using CommunityToolkit.WinUI.UI.Converters;
+using Snap.Hutao.Control;
+
+namespace Snap.Hutao.View.Converter;
+
+///
+/// 字符串空检查转换器
+///
+internal sealed class StringBoolConverter : EmptyStringToObjectConverter
+{
+ ///
+ /// 构造一个新的字符串空检查转换器
+ ///
+ public StringBoolConverter()
+ {
+ EmptyValue = BoxedValues.False;
+ NotEmptyValue = BoxedValues.True;
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml
new file mode 100644
index 00000000..d9dcc181
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml.cs
new file mode 100644
index 00000000..ceba7e01
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoPassportPage.xaml.cs
@@ -0,0 +1,22 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Control;
+using Snap.Hutao.ViewModel;
+
+namespace Snap.Hutao.View.Page;
+
+///
+/// ֤ͨҳ
+///
+internal sealed partial class HutaoPassportPage : ScopedPage
+{
+ ///
+ /// һµĺ֤ͨҳ
+ ///
+ public HutaoPassportPage()
+ {
+ InitializeWith();
+ InitializeComponent();
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml
index 5c082d14..eda7e659 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/SettingPage.xaml
@@ -73,9 +73,11 @@
Header="{shcm:ResourceString Name=AppName}"
HeaderIcon="{shcm:FontIcon Glyph=}"/>
+ HeaderIcon="{shcm:FontIcon Glyph=}"
+ IsClickEnabled="True"/>
+/// 胡桃通行证视图模型
+///
+[Injection(InjectAs.Scoped)]
+internal sealed class HutaoPassportViewModel : Abstraction.ViewModel
+{
+ private readonly IServiceProvider serviceProvider;
+ private readonly HomaPassportClient homaPassportClient;
+
+ private string? userName;
+ private string? password;
+ private string? verifyCode;
+
+ ///
+ /// 构造一个新的胡桃通行证视图模型
+ ///
+ /// 服务提供器
+ public HutaoPassportViewModel(IServiceProvider serviceProvider)
+ {
+ homaPassportClient = serviceProvider.GetRequiredService();
+ this.serviceProvider = serviceProvider;
+
+ RegisterVerifyCommand = new AsyncRelayCommand(RegisterVerifyAsync);
+ RegisterCommand = new AsyncRelayCommand(RegisterAsync);
+ ResetPasswordVerifyCommand = new AsyncRelayCommand(ResetPasswordVerifyAsync);
+ ResetPasswordCommand = new AsyncRelayCommand(ResetPasswordAsync);
+ LoginCommand = new AsyncRelayCommand(LoginAsync);
+ }
+
+ ///
+ /// 用户名
+ ///
+ public string? UserName { get => userName; set => SetProperty(ref userName, value); }
+
+ ///
+ /// 密码
+ ///
+ public string? Password { get => password; set => SetProperty(ref password, value); }
+
+ ///
+ /// 验证码
+ ///
+ public string? VerifyCode { get => verifyCode; set => SetProperty(ref verifyCode, value); }
+
+ ///
+ /// 注册验证命令
+ ///
+ public ICommand RegisterVerifyCommand { get; }
+
+ ///
+ /// 注册命令
+ ///
+ public ICommand RegisterCommand { get; }
+
+ ///
+ /// 注册验证命令
+ ///
+ public ICommand ResetPasswordVerifyCommand { get; }
+
+ ///
+ /// 注册命令
+ ///
+ public ICommand ResetPasswordCommand { get; }
+
+ ///
+ /// 登录命令
+ ///
+ public ICommand LoginCommand { get; }
+
+ ///
+ protected override Task OpenUIAsync()
+ {
+ return Task.CompletedTask;
+ }
+
+ private Task RegisterVerifyAsync()
+ {
+ return VerifyAsync(false);
+ }
+
+ private async Task RegisterAsync()
+ {
+ if (UserName == null || Password == null || VerifyCode == null)
+ {
+ return;
+ }
+
+ Response response = await homaPassportClient.RegisterAsync(UserName, Password, VerifyCode).ConfigureAwait(false);
+
+ if (response.IsOk())
+ {
+ SaveUserNameAndPassword();
+ serviceProvider.GetRequiredService().Information(response.Message);
+ HutaoUserOptions options = serviceProvider.GetRequiredService();
+
+ await ThreadHelper.SwitchToMainThreadAsync();
+ options.UserName = UserName;
+ options.Token = response.Data;
+
+ await serviceProvider
+ .GetRequiredService()
+ .NavigateAsync(INavigationAwaiter.Default, true)
+ .ConfigureAwait(false);
+ }
+ }
+
+ private Task ResetPasswordVerifyAsync()
+ {
+ return VerifyAsync(true);
+ }
+
+ private async Task ResetPasswordAsync()
+ {
+ if (UserName == null || Password == null || VerifyCode == null)
+ {
+ return;
+ }
+
+ Response response = await homaPassportClient.ResetPasswordAsync(UserName, Password, VerifyCode).ConfigureAwait(false);
+
+ if (response.IsOk())
+ {
+ SaveUserNameAndPassword();
+ serviceProvider.GetRequiredService().Information(response.Message);
+ HutaoUserOptions options = serviceProvider.GetRequiredService();
+
+ await ThreadHelper.SwitchToMainThreadAsync();
+ options.UserName = UserName;
+ options.Token = response.Data;
+
+ await serviceProvider
+ .GetRequiredService()
+ .NavigateAsync(INavigationAwaiter.Default, true)
+ .ConfigureAwait(false);
+ }
+ }
+
+ private async Task LoginAsync()
+ {
+ if (UserName == null || Password == null)
+ {
+ return;
+ }
+
+ Response response = await homaPassportClient.LoginAsync(UserName, Password).ConfigureAwait(false);
+
+ if (response.IsOk())
+ {
+ SaveUserNameAndPassword();
+ serviceProvider.GetRequiredService().Information(response.Message);
+ HutaoUserOptions options = serviceProvider.GetRequiredService();
+
+ await ThreadHelper.SwitchToMainThreadAsync();
+ options.UserName = UserName;
+ options.Token = response.Data;
+
+ await serviceProvider
+ .GetRequiredService()
+ .NavigateAsync(INavigationAwaiter.Default, true)
+ .ConfigureAwait(false);
+ }
+ }
+
+ private async Task VerifyAsync(bool isResetPassword)
+ {
+ if (UserName == null)
+ {
+ return;
+ }
+
+ Response response = await homaPassportClient.VerifyAsync(UserName, isResetPassword).ConfigureAwait(false);
+ serviceProvider.GetRequiredService().Information(response.Message);
+ }
+
+ private void SaveUserNameAndPassword()
+ {
+ if (UserName != null && Password != null)
+ {
+ LocalSetting.Set(SettingKeys.PassportUserName, UserName);
+ LocalSetting.Set(SettingKeys.PassportPassword, Password);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
index ec05dc66..9cde203e 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
@@ -16,6 +16,8 @@ using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.GachaLog.QueryProvider;
using Snap.Hutao.Service.Game;
using Snap.Hutao.Service.Game.Locator;
+using Snap.Hutao.Service.Hutao;
+using Snap.Hutao.Service.Navigation;
using Snap.Hutao.View.Dialog;
using System.Globalization;
using System.IO;
@@ -64,6 +66,7 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
logger = serviceProvider.GetRequiredService>();
Experimental = serviceProvider.GetRequiredService();
Options = serviceProvider.GetRequiredService();
+ UserOptions = serviceProvider.GetRequiredService();
this.serviceProvider = serviceProvider;
selectedCulture = cultures.FirstOrDefault(c => c.Value == Options.CurrentCulture.Name);
@@ -76,6 +79,7 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
SetDataFolderCommand = new AsyncRelayCommand(SetDataFolderAsync);
ResetStaticResourceCommand = new RelayCommand(ResetStaticResource);
CopyDeviceIdCommand = new RelayCommand(CopyDeviceId);
+ NavigateToHutaoPassportCommand = new RelayCommand(NavigateToHutaoPassport);
}
///
@@ -110,6 +114,11 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
///
public AppOptions Options { get; }
+ ///
+ /// 胡桃用户选项
+ ///
+ public HutaoUserOptions UserOptions { get; }
+
///
/// 背景类型
///
@@ -203,6 +212,11 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
///
public ICommand CopyDeviceIdCommand { get; }
+ ///
+ /// 导航到胡桃通行证界面
+ ///
+ public ICommand NavigateToHutaoPassportCommand { get; }
+
///
protected override Task OpenUIAsync()
{
@@ -299,13 +313,21 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
private void CopyDeviceId()
{
+ IInfoBarService infoBarService = serviceProvider.GetRequiredService();
+
try
{
Clipboard.SetText(DeviceId);
- serviceProvider.GetRequiredService().Success(SH.ViewModelSettingCopyDeviceIdSuccess);
+ infoBarService.Success(SH.ViewModelSettingCopyDeviceIdSuccess);
}
- catch (COMException)
+ catch (COMException ex)
{
+ infoBarService.Error(ex);
}
}
+
+ private void NavigateToHutaoPassport()
+ {
+ serviceProvider.GetRequiredService().Navigate(INavigationAwaiter.Default);
+ }
}
\ No newline at end of file