Skip to content

Upgrades bottom nav bar Upgrade Bottom Navigation Bar - #61

Merged
Devasy merged 15 commits into
r2.1.0from
upgrades-bottom-nav-bar
Jul 23, 2026
Merged

Upgrades bottom nav bar Upgrade Bottom Navigation Bar#61
Devasy merged 15 commits into
r2.1.0from
upgrades-bottom-nav-bar

Conversation

@Devasy

@Devasy Devasy commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Introduced a floating, glass-style navigation bar with animated tab expansion, badges, and scroll-aware visibility.
    • Updated Android release builds with improved optimization, code protection, and symbol output for diagnostics.
    • Added flexible release signing configuration for local and automated builds.
  • Bug Fixes

    • Workout summaries now replace the active workout screen, preventing outdated screens from remaining in navigation history.
  • Quality

    • Expanded automated coverage for settings, storage, workouts, routines, history, health data, and API behavior.

Devasy added 10 commits July 11, 2026 19:15
…hain

- compileSdk + targetSdk: 36 → 37 (Android 17 / API 37)
- Removed compileSdkExtension (not needed for base API 37)
- Java source/target compatibility: VERSION_11 → VERSION_17
- Kotlin jvmTarget: 11 → 17
- Gradle wrapper: 8.12 → 8.14.1
- AGP: 8.9.1 → 8.11.1
- Kotlin Gradle Plugin: 2.1.0 → 2.2.20
- Enable android.builtInKotlin=true + android.newDsl=true
- Remove explicit id(kotlin-android) plugin (now injected by Flutter)
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 984002f3-a7be-41df-81d9-ce2d248ab312

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The pull request updates Android release tooling and CI workflows, replaces the home navigation bar with a floating implementation, changes workout completion navigation, and adds service, storage, model, and widget-flow tests.

Changes

Android release and CI

Layer / File(s) Summary
Android toolchain and signing
workout-logger/android/app/build.gradle.kts, workout-logger/android/key.properties.example, workout-logger/.gitignore
Android SDK and Java/Kotlin targets are raised, release signing supports environment or properties-file credentials, and credential files are ignored.
Release packaging and local build
.github/workflows/release.yml, workout-logger/android/app/proguard-rules.pro, workout-logger/scripts/build_release.py
Release builds enable shrinking, ProGuard, obfuscation, and split debug output; keystore validation and a local build script are added.
CI workflow execution
.github/workflows/release.yml, .github/workflows/test.yml
Workflow concurrency, action versions, permissions, caching, and shell failure detection are updated.

Floating navigation

Layer / File(s) Summary
Floating navigation widget
workout-logger/lib/screens/widgets/floating_nav_bar.dart
Adds floating navigation items, theming, glass effects, animated chips, badges, shadows, and scroll-aware visibility.
Home screen navigation integration
workout-logger/lib/screens/home_screen.dart, workout-logger/lib/screens/widgets/rf_widgets.dart
HomeScreen uses FloatingNavBarScaffold, and the previous RF navigation implementation is removed.

Application behavior and validation

Layer / File(s) Summary
Workout summary navigation
workout-logger/lib/screens/workout_flow_screen.dart
Completed workouts replace the active workout route when opening the summary screen.
Service, provider, and model coverage
workout-logger/test/api_service_test.dart, workout-logger/test/debug_log_buffer_test.dart, workout-logger/test/gemini_context_builder_test.dart, workout-logger/test/settings_provider_test.dart, workout-logger/test/sleep_hr_*, workout-logger/test/test_utils/*
Tests cover API behavior, logging, prompt construction, settings, sleep and heart-rate builders, and related models.
Storage persistence coverage
workout-logger/test/storage_service_test.dart
Hive-backed tests cover session, routine, target, custom exercise, and export/import persistence.
Widget userflow coverage
workout-logger/test/userflow_*
Widget tests cover history details, routine creation, settings persistence, workout logging, rest timers, and summaries.

Possibly related PRs

  • Devasy/RepForge#59: Android Gradle toolchain and SDK upgrades overlap with this pull request.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clearly related to the main change: a bottom navigation bar upgrade.
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.

@coderabbitai coderabbitai Bot changed the title Upgrades bottom nav bar @coderabbitai Upgrades bottom nav bar Upgrade Bottom Navigation Bar Jul 23, 2026

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

🤖 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 @.github/workflows/release.yml:
- Line 140: Update the release workflow step containing the Flutter APK build to
retain both Dart symbols from build/app/outputs/symbols and the R8 mapping file
at android/app/build/outputs/mapping/release/mapping.txt. Add a private artifact
upload with retention configured so these deobfuscation files are preserved
alongside the published APKs.
- Around line 127-130: Ensure release signing fails when any credential is
missing: in .github/workflows/release.yml lines 127-130, validate
KEYSTORE_BASE64, KEY_STORE_PASSWORD, KEY_ALIAS, and KEY_PASSWORD before
building; in workout-logger/android/app/build.gradle.kts lines 44-48, treat
blank environment values as absent before falling back to key.properties,
preventing incomplete credentials from selecting debug signing.
- Line 25: Pin every listed GitHub Action to a reviewed immutable commit SHA
instead of a mutable tag or branch. Update actions/checkout, actions/setup-java,
gradle/actions/setup-gradle, subosito/flutter-action, actions/upload-artifact,
softprops/action-gh-release, and codecov/codecov-action at all affected sites:
.github/workflows/release.yml lines 25-25, 31-31, 37-37, and 164-164, plus
.github/workflows/test.yml line 25-25.

In @.github/workflows/test.yml:
- Line 64: Remove the trailing blank line at the end of the workflow file so the
YAML lint check passes.
- Around line 37-40: Update the dependency installation step in the workflow to
run flutter pub get on every checkout by removing the CACHE-HIT condition from
the step using the flutter-action output. Preserve its working-directory and
command.

In `@workout-logger/lib/screens/widgets/floating_nav_bar.dart`:
- Around line 515-535: Update the chip decoration in the floating navigation bar
to use FloatingNavBarTheme.defaultChipBorderOpacity for the border alpha and
defaultChipShadowOpacity for the shadow alpha instead of the hardcoded 0.28 and
0.18 values. Preserve the existing colorP scaling and conditional rendering.
- Around line 584-602: Wrap the label Text in the showLabels branch of the
floating navigation bar’s chip content with Flexible, preserving its existing
opacity, styling, single-line, and clipping behavior so long labels remain
within the fixed-width Container.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5cc2e9ba-cbed-47fe-9db7-2bf5de8b69a1

📥 Commits

Reviewing files that changed from the base of the PR and between 5624818 and 3938598.

⛔ Files ignored due to path filters (1)
  • workout-logger/pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • .github/workflows/release.yml
  • .github/workflows/test.yml
  • README.md
  • workout-logger/.gitignore
  • workout-logger/android/app/build.gradle.kts
  • workout-logger/android/app/proguard-rules.pro
  • workout-logger/android/gradle.properties
  • workout-logger/android/gradle/wrapper/gradle-wrapper.properties
  • workout-logger/android/key.properties.example
  • workout-logger/android/settings.gradle.kts
  • workout-logger/fastlane/metadata/android/en-US/full_description.txt
  • workout-logger/lib/screens/home_screen.dart
  • workout-logger/lib/screens/widgets/floating_nav_bar.dart
  • workout-logger/lib/screens/widgets/rf_widgets.dart
  • workout-logger/pubspec.yaml
  • workout-logger/scripts/build_release.py

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow pins =="
grep -nE 'uses: [^[:space:]]+@' .github/workflows/release.yml .github/workflows/test.yml 2>/dev/null || true

echo
echo "== tracked workflow files =="
git ls-files .github/workflows || true

Repository: Devasy/RepForge

Length of output: 907


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re
for path in [Path(".github/workflows/release.yml"), Path(".github/workflows/test.yml")]:
    print(f"\n== {path} ==")
    for i, line in enumerate(path.read_text().splitlines(), 1):
        m = re.search(r'uses:\s*([^\s#]+)@([^\s#]+)', line)
        if m:
            ref = m.group(2)
            status = "SHA-like" if re.fullmatch(r'[0-9a-fA-F]{40}', ref) else "ref-like"
            print(f"{i}: {m.group(1)}@{m.group(2)} :: {status}")
PY

Repository: Devasy/RepForge

Length of output: 601


Pin GitHub Actions to immutable commit SHAs. Mutable tags/branches let upstream changes alter release or test workflow execution. Pin the checked-in action references to reviewed commit SHAs, including actions/checkout, actions/setup-java, gradle/actions/setup-gradle, subosito/flutter-action, actions/upload-artifact, softprops/action-gh-release, and codecov/codecov-action.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

📍 Affects 2 files
  • .github/workflows/release.yml#L25-L25 (this comment)
  • .github/workflows/release.yml#L31-L31
  • .github/workflows/release.yml#L37-L37
  • .github/workflows/release.yml#L164-L164
  • .github/workflows/test.yml#L25-L25
🤖 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 @.github/workflows/release.yml at line 25, Pin every listed GitHub Action to
a reviewed immutable commit SHA instead of a mutable tag or branch. Update
actions/checkout, actions/setup-java, gradle/actions/setup-gradle,
subosito/flutter-action, actions/upload-artifact, softprops/action-gh-release,
and codecov/codecov-action at all affected sites: .github/workflows/release.yml
lines 25-25, 31-31, 37-37, and 164-164, plus .github/workflows/test.yml line
25-25.

Source: Linters/SAST tools

Comment on lines +127 to +130
if [ -z "${{ secrets.KEYSTORE_BASE64 }}" ]; then
echo "Error: KEYSTORE_BASE64 secret is not configured in repository secrets."
exit 1
fi

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

Fail releases when any signing credential is absent. The workflow validates only KEYSTORE_BASE64, while Gradle leaves release signing unset when any password or alias is blank and silently signs with the debug key.

  • .github/workflows/release.yml#L127-L130: validate KEYSTORE_BASE64, KEY_STORE_PASSWORD, KEY_ALIAS, and KEY_PASSWORD before building.
  • workout-logger/android/app/build.gradle.kts#L44-L48: treat blank environment values as absent before falling back to key.properties.
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 127-127: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

📍 Affects 2 files
  • .github/workflows/release.yml#L127-L130 (this comment)
  • workout-logger/android/app/build.gradle.kts#L44-L48
🤖 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 @.github/workflows/release.yml around lines 127 - 130, Ensure release signing
fails when any credential is missing: in .github/workflows/release.yml lines
127-130, validate KEYSTORE_BASE64, KEY_STORE_PASSWORD, KEY_ALIAS, and
KEY_PASSWORD before building; in workout-logger/android/app/build.gradle.kts
lines 44-48, treat blank environment values as absent before falling back to
key.properties, preventing incomplete credentials from selecting debug signing.

KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: flutter build apk --release --split-per-abi
run: flutter build apk --release --split-per-abi --obfuscate --split-debug-info=build/app/outputs/symbols

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Retain Dart and R8 deobfuscation artifacts.

This runner is ephemeral and later steps only publish APKs, so production stack traces cannot be decoded. Upload build/app/outputs/symbols and android/app/build/outputs/mapping/release/mapping.txt as a private retained artifact.

🤖 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 @.github/workflows/release.yml at line 140, Update the release workflow step
containing the Flutter APK build to retain both Dart symbols from
build/app/outputs/symbols and the R8 mapping file at
android/app/build/outputs/mapping/release/mapping.txt. Add a private artifact
upload with retention configured so these deobfuscation files are preserved
alongside the published APKs.

Comment on lines 37 to 40
- name: Install dependencies
if: steps.flutter-action.outputs.PUB-CACHE-HIT != 'true'
if: steps.flutter-action.outputs.CACHE-HIT != 'true'
working-directory: ./workout-logger
run: flutter pub get

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow files =="
git ls-files .github/workflows || true

echo "== test workflow excerpt =="
if [ -f .github/workflows/test.yml ]; then
  nl -ba .github/workflows/test.yml | sed -n '1,140p'
fi

echo "== flutter-action/cache references =="
rg -n "flutter-action|CACHE-HIT|flutter pub get|pub get|dart_tool/package_config|flutter analyze|flutter test" .github/workflows workout-logger 2>/dev/null || true

echo "== flutter action usage context in tracked files =="
for f in $(git ls-files .github/workflows); do
  echo "--- $f"
  nl -ba "$f" | sed -n '1,220p'
done

Repository: Devasy/RepForge

Length of output: 299


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpts =="
for f in .github/workflows/release.yml .github/workflows/test.yml; do
  if [ -f "$f" ]; then
    echo "--- $f"
    awk '{printf "%6d  %s\n", NR, $0}' "$f" | sed -n '1,220p'
  fi
done

echo "== search relevant references =="
rg -n "flutter-action|CACHE-HIT|flutter pub get|pub get|dart_tool/package_config|flutter analyze|flutter test|subosito" .github/workflows workout-logger 2>/dev/null || true

Repository: Devasy/RepForge

Length of output: 11942


🌐 Web query:

subosito flutter-action v2 cache true CACHE-HIT output generated files .dart_tool/package_config.json

💡 Result:

The subosito/flutter-action action (v2) with cache: true enabled does not automatically cache the.dart_tool/package_config.json file or your project's generated files [1][2][3]. When you enable cache: true, the action uses actions/cache internally to cache two specific areas [4]: 1. The Flutter SDK installation [1][4]. 2. The Dart/Flutter pub package cache (commonly located in ~/.pub-cache) [1][4][5]. The CACHE-HIT and PUB-CACHE-HIT outputs provided by the action reflect whether an exact match was found for these specific SDK and pub caches, respectively [2][6][3]. They do not indicate the presence or validity of your project's local build artifacts like.dart_tool/package_config.json [2][7]. If you need to persist generated files (such as those in.dart_tool,.g.dart files, etc.) across workflow runs, you must explicitly add a separate actions/cache step to your workflow configuration [8]. Example of how to manually cache these files: - name: Cache generated files uses: actions/cache@v4 with: path: |.dart_tool/package_config.json /.dart_tool key: build-artifacts-${{ hashFiles('/pubspec.lock') }} [8] The CACHE-HIT output from subosito/flutter-action is solely for the action's own internal caching logic [2][9]. You should not rely on it as a proxy for the state of your application's generated build artifacts [2][7].

Citations:


Run flutter pub get on every checkout.

A cache hit from subosito/flutter-action restores the Flutter package cache/SDK, not the checkout’s generated .dart_tool/package_config.json; skipping flutter pub get on cache hits can make analyze or test fail.

Proposed fix
       - name: Install dependencies
-        if: steps.flutter-action.outputs.CACHE-HIT != 'true'
         working-directory: ./workout-logger
         run: flutter pub get
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Install dependencies
if: steps.flutter-action.outputs.PUB-CACHE-HIT != 'true'
if: steps.flutter-action.outputs.CACHE-HIT != 'true'
working-directory: ./workout-logger
run: flutter pub get
- name: Install dependencies
working-directory: ./workout-logger
run: flutter pub get
🤖 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 @.github/workflows/test.yml around lines 37 - 40, Update the dependency
installation step in the workflow to run flutter pub get on every checkout by
removing the CACHE-HIT condition from the step using the flutter-action output.
Preserve its working-directory and command.

with:
files: workout-logger/coverage/lcov.info
token: ${{ secrets.CODECOV_TOKEN }}

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the trailing blank line.

YAMLlint reports this as an error, so the workflow lint check will fail.

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 64-64: too many blank lines (1 > 0)

(empty-lines)

🤖 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 @.github/workflows/test.yml at line 64, Remove the trailing blank line at the
end of the workflow file so the YAML lint check passes.

Source: Linters/SAST tools

Comment on lines +515 to +535
decoration: BoxDecoration(
color: Color.lerp(Colors.transparent, widget.chipBg, colorP),
borderRadius: BorderRadius.circular(9999),
border: colorP > 0.05
? Border.all(
color: (t.selectedChipBorderColor ?? widget.chipContent)
.withValues(alpha: 0.28 * colorP),
width: 1.0,
)
: null,
boxShadow: colorP > 0.05
? [
BoxShadow(
color:
(t.selectedChipShadowColor ?? widget.chipContent)
.withValues(alpha: 0.18 * colorP),
blurRadius: 14,
spreadRadius: -2,
),
]
: null,

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.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Chip border/shadow opacities are hardcoded, ignoring the theme fields.

defaultChipBorderOpacity (0.25) and defaultChipShadowOpacity (0.15) are declared on FloatingNavBarTheme (Lines 209-210) but never read — the chip decoration uses literals 0.28 and 0.18 instead, so these knobs are dead. Wire them through for a consistent, configurable API.

♻️ Use theme-configured opacities
                 border: colorP > 0.05
                     ? Border.all(
                         color: (t.selectedChipBorderColor ?? widget.chipContent)
-                            .withValues(alpha: 0.28 * colorP),
+                            .withValues(alpha: t.defaultChipBorderOpacity * colorP),
                         width: 1.0,
                       )
                     : null,
                 boxShadow: colorP > 0.05
                     ? [
                         BoxShadow(
                           color:
                               (t.selectedChipShadowColor ?? widget.chipContent)
-                                  .withValues(alpha: 0.18 * colorP),
+                                  .withValues(alpha: t.defaultChipShadowOpacity * colorP),
                           blurRadius: 14,
                           spreadRadius: -2,
                         ),
                       ]
                     : null,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
decoration: BoxDecoration(
color: Color.lerp(Colors.transparent, widget.chipBg, colorP),
borderRadius: BorderRadius.circular(9999),
border: colorP > 0.05
? Border.all(
color: (t.selectedChipBorderColor ?? widget.chipContent)
.withValues(alpha: 0.28 * colorP),
width: 1.0,
)
: null,
boxShadow: colorP > 0.05
? [
BoxShadow(
color:
(t.selectedChipShadowColor ?? widget.chipContent)
.withValues(alpha: 0.18 * colorP),
blurRadius: 14,
spreadRadius: -2,
),
]
: null,
decoration: BoxDecoration(
color: Color.lerp(Colors.transparent, widget.chipBg, colorP),
borderRadius: BorderRadius.circular(9999),
border: colorP > 0.05
? Border.all(
color: (t.selectedChipBorderColor ?? widget.chipContent)
.withValues(alpha: t.defaultChipBorderOpacity * colorP),
width: 1.0,
)
: null,
boxShadow: colorP > 0.05
? [
BoxShadow(
color:
(t.selectedChipShadowColor ?? widget.chipContent)
.withValues(alpha: t.defaultChipShadowOpacity * colorP),
blurRadius: 14,
spreadRadius: -2,
),
]
: null,
🤖 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 `@workout-logger/lib/screens/widgets/floating_nav_bar.dart` around lines 515 -
535, Update the chip decoration in the floating navigation bar to use
FloatingNavBarTheme.defaultChipBorderOpacity for the border alpha and
defaultChipShadowOpacity for the shadow alpha instead of the hardcoded 0.28 and
0.18 values. Preserve the existing colorP scaling and conditional rendering.

Comment on lines +584 to +602
if (t.showLabels && extraW > 1.0) ...[
Opacity(
opacity: labelOpacity,
child: Text(
widget.item.label,
style: (t.labelStyle ??
const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
letterSpacing: 0.1,
))
.copyWith(color: widget.chipContent),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
),
),
SizedBox(width: rightPad),
],

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Unconstrained label can overflow the fixed-width chip.

The chip Container width is clamped using the constant labelWidth (Line 511-514), but the label Text has an intrinsic width driven by the actual string. For longer labels the Row (mainAxisSize.min) can exceed the container width and trip a RenderFlex overflow. Since this is a reusable widget, wrap the label in Flexible so it clips within the available space instead of overflowing.

🛡️ Constrain the label
-                      Opacity(
-                        opacity: labelOpacity,
-                        child: Text(
-                          widget.item.label,
-                          style: (t.labelStyle ??
-                                  const TextStyle(
-                                    fontSize: 13,
-                                    fontWeight: FontWeight.w600,
-                                    letterSpacing: 0.1,
-                                  ))
-                              .copyWith(color: widget.chipContent),
-                          maxLines: 1,
-                          softWrap: false,
-                          overflow: TextOverflow.clip,
-                        ),
-                      ),
+                      Flexible(
+                        child: Opacity(
+                          opacity: labelOpacity,
+                          child: Text(
+                            widget.item.label,
+                            style: (t.labelStyle ??
+                                    const TextStyle(
+                                      fontSize: 13,
+                                      fontWeight: FontWeight.w600,
+                                      letterSpacing: 0.1,
+                                    ))
+                                .copyWith(color: widget.chipContent),
+                            maxLines: 1,
+                            softWrap: false,
+                            overflow: TextOverflow.clip,
+                          ),
+                        ),
+                      ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (t.showLabels && extraW > 1.0) ...[
Opacity(
opacity: labelOpacity,
child: Text(
widget.item.label,
style: (t.labelStyle ??
const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
letterSpacing: 0.1,
))
.copyWith(color: widget.chipContent),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
),
),
SizedBox(width: rightPad),
],
Flexible(
child: Opacity(
opacity: labelOpacity,
child: Text(
widget.item.label,
style: (t.labelStyle ??
const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
letterSpacing: 0.1,
))
.copyWith(color: widget.chipContent),
maxLines: 1,
softWrap: false,
overflow: TextOverflow.clip,
),
),
),
SizedBox(width: rightPad),
🤖 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 `@workout-logger/lib/screens/widgets/floating_nav_bar.dart` around lines 584 -
602, Wrap the label Text in the showLabels branch of the floating navigation
bar’s chip content with Flexible, preserving its existing opacity, styling,
single-line, and clipping behavior so long labels remain within the fixed-width
Container.

@Devasy
Devasy changed the base branch from main to r2.1.0 July 23, 2026 10:29
@Devasy

Devasy commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🤖 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 `@workout-logger/test/sleep_hr_builder_test.dart`:
- Around line 7-38: Extract the duplicated _StubHcService implementation from
workout-logger/test/sleep_hr_builder_test.dart lines 7-38 into
workout-logger/test/test_utils/stub_health_connect_service.dart, preserving its
constructor defaults and IHealthConnectService behavior. Update
workout-logger/test/sleep_hr_builder_test.dart lines 7-38 to import and use the
shared helper, and replace the duplicate definition in
workout-logger/test/userflow_history_and_session_details_test.dart lines 15-36
with the same shared helper.

In `@workout-logger/test/sleep_hr_models_test.dart`:
- Around line 24-32: Make the SleepStageStats construction assigned to stats
const, matching the existing const construction later in the test and the
literal-only arguments.

In `@workout-logger/test/userflow_history_and_session_details_test.dart`:
- Around line 124-151: The tests directly construct sub-widgets instead of
exercising their real userflow transitions. In
workout-logger/test/userflow_history_and_session_details_test.dart:124-151,
update the test around SessionDetailsSheet to pump HistoryScreen and tap the
relevant history list item; in
workout-logger/test/userflow_workout_logging_test.dart:79-129, drive
WorkoutFlowScreen through an actual rest-timer countdown and workout completion
so RestTimerView and WorkoutSummaryScreen appear through the production flow,
preserving the existing assertions.

In `@workout-logger/test/userflow_settings_and_storage_test.dart`:
- Around line 64-76: The test “Toggling weight unit in SettingsProvider persists
to storage and updates display label” only checks provider state, not rendered
UI. Update this test to render SettingsScreen with the test harness, toggle the
weight unit through the screen, and assert the updated label using the widget
finder pattern established by the first test in the file, while retaining the
existing persistence and provider assertions.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3d79a405-f0a6-4cca-b623-5f24324ee083

📥 Commits

Reviewing files that changed from the base of the PR and between 3938598 and 6553a7d.

📒 Files selected for processing (11)
  • workout-logger/test/api_service_test.dart
  • workout-logger/test/debug_log_buffer_test.dart
  • workout-logger/test/gemini_context_builder_test.dart
  • workout-logger/test/settings_provider_test.dart
  • workout-logger/test/sleep_hr_builder_test.dart
  • workout-logger/test/sleep_hr_models_test.dart
  • workout-logger/test/storage_service_test.dart
  • workout-logger/test/userflow_history_and_session_details_test.dart
  • workout-logger/test/userflow_routine_creation_test.dart
  • workout-logger/test/userflow_settings_and_storage_test.dart
  • workout-logger/test/userflow_workout_logging_test.dart

Comment thread workout-logger/test/sleep_hr_builder_test.dart Outdated
Comment thread workout-logger/test/sleep_hr_models_test.dart Outdated
Comment thread workout-logger/test/userflow_history_and_session_details_test.dart Outdated
Comment on lines +64 to +76
testWidgets('Toggling weight unit in SettingsProvider persists to storage and updates display label', (tester) async {
expect(settingsProvider.weightUnit, equals(WeightUnit.kg));
expect(settingsProvider.unitLabel, equals('kg'));

await settingsProvider.setWeightUnit(WeightUnit.lbs);
expect(settingsProvider.weightUnit, equals(WeightUnit.lbs));
expect(settingsProvider.unitLabel, equals('lbs'));
expect(mockStorage.settings['weightUnit'], equals('lbs'));

await settingsProvider.setWeightIncrement(5.0);
expect(settingsProvider.weightIncrement, equals(5.0));
expect(mockStorage.settings['weightIncrement'], equals('5.0'));
});

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.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't verify the "display label" update it claims to.

This test only exercises SettingsProvider directly (no pumpWidget call), so the described UI-label-update behavior is never actually checked against rendered output. Consider rendering SettingsScreen and asserting the updated unit label appears (e.g. via find.text), similar to the first test in this file.

🤖 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 `@workout-logger/test/userflow_settings_and_storage_test.dart` around lines 64
- 76, The test “Toggling weight unit in SettingsProvider persists to storage and
updates display label” only checks provider state, not rendered UI. Update this
test to render SettingsScreen with the test harness, toggle the weight unit
through the screen, and assert the updated label using the widget finder pattern
established by the first test in the file, while retaining the existing
persistence and provider assertions.

@Devasy

Devasy commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Caution

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

⚠️ Outside diff range comments (1)
workout-logger/test/sleep_hr_builder_test.dart (1)

80-82: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the calculated sleep values, not only non-emptiness.

This test is named as a calculation test but would pass with incorrect values. Assert representative segment and deep-stage statistics such as min/max BPM, stage, and sample count.

🤖 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 `@workout-logger/test/sleep_hr_builder_test.dart` around lines 80 - 82,
Strengthen the calculation test assertions after the existing snapshot checks by
verifying representative calculated values in snapshot.segments and
snapshot.stageStats, including expected minimum and maximum BPM, sleep stage,
and sample count. Use the fixture’s known expected values so the test fails when
calculations are incorrect rather than merely empty.
🤖 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 `@workout-logger/test/sleep_hr_builder_test.dart`:
- Line 9: Update the granted HealthReadType set in the test to include
HealthReadType.restingHeartRate, then assert that the resulting
buildHrDaySnapshot value has restingBpm equal to 58. Apply the same fixture and
assertion adjustment to the related test ranges so the resting-HR branch is
exercised consistently.

In `@workout-logger/test/test_utils/stub_health_connect_service.dart`:
- Around line 16-20: Update the read methods in the health-connect stub,
including readSleepSessions, readHeartRateSamples, and readRestingHeartRate, to
return fresh list copies rather than the backing fixture lists. Preserve the
existing fixture contents while preventing callers such as buildHrDaySnapshot
from mutating shared test state.
- Around line 9-13: Update the StubHcService constructor to be const, preserving
its existing parameters and compile-time default values.

---

Outside diff comments:
In `@workout-logger/test/sleep_hr_builder_test.dart`:
- Around line 80-82: Strengthen the calculation test assertions after the
existing snapshot checks by verifying representative calculated values in
snapshot.segments and snapshot.stageStats, including expected minimum and
maximum BPM, sleep stage, and sample count. Use the fixture’s known expected
values so the test fails when calculations are incorrect rather than merely
empty.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 621e3f68-e3d6-4464-94da-9fa1b10efecc

📥 Commits

Reviewing files that changed from the base of the PR and between 6553a7d and fefbd92.

📒 Files selected for processing (7)
  • workout-logger/lib/screens/workout_flow_screen.dart
  • workout-logger/test/sleep_hr_builder_test.dart
  • workout-logger/test/sleep_hr_models_test.dart
  • workout-logger/test/test_utils/stub_health_connect_service.dart
  • workout-logger/test/userflow_history_and_session_details_test.dart
  • workout-logger/test/userflow_settings_and_storage_test.dart
  • workout-logger/test/userflow_workout_logging_test.dart

import 'test_utils/stub_health_connect_service.dart';

void main() {
final granted = <HealthReadType>{HealthReadType.heartRate, HealthReadType.sleep};

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Exercise the resting-HR branch instead of supplying dead fixture data.

Line 9 omits HealthReadType.restingHeartRate, so buildHrDaySnapshot never reads the resting fixture and falls back to the ordinary HR samples. Add that permission and assert snapshot.restingBpm == 58 so this test verifies the behavior named in its description.

Proposed test adjustment
-  final granted = <HealthReadType>{HealthReadType.heartRate, HealthReadType.sleep};
+  final granted = <HealthReadType>{
+    HealthReadType.heartRate,
+    HealthReadType.sleep,
+    HealthReadType.restingHeartRate,
+  };

...
       expect(snapshot!.minBpm, equals(70));
       expect(snapshot.maxBpm, equals(120));
+      expect(snapshot.restingBpm, equals(58));
       expect(snapshot.buckets, isNotEmpty);

Also applies to: 29-37, 41-44

🤖 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 `@workout-logger/test/sleep_hr_builder_test.dart` at line 9, Update the granted
HealthReadType set in the test to include HealthReadType.restingHeartRate, then
assert that the resulting buildHrDaySnapshot value has restingBpm equal to 58.
Apply the same fixture and assertion adjustment to the related test ranges so
the resting-HR branch is exercised consistently.

Comment on lines +9 to +13
StubHcService({
this.sleepPeriods = const [],
this.hrSamples = const [],
this.restingHrSamples = const [],
});

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.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the test stub constructor const.

All fields are final and the default values are compile-time constants, so this constructor can be declared const, as required by the Dart guidelines.

Proposed fix
-  StubHcService({
+  const StubHcService({
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
StubHcService({
this.sleepPeriods = const [],
this.hrSamples = const [],
this.restingHrSamples = const [],
});
const StubHcService({
this.sleepPeriods = const [],
this.hrSamples = const [],
this.restingHrSamples = const [],
});
🤖 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 `@workout-logger/test/test_utils/stub_health_connect_service.dart` around lines
9 - 13, Update the StubHcService constructor to be const, preserving its
existing parameters and compile-time default values.

Source: Coding guidelines

Comment on lines +16 to +20
Future<List<SleepPeriod>> readSleepSessions(DateTime start, DateTime end) async => sleepPeriods;
@override
Future<List<HealthSample>> readHeartRateSamples(DateTime start, DateTime end) async => hrSamples;
@override
Future<List<HealthSample>> readRestingHeartRate(DateTime start, DateTime end) async => restingHrSamples;

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 | 🔵 Trivial | ⚡ Quick win

Return copies of fixture lists from the stub.

buildHrDaySnapshot sorts the list returned by readRestingHeartRate in place. Returning restingHrSamples directly mutates the caller’s fixture and can leak state between tests; return fresh lists for all read methods.

Proposed fix
-  Future<List<SleepPeriod>> readSleepSessions(DateTime start, DateTime end) async => sleepPeriods;
+  Future<List<SleepPeriod>> readSleepSessions(DateTime start, DateTime end) async => List.of(sleepPeriods);
...
-  Future<List<HealthSample>> readHeartRateSamples(DateTime start, DateTime end) async => hrSamples;
+  Future<List<HealthSample>> readHeartRateSamples(DateTime start, DateTime end) async => List.of(hrSamples);
...
-  Future<List<HealthSample>> readRestingHeartRate(DateTime start, DateTime end) async => restingHrSamples;
+  Future<List<HealthSample>> readRestingHeartRate(DateTime start, DateTime end) async => List.of(restingHrSamples);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Future<List<SleepPeriod>> readSleepSessions(DateTime start, DateTime end) async => sleepPeriods;
@override
Future<List<HealthSample>> readHeartRateSamples(DateTime start, DateTime end) async => hrSamples;
@override
Future<List<HealthSample>> readRestingHeartRate(DateTime start, DateTime end) async => restingHrSamples;
Future<List<SleepPeriod>> readSleepSessions(DateTime start, DateTime end) async => List.of(sleepPeriods);
`@override`
Future<List<HealthSample>> readHeartRateSamples(DateTime start, DateTime end) async => List.of(hrSamples);
`@override`
Future<List<HealthSample>> readRestingHeartRate(DateTime start, DateTime end) async => List.of(restingHrSamples);
🤖 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 `@workout-logger/test/test_utils/stub_health_connect_service.dart` around lines
16 - 20, Update the read methods in the health-connect stub, including
readSleepSessions, readHeartRateSamples, and readRestingHeartRate, to return
fresh list copies rather than the backing fixture lists. Preserve the existing
fixture contents while preventing callers such as buildHrDaySnapshot from
mutating shared test state.

@Devasy
Devasy merged commit d386bbe into r2.1.0 Jul 23, 2026
1 check passed
@Devasy
Devasy deleted the upgrades-bottom-nav-bar branch July 23, 2026 15:45
@coderabbitai coderabbitai Bot mentioned this pull request Aug 7, 2026
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