Launch Game QoL

This commit is contained in:
DismissedLight
2023-04-04 18:44:19 +08:00
parent 79118cdb4d
commit 179b78ca83
9 changed files with 143 additions and 116 deletions

View File

@@ -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;
/// <summary>
/// 内存缓存拓展
/// </summary>
internal static class MemoryCacheExtension
{
/// <summary>
/// 尝试从 IMemoryCache 中移除并返回具有指定键的值
/// </summary>
/// <param name="memoryCache">缓存</param>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>是否移除成功</returns>
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;
}
}

View File

@@ -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<NameValue<int>> refreshTimes = new()
{
new(SH.ViewModelDailyNoteRefreshTime4, 240),
new(SH.ViewModelDailyNoteRefreshTime8, 480),
new(SH.ViewModelDailyNoteRefreshTime30, 1800),
new(SH.ViewModelDailyNoteRefreshTime40, 2400),
new(SH.ViewModelDailyNoteRefreshTime60, 3600),
};
private NameValue<int>? selectedRefreshTime;
private bool? isReminderNotification;
private bool? isSilentWhenPlayingGame;
/// <summary>
/// 构造一个新的实时便笺选项
/// </summary>
/// <param name="serviceScopeFactory">服务范围工厂</param>
public DailyNoteOptions(IServiceScopeFactory serviceScopeFactory)
: base(serviceScopeFactory)
/// <param name="serviceProvider">服务提供器</param>
public DailyNoteOptions(IServiceProvider serviceProvider)
: base(serviceProvider.GetRequiredService<IServiceScopeFactory>())
{
this.serviceProvider = serviceProvider;
}
/// <summary>
/// 刷新时间
/// </summary>
public List<NameValue<int>> RefreshTimes { get => refreshTimes; }
/// <summary>
/// 选中的刷新时间
/// </summary>
public NameValue<int>? 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<IInfoBarService>().Warning(SH.ViewModelDailyNoteRegisterTaskFail);
}
}
}
}
/// <summary>
/// 提醒式通知
/// </summary>
public bool IsReminderNotification
{
get => GetOption(ref isReminderNotification, SettingEntry.DailyNoteReminderNotify);
set => SetOption(ref isReminderNotification, SettingEntry.DailyNoteReminderNotify, value);
}
/// <summary>
/// 是否开启免打扰模式
/// </summary>
public bool IsSilentWhenPlayingGame
{
get => GetOption(ref isSilentWhenPlayingGame, SettingEntry.DailyNoteSilentWhenPlayingGame);
set => SetOption(ref isSilentWhenPlayingGame, SettingEntry.DailyNoteSilentWhenPlayingGame, value);
}
}

View File

@@ -368,6 +368,28 @@ internal sealed class GameService : IGameService
}
}
/// <inheritdoc/>
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;
}
/// <inheritdoc/>
public bool SetGameAccount(GameAccount account)
{

View File

@@ -92,4 +92,10 @@ internal interface IGameService
/// <param name="scheme">方案</param>
/// <returns>是否更改了ini文件</returns>
bool SetMultiChannel(LaunchScheme scheme);
/// <summary>
/// 检测账号
/// </summary>
/// <returns>账号</returns>
GameAccount? DetectCurrentGameAccount();
}

View File

@@ -148,7 +148,7 @@ internal sealed class LaunchOptions : DbStoreOptions
public NameValue<int> 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");
}
/// <summary>

View File

@@ -85,7 +85,7 @@
<AppBarButton.Flyout>
<Flyout Placement="BottomEdgeAlignedRight">
<StackPanel>
<RadioButtons ItemsSource="{Binding RefreshTimes}" SelectedItem="{Binding SelectedRefreshTime, Mode=TwoWay}">
<RadioButtons ItemsSource="{Binding Options.RefreshTimes}" SelectedItem="{Binding Options.SelectedRefreshTime, Mode=TwoWay}">
<RadioButtons.Header>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageDailyNoteRefreshTime}"/>
</RadioButtons.Header>
@@ -106,13 +106,13 @@
Description="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeDescription}"
Header="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xE7ED;}">
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding IsSilentWhenPlayingGame, Mode=TwoWay}"/>
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding Options.IsSilentWhenPlayingGame, Mode=TwoWay}"/>
</clw:SettingsCard>
<clw:SettingsCard
Description="{shcm:ResourceString Name=ViewPageDailyNoteReminderDescription}"
Header="{shcm:ResourceString Name=ViewPageDailyNoteReminderHeader}"
HeaderIcon="{shcm:FontIcon Glyph=&#xEA8F;}">
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding IsReminderNotification, Mode=TwoWay}"/>
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding Options.IsReminderNotification, Mode=TwoWay}"/>
</clw:SettingsCard>
</StackPanel>
</StackPanel>

View File

@@ -28,24 +28,8 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel
private readonly IDailyNoteService dailyNoteService;
private readonly AppDbContext appDbContext;
private readonly List<NameValue<int>> 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<int>? selectedRefreshTime;
private ObservableCollection<UserAndUid>? userAndUids;
private SettingEntry? refreshSecondsEntry;
private SettingEntry? reminderNotifyEntry;
private SettingEntry? silentModeEntry;
private ObservableCollection<DailyNoteEntry>? dailyNoteEntries;
private bool isSilentWhenPlayingGame;
/// <summary>
/// 构造一个新的实时便笺视图模型
@@ -56,6 +40,7 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel
userService = serviceProvider.GetRequiredService<IUserService>();
dailyNoteService = serviceProvider.GetRequiredService<IDailyNoteService>();
appDbContext = serviceProvider.GetRequiredService<AppDbContext>();
Options = serviceProvider.GetRequiredService<DailyNoteOptions>();
this.serviceProvider = serviceProvider;
TrackRoleCommand = new AsyncRelayCommand<UserAndUid>(TrackRoleAsync);
@@ -66,67 +51,9 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel
}
/// <summary>
/// 刷新时间
/// 选项
/// </summary>
public List<NameValue<int>> RefreshTimes { get => refreshTimes; }
/// <summary>
/// 选中的刷新时间
/// </summary>
public NameValue<int>? SelectedRefreshTime
{
get => selectedRefreshTime;
set
{
if (SetProperty(ref selectedRefreshTime, value))
{
if (value != null)
{
if (!ScheduleTaskHelper.RegisterForDailyNoteRefresh(value.Value))
{
serviceProvider.GetRequiredService<IInfoBarService>().Warning(SH.ViewModelDailyNoteRegisterTaskFail);
}
else
{
refreshSecondsEntry!.SetInt32(value.Value);
appDbContext.Settings.UpdateAndSave(refreshSecondsEntry!);
}
}
}
}
}
/// <summary>
/// 提醒式通知
/// </summary>
public bool IsReminderNotification
{
get => isReminderNotification;
set
{
if (SetProperty(ref isReminderNotification, value))
{
reminderNotifyEntry!.SetBoolean(value);
appDbContext.Settings.UpdateAndSave(reminderNotifyEntry!);
}
}
}
/// <summary>
/// 是否开启免打扰模式
/// </summary>
public bool IsSilentWhenPlayingGame
{
get => isSilentWhenPlayingGame;
set
{
if (SetProperty(ref isSilentWhenPlayingGame, value))
{
silentModeEntry!.SetBoolean(value);
appDbContext.Settings.UpdateAndSave(silentModeEntry!);
}
}
}
public DailyNoteOptions Options { get; }
/// <summary>
/// 用户与角色集合
@@ -168,43 +95,19 @@ internal sealed class DailyNoteViewModel : Abstraction.ViewModel
{
try
{
UserAndUids = await userService.GetRoleCollectionAsync().ConfigureAwait(true);
await ThreadHelper.SwitchToBackgroundAsync();
ObservableCollection<UserAndUid> roles = await userService.GetRoleCollectionAsync().ConfigureAwait(false);
ObservableCollection<DailyNoteEntry> entries = await dailyNoteService.GetDailyNoteEntriesAsync().ConfigureAwait(false);
await ThreadHelper.SwitchToMainThreadAsync();
UserAndUids = roles;
DailyNoteEntries = entries;
}
catch (Core.ExceptionService.UserdataCorruptedException ex)
{
serviceProvider.GetRequiredService<IInfoBarService>().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<DailyNoteEntry> entries = await dailyNoteService.GetDailyNoteEntriesAsync().ConfigureAwait(false);
await ThreadHelper.SwitchToMainThreadAsync();
DailyNoteEntries = entries;
}
catch (OperationCanceledException)
{
}
}
private async Task TrackRoleAsync(UserAndUid? role)

View File

@@ -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)

View File

@@ -65,6 +65,7 @@ internal readonly struct PlayerUid
// CN
>= '1' and <= '4' => "cn_gf01", // 国服
'5' => "cn_qd01", // 渠道
// OS
'6' => "os_usa", // 美服
'7' => "os_euro", // 欧服