From 17daacded2257886e5fdfdd56d4156afe27bd9bb Mon Sep 17 00:00:00 2001 From: Leon Zhou Date: Wed, 18 Dec 2024 11:45:23 +0800 Subject: [PATCH] Fixed a bug that can allow multiple instances to run in the background, and added buttons to toast notifications. --- App/App.csproj | 6 +++ App/App.xaml | 3 +- App/App.xaml.cs | 34 +++++++++++- App/Extensions/ToastNotificationExtensions.cs | 29 ++++++++++ App/NotificationType.cs | 10 ---- App/TrayIconWindow.xaml.cs | 54 +++++++------------ Pack/Package.appxmanifest | 20 ++++++- 7 files changed, 107 insertions(+), 49 deletions(-) create mode 100644 App/Extensions/ToastNotificationExtensions.cs delete mode 100644 App/NotificationType.cs diff --git a/App/App.csproj b/App/App.csproj index caa2c3b..f7e3c18 100644 --- a/App/App.csproj +++ b/App/App.csproj @@ -15,6 +15,12 @@ 10.0.22000.0 PerMonitorV2 AnyCPU;x64;ARM64;x86 + 2.1.1 + https://github.com/soleon/Percentage + https://github.com/soleon/Percentage?tab=MIT-1-ov-file + Icon.png + https://github.com/soleon/Percentage + git diff --git a/App/App.xaml b/App/App.xaml index a51e39c..ee4042f 100644 --- a/App/App.xaml +++ b/App/App.xaml @@ -2,8 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" - StartupUri="TrayIconWindow.xaml" - ShutdownMode="OnExplicitShutdown"> + StartupUri="TrayIconWindow.xaml"> diff --git a/App/App.xaml.cs b/App/App.xaml.cs index 3e96b72..fc6e209 100644 --- a/App/App.xaml.cs +++ b/App/App.xaml.cs @@ -1,8 +1,12 @@ using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; +using Microsoft.Toolkit.Uwp.Notifications; +using Percentage.App.Extensions; +using Percentage.App.Pages; using Wpf.Ui; using Wpf.Ui.Markup; using static Percentage.App.Properties.Settings; @@ -42,7 +46,13 @@ public App() { _appMutex = new Mutex(true, Id, out var isNewInstance); - if (!isNewInstance) Shutdown(1); + if (!isNewInstance) + { + Shutdown(1); + return; + } + + ShutdownMode = ShutdownMode.OnExplicitShutdown; DispatcherUnhandledException += (_, e) => HandleException(e.Exception); @@ -54,6 +64,28 @@ public App() // User settings migration for backward compatibility. MigrateUserSettings(); + + // Subscribe to toast notification activations. + ToastNotificationManagerCompat.OnActivated += async toastArgs => + { + if (ToastArguments.Parse(toastArgs.Argument).GetActionArgument() == + ToastNotificationExtensions.Action.ViewDetails) + await Dispatcher.InvokeAsync(() => ActivateMainWindow().NavigateToPage()); + }; + } + + internal static MainWindow ActivateMainWindow() + { + var window = Current.Windows.OfType().FirstOrDefault(); + if (window != null) + { + window.Activate(); + return window; + } + + window = new MainWindow(); + window.Show(); + return window; } internal static Exception GetTrayIconUpdateError() diff --git a/App/Extensions/ToastNotificationExtensions.cs b/App/Extensions/ToastNotificationExtensions.cs new file mode 100644 index 0000000..b572714 --- /dev/null +++ b/App/Extensions/ToastNotificationExtensions.cs @@ -0,0 +1,29 @@ +using Microsoft.Toolkit.Uwp.Notifications; + +namespace Percentage.App.Extensions; + +internal static class ToastNotificationExtensions +{ + private const string ActionArgumentKey = "action"; + + internal static Action GetActionArgument(this ToastArguments arguments) + { + return arguments.GetEnum(ActionArgumentKey); + } + + internal static void ShowToastNotification(string header, string body) + { + new ToastContentBuilder() + .AddText(header) + .AddText(body) + .AddButton(new ToastButton().SetContent("See more details") + .AddArgument(ActionArgumentKey, Action.ViewDetails)) + .AddButton(new ToastButtonDismiss()) + .Show(); + } + + internal enum Action + { + ViewDetails = 0 + } +} \ No newline at end of file diff --git a/App/NotificationType.cs b/App/NotificationType.cs deleted file mode 100644 index 1e1ce18..0000000 --- a/App/NotificationType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Percentage.App; - -internal enum NotificationType : byte -{ - None = 0, - Critical, - Low, - High, - Full -} \ No newline at end of file diff --git a/App/TrayIconWindow.xaml.cs b/App/TrayIconWindow.xaml.cs index 5630ecc..8cae1df 100644 --- a/App/TrayIconWindow.xaml.cs +++ b/App/TrayIconWindow.xaml.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using System.Linq; using System.Reactive.Linq; using System.Reactive.Subjects; using System.Windows; @@ -10,8 +9,8 @@ using System.Windows.Media.Imaging; using System.Windows.Threading; using Windows.Devices.Power; -using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Win32; +using Percentage.App.Extensions; using Percentage.App.Pages; using Wpf.Ui.Appearance; using Wpf.Ui.Markup; @@ -44,20 +43,6 @@ public TrayIconWindow() _refreshTimer.Tick += (_, _) => _batteryStatusUpdateSubject.OnNext(false); } - private static MainWindow ActivateMainWindow() - { - var window = Application.Current.Windows.OfType().FirstOrDefault(); - if (window != null) - { - window.Activate(); - return window; - } - - window = new MainWindow(); - window.Show(); - return window; - } - private static Brush GetBrushFromColourHexString(string hexString, Brush fallbackBrush) { object colour; @@ -121,12 +106,12 @@ private Brush GetTargetBrush(bool isUsingAutoColour, string targetColour, Brush private void OnAboutMenuItemClick(object sender, RoutedEventArgs e) { - ActivateMainWindow().NavigateToPage(); + App.ActivateMainWindow().NavigateToPage(); } private void OnDetailsMenuItemClick(object sender, RoutedEventArgs e) { - ActivateMainWindow().NavigateToPage(); + App.ActivateMainWindow().NavigateToPage(); } private void OnExitMenuItemClick(object sender, RoutedEventArgs e) @@ -138,7 +123,7 @@ private void OnLoaded(object sender, RoutedEventArgs args) { Visibility = Visibility.Collapsed; - if (!Default.HideAtStartup) ActivateMainWindow().NavigateToPage(); + if (!Default.HideAtStartup) App.ActivateMainWindow().NavigateToPage(); // Debounce calls to update battery status. // This should be the only place that calls the UpdateBatteryStatus method. @@ -173,12 +158,12 @@ private void OnLoaded(object sender, RoutedEventArgs args) private void OnNotifyIconLeftDoubleClick(NotifyIcon sender, RoutedEventArgs e) { - ActivateMainWindow().NavigateToPage(); + App.ActivateMainWindow().NavigateToPage(); } private void OnSettingsMenuItemClick(object sender, RoutedEventArgs e) { - ActivateMainWindow().NavigateToPage(); + App.ActivateMainWindow().NavigateToPage(); } private void OnUserSettingsPropertyChanged(string propertyName) @@ -401,21 +386,22 @@ void CheckAndSendNotification() return; var utcNow = DateTime.UtcNow; - if (_lastNotification.Type != notificationType) - // Notification required, and battery status has changed from last notification, notify user. - new ToastContentBuilder() - .AddText(_notificationTitle) - .AddText(_notificationText) - .Show(); - else if (utcNow - _lastNotification.DateTime > TimeSpan.FromMinutes(5)) - // Notification required, but battery status is the same as last notification for more than 5 minutes, - // notify user. - new ToastContentBuilder() - .AddText(_notificationTitle) - .AddText(_notificationText) - .Show(); + if (_lastNotification.Type != notificationType || + utcNow - _lastNotification.DateTime > TimeSpan.FromMinutes(5)) + // Notification is required if the existing notification type is different from the previous one or + // battery status is the same, but it has been more than 5 minutes since the last notification was shown. + ToastNotificationExtensions.ShowToastNotification(_notificationTitle, _notificationText); _lastNotification = (notificationType, utcNow); } } + + private enum NotificationType : byte + { + None = 0, + Critical, + Low, + High, + Full + } } \ No newline at end of file diff --git a/Pack/Package.appxmanifest b/Pack/Package.appxmanifest index b1eed6c..9471b84 100644 --- a/Pack/Package.appxmanifest +++ b/Pack/Package.appxmanifest @@ -4,13 +4,15 @@ xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" + xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" + xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" - IgnorableNamespaces="uap rescap"> + IgnorableNamespaces="uap rescap com desktop"> + Version="2.1.1.0" /> Battery Percentage Icon @@ -47,6 +49,20 @@ Enabled="true" DisplayName="Battery Percentage Icon" /> + + + + + + + + + + + + + +