mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
support remove users
This commit is contained in:
@@ -50,14 +50,13 @@ internal static partial class ServiceCollectionExtensions
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Snap.Hutao.SourceGeneration.DedendencyInjection.InjectionGenerator"","" 1.0.0.0"")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public static partial IServiceCollection AddInjections(this IServiceCollection services)
|
||||
{");
|
||||
{
|
||||
return services");
|
||||
|
||||
sourceCodeBuilder.Append("\r\n");
|
||||
FillWithInjectionServices(receiver, sourceCodeBuilder);
|
||||
sourceCodeBuilder.Append(@" return services;
|
||||
sourceCodeBuilder.Append(@";
|
||||
}
|
||||
}");
|
||||
sourceCodeBuilder.Append("\r\n");
|
||||
|
||||
context.AddSource("ServiceCollectionExtensions.g.cs", SourceText.From(sourceCodeBuilder.ToString(), Encoding.UTF8));
|
||||
}
|
||||
@@ -66,6 +65,8 @@ internal static partial class ServiceCollectionExtensions
|
||||
{
|
||||
foreach (INamedTypeSymbol classSymbol in receiver.Classes.OrderByDescending(symbol => symbol.ToDisplayString()))
|
||||
{
|
||||
sourceCodeBuilder.Append("\r\n");
|
||||
|
||||
AttributeData injectionInfo = classSymbol
|
||||
.GetAttributes()
|
||||
.Single(attr => attr.AttributeClass!.ToDisplayString() == InjectionSyntaxContextReceiver.AttributeName);
|
||||
@@ -77,10 +78,10 @@ internal static partial class ServiceCollectionExtensions
|
||||
switch (injectAsName)
|
||||
{
|
||||
case "Snap.Hutao.Core.DependencyInjection.InjectAs.Singleton":
|
||||
sourceCodeBuilder.Append(@" services.AddSingleton(");
|
||||
sourceCodeBuilder.Append(@" .AddSingleton(");
|
||||
break;
|
||||
case "Snap.Hutao.Core.DependencyInjection.InjectAs.Transient":
|
||||
sourceCodeBuilder.Append(@" services.AddTransient(");
|
||||
sourceCodeBuilder.Append(@" .AddTransient(");
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"非法的InjectAs值: [{injectAsName}]。");
|
||||
@@ -92,7 +93,7 @@ internal static partial class ServiceCollectionExtensions
|
||||
sourceCodeBuilder.Append($"{interfaceType.ToCSharpString()}, ");
|
||||
}
|
||||
|
||||
sourceCodeBuilder.Append($"typeof({classSymbol.ToDisplayString()}));\r\n");
|
||||
sourceCodeBuilder.Append($"typeof({classSymbol.ToDisplayString()}))");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,8 @@
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.SourceGeneration.DedendencyInjection;
|
||||
|
||||
@@ -17,6 +13,9 @@ namespace Snap.Hutao.SourceGeneration.DedendencyInjection;
|
||||
/// </summary>
|
||||
public class InjectionSyntaxContextReceiver : ISyntaxContextReceiver
|
||||
{
|
||||
/// <summary>
|
||||
/// 注入特性的名称
|
||||
/// </summary>
|
||||
public const string AttributeName = "Snap.Hutao.Core.DependencyInjection.Annotation.InjectionAttribute";
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -23,6 +24,8 @@ public partial class App : Application
|
||||
// load app resource
|
||||
InitializeComponent();
|
||||
InitializeDependencyInjection();
|
||||
|
||||
UnhandledException += AppUnhandledException;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -44,15 +47,28 @@ public partial class App : Application
|
||||
private static void InitializeDependencyInjection()
|
||||
{
|
||||
IServiceProvider services = new ServiceCollection()
|
||||
|
||||
// Microsoft extension
|
||||
.AddLogging(builder => builder.AddDebug())
|
||||
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
|
||||
.AddMemoryCache()
|
||||
|
||||
// Hutao extensions
|
||||
.AddInjections()
|
||||
.AddDatebase()
|
||||
.AddHttpClients()
|
||||
.AddDefaultJsonSerializerOptions()
|
||||
.AddInjections()
|
||||
|
||||
// Discrete services
|
||||
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
|
||||
|
||||
.BuildServiceProvider();
|
||||
|
||||
Ioc.Default.ConfigureServices(services);
|
||||
}
|
||||
|
||||
private void AppUnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
ILogger<App> logger = Ioc.Default.GetRequiredService<ILogger<App>>();
|
||||
logger.LogError(EventIds.UnhandledException, e.Exception, "未经处理的异常");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,14 @@ using Snap.Hutao.Context.FileSystem;
|
||||
|
||||
namespace Snap.Hutao.Context.Database;
|
||||
|
||||
/// <summary>
|
||||
/// 此类只用于在生成迁移时提供数据库上下文
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class AppDbContextDesignTimeFactory : IDesignTimeDbContextFactory<AppDbContext>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public AppDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
MyDocumentContext myDocument = new(new());
|
||||
|
||||
@@ -11,5 +11,10 @@ internal static class EventIds
|
||||
/// <summary>
|
||||
/// 导航失败
|
||||
/// </summary>
|
||||
public static readonly EventId NavigationFailed = new(100000, "NavigationFailed");
|
||||
public static readonly EventId NavigationFailed = new(100000, nameof(NavigationFailed));
|
||||
|
||||
/// <summary>
|
||||
/// 未处理的异常
|
||||
/// </summary>
|
||||
public static readonly EventId UnhandledException = new(100000, nameof(UnhandledException));
|
||||
}
|
||||
|
||||
@@ -50,17 +50,15 @@ internal static class IocConfiguration
|
||||
// temporarily create a context
|
||||
using (AppDbContext context = AppDbContext.CreateFrom(sqlConnectionString))
|
||||
{
|
||||
Debug.WriteLine("Migrate started");
|
||||
if (context.Database.GetPendingMigrations().Any())
|
||||
{
|
||||
Debug.WriteLine("Migrate started");
|
||||
context.Database.Migrate();
|
||||
Debug.WriteLine("Migrate completed");
|
||||
}
|
||||
|
||||
Debug.WriteLine("Migrate completed");
|
||||
}
|
||||
|
||||
// LocalSetting.Set(SettingKeys.LastAppVersion, CoreEnvironment.Version.ToString());
|
||||
return services
|
||||
.AddDbContextPool<AppDbContext>(builder => builder.UseSqlite(sqlConnectionString));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,12 +25,12 @@ internal static class IocHttpClientConfiguration
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
public static IServiceCollection AddHttpClients(this IServiceCollection services)
|
||||
{
|
||||
services.AddHttpClient<HutaoClient>().ConfigureHttpClient(DefaultConfiguration);
|
||||
services.AddHttpClient<AnnouncementClient>().ConfigureHttpClient(DefaultConfiguration);
|
||||
services.AddHttpClient<UserGameRoleClient>().ConfigureHttpClient(DefaultConfiguration);
|
||||
services.AddHttpClient<HutaoClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<AnnouncementClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<UserGameRoleClient>(DefaultConfiguration);
|
||||
|
||||
services.AddHttpClient<GameRecordClient>().ConfigureHttpClient(XRpcConfiguration);
|
||||
services.AddHttpClient<UserClient>().ConfigureHttpClient(XRpcConfiguration);
|
||||
services.AddHttpClient<GameRecordClient>(XRpcConfiguration);
|
||||
services.AddHttpClient<UserClient>(XRpcConfiguration);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Snap.Hutao.Migrations
|
||||
{
|
||||
[SuppressMessage("", "SA1413")]
|
||||
[SuppressMessage("", "SA1600")]
|
||||
[SuppressMessage("", "SA1601")]
|
||||
public partial class SettingAndUser : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Snap.Hutao.Context.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
@@ -62,6 +62,12 @@ public class User : Observable
|
||||
private set => Set(ref selectedUserGameRole, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除命令
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public ICommand? RemoveCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断用户是否为空用户
|
||||
/// </summary>
|
||||
@@ -91,6 +97,7 @@ public class User : Observable
|
||||
|
||||
/// <summary>
|
||||
/// 初始化此用户
|
||||
/// 初始化前必须设置 <see cref="RemoveCommand"/> 属性
|
||||
/// </summary>
|
||||
/// <param name="userClient">用户客户端</param>
|
||||
/// <param name="userGameRoleClient">角色客户端</param>
|
||||
@@ -103,6 +110,8 @@ public class User : Observable
|
||||
return false;
|
||||
}
|
||||
|
||||
Must.NotNull(RemoveCommand!);
|
||||
|
||||
UserInfo = await userClient
|
||||
.GetUserFullInfoAsync(this, token)
|
||||
.ConfigureAwait(false);
|
||||
@@ -111,9 +120,9 @@ public class User : Observable
|
||||
.GetUserGameRolesAsync(this, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
SelectedUserGameRole = UserGameRoles.FirstOrDefault(role => role.IsChosen) ?? UserGameRoles.FirstOrDefault();
|
||||
SelectedUserGameRole = UserGameRoles.FirstOrFirstOrDefault(role => role.IsChosen);
|
||||
|
||||
return UserInfo != null && UserGameRoles != null;
|
||||
return UserInfo != null && UserGameRoles.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.0.3.0" />
|
||||
Version="1.0.4.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
|
||||
@@ -22,7 +22,7 @@ public static class Program
|
||||
XamlCheckProcessRequirements();
|
||||
|
||||
ComWrappersSupport.InitializeComWrappers();
|
||||
Application.Start((p) =>
|
||||
Application.Start(p =>
|
||||
{
|
||||
DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread());
|
||||
SynchronizationContext.SetSynchronizationContext(context);
|
||||
|
||||
@@ -28,17 +28,17 @@ public interface IInfoBarService
|
||||
/// <summary>
|
||||
/// 显示错误消息
|
||||
/// </summary>
|
||||
/// <param name="ex">异常</param>
|
||||
/// <param name="exception">异常</param>
|
||||
/// <param name="delay">关闭延迟</param>
|
||||
void Error(Exception ex, int delay = 0);
|
||||
void Error(Exception exception, int delay = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 显示错误消息
|
||||
/// </summary>
|
||||
/// <param name="ex">异常</param>
|
||||
/// <param name="exception">异常</param>
|
||||
/// <param name="title">标题</param>
|
||||
/// <param name="delay">关闭延迟</param>
|
||||
void Error(Exception ex, string title, int delay = 0);
|
||||
void Error(Exception exception, string title, int delay = 0);
|
||||
|
||||
/// <summary>
|
||||
/// 显示提示信息
|
||||
|
||||
@@ -22,9 +22,9 @@ public interface IUserService
|
||||
/// 每个用户信息都应准备完成
|
||||
/// 此操作不能取消
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <param name="removeCommand">移除用户命令</param>
|
||||
/// <returns>准备完成的用户信息枚举</returns>
|
||||
Task<ObservableCollection<User>> GetInitializedUsersAsync();
|
||||
Task<ObservableCollection<User>> GetInitializedUsersAsync(ICommand removeCommand);
|
||||
|
||||
/// <summary>
|
||||
/// 异步添加用户
|
||||
|
||||
@@ -107,7 +107,7 @@ internal class InfoBarService : IInfoBarService
|
||||
};
|
||||
|
||||
infoBar.Closed += OnInfoBarClosed;
|
||||
Must.NotNull(infoBarStack!)!.Children.Add(infoBar);
|
||||
Must.NotNull(infoBarStack!).Children.Add(infoBar);
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Abstraction.Navigation;
|
||||
using Snap.Hutao.View.Helper;
|
||||
using Snap.Hutao.View.Page;
|
||||
@@ -16,6 +17,7 @@ namespace Snap.Hutao.Service;
|
||||
[Injection(InjectAs.Singleton, typeof(INavigationService))]
|
||||
internal class NavigationService : INavigationService
|
||||
{
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ILogger<INavigationService> logger;
|
||||
|
||||
private NavigationView? navigationView;
|
||||
@@ -23,9 +25,11 @@ internal class NavigationService : INavigationService
|
||||
/// <summary>
|
||||
/// 构造一个新的导航服务
|
||||
/// </summary>
|
||||
/// <param name="infobarService">信息条服务</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public NavigationService(ILogger<INavigationService> logger)
|
||||
public NavigationService(IInfoBarService infobarService, ILogger<INavigationService> logger)
|
||||
{
|
||||
this.infoBarService = infobarService;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -108,6 +112,7 @@ internal class NavigationService : INavigationService
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(EventIds.NavigationFailed, ex, "导航到指定页面时发生了错误");
|
||||
infoBarService.Error(ex);
|
||||
}
|
||||
|
||||
logger.LogInformation("Navigate to {pageType}:{result}", pageType, navigated ? "succeed" : "failed");
|
||||
|
||||
@@ -45,15 +45,21 @@ internal class UserService : IUserService
|
||||
get => currentUser;
|
||||
set
|
||||
{
|
||||
if (!User.IsNone(currentUser))
|
||||
{
|
||||
User.SetSelectionState(currentUser, false);
|
||||
appDbContext.Users.Update(currentUser);
|
||||
}
|
||||
|
||||
// only update when not processing a deletion
|
||||
if (!User.IsNone(value))
|
||||
{
|
||||
currentUser = value;
|
||||
if (!User.IsNone(currentUser))
|
||||
{
|
||||
User.SetSelectionState(currentUser, false);
|
||||
appDbContext.Users.Update(currentUser);
|
||||
}
|
||||
}
|
||||
|
||||
// 当删除到无用户时也能正常反应状态
|
||||
currentUser = value;
|
||||
|
||||
if (!User.IsNone(currentUser))
|
||||
{
|
||||
User.SetSelectionState(currentUser, true);
|
||||
appDbContext.Users.Update(currentUser);
|
||||
}
|
||||
@@ -79,7 +85,7 @@ internal class UserService : IUserService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<ObservableCollection<User>> GetInitializedUsersAsync()
|
||||
public async Task<ObservableCollection<User>> GetInitializedUsersAsync(ICommand removeCommand)
|
||||
{
|
||||
if (cachedUser == null)
|
||||
{
|
||||
@@ -88,6 +94,7 @@ internal class UserService : IUserService
|
||||
|
||||
foreach (User user in cachedUser)
|
||||
{
|
||||
user.RemoveCommand = removeCommand;
|
||||
await user.InitializeAsync(userClient, userGameRoleClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
|
||||
namespace Snap.Hutao.View.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// Static class used to provide internal tools
|
||||
/// </summary>
|
||||
internal static class ConvertHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper method to safely cast an object to a boolean
|
||||
/// </summary>
|
||||
/// <param name="parameter">Parameter to cast to a boolean</param>
|
||||
/// <returns>Bool value or false if cast failed</returns>
|
||||
internal static bool TryParseBool(object parameter)
|
||||
{
|
||||
bool parsed = false;
|
||||
if (parameter != null)
|
||||
{
|
||||
_ = bool.TryParse(parameter.ToString(), out parsed);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to convert a value from a source type to a target type.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert</param>
|
||||
/// <param name="targetType">The target type</param>
|
||||
/// <returns>The converted value</returns>
|
||||
internal static object Convert(object value, Type targetType)
|
||||
{
|
||||
return targetType.IsInstanceOfType(value)
|
||||
? value
|
||||
: XamlBindingHelper.ConvertValue(targetType, value);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Snap.Hutao.Core;
|
||||
|
||||
namespace Snap.Hutao.View.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// 百分比转换高度
|
||||
/// </summary>
|
||||
public sealed class PercentageToHeightConverter : DependencyObject, IValueConverter
|
||||
{
|
||||
private static readonly DependencyProperty TargetWidthProperty = Property<PercentageToHeightConverter>.Depend(nameof(TargetWidth), 1080D);
|
||||
private static readonly DependencyProperty TargetHeightProperty = Property<PercentageToHeightConverter>.Depend(nameof(TargetHeight), 390D);
|
||||
|
||||
/// <summary>
|
||||
/// 目标宽度
|
||||
/// </summary>
|
||||
public double TargetWidth
|
||||
{
|
||||
get => (double)GetValue(TargetWidthProperty);
|
||||
|
||||
set => SetValue(TargetWidthProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 目标高度
|
||||
/// </summary>
|
||||
public double TargetHeight
|
||||
{
|
||||
get => (double)GetValue(TargetHeightProperty);
|
||||
|
||||
set => SetValue(TargetHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Convert(object value, Type targetType, object parameter, string culture)
|
||||
{
|
||||
return (double)value * (TargetHeight / TargetWidth);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string culture)
|
||||
{
|
||||
throw Must.NeverHappen();
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Snap.Hutao.Core;
|
||||
|
||||
namespace Snap.Hutao.View.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// 百分比转宽度
|
||||
/// </summary>
|
||||
public sealed class PercentageToWidthConverter : DependencyObject, IValueConverter
|
||||
{
|
||||
private static readonly DependencyProperty TargetWidthProperty = Property<PercentageToWidthConverter>.Depend(nameof(TargetWidth), 1080D);
|
||||
private static readonly DependencyProperty TargetHeightProperty = Property<PercentageToWidthConverter>.Depend(nameof(TargetHeight), 390D);
|
||||
|
||||
/// <summary>
|
||||
/// 目标宽度
|
||||
/// </summary>
|
||||
public double TargetWidth
|
||||
{
|
||||
get => (double)GetValue(TargetWidthProperty);
|
||||
|
||||
set => SetValue(TargetWidthProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 目标高度
|
||||
/// </summary>
|
||||
public double TargetHeight
|
||||
{
|
||||
get => (double)GetValue(TargetHeightProperty);
|
||||
|
||||
set => SetValue(TargetHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Convert(object value, Type targetType, object parameter, string culture)
|
||||
{
|
||||
return (double)value * (TargetWidth / TargetHeight);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string culture)
|
||||
{
|
||||
throw Must.NeverHappen();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:mxim="using:Microsoft.Xaml.Interactions.Media"
|
||||
mc:Ignorable="d">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="Loaded">
|
||||
@@ -25,11 +26,6 @@
|
||||
HorizontalAlignment="Left"
|
||||
Margin="4,0,4,0"
|
||||
Height="40"/>
|
||||
<!--<PersonPicture
|
||||
ProfilePicture="{Binding SelectedUser.UserInfo.Pendant,FallbackValue={x:Null},Mode=OneWay}"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="4,0,4,0"
|
||||
Height="40"/>-->
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,0,2"
|
||||
@@ -87,21 +83,72 @@
|
||||
SelectedItem="{Binding SelectedUser,Mode=TwoWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Padding="0,12">
|
||||
<Grid Padding="0,12" Background="Transparent">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<PersonPicture
|
||||
ProfilePicture="{Binding UserInfo.AvatarUrl,Mode=OneWay}"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="4,0"
|
||||
Margin="0,0"
|
||||
Height="32"/>
|
||||
|
||||
<TextBlock
|
||||
Margin="12,0,0,0"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding UserInfo.Nickname}"/>
|
||||
|
||||
<Button
|
||||
x:Name="RemoveUserButton"
|
||||
Content=""
|
||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
Grid.Column="2"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
BorderBrush="{x:Null}"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="Collapsed"
|
||||
Command="{Binding RemoveCommand}"
|
||||
CommandParameter="{Binding}"/>
|
||||
|
||||
<Grid.Resources>
|
||||
<Storyboard x:Name="RemoveUserButtonVisibleStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="RemoveUserButton"
|
||||
Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Visible</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
|
||||
<Storyboard x:Name="RemoveUserButtonCollapsedStoryboard">
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
Storyboard.TargetName="RemoveUserButton"
|
||||
Storyboard.TargetProperty="Visibility">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</Grid.Resources>
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource RemoveUserButtonVisibleStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||
<mxim:ControlStoryboardAction Storyboard="{StaticResource RemoveUserButtonCollapsedStoryboard}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
</Grid>
|
||||
|
||||
</DataTemplate>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Threading;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
@@ -23,6 +24,8 @@ internal class UserViewModel : ObservableObject
|
||||
private readonly IUserService userService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
|
||||
private ICommand removeUserCommand;
|
||||
|
||||
private User? selectedUser;
|
||||
private ObservableCollection<User>? userInfos;
|
||||
|
||||
@@ -39,6 +42,8 @@ internal class UserViewModel : ObservableObject
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
AddUserCommand = asyncRelayCommandFactory.Create<Flyout>(AddUserAsync);
|
||||
|
||||
removeUserCommand = new RelayCommand<User>(RemoveUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -110,8 +115,8 @@ internal class UserViewModel : ObservableObject
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
Users = await userService.GetInitializedUsersAsync();
|
||||
SelectedUser = Users.FirstOrDefault();
|
||||
Users = await userService.GetInitializedUsersAsync(removeUserCommand);
|
||||
SelectedUser = userService.CurrentUser;
|
||||
}
|
||||
|
||||
private async Task AddUserAsync(Flyout? flyout)
|
||||
@@ -129,7 +134,11 @@ internal class UserViewModel : ObservableObject
|
||||
if (TryValidateCookie(map, out SortedDictionary<string, string>? filteredCookie))
|
||||
{
|
||||
string simplifiedCookie = string.Join(';', filteredCookie.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
||||
User user = new() { Cookie = simplifiedCookie };
|
||||
User user = new()
|
||||
{
|
||||
Cookie = simplifiedCookie,
|
||||
RemoveCommand = removeUserCommand,
|
||||
};
|
||||
|
||||
if (!await userService.TryAddUserAsync(user))
|
||||
{
|
||||
@@ -138,4 +147,12 @@ internal class UserViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveUser(User? user)
|
||||
{
|
||||
if (!User.IsNone(user))
|
||||
{
|
||||
userService.RemoveUser(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||
@@ -31,7 +29,6 @@ internal class HutaoClient : ISupportAsyncInitialization
|
||||
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly GameRecordClient gameRecordClient;
|
||||
private readonly UserGameRoleClient userGameRoleClient;
|
||||
private readonly JsonSerializerOptions jsonSerializerOptions;
|
||||
|
||||
private bool isInitialized = false;
|
||||
@@ -41,17 +38,14 @@ internal class HutaoClient : ISupportAsyncInitialization
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="gameRecordClient">游戏记录客户端</param>
|
||||
/// <param name="userGameRoleClient">用户游戏角色客户端</param>
|
||||
/// <param name="jsonSerializerOptions">json序列化选项</param>
|
||||
public HutaoClient(
|
||||
HttpClient httpClient,
|
||||
GameRecordClient gameRecordClient,
|
||||
UserGameRoleClient userGameRoleClient,
|
||||
JsonSerializerOptions jsonSerializerOptions)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
this.gameRecordClient = gameRecordClient;
|
||||
this.userGameRoleClient = userGameRoleClient;
|
||||
this.jsonSerializerOptions = jsonSerializerOptions;
|
||||
}
|
||||
|
||||
@@ -64,13 +58,12 @@ internal class HutaoClient : ISupportAsyncInitialization
|
||||
Auth auth = new(
|
||||
"08d9e212-0cb3-4d71-8ed7-003606da7b20",
|
||||
"7ueWgZGn53dDhrm8L5ZRw+YWfOeSWtgQmJWquRgaygw=");
|
||||
JsonSerializerOptions? option = Ioc.Default.GetService<JsonSerializerOptions>();
|
||||
|
||||
HttpResponseMessage response = await httpClient
|
||||
.PostAsJsonAsync($"{AuthAPIHost}/Auth/Login", auth, option, token)
|
||||
.PostAsJsonAsync($"{AuthAPIHost}/Auth/Login", auth, jsonSerializerOptions, token)
|
||||
.ConfigureAwait(false);
|
||||
Response<Token>? resp = await response.Content
|
||||
.ReadFromJsonAsync<Response<Token>>(option, token)
|
||||
.ReadFromJsonAsync<Response<Token>>(jsonSerializerOptions, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
httpClient.DefaultRequestHeaders.Authorization = new("Bearer", Must.NotNull(resp?.Data?.AccessToken!));
|
||||
|
||||
Reference in New Issue
Block a user