diff --git a/src/ClaudeDo.Ui/Design/IslandStyles.axaml b/src/ClaudeDo.Ui/Design/IslandStyles.axaml
index cc83799..c6d7b97 100644
--- a/src/ClaudeDo.Ui/Design/IslandStyles.axaml
+++ b/src/ClaudeDo.Ui/Design/IslandStyles.axaml
@@ -499,4 +499,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs
index b750701..b096970 100644
--- a/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs
+++ b/src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Globalization;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ClaudeDo.Data;
@@ -19,12 +20,21 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
public void RequestFocusAddTask() => FocusAddTaskRequested?.Invoke(this, EventArgs.Empty);
public ObservableCollection Items { get; } = new();
+ public ObservableCollection OverdueItems { get; } = new();
+ public ObservableCollection OpenItems { get; } = new();
+ public ObservableCollection CompletedItems { get; } = new();
[ObservableProperty] private string _newTaskTitle = "";
[ObservableProperty] private TaskRowViewModel? _selectedTask;
[ObservableProperty] private string _headerTitle = "";
[ObservableProperty] private string _headerEyebrow = "";
[ObservableProperty] private string _subtitle = "";
+ [ObservableProperty] private string _statusPill = "";
+ [ObservableProperty] private bool _hasStatusPill;
+ [ObservableProperty] private bool _isShowingCompleted = true;
+ [ObservableProperty] private bool _hasOverdue;
+ [ObservableProperty] private bool _hasCompleted;
+ [ObservableProperty] private string _completedHeader = "COMPLETED";
public TasksIslandViewModel(IDbContextFactory dbFactory)
{
@@ -40,10 +50,15 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
_currentList = list;
Items.Clear();
+ OverdueItems.Clear();
+ OpenItems.Clear();
+ CompletedItems.Clear();
+ HasOverdue = false;
+ HasCompleted = false;
if (list is null) return;
HeaderTitle = list.Name;
- HeaderEyebrow = DateTime.Now.ToString("dddd · MMM dd").ToUpperInvariant();
+ HeaderEyebrow = DateTime.Now.ToString("dddd · MMM dd", CultureInfo.InvariantCulture).ToUpperInvariant();
_ = LoadForListAsync(list, ct);
}
@@ -74,17 +89,56 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
foreach (var t in filtered)
Items.Add(TaskRowViewModel.FromEntity(t));
+ Regroup();
UpdateSubtitle();
}
catch (OperationCanceledException) { }
}
+ private void Regroup()
+ {
+ OverdueItems.Clear();
+ OpenItems.Clear();
+ CompletedItems.Clear();
+
+ var today = DateTime.Today;
+ foreach (var r in Items)
+ {
+ if (r.Done)
+ CompletedItems.Add(r);
+ else if (r.ScheduledFor is { } d && d.Date < today)
+ OverdueItems.Add(r);
+ else
+ OpenItems.Add(r);
+ }
+
+ HasOverdue = OverdueItems.Count > 0;
+ HasCompleted = CompletedItems.Count > 0;
+ CompletedHeader = $"COMPLETED · {CompletedItems.Count}";
+ }
+
private void UpdateSubtitle()
{
+ var now = DateTime.Now;
var open = Items.Count(i => !i.Done);
var running = Items.Count(i => i.Status == TaskStatus.Running);
var review = Items.Count(i => i.Status == TaskStatus.Done && i.Branch != null);
- Subtitle = $"{open} open · {running} running · {review} in review";
+
+ var weekday = now.ToString("dddd", CultureInfo.CurrentCulture);
+ var month = now.ToString("MMM", CultureInfo.CurrentCulture);
+ var day = now.Day;
+ Subtitle = $"{weekday}, {month} {day} · {open} open";
+
+ if (running > 0 || review > 0)
+ {
+ StatusPill = $"{running} running · {review} review";
+ HasStatusPill = true;
+ }
+ else
+ {
+ StatusPill = "";
+ HasStatusPill = false;
+ }
}
[RelayCommand]
@@ -102,7 +156,9 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
await using var db = await _dbFactory.CreateDbContextAsync();
db.Tasks.Add(entity);
await db.SaveChangesAsync();
- Items.Insert(0, TaskRowViewModel.FromEntity(entity));
+ var row = TaskRowViewModel.FromEntity(entity);
+ Items.Insert(0, row);
+ Regroup();
NewTaskTitle = "";
UpdateSubtitle();
}
@@ -119,6 +175,7 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
row.Status = entity.Status;
await db.SaveChangesAsync();
}
+ Regroup();
UpdateSubtitle();
}
@@ -138,6 +195,15 @@ public sealed partial class TasksIslandViewModel : ViewModelBase
[RelayCommand]
private void Select(TaskRowViewModel row) => SelectedTask = row;
+ [RelayCommand]
+ private void ToggleShowCompleted() => IsShowingCompleted = !IsShowingCompleted;
+
+ [RelayCommand]
+ private void Sort() { /* placeholder — UI-only */ }
+
+ [RelayCommand]
+ private void More() { /* placeholder — UI-only */ }
+
partial void OnSelectedTaskChanged(TaskRowViewModel? value)
{
foreach (var i in Items) i.IsSelected = ReferenceEquals(i, value);
diff --git a/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml b/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml
index c1a95e1..a60afbd 100644
--- a/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml
+++ b/src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml
@@ -2,45 +2,136 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:ClaudeDo.Ui.ViewModels.Islands"
xmlns:islands="using:ClaudeDo.Ui.Views.Islands"
+ xmlns:converters="using:Avalonia.Data.Converters"
x:Class="ClaudeDo.Ui.Views.Islands.TasksIslandView"
x:DataType="vm:TasksIslandViewModel">
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+