mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
ContentDialogFactory
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Control.Extension;
|
||||
@@ -11,19 +10,6 @@ namespace Snap.Hutao.Control.Extension;
|
||||
/// </summary>
|
||||
internal static class ContentDialogExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 针对窗口进行初始化
|
||||
/// </summary>
|
||||
/// <param name="contentDialog">对话框</param>
|
||||
/// <param name="window">窗口</param>
|
||||
/// <returns>初始化完成的对话框</returns>
|
||||
public static ContentDialog InitializeWithWindow(this ContentDialog contentDialog, Window window)
|
||||
{
|
||||
contentDialog.XamlRoot = window.Content.XamlRoot;
|
||||
|
||||
return contentDialog;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阻止用户交互
|
||||
/// </summary>
|
||||
|
||||
@@ -77,4 +77,32 @@ public static partial class EnumerableExtension
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>
|
||||
public static Dictionary<TKey, TSource> ToDictionaryOverride<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
where TKey : notnull
|
||||
{
|
||||
Dictionary<TKey, TSource> dictionary = new();
|
||||
|
||||
foreach (TSource value in source)
|
||||
{
|
||||
dictionary[keySelector(value)] = value;
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey, TElement}(IEnumerable{TSource}, Func{TSource, TKey}, Func{TSource, TElement})"/>
|
||||
public static Dictionary<TKey, TValue> ToDictionaryOverride<TKey, TValue, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
|
||||
where TKey : notnull
|
||||
{
|
||||
Dictionary<TKey, TValue> dictionary = new();
|
||||
|
||||
foreach (TSource value in source)
|
||||
{
|
||||
dictionary[keySelector(value)] = valueSelector(value);
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Snap.Hutao.Extension;
|
||||
|
||||
/// <summary>
|
||||
@@ -8,26 +10,6 @@ namespace Snap.Hutao.Extension;
|
||||
/// </summary>
|
||||
public static partial class EnumerableExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 计数
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">源类型</typeparam>
|
||||
/// <typeparam name="TKey">计数的键类型</typeparam>
|
||||
/// <param name="source">源</param>
|
||||
/// <param name="keySelector">键选择器</param>
|
||||
/// <returns>计数表</returns>
|
||||
public static IEnumerable<KeyValuePair<TKey, int>> CountBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
where TKey : notnull, IEquatable<TKey>
|
||||
{
|
||||
CounterInt32<TKey> counter = new();
|
||||
foreach (TSource item in source)
|
||||
{
|
||||
counter.Increase(keySelector(item));
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 如果传入集合不为空则原路返回,
|
||||
/// 如果传入集合为空返回一个集合的空集
|
||||
@@ -64,56 +46,14 @@ public static partial class EnumerableExtension
|
||||
return source.FirstOrDefault(predicate) ?? source.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey}(IEnumerable{TSource}, Func{TSource, TKey})"/>
|
||||
public static Dictionary<TKey, TSource> ToDictionaryOverride<TKey, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||
where TKey : notnull
|
||||
{
|
||||
Dictionary<TKey, TSource> dictionary = new();
|
||||
|
||||
foreach (TSource value in source)
|
||||
{
|
||||
dictionary[keySelector(value)] = value;
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Enumerable.ToDictionary{TSource, TKey, TElement}(IEnumerable{TSource}, Func{TSource, TKey}, Func{TSource, TElement})"/>
|
||||
public static Dictionary<TKey, TValue> ToDictionaryOverride<TKey, TValue, TSource>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
|
||||
where TKey : notnull
|
||||
{
|
||||
Dictionary<TKey, TValue> dictionary = new();
|
||||
|
||||
foreach (TSource value in source)
|
||||
{
|
||||
dictionary[keySelector(value)] = valueSelector(value);
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个对 <see cref="TItem"/> 类型的计数器
|
||||
/// 转换到 <see cref="ObservableCollection{T}"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem">待计数的类型</typeparam>
|
||||
private class CounterInt32<TItem> : Dictionary<TItem, int>
|
||||
where TItem : notnull, IEquatable<TItem>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="source">源</param>
|
||||
/// <returns><see cref="ObservableCollection{T}"/></returns>
|
||||
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> source)
|
||||
{
|
||||
/// <summary>
|
||||
/// 增加计数器
|
||||
/// </summary>
|
||||
/// <param name="item">物品</param>
|
||||
public void Increase(TItem? item)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
if (!ContainsKey(item))
|
||||
{
|
||||
this[item] = 0;
|
||||
}
|
||||
|
||||
this[item] += 1;
|
||||
}
|
||||
}
|
||||
return new ObservableCollection<T>(source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Factory.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// 内容对话框工厂
|
||||
/// </summary>
|
||||
internal interface IContentDialogFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个新的内容对话框,用于确认
|
||||
/// </summary>
|
||||
/// <param name="title">标题</param>
|
||||
/// <param name="content">内容</param>
|
||||
/// <returns>内容对话框</returns>
|
||||
ContentDialog CreateForConfirm(string title, string content);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的内容对话框,用于确认或取消
|
||||
/// </summary>
|
||||
/// <param name="title">标题</param>
|
||||
/// <param name="content">内容</param>
|
||||
/// <param name="defaultButton">默认按钮</param>
|
||||
/// <returns>内容对话框</returns>
|
||||
ContentDialog CreateForConfirmCancel(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的内容对话框,用于提示未知的进度
|
||||
/// </summary>
|
||||
/// <param name="title">标题</param>
|
||||
/// <returns>内容对话框</returns>
|
||||
ContentDialog CreateForIndeterminateProgress(string title);
|
||||
}
|
||||
67
src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs
Normal file
67
src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
|
||||
namespace Snap.Hutao.Factory;
|
||||
|
||||
/// <inheritdoc cref="IContentDialogFactory"/>
|
||||
[Injection(InjectAs.Transient, typeof(IContentDialogFactory))]
|
||||
internal class ContentDialogFactory : IContentDialogFactory
|
||||
{
|
||||
private readonly MainWindow mainWindow;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的内容对话框工厂
|
||||
/// </summary>
|
||||
/// <param name="mainWindow">主窗体</param>
|
||||
public ContentDialogFactory(MainWindow mainWindow)
|
||||
{
|
||||
this.mainWindow = mainWindow;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ContentDialog CreateForConfirm(string title, string content)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
XamlRoot = mainWindow.Content.XamlRoot,
|
||||
Title = title,
|
||||
Content = content,
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
PrimaryButtonText = "确认",
|
||||
};
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ContentDialog CreateForConfirmCancel(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
XamlRoot = mainWindow.Content.XamlRoot,
|
||||
Title = title,
|
||||
Content = content,
|
||||
DefaultButton = defaultButton,
|
||||
PrimaryButtonText = "确认",
|
||||
CloseButtonText = "取消",
|
||||
};
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ContentDialog CreateForIndeterminateProgress(string title)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
XamlRoot = mainWindow.Content.XamlRoot,
|
||||
Title = title,
|
||||
Content = new ProgressBar() { IsIndeterminate = true },
|
||||
};
|
||||
|
||||
return dialog;
|
||||
}
|
||||
}
|
||||
@@ -41,4 +41,22 @@ public class UserAndRole
|
||||
{
|
||||
return new UserAndRole(user.Entity, user.SelectedUserGameRole!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试转换到用户与角色
|
||||
/// </summary>
|
||||
/// <param name="user">用户</param>
|
||||
/// <param name="userAndRole">用户与角色</param>
|
||||
/// <returns>是否转换成功</returns>
|
||||
public static bool TryFromUser(User? user, [NotNullWhen(true)]out UserAndRole? userAndRole)
|
||||
{
|
||||
if (user != null && user.SelectedUserGameRole != null)
|
||||
{
|
||||
userAndRole = FromUser(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
userAndRole = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,7 @@ internal class GachaLogUrlManualInputProvider : IGachaLogUrlProvider
|
||||
/// <inheritdoc/>
|
||||
public async Task<ValueResult<bool, string>> GetQueryAsync()
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
ValueResult<bool, string> result = await new GachaLogUrlDialog(mainWindow).GetInputUrlAsync().ConfigureAwait(false);
|
||||
ValueResult<bool, string> result = await new GachaLogUrlDialog().GetInputUrlAsync().ConfigureAwait(false);
|
||||
|
||||
if (result.IsOk)
|
||||
{
|
||||
|
||||
@@ -304,8 +304,7 @@ internal class GameService : IGameService, IDisposable
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, string name) = await new GameAccountNameDialog(mainWindow).GetInputNameAsync().ConfigureAwait(false);
|
||||
(bool isOk, string name) = await new GameAccountNameDialog().GetInputNameAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
@@ -349,8 +348,7 @@ internal class GameService : IGameService, IDisposable
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask ModifyGameAccountAsync(GameAccount gameAccount)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, string name) = await new GameAccountNameDialog(mainWindow).GetInputNameAsync().ConfigureAwait(true);
|
||||
(bool isOk, string name) = await new GameAccountNameDialog().GetInputNameAsync().ConfigureAwait(true);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
<None Remove="View\Dialog\AchievementArchiveCreateDialog.xaml" />
|
||||
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
||||
<None Remove="View\Dialog\AdoptCalculatorDialog.xaml" />
|
||||
<None Remove="View\Dialog\AvatarInfoQueryDialog.xaml" />
|
||||
<None Remove="View\Dialog\CommunityGameRecordDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
||||
@@ -306,11 +305,6 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\AvatarInfoQueryDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Page\AvatarPropertyPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -15,10 +15,10 @@ public sealed partial class AchievementArchiveCreateDialog : ContentDialog
|
||||
/// 构造一个新的成就存档创建对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public AchievementArchiveCreateDialog(Window window)
|
||||
public AchievementArchiveCreateDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -27,6 +27,7 @@ public sealed partial class AchievementArchiveCreateDialog : ContentDialog
|
||||
/// <returns>输入的结果</returns>
|
||||
public async Task<ValueResult<bool, string>> GetInputAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
string text = InputText.Text ?? string.Empty;
|
||||
|
||||
|
||||
@@ -19,12 +19,11 @@ public sealed partial class AchievementImportDialog : ContentDialog
|
||||
/// <summary>
|
||||
/// 构造一个新的成就对话框
|
||||
/// </summary>
|
||||
/// <param name="window">呈现的父窗口</param>
|
||||
/// <param name="uiaf">uiaf数据</param>
|
||||
public AchievementImportDialog(Window window, UIAF uiaf)
|
||||
public AchievementImportDialog(UIAF uiaf)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
UIAF = uiaf;
|
||||
}
|
||||
|
||||
@@ -43,6 +42,7 @@ public sealed partial class AchievementImportDialog : ContentDialog
|
||||
/// <returns>导入选项</returns>
|
||||
public async Task<ValueResult<bool, ImportStrategy>> GetImportStrategyAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
ImportStrategy strategy = (ImportStrategy)ImportModeSelector.SelectedIndex;
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ public sealed partial class AdoptCalculatorDialog : ContentDialog
|
||||
/// 构造一个新的养成计算器对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public AdoptCalculatorDialog(Window window)
|
||||
public AdoptCalculatorDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
scope = Ioc.Default.CreateScope();
|
||||
XamlRoot = scope.ServiceProvider.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
private void OnGridLoaded(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.AvatarInfoQueryDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="查询UID对应的橱窗"
|
||||
CloseButtonText="取消"
|
||||
DefaultButton="Primary"
|
||||
IsPrimaryButtonEnabled="False"
|
||||
PrimaryButtonText="请输入UID"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<TextBox
|
||||
x:Name="InputText"
|
||||
PlaceholderText="请输入UID"
|
||||
TextChanged="InputTextChanged"/>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
/// <summary>
|
||||
/// 角色信息查询UID对话框
|
||||
/// </summary>
|
||||
public sealed partial class AvatarInfoQueryDialog : ContentDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的角色信息查询UID对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗口</param>
|
||||
public AvatarInfoQueryDialog(Window window)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取玩家UID
|
||||
/// </summary>
|
||||
/// <returns>玩家UID</returns>
|
||||
public async Task<ValueResult<bool, PlayerUid>> GetPlayerUidAsync()
|
||||
{
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
|
||||
bool isOk = result == ContentDialogResult.Primary;
|
||||
|
||||
if (InputText.Text.Length != 9)
|
||||
{
|
||||
return new(false, default);
|
||||
}
|
||||
|
||||
return new(isOk, isOk && InputText.Text.Length == 9 ? new(InputText.Text) : default);
|
||||
}
|
||||
|
||||
private void InputTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
bool inputValid = string.IsNullOrEmpty(InputText.Text) && InputText.Text.Length == 9;
|
||||
|
||||
(PrimaryButtonText, IsPrimaryButtonEnabled) = inputValid switch
|
||||
{
|
||||
true => ("请输入正确的UID", false),
|
||||
false => ("确认", true),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,11 @@ public sealed partial class CommunityGameRecordDialog : ContentDialog
|
||||
/// 构造一个新的社区游戏记录对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public CommunityGameRecordDialog(MainWindow window)
|
||||
public CommunityGameRecordDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
scope = Ioc.Default.CreateScope();
|
||||
XamlRoot = scope.ServiceProvider.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
private void OnGridLoaded(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -17,10 +17,10 @@ public sealed partial class CultivateProjectDialog : ContentDialog
|
||||
/// 构造一个新的养成计划对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public CultivateProjectDialog(Window window)
|
||||
public CultivateProjectDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -19,13 +19,12 @@ public sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
/// <summary>
|
||||
/// 构造一个新的养成计算对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
/// <param name="avatar">角色</param>
|
||||
/// <param name="weapon">武器</param>
|
||||
public CultivatePromotionDeltaDialog(Window window, ICalculableAvatar? avatar, ICalculableWeapon? weapon)
|
||||
public CultivatePromotionDeltaDialog(ICalculableAvatar? avatar, ICalculableWeapon? weapon)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
DataContext = this;
|
||||
Avatar = avatar;
|
||||
Weapon = weapon;
|
||||
@@ -55,6 +54,7 @@ public sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
/// <returns>提升差异</returns>
|
||||
public async Task<ValueResult<bool, AvatarPromotionDelta>> GetPromotionDeltaAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary)
|
||||
|
||||
@@ -15,12 +15,11 @@ public sealed partial class DailyNoteNotificationDialog : ContentDialog
|
||||
/// <summary>
|
||||
/// 构造一个新的实时便笺通知设置对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗口</param>
|
||||
/// <param name="entry">实时便笺</param>
|
||||
public DailyNoteNotificationDialog(Window window, DailyNoteEntry entry)
|
||||
public DailyNoteNotificationDialog(DailyNoteEntry entry)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
DataContext = entry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
using Snap.Hutao.Model.Binding.User;
|
||||
using Snap.Hutao.Web.Bridge;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
@@ -17,23 +16,20 @@ namespace Snap.Hutao.View.Dialog;
|
||||
public sealed partial class DailyNoteVerificationDialog : ContentDialog
|
||||
{
|
||||
private readonly IServiceScope scope;
|
||||
private readonly User user;
|
||||
private readonly PlayerUid uid;
|
||||
private readonly UserAndRole userAndRole;
|
||||
|
||||
[SuppressMessage("", "IDE0052")]
|
||||
private DailyNoteJsInterface? dailyNoteJsInterface;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的实时便笺认证对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗口</param>
|
||||
/// <param name="user">用户</param>
|
||||
/// <param name="uid">uid</param>
|
||||
public DailyNoteVerificationDialog(Window window, User user, PlayerUid uid)
|
||||
/// <param name="userAndRole">用户与角色</param>
|
||||
public DailyNoteVerificationDialog(UserAndRole userAndRole)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
this.user = user;
|
||||
this.uid = uid;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
this.userAndRole = userAndRole;
|
||||
scope = Ioc.Default.CreateScope();
|
||||
}
|
||||
|
||||
@@ -47,10 +43,11 @@ public sealed partial class DailyNoteVerificationDialog : ContentDialog
|
||||
await WebView.EnsureCoreWebView2Async();
|
||||
CoreWebView2 coreWebView2 = WebView.CoreWebView2;
|
||||
|
||||
Model.Entity.User user = userAndRole.User;
|
||||
coreWebView2.SetCookie(user.CookieToken, user.Ltoken, null).SetMobileUserAgent();
|
||||
dailyNoteJsInterface = new(coreWebView2, scope.ServiceProvider);
|
||||
|
||||
string query = $"?role_id={uid.Value}&server={uid.Region}";
|
||||
string query = $"?role_id={userAndRole.Role.GameUid}&server={userAndRole.Role.Region}";
|
||||
coreWebView2.Navigate($"https://webstatic.mihoyo.com/app/community-game-records/index.html?bbs_presentation_style=fullscreen#/ys/daily/{query}");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ public sealed partial class GachaLogImportDialog : ContentDialog
|
||||
/// <summary>
|
||||
/// 构造一个新的祈愿记录导入对话框
|
||||
/// </summary>
|
||||
/// <param name="window">呈现的父窗口</param>
|
||||
/// <param name="uigf">uigf数据</param>
|
||||
public GachaLogImportDialog(Window window, UIGF uigf)
|
||||
///
|
||||
public GachaLogImportDialog(UIGF uigf)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
UIGF = uigf;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public sealed partial class GachaLogImportDialog : ContentDialog
|
||||
/// <returns>是否导入</returns>
|
||||
public async Task<bool> GetShouldImportAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
return await ShowAsync() == ContentDialogResult.Primary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ public sealed partial class GachaLogRefreshProgressDialog : ContentDialog
|
||||
/// 构造一个新的对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public GachaLogRefreshProgressDialog(Window window)
|
||||
public GachaLogRefreshProgressDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,10 +15,10 @@ public sealed partial class GachaLogUrlDialog : ContentDialog
|
||||
/// 初始化一个新的祈愿记录Url对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public GachaLogUrlDialog(Window window)
|
||||
public GachaLogUrlDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,10 +15,10 @@ public sealed partial class GameAccountNameDialog : ContentDialog
|
||||
/// 构造一个新的游戏账号命名对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public GameAccountNameDialog(Window window)
|
||||
public GameAccountNameDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,10 +15,10 @@ public sealed partial class LoginMihoyoBBSDialog : ContentDialog
|
||||
/// 构造一个新的登录到米游社对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗体</param>
|
||||
public LoginMihoyoBBSDialog(MainWindow window)
|
||||
public LoginMihoyoBBSDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -27,6 +27,7 @@ public sealed partial class LoginMihoyoBBSDialog : ContentDialog
|
||||
/// <returns>账号密码</returns>
|
||||
public async Task<ValueResult<bool, Dictionary<string, string>>> GetInputAccountPasswordAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
bool result = await ShowAsync() == ContentDialogResult.Primary;
|
||||
|
||||
Dictionary<string, string> data = new()
|
||||
|
||||
@@ -23,11 +23,11 @@ public sealed partial class SignInWebViewDialog : ContentDialog
|
||||
/// 构造一个新的签到网页视图对话框
|
||||
/// </summary>
|
||||
/// <param name="window">窗口</param>
|
||||
public SignInWebViewDialog(MainWindow window)
|
||||
public SignInWebViewDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
scope = Ioc.Default.CreateScope();
|
||||
XamlRoot = scope.ServiceProvider.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
private void OnGridLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
|
||||
@@ -15,10 +15,10 @@ public sealed partial class UserDialog : ContentDialog
|
||||
/// 构造一个新的添加用户对话框
|
||||
/// </summary>
|
||||
/// <param name="window">呈现的父窗口</param>
|
||||
public UserDialog(Window window)
|
||||
public UserDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = window.Content.XamlRoot;
|
||||
XamlRoot = Ioc.Default.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -27,6 +27,7 @@ public sealed partial class UserDialog : ContentDialog
|
||||
/// <returns>输入的结果</returns>
|
||||
public async Task<ValueResult<bool, string>> GetInputCookieAsync()
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
string cookie = InputText.Text;
|
||||
|
||||
|
||||
@@ -144,8 +144,6 @@
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding FinishDescription}"/>
|
||||
<ProgressBar
|
||||
Height="1"
|
||||
MinHeight="1"
|
||||
Margin="0,4,0,0"
|
||||
Maximum="1"
|
||||
Value="{Binding FinishPercent}"/>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<AppBarButton
|
||||
Command="{Binding CultivateCommand}"
|
||||
CommandParameter="{Binding SelectedAvatar}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="养成计算"/>
|
||||
<AppBarSeparator/>
|
||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="同步角色信息">
|
||||
@@ -141,12 +141,7 @@
|
||||
MaxWidth="800"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Transparent">
|
||||
<Border
|
||||
Margin="16"
|
||||
Background="{StaticResource CardBackgroundFillColorDefault}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefault}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}">
|
||||
<Border Margin="16" Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
@@ -483,35 +478,63 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="4*"/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{Binding MainProperty.Key}"/>
|
||||
<TextBlock Text="{Binding MainProperty.Value}"/>
|
||||
<!-- 主属性 -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="{Binding MainProperty.Key}"
|
||||
TextTrimming="CharacterEllipsis"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding MainProperty.Value}"/>
|
||||
</Grid>
|
||||
<!-- 评分 -->
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="评分"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding ScoreFormatted}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<AppBarSeparator Grid.Column="1"/>
|
||||
<ItemsControl Grid.Column="2" ItemsSource="{Binding ComposedSubProperties}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<cwucont:UniformGrid Columns="4"/>
|
||||
<cwucont:UniformGrid
|
||||
ColumnSpacing="16"
|
||||
Columns="2"
|
||||
RowSpacing="8"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{Binding Name}"/>
|
||||
<TextBlock Text="{Binding Value}"/>
|
||||
</StackPanel>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Value}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<AppBarSeparator Grid.Column="3"/>
|
||||
<StackPanel Grid.Column="4">
|
||||
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="评分"/>
|
||||
<TextBlock Text="{Binding ScoreFormatted}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Expander.Header>
|
||||
@@ -526,9 +549,16 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Padding="2" Opacity="{Binding Opacity}">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Text="{Binding Value}"/>
|
||||
<Grid Opacity="{Binding Opacity}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Value}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
@@ -545,9 +575,16 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Padding="2" Opacity="{Binding Opacity}">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Text="{Binding Value}"/>
|
||||
<Grid Opacity="{Binding Opacity}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Text="{Binding Name}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Value}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
|
||||
@@ -143,11 +143,8 @@
|
||||
<Border
|
||||
Margin="16,16,16,0"
|
||||
Padding="8"
|
||||
Background="{StaticResource CardBackgroundFillColorSecondary}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{StaticResource CompatCornerRadius}">
|
||||
<Grid Background="Transparent">
|
||||
Style="{StaticResource BorderCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
<Button Command="{Binding ShowCommunityGameRecordDialogCommand}" Content="Open"/>
|
||||
</wsc:Setting>
|
||||
|
||||
<wsc:Setting Header="AdoptCalculatorDialogTest">
|
||||
<Button Command="{Binding ShowAdoptCalculatorDialogCommand}" Content="Open"/>
|
||||
</wsc:Setting>
|
||||
|
||||
<wsc:Setting Header="DownloadStaticFileTest">
|
||||
<Button Command="{Binding DownloadStaticFileCommand}" Content="Download"/>
|
||||
</wsc:Setting>
|
||||
|
||||
@@ -42,6 +42,7 @@ internal class AchievementViewModel
|
||||
private readonly IAchievementService achievementService;
|
||||
private readonly IMetadataService metadataService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly JsonSerializerOptions options;
|
||||
|
||||
private readonly TaskCompletionSource<bool> openUICompletionSource = new();
|
||||
@@ -64,7 +65,7 @@ internal class AchievementViewModel
|
||||
/// <param name="infoBarService">信息条服务</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||
/// <param name="scopeFactory">范围工厂</param>
|
||||
/// <param name="contentDialogFactory">内容对话框工厂</param>
|
||||
/// <param name="messenger">消息器</param>
|
||||
public AchievementViewModel(
|
||||
IMetadataService metadataService,
|
||||
@@ -72,11 +73,13 @@ internal class AchievementViewModel
|
||||
IInfoBarService infoBarService,
|
||||
JsonSerializerOptions options,
|
||||
IAsyncRelayCommandFactory asyncRelayCommandFactory,
|
||||
IContentDialogFactory contentDialogFactory,
|
||||
IMessenger messenger)
|
||||
{
|
||||
this.metadataService = metadataService;
|
||||
this.achievementService = achievementService;
|
||||
this.infoBarService = infoBarService;
|
||||
this.contentDialogFactory = contentDialogFactory;
|
||||
this.options = options;
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
@@ -241,36 +244,6 @@ internal class AchievementViewModel
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Task<ContentDialogResult> ShowImportResultDialogAsync(string title, string message)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = title,
|
||||
Content = message,
|
||||
PrimaryButtonText = "确认",
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
XamlRoot = mainWindow.Content.XamlRoot,
|
||||
};
|
||||
|
||||
return dialog.ShowAsync().AsTask();
|
||||
}
|
||||
|
||||
private static Task<ContentDialogResult> ShowImportFailDialogAsync(string message)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = "导入失败",
|
||||
Content = message,
|
||||
PrimaryButtonText = "确认",
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
XamlRoot = mainWindow.Content.XamlRoot,
|
||||
};
|
||||
|
||||
return dialog.ShowAsync().AsTask();
|
||||
}
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
bool metaInitialized = await metadataService.InitializeAsync().ConfigureAwait(false);
|
||||
@@ -303,8 +276,7 @@ internal class AchievementViewModel
|
||||
{
|
||||
if (Archives != null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, string name) = await new AchievementArchiveCreateDialog(mainWindow).GetInputAsync().ConfigureAwait(false);
|
||||
(bool isOk, string name) = await new AchievementArchiveCreateDialog().GetInputAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
@@ -335,17 +307,9 @@ internal class AchievementViewModel
|
||||
{
|
||||
if (Archives != null && SelectedArchive != null)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = $"确定要删除存档 {SelectedArchive.Name} 吗?",
|
||||
Content = "该操作是不可逆的,该存档和其内的所有成就状态会丢失。",
|
||||
PrimaryButtonText = "确认",
|
||||
CloseButtonText = "取消",
|
||||
DefaultButton = ContentDialogButton.Close,
|
||||
};
|
||||
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
ContentDialogResult result = await dialog.InitializeWithWindow(mainWindow).ShowAsync();
|
||||
ContentDialogResult result = await contentDialogFactory
|
||||
.CreateForConfirmCancel($"确定要删除存档 {SelectedArchive.Name} 吗?", "该操作是不可逆的,该存档和其内的所有成就状态会丢失。")
|
||||
.ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
@@ -408,11 +372,11 @@ internal class AchievementViewModel
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
if (isOk)
|
||||
{
|
||||
await ShowImportResultDialogAsync("导出成功", "成功保存到指定位置").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导出成功", "成功保存到指定位置").ShowAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await ShowImportResultDialogAsync("导出失败", "写入文件时遇到问题").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导出失败", "写入文件时遇到问题").ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,7 +396,7 @@ internal class AchievementViewModel
|
||||
else
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
await ShowImportFailDialogAsync("数据格式不正确").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导入失败", "数据格式不正确").ShowAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,8 +408,8 @@ internal class AchievementViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
IPickerFactory pickerFactory = Ioc.Default.GetRequiredService<IPickerFactory>();
|
||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker(PickerLocationId.Desktop, "导入", ".json");
|
||||
FileOpenPicker picker = Ioc.Default.GetRequiredService<IPickerFactory>()
|
||||
.GetFileOpenPicker(PickerLocationId.Desktop, "导入", ".json");
|
||||
|
||||
if (await picker.PickSingleFileAsync() is StorageFile file)
|
||||
{
|
||||
@@ -459,7 +423,7 @@ internal class AchievementViewModel
|
||||
else
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
await ShowImportFailDialogAsync("文件的数据格式不正确").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导入失败", "文件的数据格式不正确").ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -481,20 +445,12 @@ internal class AchievementViewModel
|
||||
{
|
||||
if (uiaf.IsCurrentVersionSupported())
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
(bool isOk, ImportStrategy strategy) = await new AchievementImportDialog(mainWindow, uiaf).GetImportStrategyAsync().ConfigureAwait(true);
|
||||
(bool isOk, ImportStrategy strategy) = await new AchievementImportDialog(uiaf).GetImportStrategyAsync().ConfigureAwait(true);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
ContentDialog importingDialog = new()
|
||||
{
|
||||
Title = "导入成就中",
|
||||
Content = new ProgressBar() { IsIndeterminate = true },
|
||||
};
|
||||
|
||||
ImportResult result;
|
||||
await using (await importingDialog.InitializeWithWindow(mainWindow).BlockAsync().ConfigureAwait(false))
|
||||
await using (await contentDialogFactory.CreateForIndeterminateProgress("导入成就中").BlockAsync().ConfigureAwait(false))
|
||||
{
|
||||
result = await achievementService.ImportFromUIAFAsync(archive, uiaf.List, strategy).ConfigureAwait(false);
|
||||
}
|
||||
@@ -507,7 +463,7 @@ internal class AchievementViewModel
|
||||
else
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
await ShowImportFailDialogAsync("数据的 UIAF 版本过低,无法导入").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导入失败", "数据的 UIAF 版本过低,无法导入").ShowAsync();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -204,8 +204,7 @@ internal class AvatarPropertyViewModel : ObservableObject, ISupportCancellation
|
||||
|
||||
if (userService.Current != null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(mainWindow, avatar.ToCalculable(), avatar.Weapon.ToCalculable())
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(avatar.ToCalculable(), avatar.Weapon.ToCalculable())
|
||||
.GetPromotionDeltaAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -150,8 +150,7 @@ internal class CultivationViewModel : ObservableObject, ISupportCancellation
|
||||
|
||||
private async Task AddProjectAsync()
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, CultivateProject project) = await new CultivateProjectDialog(mainWindow).CreateProjectAsync().ConfigureAwait(false);
|
||||
(bool isOk, CultivateProject project) = await new CultivateProjectDialog().CreateProjectAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
|
||||
@@ -220,18 +220,16 @@ internal class DailyNoteViewModel : ObservableObject, ISupportCancellation
|
||||
{
|
||||
if (entry != null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
await new DailyNoteNotificationDialog(mainWindow, entry).ShowAsync();
|
||||
await new DailyNoteNotificationDialog(entry).ShowAsync();
|
||||
appDbContext.DailyNotes.UpdateAndSave(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task VerifyDailyNoteVerificationAsync()
|
||||
{
|
||||
if (userService.Current != null && userService.Current.SelectedUserGameRole != null)
|
||||
if (UserAndRole.TryFromUser(userService.Current, out UserAndRole? userAndRole))
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
await new DailyNoteVerificationDialog(mainWindow, userService.Current.Entity, userService.Current.SelectedUserGameRole).ShowAsync();
|
||||
await new DailyNoteVerificationDialog(userAndRole).ShowAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Control;
|
||||
using Snap.Hutao.Control.Extension;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.Threading.CodeAnalysis;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model.Binding.Gacha;
|
||||
using Snap.Hutao.Model.Entity;
|
||||
@@ -29,6 +28,7 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
private readonly IGachaLogService gachaLogService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly IPickerFactory pickerFactory;
|
||||
private readonly IContentDialogFactory contentDialogFactory;
|
||||
private readonly JsonSerializerOptions options;
|
||||
|
||||
private ObservableCollection<GachaArchive>? archives;
|
||||
@@ -45,26 +45,27 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
/// <param name="infoBarService">信息</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||
/// <param name="contentDialogFactory">内容对话框工厂</param>
|
||||
/// <param name="pickerFactory">文件选择器工厂</param>
|
||||
public GachaLogViewModel(
|
||||
IGachaLogService gachaLogService,
|
||||
IInfoBarService infoBarService,
|
||||
JsonSerializerOptions options,
|
||||
IAsyncRelayCommandFactory asyncRelayCommandFactory,
|
||||
IContentDialogFactory contentDialogFactory,
|
||||
IPickerFactory pickerFactory)
|
||||
{
|
||||
this.gachaLogService = gachaLogService;
|
||||
this.infoBarService = infoBarService;
|
||||
this.pickerFactory = pickerFactory;
|
||||
this.contentDialogFactory = contentDialogFactory;
|
||||
this.options = options;
|
||||
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
RefreshByWebCacheCommand = asyncRelayCommandFactory.Create(RefreshByWebCacheAsync);
|
||||
RefreshByStokenCommand = asyncRelayCommandFactory.Create(RefreshByStokenAsync);
|
||||
RefreshByManualInputCommand = asyncRelayCommandFactory.Create(RefreshByManualInputAsync);
|
||||
ImportFromUIGFExcelCommand = asyncRelayCommandFactory.Create(ImportFromUIGFExcelAsync);
|
||||
ImportFromUIGFJsonCommand = asyncRelayCommandFactory.Create(ImportFromUIGFJsonAsync);
|
||||
ExportToUIGFExcelCommand = asyncRelayCommandFactory.Create(ExportToUIGFExcelAsync);
|
||||
ExportToUIGFJsonCommand = asyncRelayCommandFactory.Create(ExportToUIGFJsonAsync);
|
||||
RemoveArchiveCommand = asyncRelayCommandFactory.Create(RemoveArchiveAsync);
|
||||
}
|
||||
@@ -137,21 +138,11 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
/// </summary>
|
||||
public ICommand RefreshByManualInputCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 从 UIGF Excel 导入命令
|
||||
/// </summary>
|
||||
public ICommand ImportFromUIGFExcelCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 从 UIGF Json 导入命令
|
||||
/// </summary>
|
||||
public ICommand ImportFromUIGFJsonCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 导出到 UIGF Excel 命令
|
||||
/// </summary>
|
||||
public ICommand ExportToUIGFExcelCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 导出到 UIGF Json 命令
|
||||
/// </summary>
|
||||
@@ -162,21 +153,6 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
/// </summary>
|
||||
public ICommand RemoveArchiveCommand { get; }
|
||||
|
||||
[ThreadAccess(ThreadAccessState.MainThread)]
|
||||
private static Task<ContentDialogResult> ShowImportResultDialogAsync(string title, string message)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = title,
|
||||
Content = message,
|
||||
PrimaryButtonText = "确认",
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
return dialog.InitializeWithWindow(mainWindow).ShowAsync().AsTask();
|
||||
}
|
||||
|
||||
private async Task OpenUIAsync()
|
||||
{
|
||||
if (await gachaLogService.InitializeAsync().ConfigureAwait(true))
|
||||
@@ -216,9 +192,7 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
{
|
||||
RefreshStrategy strategy = IsAggressiveRefresh ? RefreshStrategy.AggressiveMerge : RefreshStrategy.LazyMerge;
|
||||
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
GachaLogRefreshProgressDialog dialog = new(mainWindow);
|
||||
GachaLogRefreshProgressDialog dialog = new();
|
||||
IAsyncDisposable dialogHider = await dialog.BlockAsync().ConfigureAwait(false);
|
||||
Progress<FetchState> progress = new(dialog.OnReport);
|
||||
bool authkeyValid = await gachaLogService.RefreshGachaLogAsync(query, strategy, progress, default).ConfigureAwait(false);
|
||||
@@ -246,11 +220,6 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ImportFromUIGFExcelAsync()
|
||||
{
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
private async Task ImportFromUIGFJsonAsync()
|
||||
{
|
||||
FileOpenPicker picker = pickerFactory.GetFileOpenPicker(PickerLocationId.Desktop, "导入", ".json");
|
||||
@@ -266,16 +235,11 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
else
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
await ShowImportResultDialogAsync("导入失败", "文件的数据格式不正确").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导入失败", "文件的数据格式不正确").ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExportToUIGFExcelAsync()
|
||||
{
|
||||
await Task.Yield();
|
||||
}
|
||||
|
||||
private async Task ExportToUIGFJsonAsync()
|
||||
{
|
||||
if (SelectedArchive == null)
|
||||
@@ -297,11 +261,11 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
if (isOk)
|
||||
{
|
||||
await ShowImportResultDialogAsync("导出成功", "成功保存到指定位置").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导出成功", "成功保存到指定位置").ShowAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await ShowImportResultDialogAsync("导出失败", "写入文件时遇到问题").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导出失败", "写入文件时遇到问题").ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -310,17 +274,9 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
{
|
||||
if (Archives != null && SelectedArchive != null)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = $"确定要删除存档 {SelectedArchive.Uid} 吗?",
|
||||
Content = "该操作是不可逆的,该存档和其内的所有祈愿数据会丢失。",
|
||||
PrimaryButtonText = "确认",
|
||||
CloseButtonText = "取消",
|
||||
DefaultButton = ContentDialogButton.Close,
|
||||
};
|
||||
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
ContentDialogResult result = await dialog.InitializeWithWindow(mainWindow).ShowAsync();
|
||||
ContentDialogResult result = await contentDialogFactory
|
||||
.CreateForConfirmCancel($"确定要删除存档 {SelectedArchive.Uid} 吗?", "该操作是不可逆的,该存档和其内的所有祈愿数据会丢失。")
|
||||
.ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
@@ -332,7 +288,6 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
}
|
||||
}
|
||||
|
||||
[ThreadAccess(ThreadAccessState.MainThread)]
|
||||
private void SetSelectedArchiveAndUpdateStatistics(GachaArchive? archive, bool forceUpdate = false)
|
||||
{
|
||||
bool changed = false;
|
||||
@@ -357,7 +312,6 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
}
|
||||
}
|
||||
|
||||
[ThreadAccess(ThreadAccessState.MainThread)]
|
||||
private async Task UpdateStatisticsAsync(GachaArchive? archive)
|
||||
{
|
||||
GachaStatistics temp = await gachaLogService.GetStatisticsAsync(archive).ConfigureAwait(false);
|
||||
@@ -365,22 +319,13 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
Statistics = temp;
|
||||
}
|
||||
|
||||
[ThreadAccess(ThreadAccessState.AnyThread)]
|
||||
private async Task<bool> TryImportUIGFInternalAsync(UIGF uigf)
|
||||
{
|
||||
if (uigf.IsCurrentVersionSupported())
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
if (await new GachaLogImportDialog(mainWindow, uigf).GetShouldImportAsync().ConfigureAwait(true))
|
||||
if (await new GachaLogImportDialog(uigf).GetShouldImportAsync().ConfigureAwait(true))
|
||||
{
|
||||
ContentDialog importingDialog = new()
|
||||
{
|
||||
Title = "导入祈愿记录中",
|
||||
Content = new ProgressBar() { IsIndeterminate = true },
|
||||
};
|
||||
|
||||
await using (await importingDialog.InitializeWithWindow(mainWindow).BlockAsync().ConfigureAwait(false))
|
||||
await using (await contentDialogFactory.CreateForIndeterminateProgress("导入祈愿记录中").BlockAsync().ConfigureAwait(false))
|
||||
{
|
||||
await gachaLogService.ImportFromUIGFAsync(uigf.List, uigf.Info.Uid).ConfigureAwait(false);
|
||||
}
|
||||
@@ -394,7 +339,7 @@ internal class GachaLogViewModel : ObservableObject, ISupportCancellation
|
||||
else
|
||||
{
|
||||
await ThreadHelper.SwitchToMainThreadAsync();
|
||||
await ShowImportResultDialogAsync("导入失败", "数据的 UIGF 版本过低,无法导入").ConfigureAwait(false);
|
||||
await contentDialogFactory.CreateForConfirm("导入失败", "数据的 UIGF 版本过低,无法导入").ShowAsync();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -207,10 +207,9 @@ internal class SettingViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ShowSignInWebViewDialogAsync()
|
||||
private Task ShowSignInWebViewDialogAsync()
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
await new SignInWebViewDialog(mainWindow).ShowAsync();
|
||||
return new SignInWebViewDialog().ShowAsync().AsTask();
|
||||
}
|
||||
|
||||
private async Task DebugThrowExceptionAsync()
|
||||
|
||||
@@ -29,6 +29,7 @@ internal class TestViewModel : ObservableObject, ISupportCancellation
|
||||
public TestViewModel(IAsyncRelayCommandFactory asyncRelayCommandFactory)
|
||||
{
|
||||
ShowCommunityGameRecordDialogCommand = asyncRelayCommandFactory.Create(ShowCommunityGameRecordDialogAsync);
|
||||
ShowAdoptCalculatorDialogCommand = asyncRelayCommandFactory.Create(ShowAdoptCalculatorDialogAsync);
|
||||
DangerousLoginMihoyoBbsCommand = asyncRelayCommandFactory.Create(DangerousLoginMihoyoBbsAsync);
|
||||
DownloadStaticFileCommand = asyncRelayCommandFactory.Create(DownloadStaticFileAsync);
|
||||
}
|
||||
@@ -41,6 +42,11 @@ internal class TestViewModel : ObservableObject, ISupportCancellation
|
||||
/// </summary>
|
||||
public ICommand ShowCommunityGameRecordDialogCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 打开养成计算对话框命令
|
||||
/// </summary>
|
||||
public ICommand ShowAdoptCalculatorDialogCommand { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Dangerous 登录米游社命令
|
||||
/// </summary>
|
||||
@@ -53,14 +59,17 @@ internal class TestViewModel : ObservableObject, ISupportCancellation
|
||||
|
||||
private async Task ShowCommunityGameRecordDialogAsync()
|
||||
{
|
||||
CommunityGameRecordDialog dialog = ActivatorUtilities.CreateInstance<CommunityGameRecordDialog>(Ioc.Default);
|
||||
await dialog.ShowAsync();
|
||||
await new CommunityGameRecordDialog().ShowAsync();
|
||||
}
|
||||
|
||||
private async Task ShowAdoptCalculatorDialogAsync()
|
||||
{
|
||||
await new AdoptCalculatorDialog().ShowAsync();
|
||||
}
|
||||
|
||||
private async Task DangerousLoginMihoyoBbsAsync()
|
||||
{
|
||||
LoginMihoyoBBSDialog dialog = ActivatorUtilities.CreateInstance<LoginMihoyoBBSDialog>(Ioc.Default);
|
||||
(bool isOk, Dictionary<string, string>? data) = await dialog.GetInputAccountPasswordAsync().ConfigureAwait(false);
|
||||
(bool isOk, Dictionary<string, string>? data) = await new LoginMihoyoBBSDialog().GetInputAccountPasswordAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
|
||||
@@ -107,8 +107,7 @@ internal class UserViewModel : ObservableObject
|
||||
private async Task AddUserAsync()
|
||||
{
|
||||
// Get cookie from user input
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
ValueResult<bool, string> result = await new UserDialog(mainWindow).GetInputCookieAsync().ConfigureAwait(false);
|
||||
ValueResult<bool, string> result = await new UserDialog().GetInputCookieAsync().ConfigureAwait(false);
|
||||
|
||||
// User confirms the input
|
||||
if (result.IsOk)
|
||||
|
||||
@@ -71,6 +71,7 @@ internal class WelcomeViewModel : ObservableObject
|
||||
downloadSummaries.Add(new(serviceProvider, "成就图标", "AchievementIcon"));
|
||||
downloadSummaries.Add(new(serviceProvider, "物品图标", "ItemIcon"));
|
||||
downloadSummaries.Add(new(serviceProvider, "元素图标", "IconElement"));
|
||||
downloadSummaries.Add(new(serviceProvider, "圣遗物图标", "RelicIcon"));
|
||||
}
|
||||
|
||||
DownloadSummaries = new(downloadSummaries);
|
||||
|
||||
@@ -129,8 +129,7 @@ internal class WikiAvatarViewModel : ObservableObject
|
||||
|
||||
if (userService.Current != null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(mainWindow, avatar.ToCalculable(), null)
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(avatar.ToCalculable(), null)
|
||||
.GetPromotionDeltaAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
@@ -132,8 +132,7 @@ internal class WikiWeaponViewModel : ObservableObject, ISupportCancellation
|
||||
|
||||
if (userService.Current != null)
|
||||
{
|
||||
MainWindow mainWindow = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(mainWindow, null, weapon.ToCalculable())
|
||||
(bool isOk, CalcAvatarPromotionDelta delta) = await new CultivatePromotionDeltaDialog(null, weapon.ToCalculable())
|
||||
.GetPromotionDeltaAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user