mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
style improvement
This commit is contained in:
@@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -19,6 +20,9 @@ namespace Snap.Hutao.SourceGeneration.DedendencyInjection;
|
|||||||
[Generator]
|
[Generator]
|
||||||
public class InjectionGenerator : ISourceGenerator
|
public class InjectionGenerator : ISourceGenerator
|
||||||
{
|
{
|
||||||
|
private const string InjectAsSingletonName = "Snap.Hutao.Core.DependencyInjection.InjectAs.Singleton";
|
||||||
|
private const string InjectAsTransientName = "Snap.Hutao.Core.DependencyInjection.InjectAs.Transient";
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
@@ -63,9 +67,14 @@ internal static partial class ServiceCollectionExtensions
|
|||||||
|
|
||||||
private static void FillWithInjectionServices(InjectionSyntaxContextReceiver receiver, StringBuilder sourceCodeBuilder)
|
private static void FillWithInjectionServices(InjectionSyntaxContextReceiver receiver, StringBuilder sourceCodeBuilder)
|
||||||
{
|
{
|
||||||
foreach (INamedTypeSymbol classSymbol in receiver.Classes.OrderByDescending(symbol => symbol.ToDisplayString()))
|
List<string> lines = new();
|
||||||
|
StringBuilder lineBuilder = new();
|
||||||
|
|
||||||
|
foreach (INamedTypeSymbol classSymbol in receiver.Classes)
|
||||||
{
|
{
|
||||||
sourceCodeBuilder.Append("\r\n");
|
lineBuilder
|
||||||
|
.Clear()
|
||||||
|
.Append("\r\n");
|
||||||
|
|
||||||
AttributeData injectionInfo = classSymbol
|
AttributeData injectionInfo = classSymbol
|
||||||
.GetAttributes()
|
.GetAttributes()
|
||||||
@@ -77,11 +86,11 @@ internal static partial class ServiceCollectionExtensions
|
|||||||
string injectAsName = injectAs.ToCSharpString();
|
string injectAsName = injectAs.ToCSharpString();
|
||||||
switch (injectAsName)
|
switch (injectAsName)
|
||||||
{
|
{
|
||||||
case "Snap.Hutao.Core.DependencyInjection.InjectAs.Singleton":
|
case InjectAsSingletonName:
|
||||||
sourceCodeBuilder.Append(@" .AddSingleton(");
|
lineBuilder.Append(@" .AddSingleton(");
|
||||||
break;
|
break;
|
||||||
case "Snap.Hutao.Core.DependencyInjection.InjectAs.Transient":
|
case InjectAsTransientName:
|
||||||
sourceCodeBuilder.Append(@" .AddTransient(");
|
lineBuilder.Append(@" .AddTransient(");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"非法的InjectAs值: [{injectAsName}]。");
|
throw new InvalidOperationException($"非法的InjectAs值: [{injectAsName}]。");
|
||||||
@@ -90,10 +99,17 @@ internal static partial class ServiceCollectionExtensions
|
|||||||
if (arguments.Length == 2)
|
if (arguments.Length == 2)
|
||||||
{
|
{
|
||||||
TypedConstant interfaceType = arguments[1];
|
TypedConstant interfaceType = arguments[1];
|
||||||
sourceCodeBuilder.Append($"{interfaceType.ToCSharpString()}, ");
|
lineBuilder.Append($"{interfaceType.ToCSharpString()}, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCodeBuilder.Append($"typeof({classSymbol.ToDisplayString()}))");
|
lineBuilder.Append($"typeof({classSymbol.ToDisplayString()}))");
|
||||||
|
|
||||||
|
lines.Add(lineBuilder.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string line in lines.OrderByDescending(x => x))
|
||||||
|
{
|
||||||
|
sourceCodeBuilder.Append(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
<StaticResource x:Key="WindowCaptionForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
|
<StaticResource x:Key="WindowCaptionForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||||
<StaticResource x:Key="WindowCaptionForegroundDisabled" ResourceKey="SystemControlForegroundBaseHighBrush" />
|
<StaticResource x:Key="WindowCaptionForegroundDisabled" ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||||
|
|
||||||
|
<Thickness x:Key="InfoBarIconMargin">6,16,16,16</Thickness>
|
||||||
|
<Thickness x:Key="InfoBarContentRootPadding">16,0,0,0</Thickness>
|
||||||
|
|
||||||
<CornerRadius x:Key="CompatCornerRadius">4</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadius">4</CornerRadius>
|
||||||
<CornerRadius x:Key="CompatCornerRadiusTop">4,4,0,0</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusTop">4,4,0,0</CornerRadius>
|
||||||
<CornerRadius x:Key="CompatCornerRadiusRight">0,4,4,0</CornerRadius>
|
<CornerRadius x:Key="CompatCornerRadiusRight">0,4,4,0</CornerRadius>
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ internal class AutoHeightBehavior : BehaviorBase<FrameworkElement>
|
|||||||
public double TargetWidth
|
public double TargetWidth
|
||||||
{
|
{
|
||||||
get => (double)GetValue(TargetWidthProperty);
|
get => (double)GetValue(TargetWidthProperty);
|
||||||
|
|
||||||
set => SetValue(TargetWidthProperty, value);
|
set => SetValue(TargetWidthProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,15 +30,14 @@ internal class AutoHeightBehavior : BehaviorBase<FrameworkElement>
|
|||||||
public double TargetHeight
|
public double TargetHeight
|
||||||
{
|
{
|
||||||
get => (double)GetValue(TargetHeightProperty);
|
get => (double)GetValue(TargetHeightProperty);
|
||||||
|
|
||||||
set => SetValue(TargetHeightProperty, value);
|
set => SetValue(TargetHeightProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnAssociatedObjectLoaded()
|
protected override void OnAssociatedObjectLoaded()
|
||||||
{
|
{
|
||||||
AssociatedObject.SizeChanged += OnSizeChanged;
|
|
||||||
UpdateElementHeight();
|
UpdateElementHeight();
|
||||||
|
AssociatedObject.SizeChanged += OnSizeChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class CancellablePage : Page
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||||
{
|
{
|
||||||
viewLoadingConcellationTokenSource.Cancel();
|
|
||||||
base.OnNavigatingFrom(e);
|
base.OnNavigatingFrom(e);
|
||||||
|
viewLoadingConcellationTokenSource.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,9 @@ public sealed partial class MainWindow : Window
|
|||||||
private void MainWindowClosed(object sender, WindowEventArgs args)
|
private void MainWindowClosed(object sender, WindowEventArgs args)
|
||||||
{
|
{
|
||||||
// save datebase
|
// save datebase
|
||||||
Ioc.Default.GetRequiredService<AppDbContext>().SaveChanges();
|
AppDbContext appDbContext = Ioc.Default.GetRequiredService<AppDbContext>();
|
||||||
|
int changes = appDbContext.SaveChanges();
|
||||||
|
|
||||||
|
Verify.Operation(changes == 0, "存在可避免的未经处理的数据库更改");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
|
using Snap.Hutao.Service.Abstraction;
|
||||||
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Entity;
|
namespace Snap.Hutao.Model.Entity;
|
||||||
|
|
||||||
@@ -21,6 +24,7 @@ public class User : Observable
|
|||||||
/// 无用户
|
/// 无用户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly User None = new();
|
public static readonly User None = new();
|
||||||
|
private bool isInitialized = false;
|
||||||
private UserGameRole? selectedUserGameRole;
|
private UserGameRole? selectedUserGameRole;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -68,6 +72,12 @@ public class User : Observable
|
|||||||
[NotMapped]
|
[NotMapped]
|
||||||
public ICommand? RemoveCommand { get; set; }
|
public ICommand? RemoveCommand { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 复制Cookie命令
|
||||||
|
/// </summary>
|
||||||
|
[NotMapped]
|
||||||
|
public ICommand? CopyCookieCommand { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 判断用户是否为空用户
|
/// 判断用户是否为空用户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -110,6 +120,12 @@ public class User : Observable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isInitialized)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyCookieCommand = new RelayCommand(CopyCookie);
|
||||||
Must.NotNull(RemoveCommand!);
|
Must.NotNull(RemoveCommand!);
|
||||||
|
|
||||||
UserInfo = await userClient
|
UserInfo = await userClient
|
||||||
@@ -122,6 +138,8 @@ public class User : Observable
|
|||||||
|
|
||||||
SelectedUserGameRole = UserGameRoles.FirstOrFirstOrDefault(role => role.IsChosen);
|
SelectedUserGameRole = UserGameRoles.FirstOrFirstOrDefault(role => role.IsChosen);
|
||||||
|
|
||||||
|
isInitialized = true;
|
||||||
|
|
||||||
return UserInfo != null && UserGameRoles.Any();
|
return UserInfo != null && UserGameRoles.Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,4 +159,21 @@ public class User : Observable
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CopyCookie()
|
||||||
|
{
|
||||||
|
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DataPackage content = new();
|
||||||
|
content.SetText(Must.NotNull(Cookie!));
|
||||||
|
Clipboard.SetContent(content);
|
||||||
|
|
||||||
|
infoBarService.Success($"{UserInfo?.Nickname} 的 Cookie 复制成功");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
infoBarService.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,7 @@ public interface IUserService
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步添加用户
|
/// 异步添加用户
|
||||||
|
/// 通常用户是未初始化的
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">待添加的用户</param>
|
/// <param name="user">待添加的用户</param>
|
||||||
/// <returns>用户初始化是否成功</returns>
|
/// <returns>用户初始化是否成功</returns>
|
||||||
@@ -37,7 +38,8 @@ public interface IUserService
|
|||||||
/// 异步移除用户
|
/// 异步移除用户
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">待移除的用户</param>
|
/// <param name="user">待移除的用户</param>
|
||||||
void RemoveUser(User user);
|
/// <returns>任务</returns>
|
||||||
|
Task RemoveUserAsync(User user);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将cookie的字符串形式转换为字典
|
/// 将cookie的字符串形式转换为字典
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示导航等待器
|
||||||
|
/// </summary>
|
||||||
|
public interface INavigationAwaiter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 默认的等待器
|
||||||
|
/// </summary>
|
||||||
|
static readonly INavigationAwaiter Default = new NavigationExtra();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 等待导航完成,或直到抛出异常
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>导航完成的任务</returns>
|
||||||
|
Task WaitForCompletionAsync();
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||||
|
|
||||||
|
public interface INavigationExtra
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 数据
|
||||||
|
/// </summary>
|
||||||
|
object? Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通知导航服务导航已经结束
|
||||||
|
/// </summary>
|
||||||
|
void NotifyNavigationCompleted();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通知导航服务导航异常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exception">异常</param>
|
||||||
|
void NotifyNavigationException(Exception exception);
|
||||||
|
}
|
||||||
@@ -41,29 +41,29 @@ public interface INavigationService
|
|||||||
/// 导航到指定类型的页面
|
/// 导航到指定类型的页面
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageType">指定的页面类型</param>
|
/// <param name="pageType">指定的页面类型</param>
|
||||||
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
|
|
||||||
/// <param name="data">要传递的数据</param>
|
/// <param name="data">要传递的数据</param>
|
||||||
|
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
|
||||||
/// <returns>是否导航成功</returns>
|
/// <returns>是否导航成功</returns>
|
||||||
NavigationResult Navigate(Type pageType, bool isSyncTabRequested = false, NavigationExtra? data = null);
|
NavigationResult Navigate(Type pageType, INavigationAwaiter data, bool isSyncTabRequested = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导航到指定类型的页面
|
/// 导航到指定类型的页面
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">指定的页面类型</typeparam>
|
/// <typeparam name="T">指定的页面类型</typeparam>
|
||||||
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
|
|
||||||
/// <param name="data">要传递的数据</param>
|
/// <param name="data">要传递的数据</param>
|
||||||
|
/// <param name="isSyncTabRequested">是否同步标签,当在代码中调用时应设为 true</param>
|
||||||
/// <returns>是否导航成功</returns>
|
/// <returns>是否导航成功</returns>
|
||||||
NavigationResult Navigate<T>(bool isSyncTabRequested = false, NavigationExtra? data = null)
|
NavigationResult Navigate<T>(INavigationAwaiter data, bool isSyncTabRequested = false)
|
||||||
where T : Page;
|
where T : Page;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步的导航到指定类型的页面
|
/// 异步的导航到指定类型的页面
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TPage">指定的页面类型</typeparam>
|
/// <typeparam name="TPage">指定的页面类型</typeparam>
|
||||||
/// <param name="syncNavigationViewItem">是否同步标签,当在代码中调用时应设为 true</param>
|
|
||||||
/// <param name="data">要传递的数据</param>
|
/// <param name="data">要传递的数据</param>
|
||||||
|
/// <param name="syncNavigationViewItem">是否同步标签,当在代码中调用时应设为 true</param>
|
||||||
/// <returns>是否导航成功</returns>
|
/// <returns>是否导航成功</returns>
|
||||||
Task<NavigationResult> NavigateAsync<TPage>(bool syncNavigationViewItem = false, NavigationExtra? data = null)
|
Task<NavigationResult> NavigateAsync<TPage>(INavigationAwaiter data, bool syncNavigationViewItem = false)
|
||||||
where TPage : Page;
|
where TPage : Page;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -6,8 +6,13 @@ namespace Snap.Hutao.Service.Abstraction.Navigation;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导航额外信息
|
/// 导航额外信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NavigationExtra
|
public class NavigationExtra : INavigationExtra, INavigationAwaiter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 任务完成源
|
||||||
|
/// </summary>
|
||||||
|
private readonly TaskCompletionSource navigationCompletedTaskCompletionSource = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的导航额外信息
|
/// 构造一个新的导航额外信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -17,13 +22,24 @@ public class NavigationExtra
|
|||||||
Data = data;
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// 数据
|
|
||||||
/// </summary>
|
|
||||||
public object? Data { get; set; }
|
public object? Data { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// 任务完成源
|
public Task WaitForCompletionAsync()
|
||||||
/// </summary>
|
{
|
||||||
public TaskCompletionSource NavigationCompletedTaskCompletionSource { get; } = new();
|
return navigationCompletedTaskCompletionSource.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void NotifyNavigationCompleted()
|
||||||
|
{
|
||||||
|
navigationCompletedTaskCompletionSource.TrySetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void NotifyNavigationException(Exception exception)
|
||||||
|
{
|
||||||
|
navigationCompletedTaskCompletionSource.TrySetException(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,11 +25,11 @@ internal class NavigationService : INavigationService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的导航服务
|
/// 构造一个新的导航服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="infobarService">信息条服务</param>
|
/// <param name="infoBarService">信息条服务</param>
|
||||||
/// <param name="logger">日志器</param>
|
/// <param name="logger">日志器</param>
|
||||||
public NavigationService(IInfoBarService infobarService, ILogger<INavigationService> logger)
|
public NavigationService(IInfoBarService infoBarService, ILogger<INavigationService> logger)
|
||||||
{
|
{
|
||||||
this.infoBarService = infobarService;
|
this.infoBarService = infoBarService;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ internal class NavigationService : INavigationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public NavigationResult Navigate(Type pageType, bool syncNavigationViewItem = false, NavigationExtra? data = null)
|
public NavigationResult Navigate(Type pageType, INavigationAwaiter data, bool syncNavigationViewItem = false)
|
||||||
{
|
{
|
||||||
Type? currentType = Frame?.Content?.GetType();
|
Type? currentType = Frame?.Content?.GetType();
|
||||||
|
|
||||||
@@ -123,22 +123,28 @@ internal class NavigationService : INavigationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public NavigationResult Navigate<TPage>(bool syncNavigationViewItem = false, NavigationExtra? data = null)
|
public NavigationResult Navigate<TPage>(INavigationAwaiter data, bool syncNavigationViewItem = false)
|
||||||
where TPage : Page
|
where TPage : Page
|
||||||
{
|
{
|
||||||
return Navigate(typeof(TPage), syncNavigationViewItem, data);
|
return Navigate(typeof(TPage), data, syncNavigationViewItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<NavigationResult> NavigateAsync<TPage>(bool syncNavigationViewItem = false, NavigationExtra? data = null)
|
public async Task<NavigationResult> NavigateAsync<TPage>(INavigationAwaiter data, bool syncNavigationViewItem = false)
|
||||||
where TPage : Page
|
where TPage : Page
|
||||||
{
|
{
|
||||||
data ??= new NavigationExtra();
|
NavigationResult result = Navigate<TPage>(data, syncNavigationViewItem);
|
||||||
NavigationResult result = Navigate<TPage>(syncNavigationViewItem, data);
|
|
||||||
|
|
||||||
if (result is NavigationResult.Succeed)
|
if (result is NavigationResult.Succeed)
|
||||||
{
|
{
|
||||||
await data.NavigationCompletedTaskCompletionSource.Task;
|
try
|
||||||
|
{
|
||||||
|
await data.WaitForCompletionAsync();
|
||||||
|
}
|
||||||
|
catch (AggregateException)
|
||||||
|
{
|
||||||
|
return NavigationResult.Failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -158,7 +164,8 @@ internal class NavigationService : INavigationService
|
|||||||
? typeof(SettingPage)
|
? typeof(SettingPage)
|
||||||
: NavHelper.GetNavigateTo(Selected);
|
: NavHelper.GetNavigateTo(Selected);
|
||||||
|
|
||||||
Navigate(Must.NotNull(targetType!), false, new(NavHelper.GetExtraData(Selected)));
|
INavigationAwaiter navigationAwaiter = new NavigationExtra(NavHelper.GetExtraData(Selected));
|
||||||
|
Navigate(Must.NotNull(targetType!), navigationAwaiter, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
|
private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ internal class UserService : IUserService
|
|||||||
private readonly UserGameRoleClient userGameRoleClient;
|
private readonly UserGameRoleClient userGameRoleClient;
|
||||||
|
|
||||||
private User? currentUser;
|
private User? currentUser;
|
||||||
private ObservableCollection<User>? cachedUser = null;
|
private ObservableCollection<User>? cachedUsers = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的用户服务
|
/// 构造一个新的用户服务
|
||||||
@@ -52,6 +52,7 @@ internal class UserService : IUserService
|
|||||||
{
|
{
|
||||||
User.SetSelectionState(currentUser, false);
|
User.SetSelectionState(currentUser, false);
|
||||||
appDbContext.Users.Update(currentUser);
|
appDbContext.Users.Update(currentUser);
|
||||||
|
appDbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ internal class UserService : IUserService
|
|||||||
{
|
{
|
||||||
User.SetSelectionState(currentUser, true);
|
User.SetSelectionState(currentUser, true);
|
||||||
appDbContext.Users.Update(currentUser);
|
appDbContext.Users.Update(currentUser);
|
||||||
|
appDbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,6 +74,7 @@ internal class UserService : IUserService
|
|||||||
if (await user.InitializeAsync(userClient, userGameRoleClient))
|
if (await user.InitializeAsync(userClient, userGameRoleClient))
|
||||||
{
|
{
|
||||||
appDbContext.Users.Add(user);
|
appDbContext.Users.Add(user);
|
||||||
|
await appDbContext.SaveChangesAsync();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,20 +82,21 @@ internal class UserService : IUserService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void RemoveUser(User user)
|
public async Task RemoveUserAsync(User user)
|
||||||
{
|
{
|
||||||
appDbContext.Users.Remove(user);
|
appDbContext.Users.Remove(user);
|
||||||
|
await appDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<ObservableCollection<User>> GetInitializedUsersAsync(ICommand removeCommand)
|
public async Task<ObservableCollection<User>> GetInitializedUsersAsync(ICommand removeCommand)
|
||||||
{
|
{
|
||||||
if (cachedUser == null)
|
if (cachedUsers == null)
|
||||||
{
|
{
|
||||||
appDbContext.Users.Load();
|
appDbContext.Users.Load();
|
||||||
cachedUser = appDbContext.Users.Local.ToObservableCollection();
|
cachedUsers = appDbContext.Users.Local.ToObservableCollection();
|
||||||
|
|
||||||
foreach (User user in cachedUser)
|
foreach (User user in cachedUsers)
|
||||||
{
|
{
|
||||||
user.RemoveCommand = removeCommand;
|
user.RemoveCommand = removeCommand;
|
||||||
await user.InitializeAsync(userClient, userGameRoleClient);
|
await user.InitializeAsync(userClient, userGameRoleClient);
|
||||||
@@ -101,7 +105,7 @@ internal class UserService : IUserService
|
|||||||
CurrentUser = await appDbContext.Users.SingleOrDefaultAsync(user => user.IsSelected);
|
CurrentUser = await appDbContext.Users.SingleOrDefaultAsync(user => user.IsSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedUser;
|
return cachedUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<NavigationView
|
<NavigationView
|
||||||
x:Name="NavView"
|
x:Name="NavView"
|
||||||
CompactPaneLength="48"
|
CompactPaneLength="48"
|
||||||
OpenPaneLength="200"
|
OpenPaneLength="244"
|
||||||
CompactModeThresholdWidth="128"
|
CompactModeThresholdWidth="128"
|
||||||
ExpandedModeThresholdWidth="720"
|
ExpandedModeThresholdWidth="720"
|
||||||
IsPaneOpen="True"
|
IsPaneOpen="True"
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ public sealed partial class MainView : UserControl
|
|||||||
|
|
||||||
navigationService = Ioc.Default.GetRequiredService<INavigationService>();
|
navigationService = Ioc.Default.GetRequiredService<INavigationService>();
|
||||||
navigationService.Initialize(NavView, ContentFrame);
|
navigationService.Initialize(NavView, ContentFrame);
|
||||||
navigationService.Navigate<Page.AnnouncementPage>(true);
|
navigationService.Navigate<Page.AnnouncementPage>(INavigationAwaiter.Default, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,14 +35,14 @@ openInWebview: function(url){ location.href = url }}";
|
|||||||
{
|
{
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
|
|
||||||
if (e.Parameter is NavigationExtra extra)
|
if (e.Parameter is INavigationExtra extra)
|
||||||
{
|
{
|
||||||
targetContent = extra.Data as string;
|
targetContent = extra.Data as string;
|
||||||
LoadAnnouncementAsync(extra).Forget();
|
LoadAnnouncementAsync(extra).Forget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadAnnouncementAsync(NavigationExtra extra)
|
private async Task LoadAnnouncementAsync(INavigationExtra extra)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -51,12 +51,13 @@ openInWebview: function(url){ location.href = url }}";
|
|||||||
await WebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(MihoyoSDKDefinition);
|
await WebView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(MihoyoSDKDefinition);
|
||||||
WebView.CoreWebView2.WebMessageReceived += (_, e) => Browser.Open(e.TryGetWebMessageAsString);
|
WebView.CoreWebView2.WebMessageReceived += (_, e) => Browser.Open(e.TryGetWebMessageAsString);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
extra.NotifyNavigationException(ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebView.NavigateToString(targetContent);
|
WebView.NavigateToString(targetContent);
|
||||||
extra.NavigationCompletedTaskCompletionSource.TrySetResult();
|
extra.NotifyNavigationCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
xmlns:shvc="using:Snap.Hutao.View.Converter"
|
xmlns:shvc="using:Snap.Hutao.View.Converter"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
<mxi:Interaction.Behaviors>
|
<mxi:Interaction.Behaviors>
|
||||||
<mxic:EventTriggerBehavior EventName="Loaded">
|
<mxic:EventTriggerBehavior EventName="Loaded">
|
||||||
<mxic:InvokeCommandAction Command="{Binding OpenUICommand}"/>
|
<mxic:InvokeCommandAction Command="{Binding OpenUICommand}"/>
|
||||||
@@ -46,7 +45,7 @@
|
|||||||
<cwucont:AdaptiveGridView
|
<cwucont:AdaptiveGridView
|
||||||
cwua:ItemsReorderAnimation.Duration="0:0:0.06"
|
cwua:ItemsReorderAnimation.Duration="0:0:0.06"
|
||||||
SelectionMode="None"
|
SelectionMode="None"
|
||||||
DesiredWidth="320"
|
DesiredWidth="280"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
ItemsSource="{Binding List}"
|
ItemsSource="{Binding List}"
|
||||||
Margin="0,0,2,0">
|
Margin="0,0,2,0">
|
||||||
@@ -70,7 +69,6 @@
|
|||||||
<Border
|
<Border
|
||||||
cwu:UIElementExtensions.ClipToBounds="True">
|
cwu:UIElementExtensions.ClipToBounds="True">
|
||||||
<Border
|
<Border
|
||||||
CompositeMode="SourceOver"
|
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
cwu:VisualExtensions.NormalizedCenterPoint="0.5">
|
cwu:VisualExtensions.NormalizedCenterPoint="0.5">
|
||||||
<mxi:Interaction.Behaviors>
|
<mxi:Interaction.Behaviors>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
x:Class="Snap.Hutao.View.UserView"
|
x:Class="Snap.Hutao.View.UserView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="using:Snap.Hutao.View"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||||
@@ -14,157 +13,188 @@
|
|||||||
<mxic:InvokeCommandAction Command="{Binding OpenUICommand}"/>
|
<mxic:InvokeCommandAction Command="{Binding OpenUICommand}"/>
|
||||||
</mxic:EventTriggerBehavior>
|
</mxic:EventTriggerBehavior>
|
||||||
</mxi:Interaction.Behaviors>
|
</mxi:Interaction.Behaviors>
|
||||||
<Grid Height="48">
|
<Grid Height="58">
|
||||||
<Grid Height="48">
|
<Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<RowDefinition />
|
||||||
<ColumnDefinition Width="auto"/>
|
<RowDefinition Height="auto"/>
|
||||||
<ColumnDefinition/>
|
</Grid.RowDefinitions>
|
||||||
<ColumnDefinition Width="auto"/>
|
<Grid.ColumnDefinitions>
|
||||||
</Grid.ColumnDefinitions>
|
<ColumnDefinition Width="auto"/>
|
||||||
<PersonPicture
|
<ColumnDefinition/>
|
||||||
ProfilePicture="{Binding SelectedUser.UserInfo.AvatarUrl,Mode=OneWay}"
|
<ColumnDefinition Width="auto"/>
|
||||||
HorizontalAlignment="Left"
|
</Grid.ColumnDefinitions>
|
||||||
Margin="4,0,4,0"
|
<PersonPicture
|
||||||
Height="40"/>
|
ProfilePicture="{Binding SelectedUser.UserInfo.AvatarUrl,Mode=OneWay}"
|
||||||
<TextBlock
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
Margin="4,0,4,0"
|
||||||
Margin="0,0,0,2"
|
Height="40"/>
|
||||||
Grid.Column="1"
|
<TextBlock
|
||||||
Text="{Binding SelectedUser.UserInfo.Nickname,Mode=OneWay}"
|
VerticalAlignment="Center"
|
||||||
TextTrimming="CharacterEllipsis"/>
|
Margin="0,0,0,2"
|
||||||
<Button
|
Grid.Column="1"
|
||||||
x:Name="UsersFlyoutButton"
|
Text="{Binding SelectedUser.UserInfo.Nickname,Mode=OneWay}"
|
||||||
Background="Transparent"
|
TextTrimming="CharacterEllipsis"/>
|
||||||
BorderBrush="{x:Null}"
|
<Button
|
||||||
Height="38.4"
|
x:Name="UsersFlyoutButton"
|
||||||
Content=""
|
Background="Transparent"
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
BorderBrush="{x:Null}"
|
||||||
Grid.Column="2"
|
Height="38.4"
|
||||||
Margin="4">
|
Content=""
|
||||||
<Button.Flyout>
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
<Flyout
|
Grid.Column="2"
|
||||||
Placement="TopEdgeAlignedRight"
|
Margin="4">
|
||||||
LightDismissOverlayMode="On">
|
<Button.Flyout>
|
||||||
<Flyout.FlyoutPresenterStyle>
|
<Flyout
|
||||||
<Style
|
Placement="TopEdgeAlignedRight"
|
||||||
TargetType="FlyoutPresenter"
|
LightDismissOverlayMode="On">
|
||||||
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}">
|
<Flyout.FlyoutPresenterStyle>
|
||||||
<Setter Property="Padding" Value="0,2,0,2"/>
|
<Style
|
||||||
</Style>
|
TargetType="FlyoutPresenter"
|
||||||
</Flyout.FlyoutPresenterStyle>
|
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}">
|
||||||
<StackPanel Width="192">
|
<Setter Property="Padding" Value="0,2,0,2"/>
|
||||||
<ListView
|
</Style>
|
||||||
Grid.Row="1"
|
</Flyout.FlyoutPresenterStyle>
|
||||||
Margin="4"
|
<StackPanel>
|
||||||
SelectionMode="Single"
|
<TextBlock
|
||||||
CanReorderItems="True"
|
Margin="10,6,0,6"
|
||||||
ItemsSource="{Binding SelectedUser.UserGameRoles}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
SelectedItem="{Binding SelectedUser.SelectedUserGameRole,Mode=TwoWay}">
|
Text="角色"/>
|
||||||
<ListView.ItemTemplate>
|
<ListView
|
||||||
<DataTemplate>
|
Grid.Row="1"
|
||||||
<StackPanel Padding="0,6">
|
Margin="4"
|
||||||
<TextBlock Text="{Binding Nickname}"/>
|
SelectionMode="Single"
|
||||||
<TextBlock
|
CanReorderItems="True"
|
||||||
Margin="0,2,0,0"
|
ItemsSource="{Binding SelectedUser.UserGameRoles}"
|
||||||
Opacity="0.6"
|
SelectedItem="{Binding SelectedUser.SelectedUserGameRole,Mode=TwoWay}">
|
||||||
Text="{Binding Description}"
|
<ListView.ItemTemplate>
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"/>
|
<DataTemplate>
|
||||||
</StackPanel>
|
<StackPanel Padding="0,6">
|
||||||
</DataTemplate>
|
<TextBlock Text="{Binding Nickname}"/>
|
||||||
</ListView.ItemTemplate>
|
<TextBlock
|
||||||
</ListView>
|
Margin="0,2,0,0"
|
||||||
<MenuFlyoutSeparator/>
|
Opacity="0.6"
|
||||||
<ListView
|
Text="{Binding Description}"
|
||||||
MaxHeight="224"
|
Style="{StaticResource CaptionTextBlockStyle}"/>
|
||||||
Grid.Row="1"
|
</StackPanel>
|
||||||
Margin="4"
|
</DataTemplate>
|
||||||
SelectionMode="Single"
|
</ListView.ItemTemplate>
|
||||||
ItemsSource="{Binding Users}"
|
</ListView>
|
||||||
SelectedItem="{Binding SelectedUser,Mode=TwoWay}">
|
<MenuFlyoutSeparator/>
|
||||||
<ListView.ItemTemplate>
|
<TextBlock
|
||||||
<DataTemplate>
|
Margin="10,6,0,6"
|
||||||
<Grid Padding="0,12" Background="Transparent">
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
<Grid.ColumnDefinitions>
|
Text="账号"/>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ListView
|
||||||
<ColumnDefinition/>
|
MaxHeight="224"
|
||||||
<ColumnDefinition Width="auto"/>
|
Grid.Row="1"
|
||||||
</Grid.ColumnDefinitions>
|
Margin="4"
|
||||||
<PersonPicture
|
SelectionMode="Single"
|
||||||
ProfilePicture="{Binding UserInfo.AvatarUrl,Mode=OneWay}"
|
ItemsSource="{Binding Users}"
|
||||||
HorizontalAlignment="Left"
|
SelectedItem="{Binding SelectedUser,Mode=TwoWay}">
|
||||||
Margin="0,0"
|
<ListView.ItemTemplate>
|
||||||
Height="32"/>
|
<DataTemplate>
|
||||||
|
<Grid
|
||||||
<TextBlock
|
Width="200"
|
||||||
Margin="12,0,0,0"
|
Padding="0,12"
|
||||||
Grid.Column="1"
|
Background="Transparent">
|
||||||
VerticalAlignment="Center"
|
<Grid.ColumnDefinitions>
|
||||||
Text="{Binding UserInfo.Nickname}"/>
|
<ColumnDefinition Width="auto"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
<ColumnDefinition Width="auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<PersonPicture
|
||||||
|
ProfilePicture="{Binding UserInfo.AvatarUrl,Mode=OneWay}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="0,0"
|
||||||
|
Height="32"/>
|
||||||
|
<TextBlock
|
||||||
|
Margin="12,0,0,0"
|
||||||
|
Grid.Column="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{Binding UserInfo.Nickname}"/>
|
||||||
|
<StackPanel
|
||||||
|
x:Name="ButtonPanel"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Grid.Column="2"
|
||||||
|
Visibility="Collapsed">
|
||||||
<Button
|
<Button
|
||||||
x:Name="RemoveUserButton"
|
Content=""
|
||||||
Content=""
|
|
||||||
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Grid.Column="2"
|
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
BorderBrush="{x:Null}"
|
BorderBrush="{x:Null}"
|
||||||
Margin="12,0,0,0"
|
Margin="12,0,0,0"
|
||||||
Visibility="Collapsed"
|
Command="{Binding CopyCookieCommand}"
|
||||||
|
ToolTipService.ToolTip="复制 Cookie"/>
|
||||||
|
<Button
|
||||||
|
Content=""
|
||||||
|
FontFamily="{StaticResource SymbolThemeFontFamily}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
BorderBrush="{x:Null}"
|
||||||
|
Margin="6,0,0,0"
|
||||||
Command="{Binding RemoveCommand}"
|
Command="{Binding RemoveCommand}"
|
||||||
CommandParameter="{Binding}"/>
|
CommandParameter="{Binding}"
|
||||||
|
ToolTipService.ToolTip="移除用户"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<Storyboard x:Name="RemoveUserButtonVisibleStoryboard">
|
<Storyboard x:Name="ButtonPanelVisibleStoryboard">
|
||||||
<ObjectAnimationUsingKeyFrames
|
<ObjectAnimationUsingKeyFrames
|
||||||
Storyboard.TargetName="RemoveUserButton"
|
Storyboard.TargetName="ButtonPanel"
|
||||||
Storyboard.TargetProperty="Visibility">
|
Storyboard.TargetProperty="Visibility">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0">
|
<DiscreteObjectKeyFrame KeyTime="0">
|
||||||
<DiscreteObjectKeyFrame.Value>
|
<DiscreteObjectKeyFrame.Value>
|
||||||
<Visibility>Visible</Visibility>
|
<Visibility>Visible</Visibility>
|
||||||
</DiscreteObjectKeyFrame.Value>
|
</DiscreteObjectKeyFrame.Value>
|
||||||
</DiscreteObjectKeyFrame>
|
</DiscreteObjectKeyFrame>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
|
|
||||||
<Storyboard x:Name="RemoveUserButtonCollapsedStoryboard">
|
<Storyboard x:Name="ButtonPanelCollapsedStoryboard">
|
||||||
<ObjectAnimationUsingKeyFrames
|
<ObjectAnimationUsingKeyFrames
|
||||||
Storyboard.TargetName="RemoveUserButton"
|
Storyboard.TargetName="ButtonPanel"
|
||||||
Storyboard.TargetProperty="Visibility">
|
Storyboard.TargetProperty="Visibility">
|
||||||
<DiscreteObjectKeyFrame KeyTime="0">
|
<DiscreteObjectKeyFrame KeyTime="0">
|
||||||
<DiscreteObjectKeyFrame.Value>
|
<DiscreteObjectKeyFrame.Value>
|
||||||
<Visibility>Collapsed</Visibility>
|
<Visibility>Collapsed</Visibility>
|
||||||
</DiscreteObjectKeyFrame.Value>
|
</DiscreteObjectKeyFrame.Value>
|
||||||
</DiscreteObjectKeyFrame>
|
</DiscreteObjectKeyFrame>
|
||||||
</ObjectAnimationUsingKeyFrames>
|
</ObjectAnimationUsingKeyFrames>
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</Grid.Resources>
|
</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>
|
<mxi:Interaction.Behaviors>
|
||||||
</ListView.ItemTemplate>
|
<mxic:EventTriggerBehavior EventName="PointerEntered">
|
||||||
</ListView>
|
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelVisibleStoryboard}"/>
|
||||||
<CommandBar DefaultLabelPosition="Right">
|
</mxic:EventTriggerBehavior>
|
||||||
<AppBarButton
|
<mxic:EventTriggerBehavior EventName="PointerExited">
|
||||||
Icon="Add"
|
<mxim:ControlStoryboardAction Storyboard="{StaticResource ButtonPanelCollapsedStoryboard}"/>
|
||||||
Label="添加新用户"
|
</mxic:EventTriggerBehavior>
|
||||||
Command="{Binding AddUserCommand}"
|
</mxi:Interaction.Behaviors>
|
||||||
CommandParameter="{x:Bind UsersFlyoutButton.Flyout}"/>
|
</Grid>
|
||||||
</CommandBar>
|
|
||||||
</StackPanel>
|
</DataTemplate>
|
||||||
</Flyout>
|
</ListView.ItemTemplate>
|
||||||
</Button.Flyout>
|
</ListView>
|
||||||
</Button>
|
<CommandBar DefaultLabelPosition="Right">
|
||||||
</Grid>
|
<AppBarButton
|
||||||
|
Icon="Add"
|
||||||
|
Label="添加新用户"
|
||||||
|
Command="{Binding AddUserCommand}"
|
||||||
|
CommandParameter="{x:Bind UsersFlyoutButton.Flyout}"/>
|
||||||
|
</CommandBar>
|
||||||
|
</StackPanel>
|
||||||
|
</Flyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
|
<NavigationViewItemSeparator
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
VerticalAlignment="Bottom"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ internal class AnnouncementViewModel : ObservableObject, ISupportCancellation
|
|||||||
|
|
||||||
if (WebView2Helper.IsSupported)
|
if (WebView2Helper.IsSupported)
|
||||||
{
|
{
|
||||||
navigationService.Navigate<View.Page.AnnouncementContentPage>(data: new(content));
|
navigationService.Navigate<View.Page.AnnouncementContentPage>(data: new NavigationExtra(content));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Core.Threading;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
@@ -23,8 +22,7 @@ internal class UserViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
private readonly IUserService userService;
|
private readonly IUserService userService;
|
||||||
private readonly IInfoBarService infoBarService;
|
private readonly IInfoBarService infoBarService;
|
||||||
|
private readonly ICommand removeUserCommandCache;
|
||||||
private ICommand removeUserCommand;
|
|
||||||
|
|
||||||
private User? selectedUser;
|
private User? selectedUser;
|
||||||
private ObservableCollection<User>? userInfos;
|
private ObservableCollection<User>? userInfos;
|
||||||
@@ -43,7 +41,7 @@ internal class UserViewModel : ObservableObject
|
|||||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||||
AddUserCommand = asyncRelayCommandFactory.Create<Flyout>(AddUserAsync);
|
AddUserCommand = asyncRelayCommandFactory.Create<Flyout>(AddUserAsync);
|
||||||
|
|
||||||
removeUserCommand = new RelayCommand<User>(RemoveUser);
|
removeUserCommandCache = asyncRelayCommandFactory.Create<User>(RemoveUserAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -76,46 +74,36 @@ internal class UserViewModel : ObservableObject
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ICommand AddUserCommand { get; }
|
public ICommand AddUserCommand { get; }
|
||||||
|
|
||||||
private static bool TryValidateCookie(IDictionary<string, string> map, [NotNullWhen(true)] out SortedDictionary<string, string>? filteredCookie)
|
private static bool TryValidateCookie(IDictionary<string, string> map, [NotNullWhen(true)] out IDictionary<string, string>? filteredCookie)
|
||||||
{
|
{
|
||||||
int validFlag = 4;
|
int validFlag = 4;
|
||||||
|
|
||||||
filteredCookie = new();
|
filteredCookie = new SortedDictionary<string, string>();
|
||||||
|
|
||||||
// O(1) to validate cookie
|
// O(1) to validate cookie
|
||||||
foreach ((string key, string value) in map)
|
foreach ((string key, string value) in map)
|
||||||
{
|
{
|
||||||
if (key == "account_id")
|
if (key == "account_id" || key == "cookie_token" || key == "ltoken" || key == "ltuid")
|
||||||
{
|
|
||||||
validFlag--;
|
|
||||||
filteredCookie[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == "cookie_token")
|
|
||||||
{
|
|
||||||
validFlag--;
|
|
||||||
filteredCookie[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == "ltoken")
|
|
||||||
{
|
|
||||||
validFlag--;
|
|
||||||
filteredCookie[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == "ltuid")
|
|
||||||
{
|
{
|
||||||
validFlag--;
|
validFlag--;
|
||||||
filteredCookie[key] = value;
|
filteredCookie[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validFlag == 0;
|
if (validFlag == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filteredCookie = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OpenUIAsync()
|
private async Task OpenUIAsync()
|
||||||
{
|
{
|
||||||
Users = await userService.GetInitializedUsersAsync(removeUserCommand);
|
Users = await userService.GetInitializedUsersAsync(removeUserCommandCache);
|
||||||
SelectedUser = userService.CurrentUser;
|
SelectedUser = userService.CurrentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,28 +119,37 @@ internal class UserViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
IDictionary<string, string> map = userService.ParseCookie(result.Value);
|
IDictionary<string, string> map = userService.ParseCookie(result.Value);
|
||||||
|
|
||||||
if (TryValidateCookie(map, out SortedDictionary<string, string>? filteredCookie))
|
if (TryValidateCookie(map, out IDictionary<string, string>? filteredCookie))
|
||||||
{
|
{
|
||||||
string simplifiedCookie = string.Join(';', filteredCookie.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
string simplifiedCookie = string.Join(';', filteredCookie.Select(kvp => $"{kvp.Key}={kvp.Value}"));
|
||||||
User user = new()
|
User user = new()
|
||||||
{
|
{
|
||||||
Cookie = simplifiedCookie,
|
Cookie = simplifiedCookie,
|
||||||
RemoveCommand = removeUserCommand,
|
RemoveCommand = removeUserCommandCache,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!await userService.TryAddUserAsync(user))
|
if (!await userService.TryAddUserAsync(user))
|
||||||
{
|
{
|
||||||
infoBarService.Warning("提供的Cookie无效!");
|
infoBarService.Warning("此Cookie无法获取用户信息,请重新输入");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infoBarService.Success($"成功添加用户 [{user.UserInfo!.Nickname}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infoBarService.Warning("提供的字符串并不是有效的Cookie,请重新输入");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveUser(User? user)
|
private async Task RemoveUserAsync(User? user)
|
||||||
{
|
{
|
||||||
if (!User.IsNone(user))
|
if (!User.IsNone(user))
|
||||||
{
|
{
|
||||||
userService.RemoveUser(user);
|
await userService.RemoveUserAsync(user);
|
||||||
|
infoBarService.Success($"成功移除用户 [{user.UserInfo!.Nickname}]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,11 @@ internal class HutaoClient : ISupportAsyncInitialization
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> InitializeAsync(CancellationToken token = default)
|
public async Task<bool> InitializeAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
if (isInitialized)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Auth auth = new(
|
Auth auth = new(
|
||||||
"08d9e212-0cb3-4d71-8ed7-003606da7b20",
|
"08d9e212-0cb3-4d71-8ed7-003606da7b20",
|
||||||
"7ueWgZGn53dDhrm8L5ZRw+YWfOeSWtgQmJWquRgaygw=");
|
"7ueWgZGn53dDhrm8L5ZRw+YWfOeSWtgQmJWquRgaygw=");
|
||||||
@@ -185,7 +190,7 @@ internal class HutaoClient : ISupportAsyncInitialization
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取队伍出场次数
|
/// 异步获取队伍出场次数 层间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>队伍出场列表</returns>
|
/// <returns>队伍出场列表</returns>
|
||||||
@@ -201,7 +206,7 @@ internal class HutaoClient : ISupportAsyncInitialization
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取队伍出场次数
|
/// 异步获取队伍出场次数 层
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>队伍出场列表</returns>
|
/// <returns>队伍出场列表</returns>
|
||||||
@@ -217,7 +222,7 @@ internal class HutaoClient : ISupportAsyncInitialization
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取队伍出场次数
|
/// 按角色列表异步获取推荐队伍
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="floor">楼层</param>
|
/// <param name="floor">楼层</param>
|
||||||
/// <param name="avatarIds">期望的角色,按期望出现顺序排序</param>
|
/// <param name="avatarIds">期望的角色,按期望出现顺序排序</param>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Snap.Hutao.Web.Hutao.Model;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 队伍上场率
|
/// 队伍上场率
|
||||||
|
/// 层间上场率
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record TeamCombination
|
public record TeamCombination
|
||||||
{
|
{
|
||||||
@@ -20,19 +21,3 @@ public record TeamCombination
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<Rate<Team>> Teams { get; set; } = null!;
|
public IEnumerable<Rate<Team>> Teams { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 队伍上场率2
|
|
||||||
/// </summary>
|
|
||||||
public record TeamCombination2
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 带有层的间
|
|
||||||
/// </summary>
|
|
||||||
public int Floor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 队伍
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Rate<Team>> Teams { get; set; } = null!;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 队伍上场率2
|
||||||
|
/// 层上场率
|
||||||
|
/// </summary>
|
||||||
|
public record TeamCombination2
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 带有层的间
|
||||||
|
/// </summary>
|
||||||
|
public int Floor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 队伍
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Rate<Team>> Teams { get; set; } = null!;
|
||||||
|
}
|
||||||
@@ -27,7 +27,14 @@ public class Response : ISupportValidation
|
|||||||
{
|
{
|
||||||
Ioc.Default
|
Ioc.Default
|
||||||
.GetRequiredService<IInfoBarService>()
|
.GetRequiredService<IInfoBarService>()
|
||||||
.Information(ToString());
|
.Error(ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReturnCode != 0)
|
||||||
|
{
|
||||||
|
Ioc.Default
|
||||||
|
.GetRequiredService<IInfoBarService>()
|
||||||
|
.Warning(ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class Response<TData> : Response
|
|||||||
/// <param name="returnCode">返回代码</param>
|
/// <param name="returnCode">返回代码</param>
|
||||||
/// <param name="message">消息</param>
|
/// <param name="message">消息</param>
|
||||||
/// <param name="data">数据</param>
|
/// <param name="data">数据</param>
|
||||||
|
[JsonConstructor]
|
||||||
public Response(int returnCode, string message, TData? data)
|
public Response(int returnCode, string message, TData? data)
|
||||||
: base(returnCode, message)
|
: base(returnCode, message)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user