using TeamsISO.Engine.Controller; using TeamsISO.Engine.Domain; namespace TeamsISO.App.ViewModels; /// /// Per-row view model for a participant in the participant list. /// Wraps a domain and exposes ISO toggle and naming commands. /// public sealed class ParticipantViewModel : ObservableObject { private readonly IIsoController _controller; private Participant _participant; private bool _isEnabled; private bool _isProcessing; private string _customName; public ParticipantViewModel(IIsoController controller, Participant participant) { _controller = controller; _participant = participant; _customName = string.Empty; ToggleIsoCommand = new AsyncRelayCommand(ToggleIsoAsync, () => !_isProcessing); } public Guid Id => _participant.Id; public string DisplayName => _participant.DisplayName; public string SourceMachine => _participant.CurrentSource?.MachineName ?? "(disconnected)"; public string SourceFullName => _participant.CurrentSource?.FullName ?? "(disconnected)"; public bool IsOnline => _participant.CurrentSource is not null; public bool IsEnabled { get => _isEnabled; set => SetField(ref _isEnabled, value); } public bool IsProcessing { get => _isProcessing; private set { if (SetField(ref _isProcessing, value)) ToggleIsoCommand.RaiseCanExecuteChanged(); } } public string CustomName { get => _customName; set => SetField(ref _customName, value); } public AsyncRelayCommand ToggleIsoCommand { get; } /// Refreshes the underlying participant data (called when the controller emits an updated list). public void Update(Participant updated) { _participant = updated; OnPropertyChanged(nameof(DisplayName)); OnPropertyChanged(nameof(SourceMachine)); OnPropertyChanged(nameof(SourceFullName)); OnPropertyChanged(nameof(IsOnline)); } private async Task ToggleIsoAsync() { IsProcessing = true; try { if (IsEnabled) { await _controller.DisableIsoAsync(Id, CancellationToken.None); IsEnabled = false; } else { await _controller.EnableIsoAsync( Id, string.IsNullOrWhiteSpace(_customName) ? null : _customName, CancellationToken.None); IsEnabled = true; } } finally { IsProcessing = false; } } }