Skip to content

Make a detected nap visible on the Sleep screen - #205

Open
egoran2 wants to merge 3 commits into
OpenStrap:mainfrom
egoran2:fix/naps-visible-on-sleep-screen
Open

Make a detected nap visible on the Sleep screen#205
egoran2 wants to merge 3 commits into
OpenStrap:mainfrom
egoran2:fix/naps-visible-on-sleep-screen

Conversation

@egoran2

@egoran2 egoran2 commented Aug 6, 2026

Copy link
Copy Markdown

I napped for ~1h40m this afternoon, synced, and the nap was nowhere in the app. It turned out the detection is fine (the nap shows as a band under Your day), but two things kept it off the Sleep screen.

1. The periods screen is unreachable. SleepPeriodsScreen is only pushed from an AppScaffold action in SleepDetailScreen, and the Sleep tab always builds that screen with embedded: true (screens.dart:50,55), which returns the bare Column without the scaffold. SleepDetailScreen.today() is never called either, so nothing in the shipped app can open it.

2. The periods payload is keyed wrong. The engine writes each period as is_main / start / end / asleep_min (derivation_engine.dart:3626), while the screen reads onset_ts / wake_ts / duration_min. Even if you reached the screen, every card would say "0m" with no time range.

Before: Sleep tab shows the night only, 6h40m, no sign of the nap anywhere.
After: a row under the night summary, "Daytime nap, 1h 41m, not included in the night above", which opens the per-period breakdown with real times and durations.

Also in here:

  • the main period now carries the night's TST, efficiency, stage minutes and hypnogram, so the two sleep screens can't print different numbers for the same night, and the day total is the sum of what the cards show
  • a nap has no confidence value, so it no longer gets a literal 0 and the confidence dot is hidden instead
  • test/sleep_naps_visible_test.dart covers the mapping and the row (visible with a nap, absent without, tap fires)

Nothing about how a nap is computed changed, so kAlgoVersion stays put.

Left alone deliberately, happy to do either in a follow-up: naps still don't enter TST or readiness (they only credit tonight's need via nap_min), and _daySleep returns has_sleep: false when there's no night, so a nap-only day still shows nothing.

Verified on Flutter 3.41.6 (the pinned version): flutter analyze clean, flutter test --concurrency=1 gives 1205 passed / 2 skipped, the two skips being the whoop_hist.jsonl replays that need the capture file.

Summary by CodeRabbit

  • New Features
    • Added navigation from sleep details to individual sleep periods.
    • Added daytime nap details, including total nap duration, when available.
  • Improvements
    • Sleep periods now display normalized metrics and accurate totals.
    • Main sleep metrics are enriched with available night-level data.
    • Confidence indicators appear only when confidence data exists.
  • Bug Fixes
    • Invalid or incomplete periods are filtered from display.
    • Naps no longer show fabricated or unavailable metadata.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Sleep periods are normalized into screen data, with main-sleep metrics preserved and nap metadata reduced. Sleep details now expose nap navigation and summaries. Missing confidence values no longer render as zero-confidence indicators.

Changes

Sleep period display

Layer / File(s) Summary
Sleep period mapping
lib/data/local_repository_impl.dart, test/sleep_naps_visible_test.dart
The repository builds the night payload. sleepPeriodsForScreen validates periods, maps engine fields, enriches the main period, and recalculates displayed totals. Tests cover normalization and invalid data.
Nap navigation and display
lib/ui/sleep/sleep_detail_screen.dart, test/sleep_naps_visible_test.dart
Sleep details share period navigation, parse non-main periods as naps, and show a tappable nap summary when naps exist. Widget tests cover navigation and conditional rendering.
Confidence rendering
lib/ui/sleep/sleep_periods_screen.dart
Missing confidence values remain absent. The confidence indicator renders only when a value exists.

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

Sequence Diagram(s)

sequenceDiagram
  participant SleepRepository
  participant sleepPeriodsForScreen
  participant SleepNightContent
  participant SleepPeriodsScreen
  SleepRepository->>sleepPeriodsForScreen: raw periods and night metrics
  sleepPeriodsForScreen-->>SleepRepository: normalized periods
  SleepRepository->>SleepNightContent: completed night payload
  SleepNightContent->>SleepPeriodsScreen: open periods for the current date
  SleepPeriodsScreen-->>SleepNightContent: render periods without absent confidence dots
Loading

Possibly related PRs

  • OpenStrap/edge#204: Both PRs modify sleep-period normalization and rendering, including nap fields and invalid-duration handling.

Suggested labels: Review effort 3/5

Suggested reviewers: abdulsaheel, dannymcc, localhoop

🚥 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 and concisely describes the main change: displaying detected daytime naps on the Sleep screen.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

A daytime nap is detected, stored, and drawn as a band on the day
timeline, but the Sleep screen only ever showed the main night. The
screen that does list every sleep of the day was unreachable: its only
entry point is an AppScaffold action, and the Sleep tab embeds
SleepNightContent (embedded: true), so that scaffold never builds.

The periods payload was also keyed wrong. The engine writes is_main /
start / end / asleep_min; SleepPeriodsScreen reads onset_ts / wake_ts /
duration_min, so every card would have rendered as "0m" with no time
range under it.

- map sleep_periods onto the keys the screen reads, and give the main
  period the night's TST, efficiency, stage minutes and hypnogram so the
  two sleep screens can't print different numbers for the same night
- the day total is now the sum of what the cards show
- add a naps row under the night summary; tapping it opens the
  breakdown, and it says the nap is not part of the numbers above
- a nap carries no confidence instead of a literal 0, and the
  confidence dot is hidden when there is none
- test/sleep_naps_visible_test.dart pins the mapping and the row

No stored analytics output changed, so kAlgoVersion stays put.
@egoran2
egoran2 force-pushed the fix/naps-visible-on-sleep-screen branch from 147bf3b to 7c38e28 Compare August 6, 2026 17:01
@egoran2
egoran2 marked this pull request as ready for review August 6, 2026 17:02

@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: 1

🤖 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/local_repository_impl.dart`:
- Around line 2695-2701: Validate the parsed asleep_min in the duration
calculation around asleepMin, accepting it only when it falls within
0..windowMinutes derived from end and start; otherwise use the period span as
the fallback. Ensure both main and nap duration paths use this bounded value,
and add regression cases in sleep_naps_visible_test.dart for negative and
oversized asleep_min values.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 93bc9857-0e6b-4c58-913b-760bfbbade28

📥 Commits

Reviewing files that changed from the base of the PR and between d911f60 and 7c38e28.

📒 Files selected for processing (4)
  • lib/data/local_repository_impl.dart
  • lib/ui/sleep/sleep_detail_screen.dart
  • lib/ui/sleep/sleep_periods_screen.dart
  • test/sleep_naps_visible_test.dart

Comment thread lib/data/local_repository_impl.dart Outdated
CodeRabbit review: sleepPeriodsForScreen took asleep_min at face value, so a
negative or larger-than-window value would print a negative duration on the
card and skew the day total. The engine never writes one today (a nap's
asleep_min is exactly its window), but this function parses defensively
everywhere else, so it should here too. Falls back to the window, which the
period's own start/end already vouch for.

@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: 2

Caution

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

⚠️ Outside diff range comments (1)
test/sleep_naps_visible_test.dart (1)

625-640: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add regression coverage for the recomputed day total.

The new path derives total_asleep_min from mapped period durations, but the supplied tests assert individual period fields and nap-row behavior only. Add an assertion for the existing fixture total: 400 minutes of main sleep plus 101 minutes of nap sleep equals 501 minutes. Also cover the no-period fallback if that fallback remains part of the contract.

As per coding guidelines: “Behavior changes, especially regressions involving readiness, abstention, idempotence, synchronization, migrations, and lifecycle safety, must include regression tests.”

🤖 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 `@test/sleep_naps_visible_test.dart` around lines 625 - 640, Add regression
coverage in the existing sleep/naps test near the mapped period assertions,
verifying the fixture’s recomputed total_asleep_min is 501 minutes from 400
main-sleep plus 101 nap-sleep minutes. If the no-period fallback remains
supported, add a case asserting its expected total as well.

Source: Coding guidelines

🤖 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/local_repository_impl.dart`:
- Around line 2698-2702: Validate the main period’s night['duration_min']
against windowMin using the same non-negative, upper-bound checks applied to
p['asleep_min']; when invalid, fall back to the already validated asleepMin
value before assigning duration_min. Add regression coverage for negative and
oversized main duration values.

In `@test/sleep_naps_visible_test.dart`:
- Around line 93-100: Update the test “a length outside its own window falls
back to the window” to assert that the result collection p contains exactly
three elements before checking mapped duration_min values, ensuring
everyElement(101) cannot pass for an empty iterable.

---

Outside diff comments:
In `@test/sleep_naps_visible_test.dart`:
- Around line 625-640: Add regression coverage in the existing sleep/naps test
near the mapped period assertions, verifying the fixture’s recomputed
total_asleep_min is 501 minutes from 400 main-sleep plus 101 nap-sleep minutes.
If the no-period fallback remains supported, add a case asserting its expected
total as well.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 73855007-bddc-45cb-a8ba-da6e4ca0f51c

📥 Commits

Reviewing files that changed from the base of the PR and between 7c38e28 and e790715.

📒 Files selected for processing (2)
  • lib/data/local_repository_impl.dart
  • test/sleep_naps_visible_test.dart

Comment thread lib/data/local_repository_impl.dart
Comment thread test/sleep_naps_visible_test.dart Outdated
CodeRabbit review, second pass:

- the window check covered a nap's asleep_min but not the main period, which
  took night['duration_min'] straight through. Same bound now: nobody sleeps
  longer than the window they slept in.
- the fallback test asserted everyElement on a list it never sized, so it would
  have passed if the mapper dropped all three inputs. It checks the length
  first now.

Adds a TST regression case for the negative and oversized values.

@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: 1

🤖 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/local_repository_impl.dart`:
- Around line 2706-2710: Update the duration parsing around tstMin and
durationMin to range-check the raw numeric duration before calling toInt(),
rejecting fractional values such as -0.5 and 0.5 so both main-duration and nap
asleepMin fallbacks are preserved. Add regression coverage for fractional inputs
in both paths.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 09176f3b-fa41-48a6-8291-d7508549290c

📥 Commits

Reviewing files that changed from the base of the PR and between e790715 and 0d95f06.

📒 Files selected for processing (2)
  • lib/data/local_repository_impl.dart
  • test/sleep_naps_visible_test.dart

Comment thread lib/data/local_repository_impl.dart
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