Files
LlamaCasty/ViewModels/MainViewModel.Settings.cs
T
gramps 9c0c40c688 feat(settings): make slide-out alerts persist until dismissed
Add a persisted global App Settings switch. Off keeps the existing per-severity
lifetimes (errors remain sticky); on makes every alert non-expiring and closes
it when its body is clicked. The NotificationService supplies the current
setting to each toast request.

StickyNotificationIntegrationTests covers persistence and both request modes.
618 tests green, clean build with 0 warnings.

Reference: Notification.Wpf exposes a CloseOnClick request option:
https://github.com/G-Stas/Notification.Wpf
2026-11-11 10:19:20 -08:00

85 lines
3.0 KiB
C#

using System.Windows;
using Notification.Core;
namespace ytLive.ViewModels;
/// <summary>
/// App Settings as a right-edge drawer (creator ruling 2026-11-01): the gear rail tab opens it
/// immediately, in the same exclusive-slide pattern as Stream Settings / YPP / Socials / TEST.
///
/// <para>It is a separate flag from <see cref="IsSettingsOpen"/> because the overlay shell now
/// only carries Report Bug / Feature Request / About — settings stopped being a modal.</para>
/// </summary>
public partial class MainViewModel
{
private bool _settingsDrawerOpen;
private NotificationPosition _toastPosition = NotificationPosition.BottomRight;
private bool _stickyAlertsUntilDismissed;
public bool StickyAlertsUntilDismissed
{
get => _stickyAlertsUntilDismissed;
set
{
if (!SetProperty(ref _stickyAlertsUntilDismissed, value)) return;
_layoutStore.SaveStickyAlertsUntilDismissed(value);
}
}
public NotificationPosition ToastPosition
{
get => _toastPosition;
set
{
if (!IsSupportedToastPosition(value) || !SetProperty(ref _toastPosition, value)) return;
_layoutStore.SaveNotificationPosition(value);
OnPropertyChanged(nameof(ToastAreaMargin));
}
}
public Thickness ToastAreaMargin => ToastPosition switch
{
NotificationPosition.TopLeft => new Thickness(12, 12, 0, 0),
NotificationPosition.TopRight => new Thickness(0, 12, 12, 0),
NotificationPosition.CenterLeft => new Thickness(12, 0, 0, 0),
NotificationPosition.CenterRight => new Thickness(0, 0, 12, 0),
NotificationPosition.BottomLeft => new Thickness(12, 0, 0, 96),
_ => new Thickness(0, 0, 12, 96),
};
private static bool IsSupportedToastPosition(NotificationPosition position)
=> position is NotificationPosition.TopLeft or NotificationPosition.TopRight
or NotificationPosition.CenterLeft or NotificationPosition.CenterRight
or NotificationPosition.BottomLeft or NotificationPosition.BottomRight;
public bool SettingsDrawerOpen
{
get => _settingsDrawerOpen;
private set => SetProperty(ref _settingsDrawerOpen, value);
}
internal void ToggleSettingsDrawer()
{
if (_settingsDrawerOpen)
{
SettingsDrawerOpen = false;
return;
}
// One drawer at a time, like the rail's other tabs.
BroadcastForm.IsDrawerOpen = false;
Ypp.IsDrawerOpen = false;
TestSession.IsDrawerOpen = false;
if (SocialsDrawerOpen) CloseSocialsDrawer();
SettingsDrawerOpen = true;
}
/// <summary>Called by the other drawers when they open, so settings yields to them — and by the
/// window's click-outside guard, so the gear tab retracts like every other drawer (2026-11-05).</summary>
internal void CloseSettingsDrawerIfOpen()
{
if (_settingsDrawerOpen) SettingsDrawerOpen = false;
}
}