diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs
index 3c621586..092b958f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/LocalSetting.cs
@@ -253,4 +253,4 @@ internal static class LocalSetting
{
Container.Values[key] = value;
}
-}
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/Localization.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/Localization.cs
index d402b38a..f547013e 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/Localization.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/Localization.cs
@@ -17,7 +17,7 @@ internal static class Localization
/// 语言代码
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;
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs
index 4fd2ec38..491f0c78 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/WindowSubclassManager.cs
@@ -25,7 +25,7 @@ internal sealed class WindowSubclassManager : 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;
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs
index eff876c2..cacd06f3 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs
@@ -81,6 +81,11 @@ internal sealed class SettingEntry
///
public const string LaunchTargetFps = "Launch.TargetFps";
+ ///
+ /// 启动游戏 显示器编号
+ ///
+ public const string LaunchMonitor = "Launch.Monitor";
+
///
/// 语言
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs
index c6a40aa2..ea1ae0ba 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs
@@ -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
/// [非元数据] 搭配数据
///
[JsonIgnore]
- public ComplexAvatarCollocation? Collocation { get; set; }
+ public AvatarCollocationView? Collocation { get; set; }
///
/// [非元数据] 烹饪奖励
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs
index 954f9340..79d687db 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs
@@ -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
/// [非元数据] 搭配数据
///
[JsonIgnore]
- public ComplexWeaponCollocation? Collocation { get; set; }
+ public WeaponCollocationView? Collocation { get; set; }
///
[JsonIgnore]
diff --git a/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt b/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt
index f91671bd..82d2fcd9 100644
--- a/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt
+++ b/src/Snap.Hutao/Snap.Hutao/NativeMethods.txt
@@ -10,8 +10,11 @@ MINMAXINFO
// COMCTL32
DefSubclassProc
-SetWindowSubclass
RemoveWindowSubclass
+SetWindowSubclass
+
+// GDI32
+GetDeviceCaps
// KERNEL32
CreateEvent
@@ -27,6 +30,7 @@ CoWaitForMultipleObjects
// USER32
FindWindowEx
+GetDC
GetDpiForWindow
GetWindowPlacement
diff --git a/src/Snap.Hutao/Snap.Hutao/Option/AppOptions.cs b/src/Snap.Hutao/Snap.Hutao/Option/AppOptions.cs
new file mode 100644
index 00000000..11349b82
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Option/AppOptions.cs
@@ -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;
+
+///
+/// 应用程序选项
+///
+[Injection(InjectAs.Singleton)]
+internal sealed class AppOptions : IOptions
+{
+ private readonly IServiceScopeFactory serviceScopeFactory;
+
+ ///
+ /// 构造一个新的应用程序选项
+ ///
+ /// 服务范围工厂
+ public AppOptions(IServiceScopeFactory serviceScopeFactory)
+ {
+ this.serviceScopeFactory = serviceScopeFactory;
+ }
+
+ ///
+ /// 游戏路径
+ ///
+ public string? GamePath
+ {
+ get
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ return appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.GamePath)?.Value;
+ }
+ }
+
+ set
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.GamePath);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.GamePath, value));
+ }
+ }
+ }
+
+ ///
+ /// 游戏路径
+ ///
+ public bool IsEmptyHistoryWishVisible
+ {
+ get
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.IsEmptyHistoryWishVisible);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.IsEmptyHistoryWishVisible, value.ToString()));
+ }
+ }
+ }
+
+ ///
+ /// 背景类型 默认 Mica
+ ///
+ public Core.Windowing.BackdropType BackdropType
+ {
+ get
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.SystemBackdropType)?.Value;
+ return Enum.Parse(value ?? nameof(Core.Windowing.BackdropType.Mica));
+ }
+ }
+
+ set
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.SystemBackdropType);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.SystemBackdropType, value.ToString()));
+ }
+ }
+ }
+
+ ///
+ /// 当前语言
+ ///
+ public CultureInfo CurrentCulture
+ {
+ get
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.Culture);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.Culture, value.Name));
+ }
+ }
+ }
+
+ ///
+ public AppOptions Value { get => this; }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Program.cs b/src/Snap.Hutao/Snap.Hutao/Program.cs
index 87d6453f..f6d2bf8d 100644
--- a/src/Snap.Hutao/Snap.Hutao/Program.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Program.cs
@@ -59,7 +59,6 @@ public static partial class Program
.AddDatabase()
.AddInjections()
.AddHttpClients()
-
// Discrete services
.AddSingleton(WeakReferenceMessenger.Default)
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
index 238858f7..7c1df80f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs
@@ -2139,6 +2139,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 无圣遗物或散件 的本地化字符串。
+ ///
+ internal static string ViewModelComplexReliquarySetViewEmptyName {
+ get {
+ return ResourceManager.GetString("ViewModelComplexReliquarySetViewEmptyName", resourceCulture);
+ }
+ }
+
///
/// 查找类似 养成计划添加失败 的本地化字符串。
///
@@ -3687,6 +3696,24 @@ namespace Snap.Hutao.Resource.Localization {
}
}
+ ///
+ /// 查找类似 在指定的显示器上运行 的本地化字符串。
+ ///
+ internal static string ViewPageLaunchGameMonitorsDescription {
+ get {
+ return ResourceManager.GetString("ViewPageLaunchGameMonitorsDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 显示器 的本地化字符串。
+ ///
+ internal static string ViewPageLaunchGameMonitorsHeader {
+ get {
+ return ResourceManager.GetString("ViewPageLaunchGameMonitorsHeader", resourceCulture);
+ }
+ }
+
///
/// 查找类似 在游戏时可以随时调整 的本地化字符串。
///
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index 8f22b0c1..88feb36d 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -810,6 +810,9 @@
角色展柜尚未开启,请前往游戏操作后重试
+
+ 无圣遗物或散件
+
养成计划添加失败
@@ -1326,6 +1329,12 @@
某些选项处于禁用状态,它们只在管理员模式下生效!
+
+ 在指定的显示器上运行
+
+
+ 显示器
+
在游戏时可以随时调整
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
index 8e522877..0a345d05 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs
@@ -306,7 +306,7 @@ internal sealed class GameService : IGameService
}
///
- 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);
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs
index 1e75f6e5..46f403c5 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs
@@ -61,9 +61,9 @@ internal interface IGameService
///
/// 异步启动
///
- /// 启动配置
+ /// 启动配置
/// 任务
- ValueTask LaunchAsync(LaunchConfiguration configuration);
+ ValueTask LaunchAsync(LaunchOptions options);
///
/// 异步修改游戏账号名称
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs
deleted file mode 100644
index 738eeee2..00000000
--- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchConfiguration.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) DGP Studio. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Snap.Hutao.Service.Game;
-
-///
-/// 启动游戏配置
-///
-[HighQuality]
-internal readonly struct LaunchConfiguration
-{
- ///
- /// 是否为独占全屏
- ///
- public readonly bool IsExclusive;
-
- ///
- /// 是否全屏,全屏时无边框设置将被覆盖
- ///
- public readonly bool IsFullScreen;
-
- ///
- /// 是否为无边框窗口
- ///
- public readonly bool IsBorderless;
-
- ///
- /// 窗口宽度
- ///
- public readonly int ScreenWidth;
-
- ///
- /// 窗口高度
- ///
- public readonly int ScreenHeight;
-
- ///
- /// 是否启用解锁帧率
- ///
- public readonly bool UnlockFPS;
-
- ///
- /// 目标帧率
- ///
- public readonly int TargetFPS;
-
- ///
- /// 构造一个新的启动配置
- ///
- /// 独占全屏
- /// 全屏
- /// 无边框
- /// 宽度
- /// 高度
- /// 解锁帧率
- /// 目标帧率
- 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;
- }
-}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs
new file mode 100644
index 00000000..938f4f07
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs
@@ -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;
+
+///
+/// 启动游戏选项
+///
+[Injection(InjectAs.Singleton)]
+internal sealed class LaunchOptions : ObservableObject, IOptions
+{
+ 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? monitor;
+
+ ///
+ /// 构造一个新的启动游戏选项
+ ///
+ /// 服务范围工厂
+ 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 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);
+ }
+
+ ///
+ /// 是否全屏
+ ///
+ public bool IsFullScreen
+ {
+ get
+ {
+ if (isFullScreen == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchIsFullScreen);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchIsFullScreen, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 是否无边框
+ ///
+ public bool IsBorderless
+ {
+ get
+ {
+ if (isBorderless == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchIsBorderless);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchIsBorderless, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 是否独占全屏
+ ///
+ public bool IsExclusive
+ {
+ get
+ {
+ if (isExclusive == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchIsExclusive);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchIsExclusive, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 屏幕宽度
+ ///
+ public int ScreenWidth
+ {
+ get
+ {
+ if (screenWidth == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchScreenWidth);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchScreenWidth, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 屏幕高度
+ ///
+ public int ScreenHeight
+ {
+ get
+ {
+ if (screenHeight == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchScreenHeight);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchScreenHeight, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 是否全屏
+ ///
+ public bool UnlockFps
+ {
+ get
+ {
+ if (unlockFps == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchUnlockFps);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchUnlockFps, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 目标帧率
+ ///
+ public int TargetFps
+ {
+ get
+ {
+ if (targetFps == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchTargetFps);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchTargetFps, value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ /// 所有监视器
+ ///
+ public List> Monitors { get; } = new();
+
+ ///
+ /// 目标帧率
+ ///
+ public NameValue Monitor
+ {
+ get
+ {
+ if (monitor == null)
+ {
+ using (IServiceScope scope = serviceScopeFactory.CreateScope())
+ {
+ AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService();
+ 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.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.LaunchMonitor);
+ appDbContext.Settings.AddAndSave(new(SettingEntry.LaunchMonitor, value.Value.ToString()));
+ }
+ }
+ }
+ }
+
+ ///
+ 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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs
index 3fdb6449..95d4389f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoCache.cs
@@ -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
}
///
- public List? AvatarUsageRanks { get; set; }
+ public List? AvatarUsageRanks { get; set; }
///
- public List? AvatarAppearanceRanks { get; set; }
+ public List? AvatarAppearanceRanks { get; set; }
///
- public List? AvatarConstellationInfos { get; set; }
+ public List? AvatarConstellationInfos { get; set; }
///
- public List? TeamAppearances { get; set; }
+ public List? TeamAppearances { get; set; }
///
public Overview? Overview { get; set; }
///
- public List? AvatarCollocations { get; set; }
+ public List? AvatarCollocations { get; set; }
///
- public List? WeaponCollocations { get; set; }
+ public List? WeaponCollocations { get; set; }
///
public async ValueTask 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()
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/IHutaoCache.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/IHutaoCache.cs
index 3c92717c..5c3125db 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/IHutaoCache.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/IHutaoCache.cs
@@ -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
///
/// 角色使用率
///
- List? AvatarUsageRanks { get; set; }
+ List? AvatarUsageRanks { get; set; }
///
/// 角色上场率
///
- List? AvatarAppearanceRanks { get; set; }
+ List? AvatarAppearanceRanks { get; set; }
///
/// 角色命座信息
///
- List? AvatarConstellationInfos { get; set; }
+ List? AvatarConstellationInfos { get; set; }
///
/// 队伍出场
///
- List? TeamAppearances { get; set; }
+ List? TeamAppearances { get; set; }
///
/// 总览数据
@@ -40,12 +41,12 @@ internal interface IHutaoCache
///
/// 角色搭配
///
- List? AvatarCollocations { get; set; }
+ List? AvatarCollocations { get; set; }
///
/// 武器搭配
///
- List? WeaponCollocations { get; set; }
+ List? WeaponCollocations { get; set; }
///
/// 为数据库视图模型初始化
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs
index ccb42e69..9c147df1 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs
@@ -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
diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
index 7e0a010a..af43f9da 100644
--- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
+++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj
@@ -432,7 +432,6 @@
-
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml
index 9b51a020..27fee408 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsCard.xaml
@@ -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">
@@ -19,7 +19,7 @@
-
+
@@ -69,7 +69,7 @@
FalseValue="{ThemeResource SystemFillColorCriticalBackgroundBrush}"
TrueValue="{ThemeResource CardBackgroundFillColorDefaultBrush}"/>
-
+
@@ -22,7 +21,7 @@
-
+
@@ -37,7 +36,7 @@
-
-
-
-
+
+
+
@@ -143,9 +142,9 @@
SelectionMode="None">
-
-
-
+
+
+
@@ -275,7 +274,7 @@
-
-
+
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs
index 32bbd40d..92650314 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/HutaoDatabasePage.xaml.cs
@@ -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;
diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml
index 1f2e5bae..156c3cf6 100644
--- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml
+++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml
@@ -184,7 +184,7 @@
@@ -195,7 +195,7 @@
@@ -206,7 +206,7 @@
@@ -217,7 +217,7 @@
Header="{shcm:ResourceString Name=ViewPageLaunchGameAppearanceScreenWidthHeader}"
Icon="">
-
+
-
+
+
+
+
+
+
+
@@ -243,7 +255,7 @@
@@ -253,7 +265,7 @@
-
+
@@ -261,7 +273,7 @@
Width="400"
Maximum="360"
Minimum="60"
- Value="{Binding TargetFps, Mode=TwoWay}"/>
+ Value="{Binding Options.TargetFps, Mode=TwoWay}"/>
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarCollocation.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarCollocationView.cs
similarity index 60%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarCollocation.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarCollocationView.cs
index 17c4c47d..60cbd63b 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarCollocation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarCollocationView.cs
@@ -3,13 +3,13 @@
using Snap.Hutao.Model.Primitive;
-namespace Snap.Hutao.Model.Binding.Hutao;
+namespace Snap.Hutao.ViewModel.Complex;
///
/// 角色搭配
///
[HighQuality]
-internal sealed class ComplexAvatarCollocation
+internal sealed class AvatarCollocationView
{
///
/// 角色Id
@@ -19,15 +19,15 @@ internal sealed class ComplexAvatarCollocation
///
/// 角色
///
- public List Avatars { get; set; } = default!;
+ public List Avatars { get; set; } = default!;
///
/// 武器
///
- public List Weapons { get; set; } = default!;
+ public List Weapons { get; set; } = default!;
///
/// 圣遗物套装
///
- public List ReliquarySets { get; set; } = default!;
+ public List ReliquarySets { get; set; } = default!;
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarConstellationInfo.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarConstellationInfoView.cs
similarity index 72%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarConstellationInfo.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarConstellationInfoView.cs
index 56db2f96..641a5c52 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarConstellationInfo.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarConstellationInfoView.cs
@@ -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;
/// 角色命座信息
///
[HighQuality]
-internal sealed class ComplexAvatarConstellationInfo : ComplexAvatar
+internal sealed class AvatarConstellationInfoView : AvatarView
{
///
/// 构造一个新的角色命座信息
@@ -17,7 +18,7 @@ internal sealed class ComplexAvatarConstellationInfo : ComplexAvatar
/// 角色
/// 持有率
/// 命座比率
- public ComplexAvatarConstellationInfo(Avatar avatar, double rate, IEnumerable rates)
+ public AvatarConstellationInfoView(Avatar avatar, double rate, IEnumerable rates)
: base(avatar, rate)
{
Rates = rates.Select(r => $"{r:P3}").ToList();
@@ -26,5 +27,5 @@ internal sealed class ComplexAvatarConstellationInfo : ComplexAvatar
///
/// 命座比率
///
- public List Rates { get; set; }
+ public List Rates { get; }
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarRank.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarRankView.cs
similarity index 67%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarRank.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarRankView.cs
index 84edb9bb..234c919c 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatarRank.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarRankView.cs
@@ -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;
///
/// 角色榜
///
[HighQuality]
-internal sealed class ComplexAvatarRank
+internal sealed class AvatarRankView
{
///
/// 层数
@@ -17,5 +17,5 @@ internal sealed class ComplexAvatarRank
///
/// 排行信息
///
- public List Avatars { get; set; } = default!;
+ public List Avatars { get; set; } = default!;
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatar.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs
similarity index 71%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatar.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs
index 58740715..f16b7569 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexAvatar.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs
@@ -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;
///
/// 角色
///
[HighQuality]
-internal class ComplexAvatar : INameIconSide
+internal class AvatarView : INameIconSide
{
///
/// 构造一个胡桃数据库角色
///
/// 元数据角色
/// 率
- 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
///
/// 名称
///
- public string Name { get; set; } = default!;
+ public string Name { get; }
///
/// 图标
///
- public Uri Icon { get; set; } = default!;
+ public Uri Icon { get; }
///
/// 侧面图标
///
- public Uri SideIcon { get; set; } = default!;
+ public Uri SideIcon { get; }
///
/// 星级
///
- public ItemQuality Quality { get; set; }
+ public ItemQuality Quality { get; }
///
/// 比率
///
- public string Rate { get; set; } = default!;
+ public string Rate { get; }
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/HutaoDatabaseViewModel.cs
similarity index 58%
rename from src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/HutaoDatabaseViewModel.cs
index 7254dcce..e6c54104 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/HutaoDatabaseViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/HutaoDatabaseViewModel.cs
@@ -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;
///
/// 胡桃数据库视图模型
@@ -17,10 +16,10 @@ internal sealed class HutaoDatabaseViewModel : Abstraction.ViewModel
{
private readonly IHutaoCache hutaoCache;
- private List? avatarUsageRanks;
- private List? avatarAppearanceRanks;
- private List? avatarConstellationInfos;
- private List? teamAppearances;
+ private List? avatarUsageRanks;
+ private List? avatarAppearanceRanks;
+ private List? avatarConstellationInfos;
+ private List? teamAppearances;
private Overview? overview;
///
@@ -30,41 +29,35 @@ internal sealed class HutaoDatabaseViewModel : Abstraction.ViewModel
public HutaoDatabaseViewModel(IHutaoCache hutaoCache)
{
this.hutaoCache = hutaoCache;
-
- OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
///
/// 角色使用率
///
- public List? AvatarUsageRanks { get => avatarUsageRanks; set => SetProperty(ref avatarUsageRanks, value); }
+ public List? AvatarUsageRanks { get => avatarUsageRanks; set => SetProperty(ref avatarUsageRanks, value); }
///
/// 角色上场率
///
- public List? AvatarAppearanceRanks { get => avatarAppearanceRanks; set => SetProperty(ref avatarAppearanceRanks, value); }
+ public List? AvatarAppearanceRanks { get => avatarAppearanceRanks; set => SetProperty(ref avatarAppearanceRanks, value); }
///
/// 角色命座信息
///
- public List? AvatarConstellationInfos { get => avatarConstellationInfos; set => SetProperty(ref avatarConstellationInfos, value); }
+ public List? AvatarConstellationInfos { get => avatarConstellationInfos; set => SetProperty(ref avatarConstellationInfos, value); }
///
/// 队伍出场
///
- public List? TeamAppearances { get => teamAppearances; set => SetProperty(ref teamAppearances, value); }
+ public List? TeamAppearances { get => teamAppearances; set => SetProperty(ref teamAppearances, value); }
///
/// 总览数据
///
public Overview? Overview { get => overview; set => SetProperty(ref overview, value); }
- ///
- /// 打开界面命令
- ///
- public ICommand OpenUICommand { get; }
-
- private async Task OpenUIAsync()
+ ///
+ protected override async Task OpenUIAsync()
{
if (await hutaoCache.InitializeForDatabaseViewModelAsync().ConfigureAwait(true))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexReliquarySet.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/ReliquarySetView.cs
similarity index 76%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexReliquarySet.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/ReliquarySetView.cs
index d80e261b..eb3533ff 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexReliquarySet.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/ReliquarySetView.cs
@@ -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;
///
/// 圣遗物套装
///
-internal sealed class ComplexReliquarySet
+internal sealed class ReliquarySetView
{
///
/// 构造一个新的胡桃数据库圣遗物套装
///
/// 圣遗物套装率
/// 圣遗物套装映射
- public ComplexReliquarySet(ItemRate reliquarySetRate, Dictionary idReliquarySetMap)
+ public ReliquarySetView(ItemRate reliquarySetRate, Dictionary idReliquarySetMap)
{
ReliquarySets sets = reliquarySetRate.Item;
if (sets.Count >= 1)
{
StringBuilder nameBuilder = new();
- List icons = new();
+ List 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}";
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/Team.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs
similarity index 90%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/Team.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs
index dd93bbbd..124b98a1 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/Team.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs
@@ -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;
///
/// 队伍
///
[HighQuality]
-internal sealed class Team : List
+internal sealed class Team : List
{
///
/// 构造一个新的队伍
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexTeamRank.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/TeamAppearanceView.cs
similarity index 84%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexTeamRank.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/TeamAppearanceView.cs
index 31649c01..2a9e38c6 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexTeamRank.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/TeamAppearanceView.cs
@@ -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;
///
/// 队伍排行
///
[HighQuality]
-internal sealed class ComplexTeamRank
+internal sealed class TeamAppearanceView
{
///
/// 构造一个新的队伍排行
///
/// 队伍排行
/// 映射
- public ComplexTeamRank(TeamAppearance teamRank, Dictionary idAvatarMap)
+ public TeamAppearanceView(TeamAppearance teamRank, Dictionary idAvatarMap)
{
Floor = string.Format(SH.ModelBindingHutaoComplexRankFloor, teamRank.Floor);
Up = teamRank.Up.Select(teamRate => new Team(teamRate, idAvatarMap)).ToList();
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexWeaponCollocation.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponCollocationView.cs
similarity index 68%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexWeaponCollocation.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponCollocationView.cs
index d4aea86b..b344ef93 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexWeaponCollocation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponCollocationView.cs
@@ -3,18 +3,18 @@
using Snap.Hutao.Model.Primitive;
-namespace Snap.Hutao.Model.Binding.Hutao;
+namespace Snap.Hutao.ViewModel.Complex;
///
/// 武器搭配
///
[HighQuality]
-internal sealed class ComplexWeaponCollocation
+internal sealed class WeaponCollocationView
{
///
/// 角色
///
- public List Avatars { get; set; } = default!;
+ public List Avatars { get; set; } = default!;
///
/// 武器Id
diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexWeapon.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs
similarity index 85%
rename from src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexWeapon.cs
rename to src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs
index 78e1b63a..2c5e5763 100644
--- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Hutao/ComplexWeapon.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs
@@ -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;
///
/// 胡桃数据库武器
///
[HighQuality]
-internal sealed class ComplexWeapon : INameIcon
+internal sealed class WeaponView : INameIcon
{
///
/// 构造一个胡桃数据库武器
///
/// 元数据武器
/// 率
- public ComplexWeapon(Weapon weapon, double rate)
+ public WeaponView(Weapon weapon, double rate)
{
Name = weapon.Name;
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs
index 7ac3af1b..a3f7ace3 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/LaunchGameViewModel.cs
@@ -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? 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;
///
/// 构造一个新的启动游戏视图模型
@@ -64,9 +53,9 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
gameService = serviceProvider.GetRequiredService();
appDbContext = serviceProvider.GetRequiredService();
memoryCache = serviceProvider.GetRequiredService();
+ Options = serviceProvider.GetRequiredService();
this.serviceProvider = serviceProvider;
- OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
LaunchCommand = new AsyncRelayCommand(LaunchAsync);
DetectGameAccountCommand = new AsyncRelayCommand(DetectGameAccountAsync);
ModifyGameAccountCommand = new AsyncRelayCommand(ModifyGameAccountAsync);
@@ -95,76 +84,9 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
public GameAccount? SelectedGameAccount { get => selectedGameAccount; set => SetProperty(ref selectedGameAccount, value); }
///
- /// 是否为独占全屏
+ /// 启动选项
///
- public bool IsExclusive
- {
- get => isExclusive; set
- {
- if (SetProperty(ref isExclusive, value))
- {
- if (value)
- {
- IsFullScreen = true;
- }
- }
- }
- }
-
- ///
- /// 全屏
- ///
- public bool IsFullScreen
- {
- get => isFullScreen; set
- {
- if (SetProperty(ref isFullScreen, value))
- {
- if (value)
- {
- IsBorderless = false;
- }
- }
- }
- }
-
- ///
- /// 无边框
- ///
- public bool IsBorderless
- {
- get => isBorderless; set
- {
- if (SetProperty(ref isBorderless, value))
- {
- if (value)
- {
- IsExclusive = false;
- IsFullScreen = false;
- }
- }
- }
- }
-
- ///
- /// 宽度
- ///
- public int ScreenWidth { get => screenWidth; set => SetProperty(ref screenWidth, value); }
-
- ///
- /// 高度
- ///
- public int ScreenHeight { get => screenHeight; set => SetProperty(ref screenHeight, value); }
-
- ///
- /// 解锁帧率
- ///
- public bool UnlockFps { get => unlockFps; set => SetProperty(ref unlockFps, value); }
-
- ///
- /// 目标帧率
- ///
- public int TargetFps { get => targetFps; set => SetProperty(ref targetFps, value); }
+ public LaunchOptions Options { get; }
///
/// 是否提权
@@ -172,11 +94,6 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
[SuppressMessage("", "CA1822")]
public bool IsElevated { get => Activation.GetElevated(); }
- ///
- /// 打开界面命令
- ///
- public ICommand OpenUICommand { get; }
-
///
/// 启动游戏命令
///
@@ -202,7 +119,8 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
///
public ICommand AttachGameAccountCommand { get; }
- private async Task OpenUIAsync()
+ ///
+ 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 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 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();
@@ -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)
{
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
index 59f89fb6..be1732af 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SettingViewModel.cs
@@ -46,10 +46,10 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
private readonly List> 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
}
///
- /// Webview2 版本
+ /// WebView2 版本
///
[SuppressMessage("", "CA1822")]
public string WebView2Version
@@ -226,6 +226,12 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
///
public ICommand ResetStaticResourceCommand { get; }
+ ///
+ protected override Task OpenUIAsync()
+ {
+ return Task.CompletedTask;
+ }
+
private static NameValue ToNameValue(CultureInfo info)
{
return new(info.NativeName, info.Name);
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs
index 2b5f296c..b290d9df 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyssRecordViewModel.cs
@@ -52,7 +52,6 @@ internal sealed class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecip
userService = serviceProvider.GetRequiredService();
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
///
public SpiralAbyssView? SpiralAbyssView { get => spiralAbyssView; set => SetProperty(ref spiralAbyssView, value); }
- ///
- /// 打开界面命令
- ///
- public ICommand OpenUICommand { get; }
-
///
/// 刷新界面命令
///
@@ -114,7 +108,8 @@ internal sealed class SpiralAbyssRecordViewModel : Abstraction.ViewModel, IRecip
}
}
- private async Task OpenUIAsync()
+ ///
+ protected override async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs
index 12f34e24..9ce2f21c 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/TestViewModel.cs
@@ -53,6 +53,12 @@ internal sealed class TestViewModel : Abstraction.ViewModel
///
public ICommand RestartAppCommand { get; }
+ ///
+ protected override Task OpenUIAsync()
+ {
+ return Task.CompletedTask;
+ }
+
private async Task ShowCommunityGameRecordDialogAsync()
{
// ContentDialog must be created by main thread.
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
index b14d610c..ce5548bc 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiAvatarViewModel.cs
@@ -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();
this.serviceProvider = serviceProvider;
- OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
CultivateCommand = new AsyncRelayCommand(CultivateAsync);
FilterCommand = new RelayCommand(ApplyFilter);
}
@@ -93,11 +93,6 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
///
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
- ///
- /// 打开页面命令
- ///
- public ICommand OpenUICommand { get; }
-
///
/// 养成命令
///
@@ -108,7 +103,8 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
///
public ICommand FilterCommand { get; }
- private async Task OpenUIAsync()
+ ///
+ 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 idCollocations = hutaoCache.AvatarCollocations!.ToDictionary(a => a.AvatarId);
+ Dictionary idCollocations = hutaoCache.AvatarCollocations!.ToDictionary(a => a.AvatarId);
foreach (Avatar avatar in avatars)
{
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiMonsterViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiMonsterViewModel.cs
index d47160a7..0a52fccc 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiMonsterViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiMonsterViewModel.cs
@@ -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>? levelMonsterCurveMap;
- private Dictionary? idMaterialMap;
///
/// 构造一个新的怪物资料视图模型
@@ -53,10 +34,6 @@ internal class WikiMonsterViewModel : Abstraction.ViewModel
public WikiMonsterViewModel(IServiceProvider serviceProvider)
{
metadataService = serviceProvider.GetRequiredService();
- hutaoCache = serviceProvider.GetRequiredService();
- this.serviceProvider = serviceProvider;
-
- OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
///
@@ -88,12 +65,8 @@ internal class WikiMonsterViewModel : Abstraction.ViewModel
///
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
- ///
- /// 打开界面命令
- ///
- public ICommand OpenUICommand { get; }
-
- private async Task OpenUIAsync()
+ ///
+ protected override async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs
index 636f7862..21a3a9af 100644
--- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs
+++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs
@@ -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();
this.serviceProvider = serviceProvider;
- OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
CultivateCommand = new AsyncRelayCommand(CultivateAsync);
FilterCommand = new RelayCommand(ApplyFilter);
}
@@ -95,11 +94,6 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
///
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
- ///
- /// 打开界面命令
- ///
- public ICommand OpenUICommand { get; }
-
///
/// 养成命令
///
@@ -110,7 +104,8 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
///
public ICommand FilterCommand { get; }
- private async Task OpenUIAsync()
+ ///
+ 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 idCollocations = hutaoCache.WeaponCollocations!.ToDictionary(a => a.WeaponId);
+ Dictionary idCollocations = hutaoCache.WeaponCollocations!.ToDictionary(a => a.WeaponId);
weapons.ForEach(w => w.Collocation = idCollocations.GetValueOrDefault(w.Id));
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs b/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs
index fa1c2c1f..aa2a9b03 100644
--- a/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Win32/StructMarshal.cs
@@ -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;