Some checks failed
CI / build-and-test (push) Failing after 29s
- Rename solution files: TeamsISO.sln/slnf -> Dragon-ISO.sln/slnf - Rename all src/TeamsISO.* directories and project files to src/Dragon-ISO.* equivalents - Update .gitignore to exclude build/test output logs - Update ci.yml, CHANGELOG.md, build-and-test.ps1, docs references Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
149 lines
5.9 KiB
C#
149 lines
5.9 KiB
C#
using DragonISO.App.Services;
|
|
|
|
namespace DragonISO.App.ViewModels;
|
|
|
|
// Bulk operations that touch every (or every-enabled) participant —
|
|
// Stop all ISOs, Enable all online, Snapshot all enabled frames.
|
|
// Split out of MainViewModel.cs so the main file isn't dominated by
|
|
// long async iteration loops.
|
|
//
|
|
// The RecordingCommands partial originally planned at this slot is
|
|
// intentionally absent: the recording surface was axed earlier in the
|
|
// May 2026 batch (see commit 1d1ce6a). What remains is bulk-state
|
|
// manipulation across the participants collection.
|
|
public sealed partial class MainViewModel
|
|
{
|
|
/// <summary>
|
|
/// Enable ISOs for every online + non-enabled participant in
|
|
/// parallel-ish (sequential await, but each individual EnableIsoAsync
|
|
/// is fast). Tolerates per-participant failures so one bad source
|
|
/// doesn't abort the rest.
|
|
/// </summary>
|
|
private async Task EnableAllOnlineAsync()
|
|
{
|
|
var candidates = Participants.Where(p => p.IsOnline && !p.IsEnabled).ToArray();
|
|
var enabled = 0;
|
|
foreach (var p in candidates)
|
|
{
|
|
try
|
|
{
|
|
var resolvedName = string.IsNullOrWhiteSpace(p.CustomName)
|
|
? OutputNameTemplate.Render(
|
|
OutputNameTemplate.Get(),
|
|
p.Id,
|
|
p.DisplayName)
|
|
: p.CustomName;
|
|
// 3-arg overload (no recordOverride) — recording surface axed,
|
|
// so the engine's per-pipeline recorder sink stays unattached.
|
|
await _controller.EnableIsoAsync(p.Id, resolvedName, CancellationToken.None);
|
|
p.IsEnabled = true;
|
|
enabled++;
|
|
}
|
|
catch
|
|
{
|
|
// Per-participant best-effort — one bad source shouldn't
|
|
// abort the bulk operation.
|
|
}
|
|
}
|
|
Toast.Show(enabled == 0
|
|
? "No participants to enable"
|
|
: $"Enabled {enabled} ISO(s)");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emergency-stop: disable every running ISO. Confirmation dialog with
|
|
/// default-No guards mid-show misclicks; the regret cost of yanking 5
|
|
/// ISOs is far higher than the Enter-press cost of the prompt.
|
|
/// </summary>
|
|
private async Task StopAllIsosAsync()
|
|
{
|
|
// Snapshot first so the collection doesn't mutate while we iterate.
|
|
var enabled = Participants.Where(p => p.IsEnabled).ToArray();
|
|
if (enabled.Length == 0)
|
|
{
|
|
Toast.Show("No ISOs to stop");
|
|
return;
|
|
}
|
|
var confirm = System.Windows.MessageBox.Show(
|
|
$"Stop {enabled.Length} running ISO(s)?\n\nThis tears down every active pipeline immediately.",
|
|
"Dragon-ISO — Stop all ISOs",
|
|
System.Windows.MessageBoxButton.YesNo,
|
|
System.Windows.MessageBoxImage.Warning,
|
|
System.Windows.MessageBoxResult.No);
|
|
if (confirm != System.Windows.MessageBoxResult.Yes) return;
|
|
|
|
foreach (var p in enabled)
|
|
{
|
|
try { await _controller.DisableIsoAsync(p.Id, CancellationToken.None); }
|
|
catch { /* defensive */ }
|
|
p.IsEnabled = false;
|
|
}
|
|
Toast.Show($"Stopped {enabled.Length} ISO(s)");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save a PNG of every currently-enabled participant's latest
|
|
/// processed frame to a timestamped subdirectory under
|
|
/// %USERPROFILE%\Pictures\Dragon-ISO\. One folder per Snapshot All click
|
|
/// so back-to-back clicks don't comingle. Useful for end-of-meeting
|
|
/// archives, recapping who showed up, etc.
|
|
/// </summary>
|
|
private void SnapshotAll()
|
|
{
|
|
var enabled = Participants.Where(p => p.IsEnabled).ToArray();
|
|
if (enabled.Length == 0)
|
|
{
|
|
Toast.Warn("No enabled participants to snapshot");
|
|
return;
|
|
}
|
|
|
|
var rootDir = System.IO.Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
|
|
"Dragon-ISO",
|
|
$"snapshots-{DateTimeOffset.Now:yyyyMMdd_HHmmss}");
|
|
|
|
try
|
|
{
|
|
System.IO.Directory.CreateDirectory(rootDir);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Toast.Warn($"Couldn't create snapshot dir: {ex.Message}");
|
|
return;
|
|
}
|
|
|
|
var saved = 0;
|
|
var failed = 0;
|
|
foreach (var p in enabled)
|
|
{
|
|
try
|
|
{
|
|
var frame = _controller.GetLatestProcessedFrame(p.Id);
|
|
if (frame is null || frame.Pixels.IsEmpty) { failed++; continue; }
|
|
|
|
var safeName = string.Join("_", p.DisplayName.Split(System.IO.Path.GetInvalidFileNameChars()));
|
|
if (string.IsNullOrWhiteSpace(safeName)) safeName = "participant";
|
|
var path = System.IO.Path.Combine(rootDir, $"{safeName}.png");
|
|
|
|
var stride = frame.Width * 4;
|
|
var bmp = new System.Windows.Media.Imaging.WriteableBitmap(
|
|
frame.Width, frame.Height, 96, 96,
|
|
System.Windows.Media.PixelFormats.Bgra32, null);
|
|
bmp.WritePixels(
|
|
new System.Windows.Int32Rect(0, 0, frame.Width, frame.Height),
|
|
frame.Pixels.ToArray(), stride, 0);
|
|
|
|
using var fs = new System.IO.FileStream(path, System.IO.FileMode.Create);
|
|
var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
|
|
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bmp));
|
|
encoder.Save(fs);
|
|
saved++;
|
|
}
|
|
catch { failed++; }
|
|
}
|
|
|
|
Toast.Show(failed > 0
|
|
? $"Saved {saved} snapshot(s) ({failed} failed) to Pictures\\Dragon-ISO\\{System.IO.Path.GetFileName(rootDir)}"
|
|
: $"Saved {saved} snapshot(s) to Pictures\\Dragon-ISO\\{System.IO.Path.GetFileName(rootDir)}");
|
|
}
|
|
}
|