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;