Skip to content

Today's 5: sectioned tab — opt-in Suggested + Also done today - #78

Merged
sohamM97 merged 11 commits into
mainfrom
feature/todays-five-suggestions
Jul 18, 2026
Merged

Today's 5: sectioned tab — opt-in Suggested + Also done today#78
sohamM97 merged 11 commits into
mainfrom
feature/todays-five-suggestions

Conversation

@sohamM97

Copy link
Copy Markdown
Owner

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:

  • Uses the same weighted selection as the All Tasks roulette (pickWeightedN with schedule/deadline/priority/staleness boosts + normalization), excluding tasks already pinned, done today, blocked, or dismissed this session.
  • Surfaces all eligible tasks (weighted, best first) as sleek pills in a 2-row band that scrolls sideways, lazily loaded via a horizontal ListView.builder so a large set stays cheap.
  • Each pill shows just the task name (full width); tapping the body opens an options sheet — Add to Today's 5 / Go to task / Dismiss suggestion — with the full task name + full ancestor path.
  • Accept pins it; dismiss suppresses it for the session.

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)

  • Unpinning after a full Today's 5 now repopulates the Suggested section inline (was stuck on "No suggestions right now." until a tab switch).
  • Long suggestion names no longer overflow the pill (Flexible + ellipsis).
  • The bottom-most Suggested box clears the + FAB instead of rendering behind it.

Tooling / docs

  • docs/UI_VIEWS.md and docs/TEST_COVERAGE.md kept in sync.
  • CLAUDE.md: reason about both desktop & phone form factors for width-dependent layout, and recommend /debug-build.
  • manual-test skill: design-check step, one /cleardb per round, "Add multiple" for bulk setup, always re-print full test text.

Testing

  • flutter analyze clean; flutter test test/screens/todays_five_screen_test.dart green (test file +415 lines).
  • Manually tested on Linux and on-device (Android) across empty/populated, long names, overflow, light/dark, and the options sheet.

🤖 Generated with Claude Code

Soham Marik and others added 8 commits July 17, 2026 17:18
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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread lib/screens/todays_five_screen.dart Outdated
final db = DatabaseHelper();
final paths = <int, String>{};
final allTasks = [..._todaysTasks, ..._otherDoneToday];
final allTasks = [..._todaysTasks, ..._otherDoneToday, ..._suggestions];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment thread lib/screens/todays_five_screen.dart Outdated
Comment on lines +493 to +496
_suggestions.removeWhere((t) =>
inTodaysFive.contains(t.id) ||
doneToday.contains(t.id) ||
_completedIds.contains(t.id));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread lib/screens/todays_five_screen.dart Outdated
Comment on lines +536 to +538
_suggestions = provider.pickWeightedN(
pool,
pool.length,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread lib/screens/todays_five_screen.dart Outdated
Comment on lines +129 to +130
if (pos.pixels >= pos.maxScrollExtent - 240) {
_loadMoreSuggestions();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@sohamM97
sohamM97 merged commit c2632db into main Jul 18, 2026
1 check passed
@sohamM97
sohamM97 deleted the feature/todays-five-suggestions branch July 18, 2026 15:44
sohamM97 pushed a commit that referenced this pull request Jul 26, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant