From 179b78ca832f56ad8f3e3e0f9e229368485abde8 Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Tue, 4 Apr 2023 18:44:19 +0800 Subject: [PATCH] Launch Game QoL --- .../Extension/MemoryCacheExtension.cs | 30 +++++ .../Service/DailyNote/DailyNoteOptions.cs | 69 ++++++++++- .../Snap.Hutao/Service/Game/GameService.cs | 22 ++++ .../Snap.Hutao/Service/Game/IGameService.cs | 6 + .../Snap.Hutao/Service/Game/LaunchOptions.cs | 2 +- .../Snap.Hutao/View/Page/DailyNotePage.xaml | 6 +- .../ViewModel/DailyNoteViewModel.cs | 117 ++---------------- .../ViewModel/Game/LaunchGameViewModel.cs | 6 +- .../Snap.Hutao/Web/Hoyolab/PlayerUid.cs | 1 + 9 files changed, 143 insertions(+), 116 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Extension/MemoryCacheExtension.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/MemoryCacheExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/MemoryCacheExtension.cs new file mode 100644 index 00000000..749a2fc5 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Extension/MemoryCacheExtension.cs @@ -0,0 +1,30 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.Extensions.Caching.Memory; + +namespace Snap.Hutao.Extension; + +/// +/// 内存缓存拓展 +/// +internal static class MemoryCacheExtension +{ + /// + /// 尝试从 IMemoryCache 中移除并返回具有指定键的值 + /// + /// 缓存 + /// 键 + /// 值 + /// 是否移除成功 + public static bool TryRemove(this IMemoryCache memoryCache, string key, [NotNullWhen(true)] out object? value) + { + if (memoryCache.TryGetValue(key, out value)) + { + memoryCache.Remove(key); + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs index 87625c61..a0659da3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteOptions.cs @@ -1,6 +1,9 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Core; +using Snap.Hutao.Model; +using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.Abstraction; namespace Snap.Hutao.Service.DailyNote; @@ -11,12 +14,72 @@ namespace Snap.Hutao.Service.DailyNote; [Injection(InjectAs.Singleton)] internal sealed class DailyNoteOptions : DbStoreOptions { + private readonly IServiceProvider serviceProvider; + private readonly List> refreshTimes = new() + { + new(SH.ViewModelDailyNoteRefreshTime4, 240), + new(SH.ViewModelDailyNoteRefreshTime8, 480), + new(SH.ViewModelDailyNoteRefreshTime30, 1800), + new(SH.ViewModelDailyNoteRefreshTime40, 2400), + new(SH.ViewModelDailyNoteRefreshTime60, 3600), + }; + + private NameValue? selectedRefreshTime; + private bool? isReminderNotification; + private bool? isSilentWhenPlayingGame; + /// /// 构造一个新的实时便笺选项 /// - /// 服务范围工厂 - public DailyNoteOptions(IServiceScopeFactory serviceScopeFactory) - : base(serviceScopeFactory) + /// 服务提供器 + public DailyNoteOptions(IServiceProvider serviceProvider) + : base(serviceProvider.GetRequiredService()) { + this.serviceProvider = serviceProvider; + } + + /// + /// 刷新时间 + /// + public List> RefreshTimes { get => refreshTimes; } + + /// + /// 选中的刷新时间 + /// + public NameValue? SelectedRefreshTime + { + get => GetOption(ref selectedRefreshTime, SettingEntry.DailyNoteReminderNotify, time => RefreshTimes.Single(t => t.Value == int.Parse(time)), RefreshTimes[1]); + set + { + if (value != null) + { + if (ScheduleTaskHelper.RegisterForDailyNoteRefresh(value.Value)) + { + SetOption(ref selectedRefreshTime, SettingEntry.DailyNoteReminderNotify, value, value => value.Value.ToString()); + } + else + { + serviceProvider.GetRequiredService().Warning(SH.ViewModelDailyNoteRegisterTaskFail); + } + } + } + } + + /// + /// 提醒式通知 + /// + public bool IsReminderNotification + { + get => GetOption(ref isReminderNotification, SettingEntry.DailyNoteReminderNotify); + set => SetOption(ref isReminderNotification, SettingEntry.DailyNoteReminderNotify, value); + } + + /// + /// 是否开启免打扰模式 + /// + public bool IsSilentWhenPlayingGame + { + get => GetOption(ref isSilentWhenPlayingGame, SettingEntry.DailyNoteSilentWhenPlayingGame); + set => SetOption(ref isSilentWhenPlayingGame, SettingEntry.DailyNoteSilentWhenPlayingGame, value); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs index 80e5f5fd..9c665a73 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -368,6 +368,28 @@ internal sealed class GameService : IGameService } } + /// + public GameAccount? DetectCurrentGameAccount() + { + Must.NotNull(gameAccounts!); + + string? registrySdk = RegistryInterop.Get(); + + if (!string.IsNullOrEmpty(registrySdk)) + { + try + { + return gameAccounts.SingleOrDefault(a => a.MihoyoSDK == registrySdk); + } + catch (InvalidOperationException ex) + { + ThrowHelper.UserdataCorrupted(SH.ServiceGameDetectGameAccountMultiMatched, ex); + } + } + + return null; + } + /// public bool SetGameAccount(GameAccount account) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs index 7e44433c..2ee3a81a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameService.cs @@ -92,4 +92,10 @@ internal interface IGameService /// 方案 /// 是否更改了ini文件 bool SetMultiChannel(LaunchScheme scheme); + + /// + /// 检测账号 + /// + /// 账号 + GameAccount? DetectCurrentGameAccount(); } \ 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 index 43cb4023..5a23cca4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs @@ -148,7 +148,7 @@ internal sealed class LaunchOptions : DbStoreOptions public NameValue Monitor { get => GetOption(ref monitor, SettingEntry.LaunchMonitor, index => Monitors[int.Parse(index) - 1], Monitors[0]); - set => SetOption(ref monitor, SettingEntry.LaunchMonitor, value, selected => selected.Value.ToString()); + set => SetOption(ref monitor, SettingEntry.LaunchMonitor, value, selected => selected?.Value.ToString() ?? "1"); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml index e4065715..f1d2bb61 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/DailyNotePage.xaml @@ -85,7 +85,7 @@ - + @@ -106,13 +106,13 @@ Description="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeDescription}" Header="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeHeader}" HeaderIcon="{shcm:FontIcon Glyph=}"> - + - + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs index d1ad0040..c4667184 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNoteViewModel.cs @@ -28,24 +28,8 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel private readonly IDailyNoteService dailyNoteService; private readonly AppDbContext appDbContext; - private readonly List> refreshTimes = new() - { - new(SH.ViewModelDailyNoteRefreshTime4, 240), - new(SH.ViewModelDailyNoteRefreshTime8, 480), - new(SH.ViewModelDailyNoteRefreshTime30, 1800), - new(SH.ViewModelDailyNoteRefreshTime40, 2400), - new(SH.ViewModelDailyNoteRefreshTime60, 3600), - }; - - private bool isReminderNotification; - private NameValue? selectedRefreshTime; private ObservableCollection? userAndUids; - - private SettingEntry? refreshSecondsEntry; - private SettingEntry? reminderNotifyEntry; - private SettingEntry? silentModeEntry; private ObservableCollection? dailyNoteEntries; - private bool isSilentWhenPlayingGame; /// /// 构造一个新的实时便笺视图模型 @@ -56,6 +40,7 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel userService = serviceProvider.GetRequiredService(); dailyNoteService = serviceProvider.GetRequiredService(); appDbContext = serviceProvider.GetRequiredService(); + Options = serviceProvider.GetRequiredService(); this.serviceProvider = serviceProvider; TrackRoleCommand = new AsyncRelayCommand(TrackRoleAsync); @@ -66,67 +51,9 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel } /// - /// 刷新时间 + /// 选项 /// - public List> RefreshTimes { get => refreshTimes; } - - /// - /// 选中的刷新时间 - /// - public NameValue? SelectedRefreshTime - { - get => selectedRefreshTime; - set - { - if (SetProperty(ref selectedRefreshTime, value)) - { - if (value != null) - { - if (!ScheduleTaskHelper.RegisterForDailyNoteRefresh(value.Value)) - { - serviceProvider.GetRequiredService().Warning(SH.ViewModelDailyNoteRegisterTaskFail); - } - else - { - refreshSecondsEntry!.SetInt32(value.Value); - appDbContext.Settings.UpdateAndSave(refreshSecondsEntry!); - } - } - } - } - } - - /// - /// 提醒式通知 - /// - public bool IsReminderNotification - { - get => isReminderNotification; - set - { - if (SetProperty(ref isReminderNotification, value)) - { - reminderNotifyEntry!.SetBoolean(value); - appDbContext.Settings.UpdateAndSave(reminderNotifyEntry!); - } - } - } - - /// - /// 是否开启免打扰模式 - /// - public bool IsSilentWhenPlayingGame - { - get => isSilentWhenPlayingGame; - set - { - if (SetProperty(ref isSilentWhenPlayingGame, value)) - { - silentModeEntry!.SetBoolean(value); - appDbContext.Settings.UpdateAndSave(silentModeEntry!); - } - } - } + public DailyNoteOptions Options { get; } /// /// 用户与角色集合 @@ -168,43 +95,19 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel { try { - UserAndUids = await userService.GetRoleCollectionAsync().ConfigureAwait(true); + await ThreadHelper.SwitchToBackgroundAsync(); + ObservableCollection roles = await userService.GetRoleCollectionAsync().ConfigureAwait(false); + ObservableCollection entries = await dailyNoteService.GetDailyNoteEntriesAsync().ConfigureAwait(false); + + await ThreadHelper.SwitchToMainThreadAsync(); + UserAndUids = roles; + DailyNoteEntries = entries; } catch (Core.ExceptionService.UserdataCorruptedException ex) { serviceProvider.GetRequiredService().Error(ex); return; } - - try - { - using (await EnterCriticalExecutionAsync().ConfigureAwait(false)) - { - await ThreadHelper.SwitchToMainThreadAsync(); - - refreshSecondsEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteRefreshSeconds, "480"); - int refreshSeconds = refreshSecondsEntry.GetInt32(); - selectedRefreshTime = refreshTimes.Single(t => t.Value == refreshSeconds); - OnPropertyChanged(nameof(SelectedRefreshTime)); - ScheduleTaskHelper.RegisterForDailyNoteRefresh(refreshSeconds); - - reminderNotifyEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteReminderNotify, Core.StringLiterals.False); - isReminderNotification = reminderNotifyEntry.GetBoolean(); - OnPropertyChanged(nameof(IsReminderNotification)); - - silentModeEntry = appDbContext.Settings.SingleOrAdd(SettingEntry.DailyNoteSilentWhenPlayingGame, Core.StringLiterals.False); - isSilentWhenPlayingGame = silentModeEntry.GetBoolean(); - OnPropertyChanged(nameof(IsSilentWhenPlayingGame)); - } - - await ThreadHelper.SwitchToBackgroundAsync(); - ObservableCollection entries = await dailyNoteService.GetDailyNoteEntriesAsync().ConfigureAwait(false); - await ThreadHelper.SwitchToMainThreadAsync(); - DailyNoteEntries = entries; - } - catch (OperationCanceledException) - { - } } private async Task TrackRoleAsync(UserAndUid? role) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs index 6d83c0db..8522e433 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs @@ -171,11 +171,13 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel GameAccounts = accounts; // Sync uid - if (memoryCache.TryGetValue(DesiredUid, out object? value) && value is string uid) + if (memoryCache.TryRemove(DesiredUid, out object? value) && value is string uid) { SelectedGameAccount = GameAccounts.FirstOrDefault(g => g.AttachUid == uid); - memoryCache.Remove(DesiredUid); } + + // Try set to the current account. + SelectedGameAccount ??= gameService.DetectCurrentGameAccount(); } } catch (OperationCanceledException) diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs index 4e41ff53..03713791 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs @@ -65,6 +65,7 @@ internal readonly struct PlayerUid // CN >= '1' and <= '4' => "cn_gf01", // 国服 '5' => "cn_qd01", // 渠道 + // OS '6' => "os_usa", // 美服 '7' => "os_euro", // 欧服