mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Launch Game QoL
This commit is contained in:
30
src/Snap.Hutao/Snap.Hutao/Extension/MemoryCacheExtension.cs
Normal file
30
src/Snap.Hutao/Snap.Hutao/Extension/MemoryCacheExtension.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -92,4 +92,10 @@ internal interface IGameService
|
||||
/// <param name="scheme">方案</param>
|
||||
/// <returns>是否更改了ini文件</returns>
|
||||
bool SetMultiChannel(LaunchScheme scheme);
|
||||
|
||||
/// <summary>
|
||||
/// 检测账号
|
||||
/// </summary>
|
||||
/// <returns>账号</returns>
|
||||
GameAccount? DetectCurrentGameAccount();
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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=}">
|
||||
<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=}">
|
||||
<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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -65,6 +65,7 @@ internal readonly struct PlayerUid
|
||||
// CN
|
||||
>= '1' and <= '4' => "cn_gf01", // 国服
|
||||
'5' => "cn_qd01", // 渠道
|
||||
|
||||
// OS
|
||||
'6' => "os_usa", // 美服
|
||||
'7' => "os_euro", // 欧服
|
||||
|
||||
Reference in New Issue
Block a user