Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions src/UniGetUI.Avalonia/Infrastructure/MacOsNotificationBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static bool ShowProgress(AbstractOperation operation)
string message = operation.Metadata.Status.Length > 0
? operation.Metadata.Status
: CoreTools.Translate("Please wait...");
DeliverNotification(title, message);
DeliverNotification(title, message, MainWindow.RuntimeNotificationLevel.Progress, allowInAppFallback: false);
return true;
}
catch (Exception ex)
Expand All @@ -57,7 +57,7 @@ public static bool ShowSuccess(AbstractOperation operation)
string message = operation.Metadata.SuccessMessage.Length > 0
? operation.Metadata.SuccessMessage
: CoreTools.Translate("Success!");
DeliverNotification(title, message);
DeliverNotification(title, message, MainWindow.RuntimeNotificationLevel.Success, allowInAppFallback: false);
return true;
}
catch (Exception ex)
Expand All @@ -79,7 +79,7 @@ public static bool ShowError(AbstractOperation operation)
string message = operation.Metadata.FailureMessage.Length > 0
? operation.Metadata.FailureMessage
: CoreTools.Translate("An error occurred while processing this package");
DeliverNotification(title, message);
DeliverNotification(title, message, MainWindow.RuntimeNotificationLevel.Error, allowInAppFallback: false);
return true;
}
catch (Exception ex)
Expand Down Expand Up @@ -109,7 +109,7 @@ public static void ShowUpdatesAvailableNotification(IReadOnlyList<IPackage> upgr
title = CoreTools.Translate("Updates found!");
message = CoreTools.Translate("{0} packages can be updated", upgradable.Count);
}
DeliverNotification(title, message);
DeliverNotification(title, message, MainWindow.RuntimeNotificationLevel.Success);
}
catch (Exception ex)
{
Expand All @@ -135,7 +135,7 @@ public static void ShowUpgradingPackagesNotification(IReadOnlyList<IPackage> upg
title = CoreTools.Translate("{0} packages are being updated", upgradable.Count);
message = string.Join(", ", upgradable.Select(p => p.Name));
}
DeliverNotification(title, message);
DeliverNotification(title, message, MainWindow.RuntimeNotificationLevel.Progress);
}
catch (Exception ex)
{
Expand All @@ -150,7 +150,8 @@ public static void ShowSelfUpdateAvailableNotification(string newVersion)
{
DeliverNotification(
CoreTools.Translate("{0} can be updated to version {1}", "UniGetUI", newVersion),
CoreTools.Translate("You have currently version {0} installed", CoreData.VersionName));
CoreTools.Translate("You have currently version {0} installed", CoreData.VersionName),
MainWindow.RuntimeNotificationLevel.Success);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -179,7 +180,7 @@ public static void ShowNewShortcutsNotification(IReadOnlyList<string> shortcuts)
"UniGetUI has detected {0} new desktop shortcuts that can be deleted automatically.",
shortcuts.Count);
}
DeliverNotification(title, message);
DeliverNotification(title, message, MainWindow.RuntimeNotificationLevel.Success);
}
catch (Exception ex)
{
Expand All @@ -190,8 +191,20 @@ public static void ShowNewShortcutsNotification(IReadOnlyList<string> shortcuts)

// ── Core delivery ──────────────────────────────────────────────────────

private static void DeliverNotification(string title, string message)
private static void DeliverNotification(
string title,
string message,
MainWindow.RuntimeNotificationLevel level,
bool allowInAppFallback = true)
{
if (MainWindow.IsWindowOnScreen)
{
if (allowInAppFallback)
Dispatcher.UIThread.Post(() =>
MainWindow.Instance?.ShowRuntimeNotification(title, message, level));
return;
}

if (!EnsureInitialized())
throw new InvalidOperationException("The macOS notification bridge is unavailable.");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,10 @@
bool allowInAppFallback = true)
{
#if WINDOWS
if (OperatingSystem.IsWindows() && Win32ToastNotifier.IsAvailable())
// Only fire an OS toast when the app is out of sight (minimized or hidden to the tray).
// While the window is on screen the user can already see the operations panel / in-app
// toast, so a native toast would just be noise; fall through to the in-app path instead.
if (OperatingSystem.IsWindows() && !MainWindow.IsWindowOnScreen && Win32ToastNotifier.IsAvailable())
{
string launchArg = BuildLaunchArgument(launchAction);
if (Win32ToastNotifier.Show(title, message, launchArg))
Expand Down Expand Up @@ -299,6 +302,6 @@
return true;
}

private static string BuildLaunchArgument(string action)

Check warning on line 305 in src/UniGetUI.Avalonia/Infrastructure/WindowsAppNotificationBridge.cs

View workflow job for this annotation

GitHub Actions / Linux (NativeAOT)

Private member 'WindowsAppNotificationBridge.BuildLaunchArgument' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)

Check warning on line 305 in src/UniGetUI.Avalonia/Infrastructure/WindowsAppNotificationBridge.cs

View workflow job for this annotation

GitHub Actions / Linux (Avalonia)

Private member 'WindowsAppNotificationBridge.BuildLaunchArgument' is unused (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0051)
=> $"unigetui://{action}";
}
11 changes: 10 additions & 1 deletion src/UniGetUI.Avalonia/Views/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public enum RuntimeNotificationLevel

public static MainWindow? Instance { get; private set; }

// True while the window is on screen (visible and not minimized). Read from any thread by
// the notification bridge to suppress OS toasts while the user is looking at the app.
private static volatile bool _isOnScreen;
public static bool IsWindowOnScreen => _isOnScreen;

private MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext!;
public PageType CurrentPage => ViewModel.CurrentPage_t;

Expand All @@ -136,7 +141,8 @@ public MainWindow()

Resized += (_, _) => _ = SaveGeometryAsync();
PositionChanged += (_, _) => _ = SaveGeometryAsync();
this.GetObservable(WindowStateProperty).SubscribeValue(state => { _ = SaveGeometryAsync(); });
this.GetObservable(WindowStateProperty).SubscribeValue(state => { UpdateOnScreenState(); _ = SaveGeometryAsync(); });
this.GetObservable(IsVisibleProperty).SubscribeValue(_ => UpdateOnScreenState());

_trayService = new TrayService(this);
_trayService.UpdateStatus();
Expand Down Expand Up @@ -1362,6 +1368,9 @@ private void Toast_PointerExited(object? sender, PointerEventArgs e)

public void UpdateSystemTrayStatus() => _trayService?.UpdateStatus();

private void UpdateOnScreenState()
=> _isOnScreen = IsVisible && WindowState != WindowState.Minimized;

public void ShowRuntimeNotification(string title, string message, RuntimeNotificationLevel level) =>
ShowBanner(title, message, level);

Expand Down
Loading