fix(ui): dispose VM subscriptions/timers, guard offline Stop, align review delta-path

- DetailsIslandViewModel/TasksIslandViewModel/ListsIslandViewModel: implement
  IDisposable, unsubscribe Loc.LanguageChanged and worker events (memory leaks).
- IslandsShellViewModel: dispose the three System.Timers.Timer instances.
- StopAsync: guard on Task/IsRunning/IsConnected and wrap CancelTask in try/catch.
- TaskMatchesList virtual:review now matches WaitingForReview (aligns with ReviewFilter).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-06-09 09:53:58 +02:00
parent 00a065bf7f
commit 01e0c1d794
4 changed files with 72 additions and 15 deletions

View File

@@ -14,7 +14,7 @@ using TaskStatus = ClaudeDo.Data.Models.TaskStatus;
namespace ClaudeDo.Ui.ViewModels.Islands;
public sealed partial class TasksIslandViewModel : ViewModelBase
public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
{
private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;
private readonly IWorkerClient? _worker;
@@ -71,6 +71,8 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
public Func<UnfinishedPlanningModalViewModel, Task>? ShowUnfinishedPlanningModal { get; set; }
private readonly EventHandler _langChangedHandler;
public TasksIslandViewModel(IDbContextFactory<ClaudeDoDbContext> dbFactory, IWorkerClient? worker = null)
{
_dbFactory = dbFactory;
@@ -85,7 +87,13 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
_worker.RefineStartedEvent += OnRefineStarted;
_worker.RefineFinishedEvent += OnRefineFinished;
}
Loc.LanguageChanged += (_, _) => RefreshLocalizedText();
_langChangedHandler = (_, _) => RefreshLocalizedText();
Loc.LanguageChanged += _langChangedHandler;
}
public void Dispose()
{
Loc.LanguageChanged -= _langChangedHandler;
}
private void RefreshLocalizedText()
@@ -178,7 +186,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
ListKind.Smart when list.Id == "smart:my-day" => t.IsMyDay,
ListKind.Smart when list.Id == "smart:important" => t.IsStarred,
ListKind.Smart when list.Id == "smart:planned" => t.ScheduledFor != null,
ListKind.Virtual when list.Id == "virtual:review" => t.Status == TaskStatus.Done && t.Worktree?.State == WorktreeState.Active && t.ParentTaskId == null,
ListKind.Virtual when list.Id == "virtual:review" => t.Status == TaskStatus.WaitingForReview,
ListKind.User => $"user:{t.ListId}" == list.Id,
_ => false,
};