Skip to content

feat(lookback): browse past days on the Your day screen#142

Merged
abdulsaheel merged 2 commits into
OpenStrap:mainfrom
dannymcc:feat/lookback-day-history
Jul 24, 2026
Merged

feat(lookback): browse past days on the Your day screen#142
abdulsaheel merged 2 commits into
OpenStrap:mainfrom
dannymcc:feat/lookback-day-history

Conversation

@dannymcc

@dannymcc dannymcc commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

The lookback / Your day screen only ever rendered today. This adds day navigation so users can browse past days' lookback — nap times, HR / HRV / respiration / skin-temp and movement trends — one day at a time, the way the Sleep section already lets you.

Almost all the plumbing already existed: JourneyScreen already rendered any date passed to it, already handled the retention boundary (minute detail only for recent days; older days show derived summaries) and the partial-"today" fallback, and every day-detail repo method is date-parameterised. So this is essentially a day-navigation UI addition on top of behaviour the screen already supports.

Navigation UX

The screen header gains a day-nav bar (in the scaffold's header slot, below the title):

  • Prev / next chevrons flanking the displayed date. Next is disabled at today (navigation never enters the future); prev is disabled at the earliest recorded day. Empty gaps between recorded days are skipped — stepping lands on the next day that actually has data.
  • The date is tappableshowDatePicker, bounded to [earliestAvailable, today], to jump straight to a day.
  • Disabled chevrons grey out (opacity + no tap) and carry semantics labels; the whole bar reuses existing design-system parts (RoundIconButton, Pressable, OsAppIcon, Tag) rather than inventing a new style.

JourneyScreen now holds a mutable current-date (initialised from the entry date, which stays the entry point). Every navigation re-runs the existing _load() for the new date, so refresh, empty-state and error handling are unchanged.

Retention boundary respected

No data or retention behaviour changed — navigation only moves across dates the screen already handles. Retention gating and the partial-today fallback still key off the viewed date, so older days show derived summaries, not minute curves, and truly-empty days show the empty state.

Data

Adds LocalRepository.availableDays()LocalDb.availableDayIds(): the UNION of day_result day_ids and decoded_onehz day labels (bucketed to the local calendar day), newest first. It bounds the prev/earliest control and the date picker. A day with a day_result but pruned minute-detail still appears (its summary shows); only a day with neither derived row nor raw substrate is absent.

Files

  • lib/ui/journey/journey_screen.dart — mutable current-date state, day-nav header, date picker, _go/_loadDays.
  • lib/ui/journey/day_nav.dartnew pure DayNav helper (navigable-set / next / prev / earliest maths).
  • lib/data/local_repository.dartavailableDays() on the contract.
  • lib/data/local_repository_impl.dart — implements it.
  • lib/data/db.dartavailableDayIds() query.
  • test/day_nav_test.dart — pure stepping/bounds tests (never past today, stop at earliest, skip gaps).
  • test/journey_available_days_test.dartavailableDays() over the real sqflite_ffi LocalDb (union, ordering, de-dup, empty).

Testing

Unit tests cover the new repo method and the pure stepping/bounds logic. The widget wiring (header nav bar, picker, per-date reload) is inspection-verified only — full widget tests would need repo + plugin mocking and are brittle for this screen.

Note

Runtime is unverified — no Flutter/Dart SDK or device was available in this environment, so this was verified by inspection and unit tests, not run on a device.

Closes #112

Summary by CodeRabbit

  • New Features

    • Added day navigation for journey timelines using previous and next controls.
    • Added a date picker constrained to days with locally recorded data and today.
    • Added a “Today” indicator when viewing the current day.
    • Journey data now reloads when selecting a different date.
    • Available days include dates with either processed or locally recorded data, shown newest first.
  • Bug Fixes

    • Prevented navigation beyond the earliest recorded day or into future dates.

The lookback / "Your day" screen only ever showed today. Add day
navigation so past days' naps, HR/HRV/resp/skin-temp and movement can be
browsed one day at a time, mirroring the Sleep section.

- JourneyScreen now holds a mutable current-date (initialised from the
  entry date); prev/next chevrons and a tappable date jump across days,
  each re-running the existing per-date load. Next is disabled at today
  (never into the future), prev at the earliest recorded day; empty gaps
  between recorded days are skipped. All existing behaviour is preserved:
  retention gating and the partial-today fallback still key off the
  viewed date, so older days show derived summaries rather than minute
  curves, and truly-empty days show the empty state.
- Add LocalRepository.availableDays() (LocalDb.availableDayIds: the UNION
  of day_result rows and decoded_onehz day labels, newest first) to bound
  navigation and the date picker.
- Extract the stepping/bounds maths into a pure DayNav helper.

Tests: DayNav bounds/stepping (pure) and availableDays over the real
sqflite_ffi LocalDb.

Closes OpenStrap#112
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dannymcc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: eda61911-7bc6-46dd-9c2b-61907cefeb30

📥 Commits

Reviewing files that changed from the base of the PR and between 132b6e4 and 968b907.

📒 Files selected for processing (6)
  • lib/data/db.dart
  • lib/data/local_repository.dart
  • lib/ui/journey/day_nav.dart
  • lib/ui/journey/journey_screen.dart
  • test/day_nav_test.dart
  • test/journey_available_days_test.dart
📝 Walkthrough

Walkthrough

Journey history now exposes locally recorded days, computes bounded day navigation, and integrates previous/next controls and a date picker into JourneyScreen. Timeline content reloads for the selected day, with unit and SQLite-backed tests covering navigation and day availability.

Changes

Journey history navigation

Layer / File(s) Summary
Local day availability
lib/data/db.dart, lib/data/local_repository.dart, lib/data/local_repository_impl.dart, test/journey_available_days_test.dart
Local day IDs are collected from derived and raw data, exposed through the repository, ordered newest-first, deduplicated, and validated with SQLite-backed tests.
Day navigation rules
lib/ui/journey/day_nav.dart, test/day_nav_test.dart
DayNav provides bounded day lists, adjacent-day selection, earliest-day lookup, and tests for gaps, duplicates, bounds, and empty inputs.
JourneyScreen navigation integration
lib/ui/journey/journey_screen.dart
JourneyScreen tracks the selected day, loads available-day bounds, reloads timeline content, and renders date-picker and previous/next navigation controls.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant JourneyScreen
  participant LocalRepositoryImpl
  participant LocalDb
  participant DayNav
  participant JourneyContent
  JourneyScreen->>LocalRepositoryImpl: availableDays()
  LocalRepositoryImpl->>LocalDb: availableDayIds()
  LocalDb-->>LocalRepositoryImpl: ordered day labels
  LocalRepositoryImpl-->>JourneyScreen: available days
  JourneyScreen->>DayNav: compute navigable days
  JourneyScreen->>DayNav: select next or previous day
  JourneyScreen->>JourneyContent: reload selected timeline
Loading

Suggested reviewers: abdulsaheel

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: adding past-day browsing to the Your day screen.
Linked Issues check ✅ Passed The PR adds historical day navigation and date reloading for Lookback, matching issue #112's request for past-day data.
Out of Scope Changes check ✅ Passed The changes stay focused on day navigation, availability lookup, and supporting tests, with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ui/journey/journey_screen.dart (1)

54-81: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Ignore stale timeline responses.

Rapid navigation can overlap _load() calls; an older request can finish last and overwrite the data/error state for the newly selected day.

Proposed fix
 Future<void> _load() async {
+  final requestedDate = _currentDate;
   final api = context.read<AppState>().repo;
   ...
   try {
-    final res = await api.getDayTimeline(_currentDate);
-    if (!mounted) return;
+    final res = await api.getDayTimeline(requestedDate);
+    if (!mounted || requestedDate != _currentDate) return;
     setState(() {
       _data = res;
       ...
     });
   } catch (e) {
-    if (!mounted) return;
+    if (!mounted || requestedDate != _currentDate) return;
     setState(() {
       ...
     });
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/ui/journey/journey_screen.dart` around lines 54 - 81, Update _load so
overlapping requests cannot apply stale results: capture the selected day or a
request-generation token before awaiting getDayTimeline, then verify it still
matches the current selection before applying success or error state. Preserve
the existing mounted checks and ensure only the latest request updates _data,
_phase, and _error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/data/db.dart`:
- Around line 2371-2375: Update the available-days SQL query to exclude
derivation skip markers by filtering day_result rows to skipped = 0, while
retaining partial rows and the existing decoded_onehz union and ordering.

In `@lib/data/local_repository_impl.dart`:
- Around line 513-514: Update availableDays() so it exposes only days that
getDayTimeline() can render from an existing derived bundle, or ensure raw-only
days are derived before returning them. Preserve the existing day ordering and
return behavior for timeline-renderable days.

In `@lib/ui/journey/journey_screen.dart`:
- Around line 130-148: The _openPicker method currently permits unrecorded
dates; add a selectableDayPredicate to showDatePicker backed by _navigable so
only recorded days are selectable, while preserving the existing earliest/today
bounds and initial-date handling.

---

Outside diff comments:
In `@lib/ui/journey/journey_screen.dart`:
- Around line 54-81: Update _load so overlapping requests cannot apply stale
results: capture the selected day or a request-generation token before awaiting
getDayTimeline, then verify it still matches the current selection before
applying success or error state. Preserve the existing mounted checks and ensure
only the latest request updates _data, _phase, and _error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aa0c991e-1d7f-4d84-9238-f2654830d575

📥 Commits

Reviewing files that changed from the base of the PR and between 533d110 and 132b6e4.

📒 Files selected for processing (7)
  • lib/data/db.dart
  • lib/data/local_repository.dart
  • lib/data/local_repository_impl.dart
  • lib/ui/journey/day_nav.dart
  • lib/ui/journey/journey_screen.dart
  • test/day_nav_test.dart
  • test/journey_available_days_test.dart

Comment thread lib/data/db.dart Outdated
Comment thread lib/data/local_repository_impl.dart
Comment thread lib/ui/journey/journey_screen.dart Outdated
CodeRabbit flagged that day navigation could land on a blank screen:
availableDays() unioned raw-only decoded_onehz days and included
derivation skip-markers, but getDayTimeline only renders a day with a
genuine derived bundle (returning {} otherwise). Nav chevrons and the
date picker could therefore reach a day that renders empty.

- LocalDb.availableDayIds() now returns exactly the days _bundleForDate
  would render: the latest-algo_version day_result per day with
  skipped = 0. Dropped the raw-only decoded_onehz union and excluded
  skip-markers (the skipped column is set by _markDaySkipped alongside
  the {skipped:true} payload). A day with pruned minute-detail still
  qualifies — its curves persist in the bundle payload.
- The date picker now passes selectableDayPredicate so only recorded
  days are choosable; empty gaps are greyed out instead of selectable.
  The prev/next chevrons already step over gaps via the same set.

Tests: availableDays now asserts raw-only and skip-marker days are
excluded and that the latest algo_version decides skip-vs-render; new
DayNav.isSelectable tests cover the picker predicate.
@abdulsaheel
abdulsaheel merged commit db356e6 into OpenStrap:main Jul 24, 2026
1 check passed
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.

Request history for Lookback menu

2 participants