Today's 5: sectioned tab — opt-in Suggested + Also done today - #78
Conversation
Restructures the Today tab into independent stacked sections (Today's 5 / Suggested / Also done today) so any can be absent without an awkward layout. - "Also done today" now shows even when Today's 5 is empty, not just when populated — done-today work is always visible. - New opt-in "Suggested" section, collapsed behind a "Show suggestions" button so unrelated tasks don't clutter the focus screen. On expand it offers up to 4 picks from the existing weighted algorithm (pickWeightedN with schedule/deadline/priority/staleness + normalization), excluding tasks already pinned, done today, or dismissed. Add pins into Today's 5; "Not now" dismisses; both backfill a fresh pick. Hidden when Today's 5 is full. Suggestions computed lazily on first expand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ills WIP checkpoint on the layout. Keeps the big centered "Nothing pinned yet" hero anchored at a fixed offset so expanding "Show suggestions" grows the list below it instead of jerking the hero upward. Suggestions render as sleek, content-sized, left-aligned pills (name + immediate parent, hard- truncated) rather than full-width cards. Also adds a CLAUDE.md guideline: gather all UI requirements up front before doing layout work — don't assume or half-read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WIP. Makes the "Suggested" divider a proper section header (label + rule, no leading icon) so it no longer reads like another pill, and positions the empty-state hero ~2/3 of the way toward the suggestions affordance while keeping that affordance anchored in place. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WIP. Adjusts the fixed spacers so the empty-state hero and the "Show suggestions" affordance sit where they read best. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WIP. Unifies the two states into one structure so sections don't jump around: Today's-5 area (centered "Nothing pinned yet" hero when empty / task cards when populated) takes the flexible top region, and Suggested + Also done today are pinned at the bottom in both states. - Suggested: wraps across ~2 rows of sleek pills. - Also done today: single row that shares the bottom row with the "+" FAB, ending just left of it (no tall clearance gap). - Both strips fade at the right edge to signal sideways overflow instead of chopping a chip mid-word (done-box scrolls horizontally). - Removes the bespoke anchored-hero / Stack / fraction-spacer experiments and the also-done expand/collapse machinery. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make Suggested a bordered box matching "Also done today" so the two bottom sections read as consistent cards, and fix three issues found in manual testing: - Unpinning after a full Today's 5 left the reopened Suggested section showing "No suggestions right now." until a tab switch, because the picks were cleared while full and never refreshed on removal. Refresh them inline in _confirmRemoveFromTodaysFive. - A long suggestion name + parent overflowed the pill's Row (the Text widgets weren't Flexible, so truncation alone couldn't fit them). Wrap both in Flexible + ellipsis; keep _truncateLabel as the soft cap. - The bottom-most Suggested box now takes the same right inset as the done-box so its pills end before the + FAB instead of behind it. Header sized to match the "Hide" action; suggestion pills wrap to ~2 rows (capped at 4, so all stay on-screen). Adds regression tests for each fix and keeps UI_VIEWS/TEST_COVERAGE in sync. Also updates the manual-test skill: design-check step, one /cleardb per round, "Add multiple" for bulk setup, and always re-printing full test text instead of referring to items by ID. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On a phone the content-sized pills wrapped one-per-row, so 4 suggestions stacked into 4 rows and the box grew tall — the earlier "4 pills fit in ~2 rows" assumption only held at desktop width. Replace the Wrap with a fixed 2-row band that scrolls sideways (row-major, right-edge fade), so the box stays ~2 rows tall on any width and the overflow is swipeable. Pills are width-capped (260) so their Flexible texts stay bounded inside the horizontal scroll. Also add a CLAUDE.md note to reason about both form factors (wide desktop and narrow phone) for width-dependent layout decisions and to recommend /debug-build when a change may behave differently on-device. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rework the Suggested strip around on-device feedback: - Pill body now opens an options sheet (Add / Go to task / Dismiss suggestion) with explicit, subtitled actions instead of a bare navigate — "Not now" read as "just close", so it's now "Dismiss suggestion". The sheet header (left-aligned) shows the full task name (emphasised) and full ancestor path, since the pill clips both. - Drop the parent from the pill and give the whole width to the task name (the parent lives in the sheet now). - Surface ALL eligible tasks (weighted, best first) instead of a fixed 4, so scrolling keeps revealing more; the ordered set is stable and only recomputed when emptied. - Lazy-load the strip via a horizontal ListView.builder (column-major, 2 pills per column, fixed pill height) so a large eligible set only builds the columns near the viewport. Tests updated (all eligible shown / dismiss removes one; options sheet opens + navigates + pins) and docs kept in sync. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b066a23479
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| final db = DatabaseHelper(); | ||
| final paths = <int, String>{}; | ||
| final allTasks = [..._todaysTasks, ..._otherDoneToday]; | ||
| final allTasks = [..._todaysTasks, ..._otherDoneToday, ..._suggestions]; |
There was a problem hiding this comment.
Avoid preloading metadata for every suggestion
When a user expands Suggested in a large task database, _refreshSuggestions() fills _suggestions with every eligible leaf, and _toggleSuggestions() immediately calls _loadTaskPaths(). Including all of _suggestions here makes expansion serially run getAncestorPath() for every eligible task and batch-load deadline/schedule metadata even though the horizontal ListView.builder only renders a few pills and the pill itself only shows the task name; this can make the opt-in surface freeze on large datasets. Load the path only for visible/tapped suggestions, or keep _loadTaskPaths() scoped to tasks that are actually rendered with that metadata.
Useful? React with 👍 / 👎.
| _suggestions.removeWhere((t) => | ||
| inTodaysFive.contains(t.id) || | ||
| doneToday.contains(t.id) || | ||
| _completedIds.contains(t.id)); |
There was a problem hiding this comment.
Revalidate cached suggestions before returning
If Suggested is expanded and a suggested task later becomes blocked or stops being a leaf from All Tasks/sync, refreshSnapshots() calls _refreshSuggestions(), but this cached-list prune only removes tasks that are in Today's 5 or done today; because the method returns while any cached suggestion remains, stale blocked/non-leaf entries stay visible. In the blocked case, tapping + can pin a task that the suggestion algorithm explicitly excludes, so the cache needs to re-check blocked/leaf eligibility or recompute after provider changes.
Useful? React with 👍 / 👎.
- Don't preload ancestor paths / deadline / schedule for every suggestion. Pills show only the name; the tap sheet now loads the ancestor path on demand for the single tapped task. Preloading over the whole (now unbounded) eligible set was wasted work on large DBs. - Revalidate cached suggestions on every refresh: drop entries that became blocked or non-leaf (not just those pinned/done), so a stale pill can't pin a task the algorithm excludes. Adds regression tests for both (blocked cached suggestion pruned on refresh; options sheet shows the on-demand ancestor path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dbcf7b6dac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| _suggestions = provider.pickWeightedN( | ||
| pool, | ||
| pool.length, |
There was a problem hiding this comment.
Avoid sampling every suggestion eagerly
When a user with a large task tree taps Show suggestions, this requests a weighted pick for every eligible leaf. TaskProvider.pickWeightedN recomputes weights across the remaining candidates for each selected task, so using pool.length here makes expansion quadratic before the lazy horizontal list can render anything; a few thousand leaves can block the Today tab despite suggestions being opt-in. Cap the initial materialized set or page/stream the weighted order instead of generating the full permutation up front.
Useful? React with 👍 / 👎.
Weighted-picking every eligible leaf up front is O(n²) in pickWeightedN and can freeze the Today tab on a large tree. Materialise only the first batch (24) on expand and page in further batches from the remaining pool as the strip scrolls near its end (ScrollController listener), so the up-front cost is bounded to O(batch·n). Adds @VisibleForTesting hooks and a regression test (30 leaves → 24 up front, load-more → 30, then drained). Also updates the merge-check skill: don't loop on Codex indefinitely — it re-reviews each push and may keep surfacing nits, so poll ~5 min per round and, on diminishing returns, ask the user (offer to read the Codex thread in the browser) instead of fix-looping forever. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8d9f8fa8fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (pos.pixels >= pos.maxScrollExtent - 240) { | ||
| _loadMoreSuggestions(); |
There was a problem hiding this comment.
Load more suggestions when the first batch fits
When the first materialized batch is fully visible — for example on a wide desktop window or with very short task names — the horizontal list has no scrollable extent, so the user cannot produce the scroll update that reaches this branch. Eligible tasks after the first 24 are then stranded until the user accepts/dismisses enough current pills, even though the section is intended to page through the whole eligible set; consider loading another batch after layout when the content still does not overflow, or exposing an explicit more trigger.
Useful? React with 👍 / 👎.
| _suggestionsExhausted = false; | ||
| return; | ||
| } | ||
| final provider = context.read<TaskProvider>(); |
There was a problem hiding this comment.
Guard the provider lookup after async refresh gaps
_refreshSuggestions() now reads from context, but callers such as _loadTodaysTasksInner() and _refreshSnapshotsInner() invoke it after awaiting DB work like _loadOtherDoneToday() without another mounted check. If the Today screen is disposed while suggestions are expanded during that gap, this provider lookup runs on a deactivated BuildContext before callers reach their later mounted checks, which can throw during teardown/rebuild; guard mounted here or pass in a provider captured before the async gap.
Useful? React with 👍 / 👎.
The scroll-triggered batch loader (8d9f8fa) did DB queries from the ScrollController listener. Accepting a suggestion reflows the strip, which fires the listener mid-accept, so _loadMoreSuggestions ran its queries concurrently with the accept's DB reload/persist → SQLite "locked for 10s" → the widget test (and CI) hung on "accepting a suggestion". Replace the scroll-streaming with a single bounded pick: materialise up to _suggestionCap (40) eligible leaves in one weighted pass on expand and render them lazily via the horizontal ListView.builder. This still bounds the pick to O(cap·n) — the Codex O(n²) concern — with no scroll-triggered DB, no ScrollController, no re-entrancy, so no deadlock. Keeps the earlier Codex fixes (mounted guard, blocked/leaf revalidation, on-demand path). Drops the now-moot batch/load-more test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
While merging #80 the skill's Codex guidance led to a wrong conclusion. It says to poll the issue/PR comment endpoints for the Codex bot and, after ~5 minutes of silence, report that no review comments arrived — which was then read as "no automated review at all". Codex had in fact reviewed and found no issues; it just posts to Codex Cloud (chatgpt.com/codex), never to the GitHub API. Verified on #80 and the previously merged #79: issues/{n}/comments, pulls/{n}/comments, pulls/{n}/reviews, the issue timeline, check-runs and commit statuses are ALL empty even after Codex has finished reviewing. So emptiness there carries no information about Codex, and the P2s handled on #77/#78 only reached the repo because the user relayed them from Codex Cloud. The skill now says to ask the user to check Codex Cloud rather than inferring from GitHub silence, and to keep polling the endpoints only as a cheap catch for other reviewers (a human, or claude[bot] if it is ever re-enabled). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reworks the Today tab into a consistent sectioned layout and adds an opt-in, algorithm-driven Suggested surface, plus makes Also done today always visible.
What's new
Layout — one structure for empty & populated states: a flexible top region (centered "Nothing pinned yet" hero when empty, progress bar + task cards when populated) with two bottom-pinned bordered boxes — Suggested and Also done today — that sit in the same on-screen position regardless of state. Whichever is bottom-most clears the
+FAB.Suggested (opt-in) — hidden behind a "Show suggestions" affordance so the focus screen stays uncluttered. When expanded:
pickWeightedNwith schedule/deadline/priority/staleness boosts + normalization), excluding tasks already pinned, done today, blocked, or dismissed this session.ListView.builderso a large set stays cheap.Also done today — a single sideways-scrolling row of green ✓ chips, now shown even when Today's 5 is empty (previously populated-only).
Bug fixes (each with a regression test)
+FAB instead of rendering behind it.Tooling / docs
docs/UI_VIEWS.mdanddocs/TEST_COVERAGE.mdkept in sync.CLAUDE.md: reason about both desktop & phone form factors for width-dependent layout, and recommend/debug-build.manual-testskill: design-check step, one/cleardbper round, "Add multiple" for bulk setup, always re-print full test text.Testing
flutter analyzeclean;flutter test test/screens/todays_five_screen_test.dartgreen (test file +415 lines).🤖 Generated with Claude Code