1 Commits

Author SHA1 Message Date
mika kuns
eff1045e63 General Changes 2026-04-20 09:54:13 +02:00
4 changed files with 56 additions and 4 deletions

View File

@@ -28,6 +28,7 @@ public partial class MainWindowViewModel : ViewModelBase, IDisposable
public StatusBarViewModel StatusBar { get; }
private readonly Action<string> _onTaskChanged;
private readonly Action<string> _onTaskSubtasksChanged;
public MainWindowViewModel(
IDbContextFactory<ClaudeDoDbContext> dbFactory,
@@ -45,13 +46,20 @@ public partial class MainWindowViewModel : ViewModelBase, IDisposable
StatusBar = statusBar;
_onTaskChanged = taskId => _ = TaskList.RefreshSingleAsync(taskId);
_onTaskSubtasksChanged = taskId =>
{
if (TaskDetail.CurrentTaskId == taskId)
_ = TaskDetail.RefreshSubtasksFromDbAsync();
};
TaskList.SelectedTaskChanged += OnSelectedTaskChanged;
TaskList.TaskSubtasksChanged += _onTaskSubtasksChanged;
TaskDetail.TaskChanged += _onTaskChanged;
}
public void Dispose()
{
TaskList.SelectedTaskChanged -= OnSelectedTaskChanged;
TaskList.TaskSubtasksChanged -= _onTaskSubtasksChanged;
TaskDetail.TaskChanged -= _onTaskChanged;
}

View File

@@ -51,6 +51,7 @@ public partial class TaskDetailViewModel : ViewModelBase
public ObservableCollection<SubtaskItemViewModel> Subtasks { get; } = new();
private string? _taskId;
public string? CurrentTaskId => _taskId;
private string? _listId;
private bool _isLoading;
// Cancels an in-flight LoadAsync when a new TaskUpdated event arrives
@@ -267,11 +268,13 @@ public partial class TaskDetailViewModel : ViewModelBase
var vm = SubtaskItemViewModel.From(entity);
vm.PropertyChanged += OnSubtaskPropertyChanged;
Subtasks.Add(vm);
TaskChanged?.Invoke(_taskId);
}
[RelayCommand]
private async Task RemoveSubtask(SubtaskItemViewModel item)
{
if (_taskId is null) return;
if (!string.IsNullOrEmpty(item.Id))
{
using var context = _dbFactory.CreateDbContext();
@@ -280,6 +283,7 @@ public partial class TaskDetailViewModel : ViewModelBase
}
item.PropertyChanged -= OnSubtaskPropertyChanged;
Subtasks.Remove(item);
TaskChanged?.Invoke(_taskId);
}
private async void OnSubtaskPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@@ -301,6 +305,8 @@ public partial class TaskDetailViewModel : ViewModelBase
OrderNum = Subtasks.IndexOf(vm),
CreatedAt = orig?.CreatedAt ?? DateTime.UtcNow,
});
if (e.PropertyName == nameof(SubtaskItemViewModel.Completed))
TaskChanged?.Invoke(_taskId);
}
catch (Exception ex)
{
@@ -309,6 +315,35 @@ public partial class TaskDetailViewModel : ViewModelBase
}
}
public async Task RefreshSubtasksFromDbAsync()
{
if (_taskId is null) return;
List<SubtaskEntity> subtasks;
using (var context = _dbFactory.CreateDbContext())
{
var subtaskRepo = new SubtaskRepository(context);
subtasks = await subtaskRepo.GetByTaskIdAsync(_taskId);
}
_isLoading = true;
try
{
foreach (var old in Subtasks) old.PropertyChanged -= OnSubtaskPropertyChanged;
Subtasks.Clear();
foreach (var s in subtasks)
{
var vm = SubtaskItemViewModel.From(s);
vm.PropertyChanged += OnSubtaskPropertyChanged;
Subtasks.Add(vm);
}
}
finally
{
_isLoading = false;
}
}
public void SetAgentFromPath(string path)
{
var existing = AvailableAgents.FirstOrDefault(a => a.Path == path);

View File

@@ -32,13 +32,15 @@ public partial class TaskItemViewModel : ViewModelBase
private readonly Func<string, Task>? _runNow;
private readonly Func<bool> _canRunNow;
private readonly Func<string, Task>? _toggleDone;
private readonly Action<string>? _onSubtasksChanged;
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
private bool _subtasksLoaded;
public TaskItemViewModel(TaskEntity entity, IReadOnlyList<TagEntity> tags,
Func<string, Task>? runNow, Func<bool> canRunNow,
IDbContextFactory<ClaudeDoDbContext> dbFactory, int subtaskCount,
Func<string, Task>? toggleDone = null)
Func<string, Task>? toggleDone = null,
Action<string>? onSubtasksChanged = null)
{
Entity = entity;
Id = entity.Id;
@@ -52,6 +54,7 @@ public partial class TaskItemViewModel : ViewModelBase
_runNow = runNow;
_canRunNow = canRunNow;
_toggleDone = toggleDone;
_onSubtasksChanged = onSubtasksChanged;
_dbFactory = dbFactory;
_subtaskCount = subtaskCount;
_hasSubtasks = subtaskCount > 0;
@@ -154,6 +157,8 @@ public partial class TaskItemViewModel : ViewModelBase
entity.Completed = vm.Completed;
await context.SaveChangesAsync();
}
_onSubtasksChanged?.Invoke(Id);
}
public async Task RefreshSubtasksAsync(int newCount)

View File

@@ -29,10 +29,14 @@ public partial class TaskListViewModel : ViewModelBase
[ObservableProperty] private string _inlineAddTitle = "";
public event Action<TaskItemViewModel?>? SelectedTaskChanged;
public event Action<string>? TaskSubtasksChanged;
partial void OnSelectedTaskChanged(TaskItemViewModel? value) =>
SelectedTaskChanged?.Invoke(value);
private void NotifySubtasksChanged(string taskId) =>
TaskSubtasksChanged?.Invoke(taskId);
public TaskListViewModel(IDbContextFactory<ClaudeDoDbContext> dbFactory, WorkerClient worker,
Func<TaskEditorViewModel> editorFactory, Action<string> showMessage)
{
@@ -101,7 +105,7 @@ public partial class TaskListViewModel : ViewModelBase
var tags = await taskRepo.GetEffectiveTagsAsync(e.Id);
subtaskCounts.TryGetValue(e.Id, out var count);
Tasks.Add(new TaskItemViewModel(e, tags, RunNowAsync, () => _worker.IsConnected,
_dbFactory, count, ToggleDoneAsync));
_dbFactory, count, ToggleDoneAsync, NotifySubtasksChanged));
}
}
catch (Exception ex)
@@ -143,7 +147,7 @@ public partial class TaskListViewModel : ViewModelBase
await taskRepo.AddAsync(entity);
var tags = await taskRepo.GetEffectiveTagsAsync(entity.Id);
var vm = new TaskItemViewModel(entity, tags, RunNowAsync, () => _worker.IsConnected,
_dbFactory, 0, ToggleDoneAsync);
_dbFactory, 0, ToggleDoneAsync, NotifySubtasksChanged);
Tasks.Add(vm);
SelectedTask = vm;
InlineAddTitle = "";
@@ -195,7 +199,7 @@ public partial class TaskListViewModel : ViewModelBase
var tags = await taskRepo.GetEffectiveTagsAsync(saved.Id);
Tasks.Add(new TaskItemViewModel(saved, tags, RunNowAsync, () => _worker.IsConnected,
_dbFactory, 0, ToggleDoneAsync));
_dbFactory, 0, ToggleDoneAsync, NotifySubtasksChanged));
// Auto wake-queue if agent+queued
if (saved.Status == TaskStatus.Queued &&