launch game impl switch monitor

This commit is contained in:
DismissedLight
2023-03-05 18:47:36 +08:00
parent 706fb3404b
commit b1a03662d9
41 changed files with 721 additions and 384 deletions

View File

@@ -17,7 +17,7 @@ internal static class Localization
/// <param name="culture">语言代码</param>
public static void Initialize(string culture)
{
CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(culture);
CultureInfo cultureInfo = CultureInfo.GetCultureInfo(culture);
CultureInfo.CurrentCulture = cultureInfo;
CultureInfo.CurrentUICulture = cultureInfo;
ApplicationLanguages.PrimaryLanguageOverride = culture;

View File

@@ -25,7 +25,7 @@ internal sealed class WindowSubclassManager<TWindow> : IDisposable
private readonly bool isLegacyDragBar;
private HWND hwndDragBar;
// We have to explictly hold a reference to SUBCLASSPROC
// We have to explicitly hold a reference to SUBCLASSPROC
private SUBCLASSPROC? windowProc;
private SUBCLASSPROC? dragBarProc;

View File

@@ -81,6 +81,11 @@ internal sealed class SettingEntry
/// </summary>
public const string LaunchTargetFps = "Launch.TargetFps";
/// <summary>
/// 启动游戏 显示器编号
/// </summary>
public const string LaunchMonitor = "Launch.Monitor";
/// <summary>
/// 语言
/// </summary>

View File

@@ -6,6 +6,7 @@ using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Metadata.Abstraction;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.ViewModel.GachaLog;
namespace Snap.Hutao.Model.Metadata.Avatar;
@@ -19,7 +20,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName
/// [非元数据] 搭配数据
/// </summary>
[JsonIgnore]
public ComplexAvatarCollocation? Collocation { get; set; }
public AvatarCollocationView? Collocation { get; set; }
/// <summary>
/// [非元数据] 烹饪奖励

View File

@@ -1,11 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Abstraction;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.ViewModel.GachaLog;
namespace Snap.Hutao.Model.Metadata.Weapon;
@@ -19,7 +19,7 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource
/// [非元数据] 搭配数据
/// </summary>
[JsonIgnore]
public ComplexWeaponCollocation? Collocation { get; set; }
public WeaponCollocationView? Collocation { get; set; }
/// <inheritdoc/>
[JsonIgnore]

View File

@@ -10,8 +10,11 @@ MINMAXINFO
// COMCTL32
DefSubclassProc
SetWindowSubclass
RemoveWindowSubclass
SetWindowSubclass
// GDI32
GetDeviceCaps
// KERNEL32
CreateEvent
@@ -27,6 +30,7 @@ CoWaitForMultipleObjects
// USER32
FindWindowEx
GetDC
GetDpiForWindow
GetWindowPlacement

View File

@@ -0,0 +1,136 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.UI.Windowing;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
using System.Globalization;
namespace Snap.Hutao.Option;
/// <summary>
/// 应用程序选项
/// </summary>
[Injection(InjectAs.Singleton)]
internal sealed class AppOptions : IOptions<AppOptions>
{
private readonly IServiceScopeFactory serviceScopeFactory;
/// <summary>
/// 构造一个新的应用程序选项
/// </summary>
/// <param name="serviceScopeFactory">服务范围工厂</param>
public AppOptions(IServiceScopeFactory serviceScopeFactory)
{
this.serviceScopeFactory = serviceScopeFactory;
}
/// <summary>
/// 游戏路径
/// </summary>
public string? GamePath
{
get
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
return appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.GamePath)?.Value;
}
}
set
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.GamePath);
appDbContext.Settings.AddAndSave(new(SettingEntry.GamePath, value));
}
}
}
/// <summary>
/// 游戏路径
/// </summary>
public bool IsEmptyHistoryWishVisible
{
get
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.IsEmptyHistoryWishVisible)?.Value;
return value != null && bool.Parse(value);
}
}
set
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.IsEmptyHistoryWishVisible);
appDbContext.Settings.AddAndSave(new(SettingEntry.IsEmptyHistoryWishVisible, value.ToString()));
}
}
}
/// <summary>
/// 背景类型 默认 Mica
/// </summary>
public Core.Windowing.BackdropType BackdropType
{
get
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.SystemBackdropType)?.Value;
return Enum.Parse<Core.Windowing.BackdropType>(value ?? nameof(Core.Windowing.BackdropType.Mica));
}
}
set
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.SystemBackdropType);
appDbContext.Settings.AddAndSave(new(SettingEntry.SystemBackdropType, value.ToString()));
}
}
}
/// <summary>
/// 当前语言
/// </summary>
public CultureInfo CurrentCulture
{
get
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.Culture)?.Value;
return value != null ? CultureInfo.GetCultureInfo(value) : CultureInfo.CurrentCulture;
}
}
set
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.Culture);
appDbContext.Settings.AddAndSave(new(SettingEntry.Culture, value.Name));
}
}
}
/// <inheritdoc/>
public AppOptions Value { get => this; }
}

View File

@@ -59,7 +59,6 @@ public static partial class Program
.AddDatabase()
.AddInjections()
.AddHttpClients()
// Discrete services
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)

View File

@@ -2139,6 +2139,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 无圣遗物或散件 的本地化字符串。
/// </summary>
internal static string ViewModelComplexReliquarySetViewEmptyName {
get {
return ResourceManager.GetString("ViewModelComplexReliquarySetViewEmptyName", resourceCulture);
}
}
/// <summary>
/// 查找类似 养成计划添加失败 的本地化字符串。
/// </summary>
@@ -3687,6 +3696,24 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 在指定的显示器上运行 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameMonitorsDescription {
get {
return ResourceManager.GetString("ViewPageLaunchGameMonitorsDescription", resourceCulture);
}
}
/// <summary>
/// 查找类似 显示器 的本地化字符串。
/// </summary>
internal static string ViewPageLaunchGameMonitorsHeader {
get {
return ResourceManager.GetString("ViewPageLaunchGameMonitorsHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 在游戏时可以随时调整 的本地化字符串。
/// </summary>

View File

@@ -810,6 +810,9 @@
<data name="ViewModelAvatarPropertyShowcaseNotOpen" xml:space="preserve">
<value>角色展柜尚未开启,请前往游戏操作后重试</value>
</data>
<data name="ViewModelComplexReliquarySetViewEmptyName" xml:space="preserve">
<value>无圣遗物或散件</value>
</data>
<data name="ViewModelCultivationAddWarning" xml:space="preserve">
<value>养成计划添加失败</value>
</data>
@@ -1326,6 +1329,12 @@
<data name="ViewPageLaunchGameElevationHint" xml:space="preserve">
<value>某些选项处于禁用状态,它们只在管理员模式下生效!</value>
</data>
<data name="ViewPageLaunchGameMonitorsDescription" xml:space="preserve">
<value>在指定的显示器上运行</value>
</data>
<data name="ViewPageLaunchGameMonitorsHeader" xml:space="preserve">
<value>显示器</value>
</data>
<data name="ViewPageLaunchGameSetFpsDescription" xml:space="preserve">
<value>在游戏时可以随时调整</value>
</data>

View File

@@ -306,7 +306,7 @@ internal sealed class GameService : IGameService
}
/// <inheritdoc/>
public async ValueTask LaunchAsync(LaunchConfiguration configuration)
public async ValueTask LaunchAsync(LaunchOptions options)
{
if (IsGameRunning())
{
@@ -321,13 +321,13 @@ internal sealed class GameService : IGameService
}
// https://docs.unity.cn/cn/current/Manual/PlayerCommandLineArguments.html
// TODO: impl monitor option.
string commandLine = new CommandLineBuilder()
.AppendIf("-popupwindow", configuration.IsBorderless)
.Append("-screen-fullscreen", configuration.IsFullScreen ? 1 : 0)
.AppendIf("-window-mode", configuration.IsExclusive, "exclusive")
.Append("-screen-width", configuration.ScreenWidth)
.Append("-screen-height", configuration.ScreenHeight)
.AppendIf("-popupwindow", options.IsBorderless)
.Append("-screen-fullscreen", options.IsFullScreen ? 1 : 0)
.AppendIf("-window-mode", options.IsExclusive, "exclusive")
.Append("-screen-width", options.ScreenWidth)
.Append("-screen-height", options.ScreenHeight)
.Append("-monitor", options.Monitor.Value)
.ToString();
Process game = new()
@@ -344,9 +344,9 @@ internal sealed class GameService : IGameService
using (await gameSemaphore.EnterAsync().ConfigureAwait(false))
{
if (configuration.UnlockFPS)
if (options.UnlockFps)
{
IGameFpsUnlocker unlocker = new GameFpsUnlocker(game, configuration.TargetFPS);
IGameFpsUnlocker unlocker = new GameFpsUnlocker(game, options.TargetFps);
TimeSpan findModuleDelay = TimeSpan.FromMilliseconds(100);
TimeSpan findModuleLimit = TimeSpan.FromMilliseconds(10000);

View File

@@ -61,9 +61,9 @@ internal interface IGameService
/// <summary>
/// 异步启动
/// </summary>
/// <param name="configuration">启动配置</param>
/// <param name="options">启动配置</param>
/// <returns>任务</returns>
ValueTask LaunchAsync(LaunchConfiguration configuration);
ValueTask LaunchAsync(LaunchOptions options);
/// <summary>
/// 异步修改游戏账号名称

View File

@@ -1,68 +0,0 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.Game;
/// <summary>
/// 启动游戏配置
/// </summary>
[HighQuality]
internal readonly struct LaunchConfiguration
{
/// <summary>
/// 是否为独占全屏
/// </summary>
public readonly bool IsExclusive;
/// <summary>
/// 是否全屏,全屏时无边框设置将被覆盖
/// </summary>
public readonly bool IsFullScreen;
/// <summary>
/// 是否为无边框窗口
/// </summary>
public readonly bool IsBorderless;
/// <summary>
/// 窗口宽度
/// </summary>
public readonly int ScreenWidth;
/// <summary>
/// 窗口高度
/// </summary>
public readonly int ScreenHeight;
/// <summary>
/// 是否启用解锁帧率
/// </summary>
public readonly bool UnlockFPS;
/// <summary>
/// 目标帧率
/// </summary>
public readonly int TargetFPS;
/// <summary>
/// 构造一个新的启动配置
/// </summary>
/// <param name="isExclusive">独占全屏</param>
/// <param name="isFullScreen">全屏</param>
/// <param name="isBorderless">无边框</param>
/// <param name="screenWidth">宽度</param>
/// <param name="screenHeight">高度</param>
/// <param name="unlockFps">解锁帧率</param>
/// <param name="targetFps">目标帧率</param>
public LaunchConfiguration(bool isExclusive, bool isFullScreen, bool isBorderless, int screenWidth, int screenHeight, bool unlockFps, int targetFps)
{
IsExclusive = isExclusive;
IsFullScreen = isFullScreen;
IsBorderless = isBorderless;
ScreenHeight = screenHeight;
ScreenWidth = screenWidth;
ScreenHeight = screenHeight;
UnlockFPS = unlockFps;
TargetFPS = targetFps;
}
}

View File

@@ -0,0 +1,371 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.UI.Windowing;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Model;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
using Snap.Hutao.Win32;
using Windows.Graphics;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using static Windows.Win32.PInvoke;
namespace Snap.Hutao.Service.Game;
/// <summary>
/// 启动游戏选项
/// </summary>
[Injection(InjectAs.Singleton)]
internal sealed class LaunchOptions : ObservableObject, IOptions<LaunchOptions>
{
private readonly IServiceScopeFactory serviceScopeFactory;
private readonly int primaryScreenWidth;
private readonly int primaryScreenHeight;
private readonly int primaryScreenFps;
private bool? isFullScreen;
private bool? isBorderless;
private bool? isExclusive;
private int? screenWidth;
private int? screenHeight;
private bool? unlockFps;
private int? targetFps;
private NameValue<int>? monitor;
/// <summary>
/// 构造一个新的启动游戏选项
/// </summary>
/// <param name="serviceScopeFactory">服务范围工厂</param>
public LaunchOptions(IServiceScopeFactory serviceScopeFactory)
{
this.serviceScopeFactory = serviceScopeFactory;
RectInt32 primaryRect = DisplayArea.Primary.OuterBounds;
primaryScreenWidth = primaryRect.Width;
primaryScreenHeight = primaryRect.Height;
// This list can't use foreach
IReadOnlyList<DisplayArea> displayAreas = DisplayArea.FindAll();
for (int i = 0; i < displayAreas.Count; i++)
{
DisplayArea displayArea = displayAreas[i];
int index = i + 1;
Monitors.Add(new($"{displayArea.DisplayId.Value:X8}:{index}", index));
}
InitializeScreenFps(out primaryScreenFps);
}
/// <summary>
/// 是否全屏
/// </summary>
public bool IsFullScreen
{
get
{
if (isFullScreen == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchIsFullScreen)?.Value;
isFullScreen = value != null && bool.Parse(value);
}
}
return isFullScreen.Value;
}
set
{
if (SetProperty(ref isFullScreen, value))
{
if (value)
{
IsBorderless = false;
}
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchIsFullScreen);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchIsFullScreen, value.ToString()));
}
}
}
}
/// <summary>
/// 是否无边框
/// </summary>
public bool IsBorderless
{
get
{
if (isBorderless == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchIsBorderless)?.Value;
isBorderless = value != null && bool.Parse(value);
}
}
return isBorderless.Value;
}
set
{
if (SetProperty(ref isBorderless, value))
{
if (value)
{
IsExclusive = false;
IsFullScreen = false;
}
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchIsBorderless);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchIsBorderless, value.ToString()));
}
}
}
}
/// <summary>
/// 是否独占全屏
/// </summary>
public bool IsExclusive
{
get
{
if (isExclusive == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchIsExclusive)?.Value;
isExclusive = value != null && bool.Parse(value);
}
}
return isExclusive.Value;
}
set
{
if (SetProperty(ref isExclusive, value))
{
if (value)
{
IsFullScreen = true;
}
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchIsExclusive);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchIsExclusive, value.ToString()));
}
}
}
}
/// <summary>
/// 屏幕宽度
/// </summary>
public int ScreenWidth
{
get
{
if (screenWidth == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchScreenWidth)?.Value;
screenWidth = value == null ? primaryScreenWidth : int.Parse(value);
}
}
return screenWidth.Value;
}
set
{
if (SetProperty(ref screenWidth, value))
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchScreenWidth);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchScreenWidth, value.ToString()));
}
}
}
}
/// <summary>
/// 屏幕高度
/// </summary>
public int ScreenHeight
{
get
{
if (screenHeight == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchScreenHeight)?.Value;
screenHeight = value == null ? primaryScreenHeight : int.Parse(value);
}
}
return screenHeight.Value;
}
set
{
if (SetProperty(ref screenHeight, value))
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchScreenHeight);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchScreenHeight, value.ToString()));
}
}
}
}
/// <summary>
/// 是否全屏
/// </summary>
public bool UnlockFps
{
get
{
if (unlockFps == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchUnlockFps)?.Value;
unlockFps = value != null && bool.Parse(value);
}
}
return unlockFps.Value;
}
set
{
if (SetProperty(ref unlockFps, value))
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchUnlockFps);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchUnlockFps, value.ToString()));
}
}
}
}
/// <summary>
/// 目标帧率
/// </summary>
public int TargetFps
{
get
{
if (targetFps == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchTargetFps)?.Value;
targetFps = value == null ? primaryScreenFps : int.Parse(value);
}
}
return targetFps.Value;
}
set
{
if (SetProperty(ref targetFps, value))
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchTargetFps);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchTargetFps, value.ToString()));
}
}
}
}
/// <summary>
/// 所有监视器
/// </summary>
public List<NameValue<int>> Monitors { get; } = new();
/// <summary>
/// 目标帧率
/// </summary>
public NameValue<int> Monitor
{
get
{
if (monitor == null)
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.LaunchMonitor)?.Value;
int index = value == null ? 1 : int.Parse(value);
monitor = Monitors[index - 1];
}
}
return monitor;
}
set
{
if (SetProperty(ref monitor, value))
{
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchMonitor);
appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchMonitor, value.Value.ToString()));
}
}
}
}
/// <inheritdoc/>
public LaunchOptions Value { get => this; }
private static void InitializeScreenFps(out int fps)
{
HDC hDC = GetDC(HWND.Null);
fps = GetDeviceCaps(hDC, GET_DEVICE_CAPS_INDEX.VREFRESH);
if (ReleaseDC(HWND.Null, hDC) == 0)
{
// not released
throw new Win32Exception();
}
}
}

View File

@@ -8,6 +8,7 @@ using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.Web.Hutao.Model;
namespace Snap.Hutao.Service.Hutao;
@@ -40,25 +41,25 @@ internal sealed class HutaoCache : IHutaoCache
}
/// <inheritdoc/>
public List<ComplexAvatarRank>? AvatarUsageRanks { get; set; }
public List<AvatarRankView>? AvatarUsageRanks { get; set; }
/// <inheritdoc/>
public List<ComplexAvatarRank>? AvatarAppearanceRanks { get; set; }
public List<AvatarRankView>? AvatarAppearanceRanks { get; set; }
/// <inheritdoc/>
public List<ComplexAvatarConstellationInfo>? AvatarConstellationInfos { get; set; }
public List<AvatarConstellationInfoView>? AvatarConstellationInfos { get; set; }
/// <inheritdoc/>
public List<ComplexTeamRank>? TeamAppearances { get; set; }
public List<TeamAppearanceView>? TeamAppearances { get; set; }
/// <inheritdoc/>
public Overview? Overview { get; set; }
/// <inheritdoc/>
public List<ComplexAvatarCollocation>? AvatarCollocations { get; set; }
public List<AvatarCollocationView>? AvatarCollocations { get; set; }
/// <inheritdoc/>
public List<ComplexWeaponCollocation>? WeaponCollocations { get; set; }
public List<WeaponCollocationView>? WeaponCollocations { get; set; }
/// <inheritdoc/>
public async ValueTask<bool> InitializeForDatabaseViewModelAsync()
@@ -113,12 +114,12 @@ internal sealed class HutaoCache : IHutaoCache
avatarCollocationsRaw = await hutaoService.GetAvatarCollocationsAsync().ConfigureAwait(false);
}
AvatarCollocations = avatarCollocationsRaw.Select(co => new ComplexAvatarCollocation()
AvatarCollocations = avatarCollocationsRaw.Select(co => new AvatarCollocationView()
{
AvatarId = co.AvatarId,
Avatars = co.Avatars.Select(a => new ComplexAvatar(idAvatarMap[a.Item], a.Rate)).ToList(),
Weapons = co.Weapons.Select(w => new ComplexWeapon(idWeaponMap[w.Item], w.Rate)).ToList(),
ReliquarySets = co.Reliquaries.Select(r => new ComplexReliquarySet(r, idReliquarySetMap)).ToList(),
Avatars = co.Avatars.Select(a => new AvatarView(idAvatarMap[a.Item], a.Rate)).ToList(),
Weapons = co.Weapons.Select(w => new WeaponView(idWeaponMap[w.Item], w.Rate)).ToList(),
ReliquarySets = co.Reliquaries.Select(r => new ReliquarySetView(r, idReliquarySetMap)).ToList(),
}).ToList();
wikiAvatarViewModelTaskSource.TrySetResult(true);
@@ -149,10 +150,10 @@ internal sealed class HutaoCache : IHutaoCache
weaponCollocationsRaw = await hutaoService.GetWeaponCollocationsAsync().ConfigureAwait(false);
}
WeaponCollocations = weaponCollocationsRaw.Select(co => new ComplexWeaponCollocation()
WeaponCollocations = weaponCollocationsRaw.Select(co => new WeaponCollocationView()
{
WeaponId = co.WeaponId,
Avatars = co.Avatars.Select(a => new ComplexAvatar(idAvatarMap[a.Item], a.Rate)).ToList(),
Avatars = co.Avatars.Select(a => new AvatarView(idAvatarMap[a.Item], a.Rate)).ToList(),
}).ToList();
wikiWeaponViewModelTaskSource.TrySetResult(true);
@@ -183,10 +184,10 @@ internal sealed class HutaoCache : IHutaoCache
avatarAppearanceRanksRaw = await hutaoService.GetAvatarAppearanceRanksAsync().ConfigureAwait(false);
}
AvatarAppearanceRanks = avatarAppearanceRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new ComplexAvatarRank
AvatarAppearanceRanks = avatarAppearanceRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new AvatarRankView
{
Floor = string.Format(SH.ModelBindingHutaoComplexRankFloor, rank.Floor),
Avatars = rank.Ranks.OrderByDescending(r => r.Rate).Select(rank => new ComplexAvatar(idAvatarMap[rank.Item], rank.Rate)).ToList(),
Avatars = rank.Ranks.OrderByDescending(r => r.Rate).Select(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)).ToList(),
}).ToList();
}
@@ -199,10 +200,10 @@ internal sealed class HutaoCache : IHutaoCache
avatarUsageRanksRaw = await hutaoService.GetAvatarUsageRanksAsync().ConfigureAwait(false);
}
AvatarUsageRanks = avatarUsageRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new ComplexAvatarRank
AvatarUsageRanks = avatarUsageRanksRaw.OrderByDescending(r => r.Floor).Select(rank => new AvatarRankView
{
Floor = string.Format(SH.ModelBindingHutaoComplexRankFloor, rank.Floor),
Avatars = rank.Ranks.OrderByDescending(r => r.Rate).Select(rank => new ComplexAvatar(idAvatarMap[rank.Item], rank.Rate)).ToList(),
Avatars = rank.Ranks.OrderByDescending(r => r.Rate).Select(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)).ToList(),
}).ToList();
}
@@ -217,7 +218,7 @@ internal sealed class HutaoCache : IHutaoCache
AvatarConstellationInfos = avatarConstellationInfosRaw.OrderBy(i => i.HoldingRate).Select(info =>
{
return new ComplexAvatarConstellationInfo(idAvatarMap[info.AvatarId], info.HoldingRate, info.Constellations.Select(x => x.Rate));
return new AvatarConstellationInfoView(idAvatarMap[info.AvatarId], info.HoldingRate, info.Constellations.Select(x => x.Rate));
}).ToList();
}
@@ -230,7 +231,7 @@ internal sealed class HutaoCache : IHutaoCache
teamAppearancesRaw = await hutaoService.GetTeamAppearancesAsync().ConfigureAwait(false);
}
TeamAppearances = teamAppearancesRaw.OrderByDescending(t => t.Floor).Select(team => new ComplexTeamRank(team, idAvatarMap)).ToList();
TeamAppearances = teamAppearancesRaw.OrderByDescending(t => t.Floor).Select(team => new TeamAppearanceView(team, idAvatarMap)).ToList();
}
private async Task OverviewAsync()

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.Web.Hutao.Model;
namespace Snap.Hutao.Service.Hutao;
@@ -15,22 +16,22 @@ internal interface IHutaoCache
/// <summary>
/// 角色使用率
/// </summary>
List<ComplexAvatarRank>? AvatarUsageRanks { get; set; }
List<AvatarRankView>? AvatarUsageRanks { get; set; }
/// <summary>
/// 角色上场率
/// </summary>
List<ComplexAvatarRank>? AvatarAppearanceRanks { get; set; }
List<AvatarRankView>? AvatarAppearanceRanks { get; set; }
/// <summary>
/// 角色命座信息
/// </summary>
List<ComplexAvatarConstellationInfo>? AvatarConstellationInfos { get; set; }
List<AvatarConstellationInfoView>? AvatarConstellationInfos { get; set; }
/// <summary>
/// 队伍出场
/// </summary>
List<ComplexTeamRank>? TeamAppearances { get; set; }
List<TeamAppearanceView>? TeamAppearances { get; set; }
/// <summary>
/// 总览数据
@@ -40,12 +41,12 @@ internal interface IHutaoCache
/// <summary>
/// 角色搭配
/// </summary>
List<ComplexAvatarCollocation>? AvatarCollocations { get; set; }
List<AvatarCollocationView>? AvatarCollocations { get; set; }
/// <summary>
/// 武器搭配
/// </summary>
List<ComplexWeaponCollocation>? WeaponCollocations { get; set; }
List<WeaponCollocationView>? WeaponCollocations { get; set; }
/// <summary>
/// 为数据库视图模型初始化

View File

@@ -110,7 +110,6 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
case "id": return "ID"; // Indonesian
case "it": return "IT"; // Italian
case "ja": return "JP"; // Japanese
case "kr": return "JP"; // Japanese
case "ko": return "KR"; // Korean
case "pt": return "PT"; // Portuguese
case "ru": return "RU"; // Russian

View File

@@ -432,7 +432,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Control\Extension\" />
<Folder Include="Model\Binding\Gacha\" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resource\Localization\SH.Designer.cs">

View File

@@ -9,9 +9,9 @@
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shcp="using:Snap.Hutao.Control.Panel"
xmlns:shmbg="using:Snap.Hutao.Model.Binding.Gacha"
xmlns:shvc="using:Snap.Hutao.View.Control"
d:DataContext="{d:DesignInstance shmbg:Snap.Hutao.ViewModel.GachaLog.TypedWishSummary}"
xmlns:shvg="using:Snap.Hutao.ViewModel.GachaLog"
d:DataContext="{d:DesignInstance shvg:TypedWishSummary}"
mc:Ignorable="d">
<UserControl.Resources>
@@ -19,7 +19,7 @@
<SolidColorBrush x:Key="PurpleBrush" Color="#FFA156E0"/>
<SolidColorBrush x:Key="OrangeBrush" Color="#FFBC6932"/>
<DataTemplate x:Key="OrangeListTemplate" x:DataType="shmbg:SummaryItem">
<DataTemplate x:Key="OrangeListTemplate" d:DataType="shvg:SummaryItem">
<Grid Margin="0,4,4,0" Background="Transparent">
<ToolTipService.ToolTip>
<TextBlock Text="{Binding TimeFormatted}"/>
@@ -69,7 +69,7 @@
FalseValue="{ThemeResource SystemFillColorCriticalBackgroundBrush}"
TrueValue="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
<DataTemplate x:Key="OrangeGridTemplate" x:DataType="shmbg:SummaryItem">
<DataTemplate x:Key="OrangeGridTemplate" d:DataType="shvg:SummaryItem">
<Grid Width="40" Margin="0,4,4,0">
<Border
Background="{Binding IsUp, Converter={StaticResource BoolToBrushConverter}}"

View File

@@ -9,11 +9,10 @@
xmlns:shc="using:Snap.Hutao.Control"
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shmbh="using:Snap.Hutao.Model.Binding.Hutao"
xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:shvcom="using:Snap.Hutao.ViewModel.Complex"
xmlns:shvcon="using:Snap.Hutao.View.Control"
xmlns:wsc="using:WinUICommunity.SettingsUI.Controls"
d:DataContext="{d:DesignInstance shv:HutaoDatabaseViewModel}"
d:DataContext="{d:DesignInstance shvcom:HutaoDatabaseViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
@@ -22,7 +21,7 @@
</mxi:Interaction.Behaviors>
<Page.Resources>
<DataTemplate x:Key="TeamItemTemplate" x:DataType="shmbh:Team">
<DataTemplate x:Key="TeamItemTemplate" d:DataType="shvcom:Team">
<Border Margin="12,0,12,12" Style="{StaticResource BorderCardStyle}">
<Grid Margin="6">
<Grid.ColumnDefinitions>
@@ -37,7 +36,7 @@
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<shvc:ItemIcon
<shvcon:ItemIcon
Width="48"
Height="48"
Icon="{Binding Icon}"
@@ -115,9 +114,9 @@
SelectionMode="None">
<ItemsControl.ItemTemplate>
<DataTemplate>
<shvc:BottomTextControl Text="{Binding Rate}">
<shvc:ItemIcon Icon="{Binding Icon}" Quality="{Binding Quality}"/>
</shvc:BottomTextControl>
<shvcon:BottomTextControl Text="{Binding Rate}">
<shvcon:ItemIcon Icon="{Binding Icon}" Quality="{Binding Quality}"/>
</shvcon:BottomTextControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</GridView>
@@ -143,9 +142,9 @@
SelectionMode="None">
<ItemsControl.ItemTemplate>
<DataTemplate>
<shvc:BottomTextControl Text="{Binding Rate}">
<shvc:ItemIcon Icon="{Binding Icon}" Quality="{Binding Quality}"/>
</shvc:BottomTextControl>
<shvcon:BottomTextControl Text="{Binding Rate}">
<shvcon:ItemIcon Icon="{Binding Icon}" Quality="{Binding Quality}"/>
</shvcon:BottomTextControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</GridView>
@@ -275,7 +274,7 @@
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<shvc:ItemIcon
<shvcon:ItemIcon
Width="48"
Height="48"
Icon="{Binding Icon}"
@@ -315,6 +314,6 @@
</Grid>
</PivotItem>
</Pivot>
<shvc:LoadingView IsLoading="{Binding Overview, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
<shvcon:LoadingView IsLoading="{Binding Overview, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
</Grid>
</shc:ScopedPage>

View File

@@ -2,7 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Control;
using Snap.Hutao.ViewModel;
using Snap.Hutao.ViewModel.Complex;
namespace Snap.Hutao.View.Page;

View File

@@ -184,7 +184,7 @@
<wsc:Setting.ActionContent>
<ToggleSwitch
Width="120"
IsOn="{Binding IsExclusive, Mode=TwoWay}"
IsOn="{Binding Options.IsExclusive, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
@@ -195,7 +195,7 @@
<wsc:Setting.ActionContent>
<ToggleSwitch
Width="120"
IsOn="{Binding IsFullScreen, Mode=TwoWay}"
IsOn="{Binding Options.IsFullScreen, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
@@ -206,7 +206,7 @@
<wsc:Setting.ActionContent>
<ToggleSwitch
Width="120"
IsOn="{Binding IsBorderless, Mode=TwoWay}"
IsOn="{Binding Options.IsBorderless, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchSettingStyle}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
@@ -217,7 +217,7 @@
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthHeader}"
Icon="&#xE76F;">
<wsc:Setting.ActionContent>
<NumberBox Width="156" Value="{Binding ScreenWidth, Mode=TwoWay}"/>
<NumberBox Width="156" Value="{Binding Options.ScreenWidth, Mode=TwoWay}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
<wsc:Setting
@@ -225,7 +225,19 @@
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenHeightHeader}"
Icon="&#xE784;">
<wsc:Setting.ActionContent>
<NumberBox Width="156" Value="{Binding ScreenHeight, Mode=TwoWay}"/>
<NumberBox Width="156" Value="{Binding Options.ScreenHeight, Mode=TwoWay}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
<wsc:Setting
Description="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsDescription}"
Header="{shcm:ResourceString Name=ViewPageLaunchGameMonitorsHeader}"
Icon="&#xE975;">
<wsc:Setting.ActionContent>
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding Options.Monitors}"
SelectedItem="{Binding Options.Monitor, Mode=TwoWay}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
</wsc:SettingsGroup>
@@ -243,7 +255,7 @@
<wsc:Setting.ActionContent>
<ToggleSwitch
Width="120"
IsOn="{Binding UnlockFps, Mode=TwoWay}"
IsOn="{Binding Options.UnlockFps, Mode=TwoWay}"
OffContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOff}"
OnContent="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsOn}"
Style="{StaticResource ToggleSwitchSettingStyle}"/>
@@ -253,7 +265,7 @@
<wsc:Setting.Description>
<StackPanel>
<TextBlock Text="{shcm:ResourceString Name=ViewPageLaunchGameSetFpsDescription}"/>
<TextBlock Text="{Binding TargetFps}"/>
<TextBlock Text="{Binding Options.TargetFps}"/>
</StackPanel>
</wsc:Setting.Description>
<wsc:Setting.ActionContent>
@@ -261,7 +273,7 @@
Width="400"
Maximum="360"
Minimum="60"
Value="{Binding TargetFps, Mode=TwoWay}"/>
Value="{Binding Options.TargetFps, Mode=TwoWay}"/>
</wsc:Setting.ActionContent>
</wsc:Setting>
</wsc:SettingsGroup>

View File

@@ -3,13 +3,13 @@
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 角色搭配
/// </summary>
[HighQuality]
internal sealed class ComplexAvatarCollocation
internal sealed class AvatarCollocationView
{
/// <summary>
/// 角色Id
@@ -19,15 +19,15 @@ internal sealed class ComplexAvatarCollocation
/// <summary>
/// 角色
/// </summary>
public List<ComplexAvatar> Avatars { get; set; } = default!;
public List<AvatarView> Avatars { get; set; } = default!;
/// <summary>
/// 武器
/// </summary>
public List<ComplexWeapon> Weapons { get; set; } = default!;
public List<WeaponView> Weapons { get; set; } = default!;
/// <summary>
/// 圣遗物套装
/// </summary>
public List<ComplexReliquarySet> ReliquarySets { get; set; } = default!;
public List<ReliquarySetView> ReliquarySets { get; set; } = default!;
}

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.ViewModel.Complex;
namespace Snap.Hutao.Model.Binding.Hutao;
@@ -9,7 +10,7 @@ namespace Snap.Hutao.Model.Binding.Hutao;
/// 角色命座信息
/// </summary>
[HighQuality]
internal sealed class ComplexAvatarConstellationInfo : ComplexAvatar
internal sealed class AvatarConstellationInfoView : AvatarView
{
/// <summary>
/// 构造一个新的角色命座信息
@@ -17,7 +18,7 @@ internal sealed class ComplexAvatarConstellationInfo : ComplexAvatar
/// <param name="avatar">角色</param>
/// <param name="rate">持有率</param>
/// <param name="rates">命座比率</param>
public ComplexAvatarConstellationInfo(Avatar avatar, double rate, IEnumerable<double> rates)
public AvatarConstellationInfoView(Avatar avatar, double rate, IEnumerable<double> rates)
: base(avatar, rate)
{
Rates = rates.Select(r => $"{r:P3}").ToList();
@@ -26,5 +27,5 @@ internal sealed class ComplexAvatarConstellationInfo : ComplexAvatar
/// <summary>
/// 命座比率
/// </summary>
public List<string> Rates { get; set; }
public List<string> Rates { get; }
}

View File

@@ -1,13 +1,13 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 角色榜
/// </summary>
[HighQuality]
internal sealed class ComplexAvatarRank
internal sealed class AvatarRankView
{
/// <summary>
/// 层数
@@ -17,5 +17,5 @@ internal sealed class ComplexAvatarRank
/// <summary>
/// 排行信息
/// </summary>
public List<ComplexAvatar> Avatars { get; set; } = default!;
public List<AvatarView> Avatars { get; set; } = default!;
}

View File

@@ -1,24 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Converter;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 角色
/// </summary>
[HighQuality]
internal class ComplexAvatar : INameIconSide
internal class AvatarView : INameIconSide
{
/// <summary>
/// 构造一个胡桃数据库角色
/// </summary>
/// <param name="avatar">元数据角色</param>
/// <param name="rate">率</param>
public ComplexAvatar(Avatar avatar, double rate)
public AvatarView(Avatar avatar, double rate)
{
Name = avatar.Name;
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
@@ -30,25 +31,25 @@ internal class ComplexAvatar : INameIconSide
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = default!;
public string Name { get; }
/// <summary>
/// 图标
/// </summary>
public Uri Icon { get; set; } = default!;
public Uri Icon { get; }
/// <summary>
/// 侧面图标
/// </summary>
public Uri SideIcon { get; set; } = default!;
public Uri SideIcon { get; }
/// <summary>
/// 星级
/// </summary>
public ItemQuality Quality { get; set; }
public ItemQuality Quality { get; }
/// <summary>
/// 比率
/// </summary>
public string Rate { get; set; } = default!;
public string Rate { get; }
}

View File

@@ -1,12 +1,11 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Web.Hutao.Model;
namespace Snap.Hutao.ViewModel;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 胡桃数据库视图模型
@@ -17,10 +16,10 @@ internal sealed class HutaoDatabaseViewModel : Abstraction.ViewModel
{
private readonly IHutaoCache hutaoCache;
private List<ComplexAvatarRank>? avatarUsageRanks;
private List<ComplexAvatarRank>? avatarAppearanceRanks;
private List<ComplexAvatarConstellationInfo>? avatarConstellationInfos;
private List<ComplexTeamRank>? teamAppearances;
private List<AvatarRankView>? avatarUsageRanks;
private List<AvatarRankView>? avatarAppearanceRanks;
private List<AvatarConstellationInfoView>? avatarConstellationInfos;
private List<TeamAppearanceView>? teamAppearances;
private Overview? overview;
/// <summary>
@@ -30,41 +29,35 @@ internal sealed class HutaoDatabaseViewModel : Abstraction.ViewModel
public HutaoDatabaseViewModel(IHutaoCache hutaoCache)
{
this.hutaoCache = hutaoCache;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
/// <summary>
/// 角色使用率
/// </summary>
public List<ComplexAvatarRank>? AvatarUsageRanks { get => avatarUsageRanks; set => SetProperty(ref avatarUsageRanks, value); }
public List<AvatarRankView>? AvatarUsageRanks { get => avatarUsageRanks; set => SetProperty(ref avatarUsageRanks, value); }
/// <summary>
/// 角色上场率
/// </summary>
public List<ComplexAvatarRank>? AvatarAppearanceRanks { get => avatarAppearanceRanks; set => SetProperty(ref avatarAppearanceRanks, value); }
public List<AvatarRankView>? AvatarAppearanceRanks { get => avatarAppearanceRanks; set => SetProperty(ref avatarAppearanceRanks, value); }
/// <summary>
/// 角色命座信息
/// </summary>
public List<ComplexAvatarConstellationInfo>? AvatarConstellationInfos { get => avatarConstellationInfos; set => SetProperty(ref avatarConstellationInfos, value); }
public List<AvatarConstellationInfoView>? AvatarConstellationInfos { get => avatarConstellationInfos; set => SetProperty(ref avatarConstellationInfos, value); }
/// <summary>
/// 队伍出场
/// </summary>
public List<ComplexTeamRank>? TeamAppearances { get => teamAppearances; set => SetProperty(ref teamAppearances, value); }
public List<TeamAppearanceView>? TeamAppearances { get => teamAppearances; set => SetProperty(ref teamAppearances, value); }
/// <summary>
/// 总览数据
/// </summary>
public Overview? Overview { get => overview; set => SetProperty(ref overview, value); }
/// <summary>
/// 打开界面命令
/// </summary>
public ICommand OpenUICommand { get; }
private async Task OpenUIAsync()
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
if (await hutaoCache.InitializeForDatabaseViewModelAsync().ConfigureAwait(true))
{

View File

@@ -6,30 +6,30 @@ using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Web.Hutao.Model;
using System.Text;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 圣遗物套装
/// </summary>
internal sealed class ComplexReliquarySet
internal sealed class ReliquarySetView
{
/// <summary>
/// 构造一个新的胡桃数据库圣遗物套装
/// </summary>
/// <param name="reliquarySetRate">圣遗物套装率</param>
/// <param name="idReliquarySetMap">圣遗物套装映射</param>
public ComplexReliquarySet(ItemRate<ReliquarySets, double> reliquarySetRate, Dictionary<EquipAffixId, Metadata.Reliquary.ReliquarySet> idReliquarySetMap)
public ReliquarySetView(ItemRate<ReliquarySets, double> reliquarySetRate, Dictionary<EquipAffixId, Model.Metadata.Reliquary.ReliquarySet> idReliquarySetMap)
{
ReliquarySets sets = reliquarySetRate.Item;
if (sets.Count >= 1)
{
StringBuilder nameBuilder = new();
List<Uri> icons = new();
List<Uri> icons = new(2);
foreach (ReliquarySet set in sets)
{
Metadata.Reliquary.ReliquarySet metaSet = idReliquarySetMap[set.EquipAffixId / 10];
Model.Metadata.Reliquary.ReliquarySet metaSet = idReliquarySetMap[set.EquipAffixId / 10];
if (nameBuilder.Length != 0)
{
@@ -45,7 +45,7 @@ internal sealed class ComplexReliquarySet
}
else
{
Name = "无圣遗物或散件";
Name = SH.ViewModelComplexReliquarySetViewEmptyName;
}
Rate = $"{reliquarySetRate.Rate:P3}";

View File

@@ -5,13 +5,13 @@ using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Web.Hutao.Model;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 队伍
/// </summary>
[HighQuality]
internal sealed class Team : List<ComplexAvatar>
internal sealed class Team : List<AvatarView>
{
/// <summary>
/// 构造一个新的队伍

View File

@@ -5,20 +5,20 @@ using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Web.Hutao.Model;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 队伍排行
/// </summary>
[HighQuality]
internal sealed class ComplexTeamRank
internal sealed class TeamAppearanceView
{
/// <summary>
/// 构造一个新的队伍排行
/// </summary>
/// <param name="teamRank">队伍排行</param>
/// <param name="idAvatarMap">映射</param>
public ComplexTeamRank(TeamAppearance teamRank, Dictionary<AvatarId, Avatar> idAvatarMap)
public TeamAppearanceView(TeamAppearance teamRank, Dictionary<AvatarId, Avatar> idAvatarMap)
{
Floor = string.Format(SH.ModelBindingHutaoComplexRankFloor, teamRank.Floor);
Up = teamRank.Up.Select(teamRate => new Team(teamRate, idAvatarMap)).ToList();

View File

@@ -3,18 +3,18 @@
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 武器搭配
/// </summary>
[HighQuality]
internal sealed class ComplexWeaponCollocation
internal sealed class WeaponCollocationView
{
/// <summary>
/// 角色
/// </summary>
public List<ComplexAvatar> Avatars { get; set; } = default!;
public List<AvatarView> Avatars { get; set; } = default!;
/// <summary>
/// 武器Id

View File

@@ -1,24 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.Model.Metadata.Weapon;
namespace Snap.Hutao.Model.Binding.Hutao;
namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 胡桃数据库武器
/// </summary>
[HighQuality]
internal sealed class ComplexWeapon : INameIcon
internal sealed class WeaponView : INameIcon
{
/// <summary>
/// 构造一个胡桃数据库武器
/// </summary>
/// <param name="weapon">元数据武器</param>
/// <param name="rate">率</param>
public ComplexWeapon(Weapon weapon, double rate)
public WeaponView(Weapon weapon, double rate)
{
Name = weapon.Name;
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);

View File

@@ -2,12 +2,9 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Windowing;
using Snap.Hutao.Control.Extension;
using Snap.Hutao.Core.Database;
using Snap.Hutao.Core.ExceptionService;
using Snap.Hutao.Core.LifeCycle;
using Snap.Hutao.Model.Binding.LaunchGame;
@@ -21,7 +18,6 @@ using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
using System.Collections.ObjectModel;
using System.IO;
using Windows.Graphics;
namespace Snap.Hutao.ViewModel;
@@ -47,13 +43,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
private LaunchScheme? selectedScheme;
private ObservableCollection<GameAccount>? gameAccounts;
private GameAccount? selectedGameAccount;
private bool isExclusive;
private bool isFullScreen;
private bool isBorderless;
private int screenWidth;
private int screenHeight;
private bool unlockFps;
private int targetFps;
/// <summary>
/// 构造一个新的启动游戏视图模型
@@ -64,9 +53,9 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
gameService = serviceProvider.GetRequiredService<IGameService>();
appDbContext = serviceProvider.GetRequiredService<AppDbContext>();
memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
Options = serviceProvider.GetRequiredService<LaunchOptions>();
this.serviceProvider = serviceProvider;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
LaunchCommand = new AsyncRelayCommand(LaunchAsync);
DetectGameAccountCommand = new AsyncRelayCommand(DetectGameAccountAsync);
ModifyGameAccountCommand = new AsyncRelayCommand<GameAccount>(ModifyGameAccountAsync);
@@ -95,76 +84,9 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
public GameAccount? SelectedGameAccount { get => selectedGameAccount; set => SetProperty(ref selectedGameAccount, value); }
/// <summary>
/// 是否为独占全屏
/// 启动选项
/// </summary>
public bool IsExclusive
{
get => isExclusive; set
{
if (SetProperty(ref isExclusive, value))
{
if (value)
{
IsFullScreen = true;
}
}
}
}
/// <summary>
/// 全屏
/// </summary>
public bool IsFullScreen
{
get => isFullScreen; set
{
if (SetProperty(ref isFullScreen, value))
{
if (value)
{
IsBorderless = false;
}
}
}
}
/// <summary>
/// 无边框
/// </summary>
public bool IsBorderless
{
get => isBorderless; set
{
if (SetProperty(ref isBorderless, value))
{
if (value)
{
IsExclusive = false;
IsFullScreen = false;
}
}
}
}
/// <summary>
/// 宽度
/// </summary>
public int ScreenWidth { get => screenWidth; set => SetProperty(ref screenWidth, value); }
/// <summary>
/// 高度
/// </summary>
public int ScreenHeight { get => screenHeight; set => SetProperty(ref screenHeight, value); }
/// <summary>
/// 解锁帧率
/// </summary>
public bool UnlockFps { get => unlockFps; set => SetProperty(ref unlockFps, value); }
/// <summary>
/// 目标帧率
/// </summary>
public int TargetFps { get => targetFps; set => SetProperty(ref targetFps, value); }
public LaunchOptions Options { get; }
/// <summary>
/// 是否提权
@@ -172,11 +94,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
[SuppressMessage("", "CA1822")]
public bool IsElevated { get => Activation.GetElevated(); }
/// <summary>
/// 打开界面命令
/// </summary>
public ICommand OpenUICommand { get; }
/// <summary>
/// 启动游戏命令
/// </summary>
@@ -202,7 +119,8 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
/// </summary>
public ICommand AttachGameAccountCommand { get; }
private async Task OpenUIAsync()
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
if (File.Exists(gameService.GetGamePathSkipLocator()))
{
@@ -228,9 +146,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
SelectedGameAccount = GameAccounts.FirstOrDefault(g => g.AttachUid == uid);
memoryCache.Remove(DesiredUid);
}
// Sync from Settings
RetiveSetting();
}
}
catch (OperationCanceledException)
@@ -246,44 +161,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
}
}
private void RetiveSetting()
{
DbSet<SettingEntry> settings = appDbContext.Settings;
isFullScreen = settings.SingleOrAdd(SettingEntry.LaunchIsFullScreen, Core.StringLiterals.True).GetBoolean();
OnPropertyChanged(nameof(IsFullScreen));
isBorderless = settings.SingleOrAdd(SettingEntry.LaunchIsBorderless, Core.StringLiterals.False).GetBoolean();
OnPropertyChanged(nameof(IsBorderless));
RectInt32 primaryRect = DisplayArea.Primary.OuterBounds;
screenWidth = settings.SingleOrAdd(SettingEntry.LaunchScreenWidth, $"{primaryRect.Width}").GetInt32();
OnPropertyChanged(nameof(ScreenWidth));
screenHeight = settings.SingleOrAdd(SettingEntry.LaunchScreenHeight, $"{primaryRect.Height}").GetInt32();
OnPropertyChanged(nameof(ScreenHeight));
unlockFps = settings.SingleOrAdd(SettingEntry.LaunchUnlockFps, Core.StringLiterals.False).GetBoolean();
OnPropertyChanged(nameof(UnlockFps));
targetFps = settings.SingleOrAdd(SettingEntry.LaunchTargetFps, "60").GetInt32();
OnPropertyChanged(nameof(TargetFps));
}
private void SaveSetting()
{
DbSet<SettingEntry> settings = appDbContext.Settings;
settings.SingleOrAdd(SettingEntry.LaunchIsExclusive, Core.StringLiterals.False).SetBoolean(IsExclusive);
settings.SingleOrAdd(SettingEntry.LaunchIsFullScreen, Core.StringLiterals.False).SetBoolean(IsFullScreen);
settings.SingleOrAdd(SettingEntry.LaunchIsBorderless, Core.StringLiterals.False).SetBoolean(IsBorderless);
settings.SingleOrAdd(SettingEntry.LaunchScreenWidth, "1920").SetInt32(ScreenWidth);
settings.SingleOrAdd(SettingEntry.LaunchScreenHeight, "1080").SetInt32(ScreenHeight);
settings.SingleOrAdd(SettingEntry.LaunchUnlockFps, Core.StringLiterals.False).SetBoolean(UnlockFps);
settings.SingleOrAdd(SettingEntry.LaunchTargetFps, "60").SetInt32(TargetFps);
appDbContext.SaveChanges();
}
private async Task LaunchAsync()
{
IInfoBarService infoBarService = serviceProvider.GetRequiredService<IInfoBarService>();
@@ -322,10 +199,7 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
}
}
SaveSetting();
LaunchConfiguration configuration = new(IsExclusive, IsFullScreen, IsBorderless, ScreenWidth, ScreenHeight, IsElevated && UnlockFps, TargetFps);
await gameService.LaunchAsync(configuration).ConfigureAwait(false);
await gameService.LaunchAsync(Options).ConfigureAwait(false);
}
catch (Exception ex)
{

View File

@@ -46,10 +46,10 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
private readonly List<NameValue<string>> cultures = new()
{
ToNameValue(CultureInfo.CreateSpecificCulture("zh-CN")),
ToNameValue(CultureInfo.CreateSpecificCulture("zh-TW")),
ToNameValue(CultureInfo.CreateSpecificCulture("en-US")),
ToNameValue(CultureInfo.CreateSpecificCulture("ko-KR")),
ToNameValue(CultureInfo.GetCultureInfo("zh-Hans")),
ToNameValue(CultureInfo.GetCultureInfo("zh-Hant")),
ToNameValue(CultureInfo.GetCultureInfo("en")),
ToNameValue(CultureInfo.GetCultureInfo("ko")),
};
private bool isEmptyHistoryWishVisible;
@@ -102,7 +102,7 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
}
/// <summary>
/// Webview2 版本
/// WebView2 版本
/// </summary>
[SuppressMessage("", "CA1822")]
public string WebView2Version
@@ -226,6 +226,12 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
/// </summary>
public ICommand ResetStaticResourceCommand { get; }
/// <inheritdoc/>
protected override Task OpenUIAsync()
{
return Task.CompletedTask;
}
private static NameValue<string> ToNameValue(CultureInfo info)
{
return new(info.NativeName, info.Name);

View File

@@ -52,7 +52,6 @@ internal sealed class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecip
userService = serviceProvider.GetRequiredService<IUserService>();
this.serviceProvider = serviceProvider;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
RefreshCommand = new AsyncRelayCommand(RefreshAsync);
UploadSpiralAbyssRecordCommand = new AsyncRelayCommand(UploadSpiralAbyssRecordAsync);
@@ -86,11 +85,6 @@ internal sealed class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecip
/// </summary>
public SpiralAbyssView? SpiralAbyssView { get => spiralAbyssView; set => SetProperty(ref spiralAbyssView, value); }
/// <summary>
/// 打开界面命令
/// </summary>
public ICommand OpenUICommand { get; }
/// <summary>
/// 刷新界面命令
/// </summary>
@@ -114,7 +108,8 @@ internal sealed class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecip
}
}
private async Task OpenUIAsync()
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{

View File

@@ -53,6 +53,12 @@ internal sealed class TestViewModel : Abstraction.ViewModel
/// </summary>
public ICommand RestartAppCommand { get; }
/// <inheritdoc/>
protected override Task OpenUIAsync()
{
return Task.CompletedTask;
}
private async Task ShowCommunityGameRecordDialogAsync()
{
// ContentDialog must be created by main thread.

View File

@@ -20,6 +20,7 @@ using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.Web.Response;
using System.Collections.Immutable;
using System.Runtime.InteropServices;
@@ -59,7 +60,6 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
hutaoCache = serviceProvider.GetRequiredService<IHutaoCache>();
this.serviceProvider = serviceProvider;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
CultivateCommand = new AsyncRelayCommand<Avatar>(CultivateAsync);
FilterCommand = new RelayCommand<string>(ApplyFilter);
}
@@ -93,11 +93,6 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
/// </summary>
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
/// <summary>
/// 打开页面命令
/// </summary>
public ICommand OpenUICommand { get; }
/// <summary>
/// 养成命令
/// </summary>
@@ -108,7 +103,8 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
/// </summary>
public ICommand FilterCommand { get; }
private async Task OpenUIAsync()
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
@@ -134,7 +130,7 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
{
if (await hutaoCache.InitializeForWikiAvatarViewModelAsync().ConfigureAwait(false))
{
Dictionary<AvatarId, ComplexAvatarCollocation> idCollocations = hutaoCache.AvatarCollocations!.ToDictionary(a => a.AvatarId);
Dictionary<AvatarId, AvatarCollocationView> idCollocations = hutaoCache.AvatarCollocations!.ToDictionary(a => a.AvatarId);
foreach (Avatar avatar in avatars)
{

View File

@@ -1,31 +1,15 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI.UI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Snap.Hutao.Model.Binding.BaseValue;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Intrinsic.Immutable;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Cultivation;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Response;
using System.Collections.Immutable;
using System.Runtime.InteropServices;
using CalcAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalcClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
using CalcConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Consumption;
namespace Snap.Hutao.ViewModel;
@@ -35,16 +19,13 @@ namespace Snap.Hutao.ViewModel;
[Injection(InjectAs.Scoped)]
internal class WikiMonsterViewModel : Abstraction.ViewModel
{
private readonly IServiceProvider serviceProvider;
private readonly IMetadataService metadataService;
private readonly IHutaoCache hutaoCache;
private AdvancedCollectionView? monsters;
private Monster? selected;
private string? filterText;
private BaseValueInfo? baseValueInfo;
private Dictionary<int, Dictionary<GrowCurveType, float>>? levelMonsterCurveMap;
private Dictionary<MaterialId, Material>? idMaterialMap;
/// <summary>
/// 构造一个新的怪物资料视图模型
@@ -53,10 +34,6 @@ internal class WikiMonsterViewModel : Abstraction.ViewModel
public WikiMonsterViewModel(IServiceProvider serviceProvider)
{
metadataService = serviceProvider.GetRequiredService<IMetadataService>();
hutaoCache = serviceProvider.GetRequiredService<IHutaoCache>();
this.serviceProvider = serviceProvider;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
/// <summary>
@@ -88,12 +65,8 @@ internal class WikiMonsterViewModel : Abstraction.ViewModel
/// </summary>
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
/// <summary>
/// 打开界面命令
/// </summary>
public ICommand OpenUICommand { get; }
private async Task OpenUIAsync()
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{

View File

@@ -6,7 +6,6 @@ using CommunityToolkit.WinUI.UI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Snap.Hutao.Model.Binding.BaseValue;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Intrinsic.Immutable;
@@ -19,6 +18,7 @@ using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.Web.Response;
using System.Collections.Immutable;
using System.Runtime.InteropServices;
@@ -61,7 +61,6 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
hutaoCache = serviceProvider.GetRequiredService<IHutaoCache>();
this.serviceProvider = serviceProvider;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
CultivateCommand = new AsyncRelayCommand<Weapon>(CultivateAsync);
FilterCommand = new RelayCommand<string>(ApplyFilter);
}
@@ -95,11 +94,6 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
/// </summary>
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
/// <summary>
/// 打开界面命令
/// </summary>
public ICommand OpenUICommand { get; }
/// <summary>
/// 养成命令
/// </summary>
@@ -110,7 +104,8 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
/// </summary>
public ICommand FilterCommand { get; }
private async Task OpenUIAsync()
/// <inheritdoc/>
protected override async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
@@ -137,7 +132,7 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
{
if (await hutaoCache.InitializeForWikiWeaponViewModelAsync().ConfigureAwait(false))
{
Dictionary<WeaponId, ComplexWeaponCollocation> idCollocations = hutaoCache.WeaponCollocations!.ToDictionary(a => a.WeaponId);
Dictionary<WeaponId, WeaponCollocationView> idCollocations = hutaoCache.WeaponCollocations!.ToDictionary(a => a.WeaponId);
weapons.ForEach(w => w.Collocation = idCollocations.GetValueOrDefault(w.Id));
}
}

View File

@@ -5,6 +5,7 @@ using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using Windows.Graphics;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.System.Diagnostics.ToolHelp;
using Windows.Win32.UI.WindowsAndMessaging;