mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
1 Commits
1.10.7
...
feat/notif
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca54faed2d |
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.Notifications;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Win32;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
@@ -14,6 +15,8 @@ namespace Snap.Hutao.Core;
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class RuntimeOptions
|
||||
{
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
private readonly Lazy<(Version Version, string UserAgent)> lazyVersionAndUserAgent = new(() =>
|
||||
{
|
||||
Version version = Package.Current.Id.Version.ToVersion();
|
||||
@@ -83,8 +86,14 @@ internal sealed class RuntimeOptions
|
||||
private readonly Lazy<string> lazyInstalledLocation = new(() => Package.Current.InstalledLocation.Path);
|
||||
private readonly Lazy<string> lazyFamilyName = new(() => Package.Current.Id.FamilyName);
|
||||
|
||||
public RuntimeOptions(ILogger<RuntimeOptions> logger)
|
||||
private bool isToastAvailable;
|
||||
private bool isToastAvailableInitialized;
|
||||
private object locker = new();
|
||||
|
||||
public RuntimeOptions(IServiceProvider serviceProvider, ILogger<RuntimeOptions> logger)
|
||||
{
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
AppLaunchTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
@@ -108,5 +117,19 @@ internal sealed class RuntimeOptions
|
||||
|
||||
public bool IsElevated { get => lazyElevated.Value; }
|
||||
|
||||
public bool IsToastAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(ref isToastAvailable, ref isToastAvailableInitialized, ref locker, () =>
|
||||
{
|
||||
return serviceProvider.GetRequiredService<ITaskContext>().InvokeOnMainThread(() =>
|
||||
{
|
||||
return ToastNotificationManagerCompat.CreateToastNotifier().Setting is Windows.UI.Notifications.NotificationSetting.Enabled;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public DateTimeOffset AppLaunchTime { get; }
|
||||
}
|
||||
@@ -48,4 +48,45 @@ internal static class DispatcherQueueExtension
|
||||
exceptionDispatchInfo?.Throw();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在调度器队列同步调用,直到执行结束,会持续阻塞当前线程
|
||||
/// </summary>
|
||||
/// <param name="dispatcherQueue">调度器队列</param>
|
||||
/// <param name="action">执行的回调</param>
|
||||
/// <typeparam name="T">返回类型</typeparam>
|
||||
/// <returns>回调返回值</returns>
|
||||
public static T Invoke<T>(this DispatcherQueue dispatcherQueue, Func<T> action)
|
||||
{
|
||||
T result = default!;
|
||||
|
||||
if (dispatcherQueue.HasThreadAccess)
|
||||
{
|
||||
return action();
|
||||
}
|
||||
|
||||
ExceptionDispatchInfo? exceptionDispatchInfo = null;
|
||||
using (ManualResetEventSlim blockEvent = new(false))
|
||||
{
|
||||
dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
result = action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
blockEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
blockEvent.Wait();
|
||||
exceptionDispatchInfo?.Throw();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ internal interface ITaskContext
|
||||
|
||||
void InvokeOnMainThread(Action action);
|
||||
|
||||
T InvokeOnMainThread<T>(Func<T> action);
|
||||
|
||||
ThreadPoolSwitchOperation SwitchToBackgroundAsync();
|
||||
|
||||
DispatcherQueueSwitchOperation SwitchToMainThreadAsync();
|
||||
|
||||
@@ -44,6 +44,12 @@ internal sealed class TaskContext : ITaskContext, ITaskContextUnsafe
|
||||
dispatcherQueue.Invoke(action);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T InvokeOnMainThread<T>(Func<T> action)
|
||||
{
|
||||
return dispatcherQueue.Invoke(action);
|
||||
}
|
||||
|
||||
public void BeginInvokeOnMainThread(Action action)
|
||||
{
|
||||
dispatcherQueue.TryEnqueue(() => action());
|
||||
|
||||
@@ -27,9 +27,15 @@ internal sealed partial class DailyNoteNotificationOperation
|
||||
private readonly IGameServiceFacade gameService;
|
||||
private readonly BindingClient bindingClient;
|
||||
private readonly DailyNoteOptions options;
|
||||
private readonly RuntimeOptions runtimeOptions;
|
||||
|
||||
public async ValueTask SendAsync(DailyNoteEntry entry)
|
||||
{
|
||||
if (!runtimeOptions.IsToastAvailable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.DailyNote is null)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -492,19 +492,34 @@
|
||||
</StackPanel>
|
||||
</cwc:HeaderedContentControl>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageDailyNoteNotificationHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
Description="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsSilentWhenPlayingGame, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard
|
||||
Description="{shcm:ResourceString Name=ViewPageDailyNoteReminderDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageDailyNoteReminderHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsReminderNotification, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:HeaderedContentControl
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
IsEnabled="{Binding RuntimeOptions.IsToastAvailable}">
|
||||
<cwc:HeaderedContentControl.Header>
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageDailyNoteNotificationHeader}"/>
|
||||
</cwc:HeaderedContentControl.Header>
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<InfoBar
|
||||
Title="胡桃的通知权限已被关闭"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
Severity="Warning"
|
||||
Visibility="{Binding RuntimeOptions.IsToastAvailable, Converter={StaticResource BoolToVisibilityRevertConverter}}"/>
|
||||
<cwc:SettingsCard
|
||||
Description="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageDailyNoteSlientModeHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsSilentWhenPlayingGame, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard
|
||||
Description="{shcm:ResourceString Name=ViewPageDailyNoteReminderDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageDailyNoteReminderHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}">
|
||||
<ToggleSwitch Margin="24,0,0,0" IsOn="{Binding DailyNoteOptions.IsReminderNotification, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
</StackPanel>
|
||||
</cwc:HeaderedContentControl>
|
||||
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageDailyNoteDataInteropHeader}"/>
|
||||
<cwc:SettingsCard
|
||||
|
||||
Reference in New Issue
Block a user