diff --git a/src/Snap.Hutao/SettingsUI/Controls/CheckBoxWithDescriptionControl.cs b/src/Snap.Hutao/SettingsUI/Controls/CheckBoxWithDescriptionControl.cs
index 2d692cf6..ffb07ab2 100644
--- a/src/Snap.Hutao/SettingsUI/Controls/CheckBoxWithDescriptionControl.cs
+++ b/src/Snap.Hutao/SettingsUI/Controls/CheckBoxWithDescriptionControl.cs
@@ -35,13 +35,14 @@ public class CheckBoxWithDescriptionControl : CheckBox
private void CheckBoxSubTextControl_Loaded(object sender, RoutedEventArgs e)
{
- StackPanel panel = new StackPanel() { Orientation = Orientation.Vertical };
+ StackPanel panel = new() { Orientation = Orientation.Vertical };
// Add text box only if the description is not empty. Required for additional plugin options.
if (!string.IsNullOrWhiteSpace(Description))
{
panel.Children.Add(new TextBlock() { Margin = new Thickness(0, 10, 0, 0), Text = Header });
- panel.Children.Add(new IsEnabledTextBlock() { Style = (Style)Application.Current.Resources["SecondaryIsEnabledTextBlockStyle"], Text = Description });
+ //Style = (Style)Application.Current.Resources["SecondaryIsEnabledTextBlockStyle"]
+ panel.Children.Add(new IsEnabledTextBlock() { Text = Description });
}
else
{
diff --git a/src/Snap.Hutao/SettingsUI/Styles/Button.xaml b/src/Snap.Hutao/SettingsUI/Styles/Button.xaml
index 10a32327..871b51c5 100644
--- a/src/Snap.Hutao/SettingsUI/Styles/Button.xaml
+++ b/src/Snap.Hutao/SettingsUI/Styles/Button.xaml
@@ -7,9 +7,9 @@
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
index 334af782..56dc08d3 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
@@ -3,7 +3,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.WinUI.UI;
-using Microsoft.VisualStudio.Threading;
using Snap.Hutao.Control.Cancellable;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Model.Metadata.Achievement;
@@ -20,7 +19,9 @@ namespace Snap.Hutao.ViewModel;
internal class AchievementViewModel : ObservableObject, ISupportCancellation
{
private readonly IMetadataService metadataService;
- private AdvancedCollectionView? achievementsView;
+ private AdvancedCollectionView? achievements;
+ private IList? achievementGoals;
+ private AchievementGoal? selectedAchievementGoal;
///
/// 构造一个新的成就视图模型
@@ -39,10 +40,32 @@ internal class AchievementViewModel : ObservableObject, ISupportCancellation
///
/// 成就视图
///
- public AdvancedCollectionView? AchievementsView
+ public AdvancedCollectionView? Achievements
{
- get => achievementsView;
- set => SetProperty(ref achievementsView, value);
+ get => achievements;
+ set => SetProperty(ref achievements, value);
+ }
+
+ ///
+ /// 成就分类
+ ///
+ public IList? AchievementGoals
+ {
+ get => achievementGoals;
+ set => SetProperty(ref achievementGoals, value);
+ }
+
+ ///
+ /// 选中的成就分类
+ ///
+ public AchievementGoal? SelectedAchievementGoal
+ {
+ get => selectedAchievementGoal;
+ set
+ {
+ SetProperty(ref selectedAchievementGoal, value);
+ OnGoalChanged(value);
+ }
}
///
@@ -50,17 +73,22 @@ internal class AchievementViewModel : ObservableObject, ISupportCancellation
///
public ICommand OpenUICommand { get; }
- private async Task OpenUIAsync(CancellationToken token)
+ private async Task OpenUIAsync()
{
- using (CancellationTokenExtensions.CombinedCancellationToken combined = token.CombineWith(CancellationToken))
+ if (await metadataService.InitializeAsync(CancellationToken))
{
- if (await metadataService.InitializeAsync(combined.Token))
- {
- IEnumerable achievements = await metadataService.GetAchievementsAsync(combined.Token);
-
- // TODO
- AchievementsView = new(achievements.ToList());
- }
+ Achievements = new(await metadataService.GetAchievementsAsync(CancellationToken), true);
+ AchievementGoals = await metadataService.GetAchievementGoalsAsync(CancellationToken);
}
}
-}
+
+ private void OnGoalChanged(AchievementGoal? goal)
+ {
+ if (Achievements != null)
+ {
+ Achievements.Filter = goal != null
+ ? ((object o) => o is Achievement achi && achi.Goal == goal.Id)
+ : ((object o) => true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs
index 5382f279..0c64aa1e 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/ExperimentalFeaturesViewModel.cs
@@ -41,7 +41,7 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
private Task OpenCacheFolderAsync(CancellationToken token)
{
- return Launcher.LaunchFolderAsync(App.Current.CacheFolder).AsTask(token);
+ return Launcher.LaunchFolderAsync(App.CacheFolder).AsTask(token);
}
private Task OpenDataFolderAsync(CancellationToken token)
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
index 194f38b7..6fb7fa0d 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/UserViewModel.cs
@@ -3,9 +3,10 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
+using Microsoft.UI.Xaml;
using Snap.Hutao.Core.Threading;
using Snap.Hutao.Factory.Abstraction;
-using Snap.Hutao.Model.Entity;
+using Snap.Hutao.Model.Binding;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.View.Dialog;
using System.Collections.Generic;
@@ -27,7 +28,7 @@ internal class UserViewModel : ObservableObject
private readonly IInfoBarService infoBarService;
private User? selectedUser;
- private ObservableCollection? userInfos;
+ private ObservableCollection? users;
///
/// 构造一个新的用户视图模型
@@ -64,7 +65,7 @@ internal class UserViewModel : ObservableObject
///
/// 用户信息集合
///
- public ObservableCollection? Users { get => userInfos; set => SetProperty(ref userInfos, value); }
+ public ObservableCollection? Users { get => users; set => SetProperty(ref users, value); }
///
/// 打开界面命令
@@ -90,20 +91,20 @@ internal class UserViewModel : ObservableObject
{
int validFlag = 4;
- filteredCookie = new SortedDictionary();
+ SortedDictionary filter = new();
- // O(1) to validate cookie
foreach ((string key, string value) in map)
{
if (key == AccountIdKey || key == "cookie_token" || key == "ltoken" || key == "ltuid")
{
validFlag--;
- filteredCookie.Add(key, value);
+ filter.Add(key, value);
}
}
if (validFlag == 0)
{
+ filteredCookie = filter;
return true;
}
else
@@ -115,41 +116,43 @@ internal class UserViewModel : ObservableObject
private async Task OpenUIAsync()
{
- Users = await userService.GetInitializedUsersAsync();
+ Users = await userService.GetUserCollectionAsync();
SelectedUser = userService.CurrentUser;
}
private async Task AddUserAsync()
{
- MainWindow mainWindow = Ioc.Default.GetRequiredService();
+ // Get cookie from user input
+ Window mainWindow = Ioc.Default.GetRequiredService();
Result result = await new UserDialog(mainWindow).GetInputCookieAsync();
- // user confirms the input
+ // User confirms the input
if (result.IsOk)
{
- IDictionary cookieMap = userService.ParseCookie(result.Value);
-
- if (TryValidateCookie(cookieMap, out IDictionary? filteredCookie))
+ if (TryValidateCookie(userService.ParseCookie(result.Value), out IDictionary? filteredCookie))
{
string simplifiedCookie = string.Join(';', filteredCookie.Select(kvp => $"{kvp.Key}={kvp.Value}"));
- User user = new() { Cookie = simplifiedCookie };
- switch (await userService.TryAddUserAsync(user, filteredCookie[AccountIdKey]))
+ if (await userService.CreateUserAsync(simplifiedCookie) is User user)
{
- case UserAddResult.Added:
- infoBarService.Success($"用户 [{user.UserInfo!.Nickname}] 添加成功");
- break;
- case UserAddResult.Updated:
- infoBarService.Success($"用户 [{user.UserInfo!.Nickname}] 更新成功");
- break;
- case UserAddResult.AlreadyExists:
- infoBarService.Information($"用户 [{user.UserInfo!.Nickname}] 已经存在");
- break;
- case UserAddResult.InitializeFailed:
- infoBarService.Warning("此 Cookie 无法获取用户信息,请重新输入");
- break;
- default:
- throw Must.NeverHappen();
+ switch (await userService.TryAddUserAsync(user, filteredCookie[AccountIdKey]))
+ {
+ case UserAddResult.Added:
+ infoBarService.Success($"用户 [{user.UserInfo!.Nickname}] 添加成功");
+ break;
+ case UserAddResult.Updated:
+ infoBarService.Success($"用户 [{user.UserInfo!.Nickname}] 更新成功");
+ break;
+ case UserAddResult.AlreadyExists:
+ infoBarService.Information($"用户 [{user.UserInfo!.Nickname}] 已经存在");
+ break;
+ default:
+ throw Must.NeverHappen();
+ }
+ }
+ else
+ {
+ infoBarService.Warning("此 Cookie 无法获取用户信息,请重新输入");
}
}
else
@@ -161,19 +164,14 @@ internal class UserViewModel : ObservableObject
private async Task RemoveUserAsync(User? user)
{
- if (!User.IsNone(user))
- {
- await userService.RemoveUserAsync(user);
- infoBarService.Success($"用户 [{user.UserInfo!.Nickname}] 成功移除");
- }
+ Verify.Operation(user != null, "待删除的用户不应为 null");
+ await userService.RemoveUserAsync(user);
+ infoBarService.Success($"用户 [{user.UserInfo?.Nickname}] 成功移除");
}
private void CopyCookie(User? user)
{
- if (User.IsNone(user))
- {
- return;
- }
+ Verify.Operation(user != null, "待复制 Cookie 的用户不应为 null");
IInfoBarService infoBarService = Ioc.Default.GetRequiredService();
try
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
index 8e1c8ed4..e30a7cea 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
@@ -20,6 +20,8 @@ namespace Snap.Hutao.ViewModel;
internal class WikiAvatarViewModel : ObservableObject
{
private readonly IMetadataService metadataService;
+
+ // filters
private readonly List> filterElementInfos;
private readonly List>> filterAssociationInfos;
private readonly List>> filterWeaponTypeInfos;
@@ -129,12 +131,12 @@ internal class WikiAvatarViewModel : ObservableObject
{
if (await metadataService.InitializeAsync())
{
- IEnumerable? avatars = await metadataService.GetAvatarsAsync();
+ IList avatars = await metadataService.GetAvatarsAsync();
IOrderedEnumerable sorted = avatars
.OrderBy(avatar => avatar.BeginTime)
.ThenBy(avatar => avatar.Sort);
- Avatars = new AdvancedCollectionView(new List(sorted), true);
+ Avatars = new AdvancedCollectionView(sorted.ToList(), true);
Avatars.MoveCurrentToFirst();
}
}
@@ -175,7 +177,10 @@ internal class WikiAvatarViewModel : ObservableObject
&& targeQualities.Contains(avatar.Quality)
&& targetBodies.Contains(avatar.Body);
- Avatars.MoveCurrentToFirst();
+ if (!Avatars.Contains(Selected))
+ {
+ Avatars.MoveCurrentToFirst();
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
index 3711b84e..86a04145 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Bbs/User/UserClient.cs
@@ -35,7 +35,7 @@ internal class UserClient
/// 用户
/// 取消令牌
/// 详细信息
- public async Task GetUserFullInfoAsync(Model.Entity.User user, CancellationToken token = default)
+ public async Task GetUserFullInfoAsync(Model.Binding.User user, CancellationToken token = default)
{
Response? resp = await httpClient
.UsingDynamicSecret()
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientCookieExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientCookieExtensions.cs
index 2667c678..9e8d3762 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientCookieExtensions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/HttpClientCookieExtensions.cs
@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Snap.Hutao.Model.Entity;
+using Snap.Hutao.Model.Binding;
using System.Net.Http;
namespace Snap.Hutao.Web.Hoyolab;
@@ -19,11 +19,7 @@ internal static class HttpClientCookieExtensions
/// 客户端
internal static HttpClient SetUser(this HttpClient httpClient, User user)
{
- if (!User.IsNone(user))
- {
- httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie);
- }
-
+ httpClient.DefaultRequestHeaders.Set("Cookie", user.Cookie);
return httpClient;
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRoleClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRoleClient.cs
index 0d81fbe2..6464e9c2 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRoleClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Binding/UserGameRoleClient.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Extension;
+using Snap.Hutao.Model.Binding;
using Snap.Hutao.Web.Response;
using System.Collections.Generic;
using System.Net.Http;
@@ -33,7 +34,7 @@ internal class UserGameRoleClient
/// 用户
/// 取消令牌
/// 用户角色信息
- public async Task> GetUserGameRolesAsync(Model.Entity.User user, CancellationToken token = default)
+ public async Task> GetUserGameRolesAsync(User user, CancellationToken token = default)
{
Response>? resp = await httpClient
.SetUser(user)
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs
index 735a3b92..c3663bcb 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/GameRecordClient.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Extension;
-using Snap.Hutao.Model.Entity;
+using Snap.Hutao.Model.Binding;
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
using Snap.Hutao.Web.Response;
diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoClient.cs
index 3b41d152..341da788 100644
--- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoClient.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/HutaoClient.cs
@@ -294,7 +294,7 @@ internal class HutaoClient : ISupportAsyncInitialization
/// 用户
/// 取消令牌
/// 玩家记录
- public async Task GetPlayerRecordAsync(User user, CancellationToken token = default)
+ public async Task GetPlayerRecordAsync(Snap.Hutao.Model.Binding.User user, CancellationToken token = default)
{
PlayerInfo? playerInfo = await gameRecordClient
.GetPlayerInfoAsync(user, token)