using System.Collections.ObjectModel; using ClaudeDo.Ui.Localization; using ClaudeDo.Ui.Services; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace ClaudeDo.Ui.ViewModels.Modals.Settings; public sealed partial class SessionSkillsSettingsTabViewModel : ViewModelBase { private readonly IWorkerClient _worker; public OperationStatus InstallOp { get; } = new(); public OperationStatus UpdateOp { get; } = new(); [ObservableProperty] private string _installUrl = ""; [ObservableProperty] private string _statusMessage = ""; [ObservableProperty] private bool _isBusy; [ObservableProperty] private bool _isEmpty = true; public ObservableCollection Skills { get; } = new(); public SessionSkillsSettingsTabViewModel(IWorkerClient worker) { _worker = worker; InstallOp.PropertyChanged += (_, e) => { if (e.PropertyName == nameof(OperationStatus.IsRunning)) InstallCommand.NotifyCanExecuteChanged(); }; UpdateOp.PropertyChanged += (_, e) => { if (e.PropertyName == nameof(OperationStatus.IsRunning)) UpdateCommand.NotifyCanExecuteChanged(); }; } public async Task LoadAsync() { IsBusy = true; try { var skills = await _worker.GetSessionSkillsAsync(); Skills.Clear(); foreach (var s in skills) Skills.Add(s); IsEmpty = Skills.Count == 0; } finally { IsBusy = false; } } private bool CanInstall() => !InstallOp.IsRunning; [RelayCommand(CanExecute = nameof(CanInstall))] private async Task InstallAsync() { if (string.IsNullOrWhiteSpace(InstallUrl)) return; StatusMessage = ""; using var op = InstallOp.Begin(Loc.T("ops.skills.installing")); try { var installed = await _worker.InstallSessionSkillAsync(InstallUrl.Trim()); StatusMessage = Loc.T("vm.sessionSkillsTab.installed", string.Join(", ", installed)); InstallUrl = ""; await LoadAsync(); } catch (Exception ex) { StatusMessage = Loc.T("vm.sessionSkillsTab.installFailed", ex.Message); } } private bool CanUpdate(string? sourceUrl) => !UpdateOp.IsRunning; [RelayCommand(CanExecute = nameof(CanUpdate))] private async Task UpdateAsync(string? sourceUrl) { if (string.IsNullOrWhiteSpace(sourceUrl)) return; StatusMessage = ""; using var op = UpdateOp.Begin(Loc.T("ops.skills.updating")); try { await _worker.UpdateSessionSkillAsync(sourceUrl); StatusMessage = Loc.T("vm.sessionSkillsTab.updated"); await LoadAsync(); } catch (Exception ex) { StatusMessage = Loc.T("vm.sessionSkillsTab.updateFailed", ex.Message); } } [RelayCommand] private async Task RemoveAsync(string? sourceUrl) { if (string.IsNullOrWhiteSpace(sourceUrl)) return; IsBusy = true; StatusMessage = ""; try { await _worker.RemoveSessionSkillAsync(sourceUrl); StatusMessage = Loc.T("vm.sessionSkillsTab.removed"); await LoadAsync(); } catch (Exception ex) { StatusMessage = Loc.T("vm.sessionSkillsTab.removeFailed", ex.Message); } finally { IsBusy = false; } } }