2026-05-10 14:05:28 -04:00
|
|
|
using System.Windows.Input;
|
feat(ui): toast feedback for settings actions; refresh _NEXT.md
Adds a small auto-dismissing pill notification at the bottom-center of the participants area: 'Settings saved' on Apply Changes, 'Transcoder topology applied — restart Teams to take effect' after the one-click NDI groups setup. ToastViewModel owns its own DispatcherTimer and resets the dismissal countdown on successive calls, so the most recent message is always the one visible. Hooked into MainViewModel and threaded into GlobalSettingsViewModel via constructor injection.
_NEXT.md rewritten to reflect the May 2026 hardening pass: separates engine / UI / networking / Phase E.1 / diagnostics / CI / tests sections, lists every shipped item, and re-prioritizes the remaining work (Phase E.2-E.3 embedded Teams, code-signing the MSI, refresh-discovery affordance, output thumbnail previews, settings panel UX, auto-disable on departure, operator presets).
2026-05-09 09:30:04 -04:00
|
|
|
using System.Windows.Threading;
|
|
|
|
|
|
|
|
|
|
namespace TeamsISO.App.ViewModels;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Lightweight transient-notification view-model. The main view holds a single
|
|
|
|
|
/// instance bound to a small overlay at the bottom of the content area.
|
|
|
|
|
/// <see cref="Show"/> displays a message for a fixed duration before auto-hiding;
|
|
|
|
|
/// successive Show calls reset the timer instead of stacking, so the user always
|
|
|
|
|
/// sees the most recent action's feedback.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class ToastViewModel : ObservableObject
|
|
|
|
|
{
|
|
|
|
|
private readonly DispatcherTimer _hideTimer;
|
|
|
|
|
private string _message = string.Empty;
|
|
|
|
|
private bool _isVisible;
|
|
|
|
|
private string _accent = "Wd.Accent.Cyan";
|
|
|
|
|
|
|
|
|
|
public ToastViewModel(Dispatcher dispatcher)
|
|
|
|
|
{
|
|
|
|
|
_hideTimer = new DispatcherTimer(DispatcherPriority.Background, dispatcher)
|
|
|
|
|
{
|
|
|
|
|
Interval = TimeSpan.FromSeconds(3),
|
|
|
|
|
};
|
|
|
|
|
_hideTimer.Tick += (_, _) =>
|
|
|
|
|
{
|
|
|
|
|
_hideTimer.Stop();
|
|
|
|
|
IsVisible = false;
|
|
|
|
|
};
|
2026-05-10 14:05:28 -04:00
|
|
|
DismissCommand = new RelayCommand(Hide);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Manual dismiss. Stops the auto-hide timer and hides the toast
|
|
|
|
|
/// immediately. Bound to the X close button on the toast overlay so an
|
|
|
|
|
/// operator running a live show can clear visual clutter without waiting
|
|
|
|
|
/// 3 seconds.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ICommand DismissCommand { get; }
|
|
|
|
|
|
|
|
|
|
private void Hide()
|
|
|
|
|
{
|
|
|
|
|
_hideTimer.Stop();
|
|
|
|
|
IsVisible = false;
|
feat(ui): toast feedback for settings actions; refresh _NEXT.md
Adds a small auto-dismissing pill notification at the bottom-center of the participants area: 'Settings saved' on Apply Changes, 'Transcoder topology applied — restart Teams to take effect' after the one-click NDI groups setup. ToastViewModel owns its own DispatcherTimer and resets the dismissal countdown on successive calls, so the most recent message is always the one visible. Hooked into MainViewModel and threaded into GlobalSettingsViewModel via constructor injection.
_NEXT.md rewritten to reflect the May 2026 hardening pass: separates engine / UI / networking / Phase E.1 / diagnostics / CI / tests sections, lists every shipped item, and re-prioritizes the remaining work (Phase E.2-E.3 embedded Teams, code-signing the MSI, refresh-discovery affordance, output thumbnail previews, settings panel UX, auto-disable on departure, operator presets).
2026-05-09 09:30:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Message
|
|
|
|
|
{
|
|
|
|
|
get => _message;
|
|
|
|
|
private set => SetField(ref _message, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsVisible
|
|
|
|
|
{
|
|
|
|
|
get => _isVisible;
|
|
|
|
|
private set => SetField(ref _isVisible, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Brush resource key for the accent dot. "Wd.Accent.Cyan" for success-style
|
|
|
|
|
/// (default), "Wd.Accent.Coral" for warnings.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string Accent
|
|
|
|
|
{
|
|
|
|
|
get => _accent;
|
|
|
|
|
private set => SetField(ref _accent, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Show a success-style toast for ~3 seconds.</summary>
|
|
|
|
|
public void Show(string message) => ShowImpl(message, "Wd.Accent.Cyan");
|
|
|
|
|
|
|
|
|
|
/// <summary>Show a warning-style toast (coral accent) for ~3 seconds.</summary>
|
|
|
|
|
public void Warn(string message) => ShowImpl(message, "Wd.Accent.Coral");
|
|
|
|
|
|
|
|
|
|
private void ShowImpl(string message, string accentKey)
|
|
|
|
|
{
|
|
|
|
|
Message = message;
|
|
|
|
|
Accent = accentKey;
|
|
|
|
|
IsVisible = true;
|
|
|
|
|
_hideTimer.Stop();
|
|
|
|
|
_hideTimer.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|