Toasts: non-blocking notifications replace MessageBoxes + log-only failures (TASK 24)
This commit is contained in:
+23
-13
@@ -96,6 +96,10 @@ public class MainViewModel : ViewModelBase
|
||||
private DispatcherTimer? _saveDebounce;
|
||||
private bool _isLoading;
|
||||
|
||||
// Toasts (TASK 24): non-blocking user-facing messages. Parameterless ctor
|
||||
// news up the real service; the VM is built from XAML so no DI seam exists.
|
||||
private readonly INotificationService _notifications = new NotificationService();
|
||||
|
||||
// Webcam: one camera input app-wide. The identity (DeviceId) lives on the
|
||||
// Webcam entity; each scene that shows the webcam has a WebcamSceneConfig
|
||||
// (webcam.{scene}.config). CameraManager still owns the single session.
|
||||
@@ -1593,6 +1597,8 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
TokenStore.Clear();
|
||||
AppLog.Write("Saved session could not be refreshed; signed out");
|
||||
_notifications.Info("Signed out of YouTube",
|
||||
"The saved session expired — sign in again when you next go live.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1656,6 +1662,8 @@ public class MainViewModel : ViewModelBase
|
||||
_layoutStore.SaveIsPremium(false);
|
||||
_layoutStore.SaveLicenseValidatedAt(DateTime.UtcNow);
|
||||
AppLog.Write($"License validation failed: {result.Error}");
|
||||
_notifications.Warning("Premium is no longer active",
|
||||
$"{result.Error} — watermark branding returns until the license is renewed.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -2594,9 +2602,8 @@ public class MainViewModel : ViewModelBase
|
||||
var started = await _cameraManager.AcquireAsync(_webcam.DeviceId);
|
||||
if (!started)
|
||||
{
|
||||
MessageBox.Show(
|
||||
WebcamError ?? "Couldn't start that camera. It may be in use by another app, or Windows camera access may be turned off.",
|
||||
"LlamaCasty", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
_notifications.Warning("Camera unavailable",
|
||||
WebcamError ?? "Couldn't start that camera. It may be in use by another app, or Windows camera access may be turned off.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2618,9 +2625,8 @@ public class MainViewModel : ViewModelBase
|
||||
var started = await _cameraManager.AcquireAsync(device.Id);
|
||||
if (!started)
|
||||
{
|
||||
MessageBox.Show(
|
||||
WebcamError ?? "Couldn't start that camera. It may be in use by another app, or Windows camera access may be turned off.",
|
||||
"LlamaCasty", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
_notifications.Warning("Camera unavailable",
|
||||
WebcamError ?? "Couldn't start that camera. It may be in use by another app, or Windows camera access may be turned off.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2707,7 +2713,7 @@ public class MainViewModel : ViewModelBase
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private static byte[]? PickImageBytes(string title)
|
||||
private byte[]? PickImageBytes(string title)
|
||||
{
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
@@ -2721,8 +2727,7 @@ public class MainViewModel : ViewModelBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Couldn't read that image: {ex.Message}", "LlamaCasty",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
_notifications.Warning("Couldn't read that image", ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -2889,8 +2894,7 @@ public class MainViewModel : ViewModelBase
|
||||
var channel = await Task.Run(() => _youtubeAuth.AuthenticateAsync());
|
||||
if (channel == null)
|
||||
{
|
||||
MessageBox.Show("Sign-in was unsuccessful. Please try again.", "LlamaCasty",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
_notifications.Warning("Sign-in was unsuccessful", "Please try again.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2900,8 +2904,7 @@ public class MainViewModel : ViewModelBase
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Sign-in failed: {ex.Message}", "LlamaCasty",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
_notifications.Error("Sign-in failed", ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -2985,6 +2988,8 @@ public class MainViewModel : ViewModelBase
|
||||
if (stream == null)
|
||||
{
|
||||
AppLog.Write("Reusable stream unavailable; check the OAuth session");
|
||||
_notifications.Error("Couldn't go live",
|
||||
"The reusable stream is unavailable — check the YouTube sign-in and try again.");
|
||||
StreamStatus = StreamStatus.Error;
|
||||
return;
|
||||
}
|
||||
@@ -2997,6 +3002,7 @@ public class MainViewModel : ViewModelBase
|
||||
if (_currentBroadcastId == null)
|
||||
{
|
||||
AppLog.Write("Broadcast creation failed; check the OAuth session");
|
||||
_notifications.Error("Couldn't go live", "YouTube rejected the broadcast — check the sign-in and try again.");
|
||||
StreamStatus = StreamStatus.Error;
|
||||
return;
|
||||
}
|
||||
@@ -3026,6 +3032,7 @@ public class MainViewModel : ViewModelBase
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLog.Write($"Go-live preparation failed: {ex.Message}");
|
||||
_notifications.Error("Couldn't go live", ex.Message);
|
||||
StreamStatus = StreamStatus.Error;
|
||||
return;
|
||||
}
|
||||
@@ -3159,6 +3166,8 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
MicStatus = MicStatus.NotConnected;
|
||||
AppLog.Write("Mic: no capture devices found — mic capture not started");
|
||||
_notifications.Warning("No microphone found",
|
||||
"Mic capture wasn't started — plug one in and pick it from the mixer.");
|
||||
return;
|
||||
}
|
||||
_audioMixer.Start();
|
||||
@@ -3333,6 +3342,7 @@ public class MainViewModel : ViewModelBase
|
||||
private void OnFramePumpFailed(object? sender, string message)
|
||||
{
|
||||
AppLog.Write($"Frame pump failed: {message}");
|
||||
_notifications.Error("The stream pipeline stopped", message);
|
||||
if (IsLive) StreamStatus = StreamStatus.Error;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user