Skip to content

Multiple fixes - #111

Merged
abdulsaheel merged 7 commits into
mainfrom
fix/contributor-feedback
Jul 21, 2026
Merged

Multiple fixes #111
abdulsaheel merged 7 commits into
mainfrom
fix/contributor-feedback

Conversation

@abdulsaheel

@abdulsaheel abdulsaheel commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

This pull request introduces several important privacy policy clarifications, build system improvements, and telemetry configuration changes. The privacy documentation now distinguishes between official App Store/Play Store releases and GitHub releases, clarifying when health data contribution and anonymous diagnostics are enabled. The build system for both Android and iOS is updated to make Firebase telemetry (Crashlytics, Analytics, Performance) optional, ensuring the app builds and runs even without Firebase credentials. Additionally, the algorithm version is bumped to address readiness and stress score calculation logic.

Privacy policy and documentation updates:

  • The privacy policy in both PRIVACY.md and docs/privacy.html now clearly states that health data is not collected in official App Store/Play Store releases, while GitHub releases may allow opt-in health data contribution for algorithm improvement. Anonymous diagnostics are on by default only in GitHub releases and can be disabled by the user. [1] [2] [3] [4]
  • User controls are clarified: users can disable anonymous diagnostics and health data contribution at any time from the app's settings. [1] [2]

Build system and telemetry configuration:

  • Android: Firebase plugins are now declared with apply false and only conditionally applied if google-services.json is present, allowing builds to succeed without any Firebase credentials. Crashlytics configuration is also conditional. [1] [2]
  • iOS: Adds a shell script build phase to generate a placeholder GoogleService-Info.plist if none is present, ensuring builds do not fail on a fresh clone without Firebase credentials. [1] [2]

CI configuration and health data contribution:

  • .github/workflows/build.yml: Health data contribution is now intentionally enabled (ENABLE_HEALTH_DATA_CONTRIBUTION=true) for GitHub release builds (both Android and iOS), matching the clarified privacy policy. The comments explain the rationale and user opt-in nature. [1] [2]
  • Flutter version pinning comments are simplified, but the version remains pinned to avoid breakage from upstream changes.

Algorithm versioning:

  • lib/compute/derivation_engine.dart: Bumps kAlgoVersion to 47, updating readiness score logic to require actual detected sleep sessions and removing fallback logic for stress scores, ensuring more accurate and policy-compliant metrics.

Summary by CodeRabbit

  • New Features

    • Added clearer onboarding “data collection progress” with a caught-up-to-now indicator.
    • Added a dedicated AI Coach entry in Profile settings.
    • Improved Heart chart visuals using a unified chart-with-chips layout (Now/Peak/Low) with better “to now” cutoff.
    • Updated strain details to separate training load from calories & steps.
  • Bug Fixes

    • Readiness/stress and effort fields no longer display misleading values when required sleep/SI inputs are missing.
    • Health/steps goal handling now consistently falls back when goals are unset or non-positive.
    • Fixed workout deletion so the list reliably refreshes; improved bottom panel placement for gesture navigation; long row values truncate safely.
  • Documentation

    • Updated privacy policy wording, controls, and “Last updated” date; clarified health-data collection rules by release channel and updated diagnostics control text.

Readiness's RHR input fell back to a few minutes of live daytime HR
(via the rhr metric's own dayHrValid fallback) whenever no sleep had
been detected yet, while HRV/resp/temp already correctly required a
real sleep session. That asymmetry let a no-sleep day still produce a
full numeric readiness score off RHR alone (e.g. "Readiness 100" ~10
min after first wearing the strap). rhrToday now requires
hasSleep && sleepHr.isNotEmpty.

Also removed two copies of a "100 - readiness" stress fallback
(getDayStress and stressSummaryForToday) that fabricated a
stress-looking number whenever the real Baevsky SI was absent,
violating the never-impute rule. Both now correctly return null/"-".

kAlgoVersion 46 -> 47 so affected days re-derive.
- Today screen "raw data collected" state now reads "Data from <date>
  is being collected" plus a real collection-progress bar (last
  ingested record ts vs now), instead of a bare, meaningless raw count.
- AI morning-briefing card is now hidden entirely with no BYOK key
  configured, instead of always showing a placeholder greeting that
  implies a briefing will eventually appear regardless.
- Rhythm section in the Heart screen renamed from "Rhythm screen" to
  "Rhythm" — it's a section, not its own route.
- ListRow's `value` text (e.g. companion URL) now wraps in Flexible +
  ellipsis instead of being able to overflow the row unbounded.
- Step goal default unified to 8000 (StepGoalScreen.defaultGoal)
  everywhere a fallback existed; several call sites previously fell
  back to a stale 10000.
- Calories/steps split out of the "Training load" section on the
  Strain/Body screen into their own "Calories & steps" section —
  training load (ACWR/fitness trend/effort) and energy expenditure are
  different concepts.
- Workout finish/hold-to-end control panel now adds the system
  gesture-nav bottom inset instead of a fixed offset, so it can't sit
  under the Android nav bar.
- AppState.deleteWorkout now clears `activeWorkout` when the deleted
  session is the one currently tracked live, fixing a stale "Run live"
  state after deleting a just-finished manual workout.
…file

Today's lookback card and the Heart screen's day-detail section each
hand-rolled their own copy of the HR TimeSeriesChart + peak/low/now
chip row (chips above vs below, cutoff-to-now or not, and a manually
reimplemented tooltip that happened to exactly match TimeSeriesChart's
own default formatter already) — three near-identical HR charts
drifting apart across the app. Extracted the shared HrCurveWithChips
widget (lib/ui/kit/charts.dart) with chipsPosition/cutoffToNow/
showNowChip params; both screens now call it. (The third "HR graph"
mentioned in feedback — the generic multi-metric trend/bar screen — is
intentionally shared infra every metric drills through, not an HR
duplicate, so it's untouched.)

Also added two AI entries under Profile ("Briefings & journal" and
"AI coach") — the agentic AI Coach chat was previously reachable only
via a small pill button on the Body screen, with no path to it from
Profile/Settings at all.
google-services.json / GoogleService-Info.plist are gitignored with no
committed placeholder, but the Android Gradle google-services plugin
was applied unconditionally and the iOS Xcode project statically
referenced GoogleService-Info.plist in its Resources copy phase — a
from-scratch clone with no Firebase project configured couldn't run
`flutter build apk` or `flutter build ios` at all.

- Android: the three Firebase Gradle plugins (google-services,
  firebase-perf, crashlytics) now apply only `if
  (file("google-services.json").exists())`; the release
  CrashlyticsExtension config is gated the same way (configuring an
  extension from a plugin that was never applied would otherwise fail
  Gradle's configuration phase even with the plugin skipped).
- iOS: a new "Ensure GoogleService-Info.plist" Run Script build phase
  (ordered before Resources) generates a format-valid, inert,
  never-committed placeholder plist only if one isn't already present
  — never overwrites a real file a contributor placed there for their
  own Firebase project.

Verified end-to-end: with both files absent, `flutter build apk
--debug` and `flutter build ios --debug --no-codesign --simulator`
both succeed. No Firebase telemetry (Crashlytics/Analytics/
Performance) without a real project configured — that's the intended
trade for a repo that just builds. firebase_options.dart's existing
dummy stays as-is (Dart-side init was already safe; this closes the
native-side gap).
…pp Store/Play Store always zero-collection

Reframes the privacy model by release channel instead of a single
blanket "we never collect anything" for every build we distribute:

- Official App Store/Play Store releases: unchanged, zero health-data
  collection, ever.
- GitHub Releases (sideload APK/IPA): health-data-contribution
  (kHealthDataContributionEnabled) is now compiled in, but stays
  opt-in per user via the existing "Contribute my health data" toggle
  in onboarding/Settings, which defaults off and is itself hidden
  whenever the build-time flag is false. No behavior change to the
  actual upload gating (HealthUploader.maybeUpload already re-checks
  the flag directly) — only the compile-time flag's value for the
  GitHub Releases CI job.

Fixes found while reviewing the in-flight change:
- The ios build job still had the OLD value/comment
  (ENABLE_HEALTH_DATA_CONTRIBUTION=false, "matching PRIVACY.md's we do
  not collect your data") while the android job had already moved to
  the new policy — brought ios to parity so both GitHub-release
  platforms behave the same.
- kHealthDataContributionEnabled's doc comment in health_uploader.dart
  still described the old "not enabled by ANY build" model; updated to
  describe the actual two-tier behavior.
- Root PRIVACY.md (unlinked from the app, but the plain-text copy
  anyone browsing the repo on GitHub sees) was still describing the
  old policy verbatim, two days stale relative to docs/privacy.html
  (the one the app actually links to). Brought both into sync,
  including the "Last updated" date.

Verified the code already matches what the new policy promises:
kHealthDataContributionEnabled gates both the upload path and the
Settings/onboarding toggle's visibility; the toggle itself defaults
off (profile_setup_screen.dart); maybeUpload() re-checks the flag
directly as defense in depth. No functional/runtime change beyond the
ios CI flag flip.
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d9d83fb0-f23b-4352-8657-56dad25d5e4b

📥 Commits

Reviewing files that changed from the base of the PR and between f83f3f1 and aa5f3cb.

📒 Files selected for processing (1)
  • lib/ui/workouts/workouts_screen.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ui/workouts/workouts_screen.dart

📝 Walkthrough

Walkthrough

The changes update release-channel Firebase and health-data configuration, clarify privacy disclosures, correct readiness and stress derivation behavior, and revise UI flows for charts, onboarding progress, activity metrics, step goals, settings, consent, and workout deletion.

Changes

Release configuration and privacy policy

Layer / File(s) Summary
Release Firebase and health-data configuration
.github/workflows/build.yml, android/app/build.gradle.kts, ios/Runner.xcodeproj/project.pbxproj, lib/telemetry/health_uploader.dart
Release pipelines configure GitHub health-data contribution, Firebase setup is conditional on credentials, and iOS creates a placeholder Firebase plist when absent.
Privacy policy and user controls
PRIVACY.md, docs/privacy.html
Privacy disclosures distinguish official store releases from GitHub builds and document diagnostics, AI, Health integration, and health-data controls.

Health derivation and data integrity

Layer / File(s) Summary
Sleep-gated readiness derivation
lib/compute/derivation_engine.dart, lib/compute/onehz_pipeline.dart
Readiness RHR input now requires detected sleep data, and the derivation algorithm version changes from 46 to 47.
Stress score nullability
lib/data/local_repository_impl.dart, test/workout_enrichment_test.dart
Missing SI-derived stress scores remain null instead of being inferred from readiness, with corresponding tests updated.

Application UI and state flows

Layer / File(s) Summary
Collection progress state
lib/data/db.dart, lib/ui/kit/state_card.dart, lib/ui/today/today_screen.dart
Today queries first and last record timestamps and displays collection dates and progress in an extended state card.
Reusable heart-rate chart presentation
lib/ui/kit/charts.dart, lib/ui/screens/detail_cards.dart, lib/ui/today/today_screen.dart
Heart-rate charts share a widget for extrema chips and current-time cutoffs.
Activity metric and layout presentation
lib/ui/activity/strain_detail_screen.dart, lib/ui/design/rows.dart, lib/ui/activity/live_session_screen.dart
Training load is separated from energy metrics, long row values truncate, and live-session controls include the safe-area inset.
Unified step goal defaults
lib/data/local_repository.dart, lib/data/local_repository_impl.dart, lib/ui/screens/screens.dart, lib/ui/today/..., test/week_view_feed_test.dart
Step calculations use the shared 8,000-step default, including non-positive fallback values.
Settings, consent, and workout state
lib/ui/profile/profile_screen.dart, lib/ui/profile_setup_screen.dart, lib/ui/today/today_screen.dart, lib/state/app_state.dart, lib/ui/workouts/workouts_screen.dart
AI Coach is added to Profile, briefing and health-data controls are gated appropriately, and workout deletion is routed through AppState.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • OpenStrap/edge#81: Also changes the derivation engine algorithm version.
  • OpenStrap/edge#90: Also updates privacy policy content in docs/privacy.html.
  • OpenStrap/edge#93: Also modifies health-data contribution gating across build configuration and documentation.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is too generic and does not clearly describe the main change in this pull request. Use a concise, specific title that summarizes the primary change, such as privacy, build, and algorithm updates.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/contributor-feedback

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 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 `@android/app/build.gradle.kts`:
- Around line 6-28: The Firebase plugin application guard must not treat an
empty google-services.json as configured. Update the conditional around the
apply(plugin = ...) calls to require a non-empty, valid configuration file, or
ensure the CI workflow only writes the file when Firebase secrets are present;
preserve the optional Firebase behavior for missing or empty configuration.

In `@lib/data/db.dart`:
- Around line 2192-2206: Update firstAndLastRecordTs() to aggregate only
decoded_onehz rows with rec_ts > 0, matching the filtering used by rawStats()
and lastDecodedRecTs(). Preserve the existing null tuple behavior when no
qualifying rows exist.

In `@lib/state/app_state.dart`:
- Around line 3113-3118: Update deleteWorkout to use a dedicated non-persisting
active-workout cancellation path before deleting the repository row. That path
should stop and clear _workoutTimer, stop and clear _routeTracker, end the Live
Activity, and reset the active workout state without finalizing or persisting a
session; invoke it when activeWorkout.workoutId matches id, then retain the
existing deletion and notification flow.

In `@lib/telemetry/health_uploader.dart`:
- Around line 24-41: Make health-data contribution genuinely opt-in by
initializing the Profile consent setting healthShareConsent to false and
updating its UI copy to describe the default-off behavior. In
lib/telemetry/health_uploader.dart lines 24-41, preserve the documented
default-off contract; align the corresponding policy language in PRIVACY.md
lines 24-27 and docs/privacy.html lines 44-50 with the corrected consent
behavior.

In `@lib/ui/screens/screens.dart`:
- Line 315: Update the goal fallback in the surrounding StepGoalScreen logic to
use StepGoalScreen.defaultGoal whenever goal is null or non-positive, including
zero, matching the established behavior in TodayScreen. Preserve positive goal
values unchanged so progress calculations never divide by zero.

In `@lib/ui/today/today_screen.dart`:
- Line 941: Align the local repository defaults with StepGoalScreen.defaultGoal
by updating getProfile() and _stepGoal() in LocalRepositoryImpl to use the
shared default instead of 10000, while retaining the existing Today screen
fallback.
- Around line 494-514: Cache the Future returned by
LocalDb.firstAndLastRecordTs() in the Today screen state instead of constructing
it inline in the FutureBuilder. Initialize or refresh that cached future only
when raw changes, and have the FutureBuilder use the cached future so unrelated
rebuilds preserve its snapshot and avoid redundant queries.

In `@lib/ui/workouts/workouts_screen.dart`:
- Around line 908-911: Update the detail deletion flow around app.deleteWorkout
to return a deletion result when the workout is successfully removed, and have
WorkoutsScreen await the detail route result and reload its list when deletion
is reported. Preserve the existing behavior for cancellations and failed
deletions, using the route result as the refresh signal.
🪄 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: e44e2cf3-3169-43b5-a05b-8669978f8751

📥 Commits

Reviewing files that changed from the base of the PR and between 24c336b and 127e2fd.

📒 Files selected for processing (23)
  • .github/workflows/build.yml
  • PRIVACY.md
  • android/app/build.gradle.kts
  • docs/privacy.html
  • ios/Runner.xcodeproj/project.pbxproj
  • lib/compute/derivation_engine.dart
  • lib/compute/onehz_pipeline.dart
  • lib/data/db.dart
  • lib/data/local_repository_impl.dart
  • lib/state/app_state.dart
  • lib/telemetry/health_uploader.dart
  • lib/ui/activity/live_session_screen.dart
  • lib/ui/activity/strain_detail_screen.dart
  • lib/ui/design/rows.dart
  • lib/ui/kit/charts.dart
  • lib/ui/kit/state_card.dart
  • lib/ui/profile/profile_screen.dart
  • lib/ui/screens/detail_cards.dart
  • lib/ui/screens/screens.dart
  • lib/ui/today/today_screen.dart
  • lib/ui/workouts/workouts_screen.dart
  • test/week_view_feed_test.dart
  • test/workout_enrichment_test.dart

Comment thread android/app/build.gradle.kts
Comment thread lib/data/db.dart
Comment thread lib/state/app_state.dart
Comment on lines +3113 to +3118
Future<void> deleteWorkout(String id) async {
await repo?.deleteWorkout(id);
if (activeWorkout?.workoutId == id) {
activeWorkout = null;
_workoutRawBase = null;
notifyListeners();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Fully tear down an active workout before deleting it.

This clears only the in-memory flags. _workoutTimer, _routeTracker, and the Live Activity remain active; the route tracker can continue appending GPS points for the deleted workout ID. Add a dedicated non-persisting cancellation path that stops the timer/tracker and ends the Live Activity before removing the row. Do not call stopWorkout() blindly, because it first persists a finalized session.

🤖 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/state/app_state.dart` around lines 3113 - 3118, Update deleteWorkout to
use a dedicated non-persisting active-workout cancellation path before deleting
the repository row. That path should stop and clear _workoutTimer, stop and
clear _routeTracker, end the Live Activity, and reset the active workout state
without finalizing or persisting a session; invoke it when
activeWorkout.workoutId matches id, then retain the existing deletion and
notification flow.

Comment on lines +24 to +41
/// Two-tier by release channel (see docs/privacy.html's "GitHub releases"
/// section, the user-facing policy): OFF for any official App Store/Play
/// Store submission (once that pipeline exists it must pass
/// `ENABLE_HEALTH_DATA_CONTRIBUTION=false` explicitly), ON for the GitHub
/// Releases build (.github/workflows/build.yml, both android + ios jobs) —
/// but "ON" here only means the feature EXISTS in that binary; actual
/// upload additionally requires the user to explicitly flip the in-app
/// toggle, which defaults off and is itself hidden whenever this flag is
/// false. Uploading someone's entire raw + derived health history to a
/// backend is by far the biggest privacy/compliance surface this app could
/// have, so keep the App Store/Play Store channel's "we do not collect
/// your health data" promise (docs/privacy.html) true by construction of
/// the CI config, not contingent on nobody flipping this default later.
///
/// This flag exists purely because the code is open source: an independent
/// developer compiling their OWN build from this repo can opt in and point
/// it at a backend of their own choosing. That is their build and their
/// responsibility, not something our privacy policy governs.
/// developer compiling their OWN build from this repo can also opt in and
/// point it at a backend of their own choosing. That is their build and
/// their responsibility, not something our privacy policy governs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make health-data contribution genuinely opt-in before claiming it is.

The supplied Profile toggle says “On by default,” while these changes promise explicit consent and a default-off setting. This can permit full local health-database uploads after Wi-Fi/charging checks without the documented opt-in. Initialize healthShareConsent to false and update the UI copy, or revise all disclosures to describe the actual behavior.

  • lib/telemetry/health_uploader.dart#L24-L41: keep the default-off contract only after the consent default is corrected.
  • PRIVACY.md#L24-L27: align the policy with the corrected consent behavior.
  • docs/privacy.html#L44-L50: mirror the corrected policy language.
📍 Affects 3 files
  • lib/telemetry/health_uploader.dart#L24-L41 (this comment)
  • PRIVACY.md#L24-L27
  • docs/privacy.html#L44-L50
🤖 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/telemetry/health_uploader.dart` around lines 24 - 41, Make health-data
contribution genuinely opt-in by initializing the Profile consent setting
healthShareConsent to false and updating its UI copy to describe the default-off
behavior. In lib/telemetry/health_uploader.dart lines 24-41, preserve the
documented default-off contract; align the corresponding policy language in
PRIVACY.md lines 24-27 and docs/privacy.html lines 44-50 with the corrected
consent behavior.

Comment thread lib/ui/screens/screens.dart Outdated
Comment thread lib/ui/today/today_screen.dart
Comment thread lib/ui/today/today_screen.dart
Comment thread lib/ui/workouts/workouts_screen.dart
- android/build.gradle.kts + ios pbxproj: the Firebase-optional guard
  checked file existence only. CI writes google-services.json /
  GoogleService-Info.plist unconditionally from a secret
  (base64 -d > file), so an unset/blank secret produced a 0-byte file
  that still passed the "is Firebase configured" check and then failed
  the google-services plugin / Xcode resource copy trying to parse it.
  Both sides now also require the file to be non-empty.
- db.dart: firstAndLastRecordTs() was missing the `rec_ts > 0` filter
  its sibling queries (rawStats/lastDecodedRecTs) already have — a
  stray rec_ts=0 row would have rendered "Data from Jan 1" (1970
  epoch) in the onboarding progress card.
- app_state.dart: deleteWorkout only cleared activeWorkout in-memory;
  if the deleted session was GENUINELY still live, its timer, GPS
  route tracker, and Live Activity kept running against a now-deleted
  id. New _cancelActiveWorkoutTeardown() stops all three without
  persisting (unlike stopWorkout, which finalizes a session).
- workouts_screen.dart: deleting a workout from the detail screen
  popped without signaling the list screen (which doesn't observe
  AppState), leaving the deleted row visible until a manual refresh.
  Detail now pop(true)s on delete; the list awaits the push and
  reloads on that signal.
- profile_setup_screen.dart (real, more serious than reported):
  `_healthShare` and `ProfileSetupForm.healthShareInitial` both
  defaulted to `kHealthDataContributionEnabled` itself — meaning on
  any build compiling the feature in (GitHub releases, per the prior
  commit's new policy), the "Contribute my health data" toggle was
  PRE-CHECKED for every fresh enrollment, not off-by-default as
  promised. The flag must gate only whether the toggle is offered,
  never its starting value. Both now default to `false` unconditionally;
  a returning user's own previously-recorded choice is still honored.
  Updated the test that had encoded the buggy default as expected.
- screens.dart: the `goal ?? StepGoalScreen.defaultGoal` fallback
  didn't guard `goal == 0`/negative (division-by-zero /
  misleading-progress risk), inconsistent with today_screen.dart's
  `stepWeekRingData` which already guards `goal > 0`.
- Actual root cause of the step-goal-default miss: local_repository_impl.dart's
  getProfile()/_stepGoal() still hardcoded 10000 — that's where
  TodayData.stepGoal gets its default BEFORE any UI-level `?? 8000`
  fallback ever sees a null, so the UI fallback from the previous
  commit never actually fired for real profile data. Introduced
  kDefaultStepGoal (lib/data/local_repository.dart) as the single
  source of truth; StepGoalScreen.defaultGoal now just aliases it.

Verified: full test suite green (489 tests), flutter analyze clean,
and the two build-tooling fixes validated by actually building with a
0-byte google-services.json (fails before this fix, succeeds after).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/ui/workouts/workouts_screen.dart`:
- Around line 377-387: Guard the post-navigation refresh in the
WorkoutDetailScreen onTap callback by checking mounted before calling _load()
when deleted is true. Preserve the existing deletion signal and avoid invoking
_load() after WorkoutsScreen has been unmounted.
🪄 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: 1d6541ba-c51f-4c4e-85f0-e051751ad1cd

📥 Commits

Reviewing files that changed from the base of the PR and between 127e2fd and f83f3f1.

📒 Files selected for processing (12)
  • android/app/build.gradle.kts
  • ios/Runner.xcodeproj/project.pbxproj
  • lib/data/db.dart
  • lib/data/local_repository.dart
  • lib/data/local_repository_impl.dart
  • lib/state/app_state.dart
  • lib/ui/profile_setup_screen.dart
  • lib/ui/screens/screens.dart
  • lib/ui/today/step_goal_screen.dart
  • lib/ui/today/today_screen.dart
  • lib/ui/workouts/workouts_screen.dart
  • test/flow_screens_redesign_test.dart
🚧 Files skipped from review as they are similar to previous changes (6)
  • lib/state/app_state.dart
  • ios/Runner.xcodeproj/project.pbxproj
  • lib/ui/screens/screens.dart
  • lib/data/db.dart
  • lib/data/local_repository_impl.dart
  • lib/ui/today/today_screen.dart

Comment thread lib/ui/workouts/workouts_screen.dart
New CodeRabbit finding on PR #111 (posted after the previous fix
commit): the onTap handler awaits the detail-screen push and then
calls _load() (which calls setState) if a deletion was signaled — but
WorkoutsScreen itself could be unmounted by the time that await
resolves. Added the mounted guard.
@abdulsaheel
abdulsaheel merged commit 87aa728 into main Jul 21, 2026
1 check passed
@abdulsaheel
abdulsaheel deleted the fix/contributor-feedback branch July 21, 2026 02:25
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