add UserFullInfo Client

This commit is contained in:
DismissedLight
2022-06-16 22:53:20 +08:00
parent c555ad1a0c
commit 23fc81bba7
22 changed files with 177 additions and 82 deletions

View File

@@ -19,4 +19,4 @@ internal interface IAsyncInitializable
/// <param name="cancellationToken">取消令牌</param>
/// <returns>初始化任务</returns>
Task<bool> InitializeAsync(CancellationToken cancellationToken = default);
}
}

View File

@@ -2,8 +2,6 @@
// Licensed under the MIT license.
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
namespace Snap.Hutao.Extension;

View File

@@ -6,7 +6,6 @@ using Microsoft.Extensions.DependencyInjection;
using Snap.Hutao.Context.Database;
using Snap.Hutao.Context.FileSystem;
using Snap.Hutao.Core;
using Snap.Hutao.Core.Json;
using Snap.Hutao.Core.Setting;
using System.Text.Json;
using System.Text.Json.Serialization;

View File

@@ -0,0 +1,32 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using System.Runtime.InteropServices;
using WinRT;
namespace Snap.Hutao;
/// <summary>
/// Program class
/// </summary>
public static class Program
{
[DllImport("Microsoft.ui.xaml.dll")]
private static extern void XamlCheckProcessRequirements();
[STAThread]
private static void Main(string[] args)
{
XamlCheckProcessRequirements();
ComWrappersSupport.InitializeComWrappers();
Application.Start((p) =>
{
DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread());
SynchronizationContext.SetSynchronizationContext(context);
_ = new App();
});
}
}

View File

@@ -13,5 +13,5 @@ public interface IUserService
/// <summary>
/// 获取当前用户信息
/// </summary>
User CurrentUser { get; }
User Current { get; }
}

View File

@@ -3,7 +3,7 @@
using Microsoft.UI.Xaml.Controls;
namespace Snap.Hutao.Service.Abstraction;
namespace Snap.Hutao.Service.Abstraction.Navigation;
/// <summary>
/// 导航服务
@@ -44,7 +44,7 @@ public interface INavigationService
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
/// <param name="data">要传递的数据</param>
/// <returns>是否导航成功</returns>
bool Navigate(Type? pageType, bool isSyncTabRequested = false, object? data = null);
NavigationResult Navigate(Type pageType, bool isSyncTabRequested = false, NavigationExtra? data = null);
/// <summary>
/// 导航到指定类型的页面
@@ -53,13 +53,23 @@ public interface INavigationService
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
/// <param name="data">要传递的数据</param>
/// <returns>是否导航成功</returns>
bool Navigate<T>(bool isSyncTabRequested = false, object? data = null)
NavigationResult Navigate<T>(bool isSyncTabRequested = false, NavigationExtra? data = null)
where T : Page;
/// <summary>
/// 异步的导航到指定类型的页面
/// </summary>
/// <typeparam name="TPage">指定的页面类型</typeparam>
/// <param name="syncNavigationViewItem">是否同步标签,当在代码中调用时应设为 true</param>
/// <param name="data">要传递的数据</param>
/// <returns>是否导航成功</returns>
Task<NavigationResult> NavigateAsync<TPage>(bool syncNavigationViewItem = false, NavigationExtra? data = null)
where TPage : Page;
/// <summary>
/// 同步导航标签
/// </summary>
/// <param name="pageType">同步的页面类型</param>
/// <returns>是否同步成功</returns>
bool SyncSelectedNavigationViewItemWith(Type pageType);
}
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Abstraction.Navigation;
/// <summary>
/// 导航额外信息
/// </summary>
public class NavigationExtra
{
/// <summary>
/// 构造一个新的导航额外信息
/// </summary>
/// <param name="data">数据</param>
public NavigationExtra(object? data = null)
{
Data = data;
}
/// <summary>
/// 数据
/// </summary>
public object? Data { get; set; }
/// <summary>
/// 任务完成源
/// </summary>
public TaskCompletionSource NavigationCompletedTaskCompletionSource { get; } = new();
}

View File

@@ -0,0 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Abstraction.Navigation;
/// <summary>
/// 导航结果
/// </summary>
public enum NavigationResult
{
/// <summary>
/// 成功
/// </summary>
Succeed,
/// <summary>
/// 失败
/// </summary>
Failed,
/// <summary>
/// 已经处于该页面
/// </summary>
AlreadyNavigatedTo,
}

View File

@@ -14,44 +14,46 @@ namespace Snap.Hutao.Service;
[Injection(InjectAs.Transient, typeof(IAnnouncementService))]
internal class AnnouncementService : IAnnouncementService
{
private readonly AnnouncementClient announcementProvider;
private readonly AnnouncementClient announcementClient;
/// <summary>
/// 构造一个新的公告服务
/// </summary>
/// <param name="announcementProvider">公告提供器</param>
public AnnouncementService(AnnouncementClient announcementProvider)
/// <param name="announcementClient">公告提供器</param>
public AnnouncementService(AnnouncementClient announcementClient)
{
this.announcementProvider = announcementProvider;
this.announcementClient = announcementClient;
}
/// <inheritdoc/>
public async Task<AnnouncementWrapper> GetAnnouncementsAsync(ICommand openAnnouncementUICommand, CancellationToken cancellationToken = default)
{
AnnouncementWrapper? wrapper = await announcementProvider.GetAnnouncementsAsync(cancellationToken);
List<AnnouncementContent> contents = await announcementProvider.GetAnnouncementContentsAsync(cancellationToken);
AnnouncementWrapper? wrapper = await announcementClient
.GetAnnouncementsAsync(cancellationToken)
.ConfigureAwait(false);
List<AnnouncementContent> contents = await announcementClient
.GetAnnouncementContentsAsync(cancellationToken)
.ConfigureAwait(false);
Dictionary<int, string?> contentMap = contents
Dictionary<int, string> contentMap = contents
.ToDictionary(id => id.AnnId, content => content.Content);
if (wrapper?.List is List<AnnouncementListWrapper> announcementListWrappers)
{
// 将活动公告置于上方
announcementListWrappers.Reverse();
Must.NotNull(wrapper!);
// 将公告内容联入公告列表
JoinAnnouncements(openAnnouncementUICommand, contentMap, announcementListWrappers);
// 将活动公告置于上方
wrapper.List.Reverse();
return wrapper;
}
// 将公告内容联入公告列表
JoinAnnouncements(openAnnouncementUICommand, contentMap, wrapper.List);
return new();
return wrapper;
}
private void JoinAnnouncements(ICommand openAnnouncementUICommand, Dictionary<int, string?> contentMap, List<AnnouncementListWrapper> announcementListWrappers)
private static void JoinAnnouncements(ICommand openAnnouncementUICommand, Dictionary<int, string> contentMap, List<AnnouncementListWrapper> announcementListWrappers)
{
// 匹配特殊的时间格式: <t>(.*?)</t>
Regex timeTagRegrex = new("&lt;t.*?&gt;(.*?)&lt;/t&gt;", RegexOptions.Multiline);
Regex timeTagInnerRegex = new("(?<=&lt;t.*?&gt;)(.*?)(?=&lt;/t&gt;)");
announcementListWrappers.ForEach(listWrapper =>
@@ -64,7 +66,7 @@ internal class AnnouncementService : IAnnouncementService
rawContent = timeTagRegrex.Replace(rawContent!, x => timeTagInnerRegex.Match(x.Value).Value);
}
item.Content = rawContent;
item.Content = rawContent ?? string.Empty;
item.OpenAnnouncementUICommand = openAnnouncementUICommand;
});
});

View File

@@ -1,11 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.AppCenter.Analytics;
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Core.Logging;
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Abstraction.Navigation;
using Snap.Hutao.View.Helper;
using Snap.Hutao.View.Page;
using System.Linq;
@@ -82,6 +80,7 @@ internal class NavigationService : INavigationService
NavigationViewItem? target = NavigationView.MenuItems
.OfType<NavigationViewItem>()
.SingleOrDefault(menuItem => NavHelper.GetNavigateTo(menuItem) == pageType);
NavigationView.SelectedItem = target;
}
@@ -90,44 +89,59 @@ internal class NavigationService : INavigationService
}
/// <inheritdoc/>
public bool Navigate(Type? pageType, bool isSyncTabRequested = false, object? data = null)
public NavigationResult Navigate(Type pageType, bool syncNavigationViewItem = false, NavigationExtra? data = null)
{
Type? currentType = Frame?.Content?.GetType();
if (pageType is null || (currentType == pageType))
if (currentType == pageType)
{
return false;
return NavigationResult.AlreadyNavigatedTo;
}
_ = isSyncTabRequested && SyncSelectedNavigationViewItemWith(pageType);
_ = syncNavigationViewItem && SyncSelectedNavigationViewItemWith(pageType);
bool result = false;
bool navigated = false;
try
{
result = Frame?.Navigate(pageType, data) ?? false;
if (data != null && data.GetType() != typeof(NavigationExtra))
{
data = new NavigationExtra(data);
}
navigated = Frame?.Navigate(pageType, data) ?? false;
}
catch (Exception ex)
{
logger.LogError(EventIds.NavigationFailed, ex, "导航到指定页面时发生了错误");
}
logger.LogInformation("Navigate to {pageType}:{result}", pageType, result ? "succeed" : "failed");
// 分析页面统计数据时不应加入启动时导航的首个页面
if (HasEverNavigated)
{
Analytics.TrackEvent("General", ("OpenUI", pageType.ToString()).AsDictionary());
}
logger.LogInformation("Navigate to {pageType}:{result}", pageType, navigated ? "succeed" : "failed");
// 首次导航失败时使属性持续保存为false
HasEverNavigated = HasEverNavigated || result;
return result;
HasEverNavigated = HasEverNavigated || navigated;
return navigated ? NavigationResult.Succeed : NavigationResult.Failed;
}
/// <inheritdoc/>
public bool Navigate<T>(bool isSyncTabRequested = false, object? data = null)
where T : Page
public NavigationResult Navigate<TPage>(bool syncNavigationViewItem = false, NavigationExtra? data = null)
where TPage : Page
{
return Navigate(typeof(T), isSyncTabRequested, data);
return Navigate(typeof(TPage), syncNavigationViewItem, data);
}
/// <inheritdoc/>
public async Task<NavigationResult> NavigateAsync<TPage>(bool syncNavigationViewItem = false, NavigationExtra? data = null)
where TPage : Page
{
data ??= new NavigationExtra();
NavigationResult result = Navigate<TPage>(syncNavigationViewItem, data);
if (result is NavigationResult.Succeed)
{
await data.NavigationCompletedTaskCompletionSource.Task;
}
return result;
}
/// <inheritdoc/>
@@ -143,7 +157,8 @@ internal class NavigationService : INavigationService
Type? targetType = args.IsSettingsInvoked
? typeof(SettingPage)
: NavHelper.GetNavigateTo(Selected);
Navigate(targetType, false, NavHelper.GetExtraData(Selected));
Navigate(Must.NotNull(targetType!), false, new(NavHelper.GetExtraData(Selected)));
}
private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
@@ -154,4 +169,4 @@ internal class NavigationService : INavigationService
SyncSelectedNavigationViewItemWith(Frame.Content.GetType());
}
}
}
}

View File

@@ -23,6 +23,8 @@
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundle>Never</AppxBundle>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<StartupObject>Snap.Hutao.Program</StartupObject>
<DefineConstants>DISABLE_XAML_GENERATED_MAIN</DefineConstants>
</PropertyGroup>
<ItemGroup>
<None Remove="stylecop.json" />
@@ -52,7 +54,7 @@
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
<PackageReference Include="Microsoft.AppCenter.Analytics" Version="4.5.1" />
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.5.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.6" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.2.32" />
@@ -60,8 +62,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.197" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.406">
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -3,6 +3,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Snap.Hutao.Core;
namespace Snap.Hutao.View.Converter;
@@ -15,14 +16,12 @@ public class BoolToObjectConverter : DependencyObject, IValueConverter
/// <summary>
/// Identifies the <see cref="TrueValue"/> property.
/// </summary>
public static readonly DependencyProperty TrueValueProperty =
DependencyProperty.Register(nameof(TrueValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null));
public static readonly DependencyProperty TrueValueProperty = Property<BoolToObjectConverter>.Depend<object>(nameof(TrueValue));
/// <summary>
/// Identifies the <see cref="FalseValue"/> property.
/// </summary>
public static readonly DependencyProperty FalseValueProperty =
DependencyProperty.Register(nameof(FalseValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null));
public static readonly DependencyProperty FalseValueProperty = Property<BoolToObjectConverter>.Depend<object>(nameof(FalseValue));
/// <summary>
/// Gets or sets the value to be returned when the boolean is true

View File

@@ -3,6 +3,7 @@
using Microsoft.UI.Xaml.Controls;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Abstraction.Navigation;
namespace Snap.Hutao.View;

View File

@@ -8,6 +8,7 @@ using Snap.Hutao.Core;
using Snap.Hutao.Core.Threading;
using Snap.Hutao.Factory.Abstraction;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Abstraction.Navigation;
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
using System.Windows.Input;

View File

@@ -1,14 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Web.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace Snap.Hutao.Web.Hoyolab.Bbs.User;

View File

@@ -26,7 +26,7 @@ internal class UserClient
/// <param name="userService">用户服务</param>
/// <param name="httpClient">http客户端</param>
/// <param name="jsonSerializerOptions">Json序列化选项</param>
public UserClient(IUserService userService,HttpClient httpClient, JsonSerializerOptions jsonSerializerOptions)
public UserClient(IUserService userService, HttpClient httpClient, JsonSerializerOptions jsonSerializerOptions)
{
this.userService = userService;
this.httpClient = httpClient;
@@ -42,7 +42,7 @@ internal class UserClient
{
Response<UserFullInfoWrapper>? resp = await httpClient
.UsingDynamicSecret()
.SetUser(userService.CurrentUser)
.SetUser(userService.Current)
.GetFromJsonAsync<Response<UserFullInfoWrapper>>(ApiEndpoints.UserFullInfo, jsonSerializerOptions, token)
.ConfigureAwait(false);
@@ -59,7 +59,7 @@ internal class UserClient
{
Response<UserFullInfoWrapper>? resp = await httpClient
.UsingDynamicSecret()
.SetUser(userService.CurrentUser)
.SetUser(userService.Current)
.GetFromJsonAsync<Response<UserFullInfoWrapper>>(string.Format(ApiEndpoints.UserFullInfoQuery, uid), jsonSerializerOptions, token)
.ConfigureAwait(false);

View File

@@ -1,13 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Web.Response;
using System;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace Snap.Hutao.Web.Hoyolab.Bbs.User;

View File

@@ -2,9 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Core.Converting;
using Snap.Hutao.Core.Json;
using System.Linq;
using System.Text;
using System.Text.Json;
namespace Snap.Hutao.Web.Hoyolab.DynamicSecret;

View File

@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using Snap.Hutao.Extension;
using Snap.Hutao.Web.Request;
using Snap.Hutao.Web.Response;
using System.Collections.Generic;
using System.Net.Http;

View File

@@ -3,7 +3,6 @@
using Snap.Hutao.Extension;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Web.Request;
using Snap.Hutao.Web.Response;
using System.Collections.Generic;
using System.Net.Http;
@@ -39,7 +38,7 @@ internal class UserGameRoleClient
public async Task<List<UserGameRole>> GetUserGameRolesAsync(CancellationToken token = default)
{
Response<ListWrapper<UserGameRole>>? resp = await httpClient
.SetUser(userService.CurrentUser)
.SetUser(userService.Current)
.GetFromJsonAsync<Response<ListWrapper<UserGameRole>>>(ApiEndpoints.UserGameRoles, token)
.ConfigureAwait(false);

View File

@@ -48,7 +48,7 @@ internal class GameRecordClient
string url = string.Format(ApiEndpoints.GameRecordIndex, uid.Value, uid.Region);
Response<PlayerInfo>? resp = await httpClient
.SetUser(userService.CurrentUser)
.SetUser(userService.Current)
.UsingDynamicSecret2(jsonSerializerOptions, url)
.GetFromJsonAsync<Response<PlayerInfo>>(url, jsonSerializerOptions, token)
.ConfigureAwait(false);
@@ -68,7 +68,7 @@ internal class GameRecordClient
string url = string.Format(ApiEndpoints.SpiralAbyss, (int)schedule, uid.Value, uid.Region);
Response<SpiralAbyss.SpiralAbyss>? resp = await httpClient
.SetUser(userService.CurrentUser)
.SetUser(userService.Current)
.UsingDynamicSecret2(jsonSerializerOptions, url)
.GetFromJsonAsync<Response<SpiralAbyss.SpiralAbyss>>(url, jsonSerializerOptions, token)
.ConfigureAwait(false);
@@ -88,7 +88,7 @@ internal class GameRecordClient
CharacterData data = new(uid, playerInfo.Avatars.Select(x => x.Id));
HttpResponseMessage? response = await httpClient
.SetUser(userService.CurrentUser)
.SetUser(userService.Current)
.UsingDynamicSecret2(jsonSerializerOptions, ApiEndpoints.Character, data)
.PostAsJsonAsync(ApiEndpoints.Character, data, token)
.ConfigureAwait(false);

View File

@@ -1,7 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
using System.Collections.Generic;
namespace Snap.Hutao.Web.Hutao.Model.Post;