feat(ui): add subtask tree view with expand/collapse in task list

Tasks with subtasks show a chevron for inline expand/collapse.
Subtask checkboxes toggle completion state directly. Also sets
Windows AppUserModelID for proper taskbar identity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-04-16 12:16:22 +02:00
parent 4ca48044db
commit 32bb52875f
5 changed files with 234 additions and 67 deletions

View File

@@ -91,10 +91,17 @@ public partial class TaskListViewModel : ViewModelBase
using var context = _dbFactory.CreateDbContext();
var taskRepo = new TaskRepository(context);
var entities = await taskRepo.GetByListIdAsync(listId);
var taskIds = entities.Select(e => e.Id).ToList();
var subtaskCounts = await context.Subtasks
.Where(s => taskIds.Contains(s.TaskId))
.GroupBy(s => s.TaskId)
.ToDictionaryAsync(g => g.Key, g => g.Count());
foreach (var e in entities)
{
var tags = await taskRepo.GetEffectiveTagsAsync(e.Id);
Tasks.Add(new TaskItemViewModel(e, tags, RunNowAsync, () => _worker.IsConnected, ToggleDoneAsync));
subtaskCounts.TryGetValue(e.Id, out var count);
Tasks.Add(new TaskItemViewModel(e, tags, RunNowAsync, () => _worker.IsConnected,
_dbFactory, count, ToggleDoneAsync));
}
}
catch (Exception ex)
@@ -135,7 +142,8 @@ public partial class TaskListViewModel : ViewModelBase
var taskRepo = new TaskRepository(context);
await taskRepo.AddAsync(entity);
var tags = await taskRepo.GetEffectiveTagsAsync(entity.Id);
var vm = new TaskItemViewModel(entity, tags, RunNowAsync, () => _worker.IsConnected, ToggleDoneAsync);
var vm = new TaskItemViewModel(entity, tags, RunNowAsync, () => _worker.IsConnected,
_dbFactory, 0, ToggleDoneAsync);
Tasks.Add(vm);
SelectedTask = vm;
InlineAddTitle = "";
@@ -183,7 +191,8 @@ public partial class TaskListViewModel : ViewModelBase
}
var tags = await taskRepo.GetEffectiveTagsAsync(saved.Id);
Tasks.Add(new TaskItemViewModel(saved, tags, RunNowAsync, () => _worker.IsConnected, ToggleDoneAsync));
Tasks.Add(new TaskItemViewModel(saved, tags, RunNowAsync, () => _worker.IsConnected,
_dbFactory, 0, ToggleDoneAsync));
// Auto wake-queue if agent+queued
if (saved.Status == TaskStatus.Queued &&
@@ -282,7 +291,11 @@ public partial class TaskListViewModel : ViewModelBase
}
var tags = await taskRepo.GetEffectiveTagsAsync(taskId);
if (existing is not null)
{
existing.Refresh(entity, tags);
var subtaskCount = await context.Subtasks.CountAsync(s => s.TaskId == taskId);
await existing.RefreshSubtasksAsync(subtaskCount);
}
}
private async Task RunNowAsync(string taskId)