Skip to content

Add CLAUDE.md with comprehensive codebase documentation - #32

Merged
Devasy merged 15 commits into
mainfrom
claude/add-1rm-weight-units-xsTBq
Apr 16, 2026
Merged

Add CLAUDE.md with comprehensive codebase documentation#32
Devasy merged 15 commits into
mainfrom
claude/add-1rm-weight-units-xsTBq

Conversation

@Devasy

@Devasy Devasy commented Apr 3, 2026

Copy link
Copy Markdown
Owner

Documents project structure, architecture patterns (SOLID), data models,
development commands, testing conventions, CI/CD pipeline, theme system,
and key conventions for AI assistants working on the codebase.

https://claude.ai/code/session_01NytaxeQoLadhKcESsKqjmT

Summary by CodeRabbit

Release Notes

  • New Features

    • Training program builder: Create and customize multi-week training programs with phases, deload weeks, and exercise programming.
    • Program import/export: Share and import training programs as JSON files.
    • Profile screen: Manage preferences, export/import workout data, and access app information.
    • Weight unit preferences: Switch between kg/lbs with customizable increments.
    • 1RM estimation: Display estimated one-rep max in analytics.
    • Program-based workouts: Execute programs with automatic superset tracking and deload adjustments.
  • Tests

    • Added automated test coverage for training programs and existing workflows.

claude and others added 15 commits March 18, 2026 16:49
Documents project structure, architecture patterns (SOLID), data models,
development commands, testing conventions, CI/CD pipeline, theme system,
and key conventions for AI assistants working on the codebase.

https://claude.ai/code/session_01NytaxeQoLadhKcESsKqjmT
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Adds a complete multi-week training program feature inspired by the
12-week periodisation reference plan (phases, deload weeks, tempo
notation, rep ranges, rest times, superset grouping).

Models (models.dart):
- ProgramExerciseSlot — per-exercise parameters (sets, rep range,
  rest seconds, tempo, weight %, notes, superset group)
- ProgramDay — named training day with ordered exercise slots
- ProgramWeek — week with deload flag, intensity factor, set reduction
- TrainingPhase — named phase spanning a range of weeks
- TrainingProgram — top-level entity; full JSON serialization

Storage:
- New 'training_programs' Hive box in StorageService
- saveTrainingProgram / getAllTrainingPrograms / getTrainingProgram /
  deleteTrainingProgram added to IStorageService interface and
  implemented in StorageService + MockStorageService

ProgramManager (SRP manager):
- loadPrograms, saveProgram, createProgram, deleteProgram
- importFromJson (assigns new UUID, marks isImported=true)
- exportToJson (pretty-printed)

WorkoutProvider:
- Exposes programManager; loadPrograms() called during init

UI (screens/programs/):
- ProgramsScreen — list with mini phase timeline, import FAB
- ProgramDetailScreen — phase timeline bar, expandable week list
  with deload badges, per-day exercise breakdown (sets×reps,
  rest, tempo chip, weight %, superset bracket, notes)
- ProgramDesignerScreen — 3-step wizard: metadata/phases →
  week structure (deload toggle, intensity/set-reduction steppers,
  add days) → exercise slots per day with full parameter editing

RoutinesScreen:
- Added Programs tab (TabBar + TabBarView) alongside existing
  Routines tab; no existing functionality changed

https://claude.ai/code/session_01E15CGTZZDU8rz7PX1nYXA3
example_12_week_program.json (docs/):
  - 12 weeks · 3 phases (Foundation W1–4, Intensify W5–8, Peak W9–12)
  - 5 training days/week: Push (Mon), Core (Wed), Pull (Thu),
    Shoulders & Arms (Fri), Legs + Rehab (Sat)
  - 344 exercise slots across 60 days (~98 KB)
  - Deload weeks 5 (85% / −1 set) and 9 (90% / −1 set)
  - Supersets encoded with supersetGroupId per phase:
    ss-push-a  (tricep pushdown + lateral raise, W5+)
    ss-pull-a  (preacher curl + hammer curl, W5+)
    ss-shld-a  (lateral raise + rear delt fly, W5+)
    ss-arm-a   (bicep curl + tricep pushdown, W5+)
  - All exercise IDs match built-in ExerciseDatabase entries
  - Tempo notation on all compound lifts (e.g. "3-1-1")

ImportProgramScreen (screens/programs/import_program_screen.dart):
  - Full-screen page replaces the cramped 8-line bottom sheet
  - Expands text area fills available viewport height (maxLines: null)
  - Live char / line / KB counter in status bar
  - Two-step flow: Validate → Import (button disabled until valid)
  - Inline field-level error messages (missing key, wrong type)
  - Green border + "Valid JSON" indicator on success
  - Red border + inline error on failure
  - Clear (×) button in AppBar

ProgramsScreen:
  - _showImportDialog / _doImport / _friendlyError removed
  - Replaced with _openImport → Navigator.push to ImportProgramScreen
  - Success snackbar shown on return with result == true

https://claude.ai/code/session_01E15CGTZZDU8rz7PX1nYXA3
file_picker (already in pubspec) is now wired into the import screen:
  - Folder icon in AppBar opens native file picker filtered to .json
  - Selected file content is read and loaded into the text field
  - Validation / Import flow unchanged after loading

Instructions banner updated to mention both input methods.

https://claude.ai/code/session_01E15CGTZZDU8rz7PX1nYXA3
- WorkoutFlowScreen: add programDay/programWeek optional params so any
  day in a program can be started directly from the detail screen
- Slot-based rest time: rest seconds are pulled from ProgramExerciseSlot
  and applied automatically when completing each set
- Superset auto-advance: completing a set advances immediately to the
  next exercise (no rest timer) when both share the same supersetGroupId
- Program meta banner: shown above the SET DONE button during
  program-mode workouts; displays target sets×rep-range, rest duration,
  tempo, 1RM %, deload indicator, superset label, and slot notes
- Pull-up/chin-up assist mode: weight input label changes to
  'Assist kg (0=BW)' for pull_ups and chin_ups exercise IDs
- ProgramDetailScreen: add 'Start <DayName>' ElevatedButton at the
  bottom of each expanded day section; navigates to WorkoutFlowScreen
  with the correct programDay and programWeek context

https://claude.ai/code/session_01E15CGTZZDU8rz7PX1nYXA3
Supersets now follow the correct E1→E2 (no rest)→rest→E1→E2 cycle:

- Add WorkoutProvider.goToExercise(index) for direct index navigation
- Track _supersetReturnIndex: set when completing the last exercise in a
  superset group if the group still has unfinished sets
- _skipRest() now navigates back to the superset group start when
  _supersetReturnIndex is set, restoring the correct exercise and rest time
- Add _supersetGroupStart() to scan backward and find the group's first index
- Add _supersetNeedsMoreSets() to check deload-adjusted target sets vs logged

Flow: set1(E1) → advance to E2 → set1(E2) → rest → return to E1 →
      set2(E1) → advance to E2 → set2(E2) → rest → continue to E3

https://claude.ai/code/session_01E15CGTZZDU8rz7PX1nYXA3
… dropsets, alongside program design and detail screens.
…xerciseScreen, along with project configuration in pubspec.yaml.
…ercises, and workout flow, supported by new screens and tests.
- Add SettingsProvider for weight unit (kg/lbs) and configurable
  weight increments (1.25/2.5/5/10 kg or 2.5/5/10/25 lbs), persisted
  via IStorageService settings key-value store
- Add Preferences section to Settings screen with unit toggle and
  increment chip selector
- Show estimated 1RM (Epley formula) per set in workout flow screen
  and as a "Best 1RM" card in analytics exercise tab
- Apply selected unit/increment throughout workout flow (labels, step
  values, display conversion) and analytics session history
- Fix numeric keyboard in weight/reps fields: use numberWithOptions
  instead of TextInputType.number; add isScrollControlled + FocusNode
  + viewInsets padding to the number picker bottom sheet so keyboard
  doesn't overlap content

https://claude.ai/code/session_01GhMv58Dda7sCxNJYznGxn9
Consolidates all user-facing settings into a dedicated Profile tab:

- Profile header with RepForge logo, app name, and version (v1.0.12)
- Preferences section: kg/lbs unit toggle + configurable weight
  increment chips (persisted via SettingsProvider)
- Data Management section: local export/import and cloud backup
  actions, migrated from standalone SettingsScreen
- Cloud Sync section: MongoDB connection string placeholder with
  "Coming Soon" badge — ready to wire up in a future update
- About section: version, created by Devasy Patel, platform, package
- Settings gear icon in home dashboard header now navigates directly
  to the Profile tab instead of pushing a separate route

https://claude.ai/code/session_01GhMv58Dda7sCxNJYznGxn9
@coderabbitai

coderabbitai Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a comprehensive training program management system including new domain models (TrainingProgram, TrainingPhase, ProgramWeek, ProgramDay, ProgramExerciseSlot), a ProgramManager service for CRUD operations, UI screens for designing/importing/viewing programs, a SettingsProvider for weight unit preferences, a ProfileScreen for user preferences and data management, GitHub Actions CI workflow, and Flutter expertise documentation.

Changes

Cohort / File(s) Summary
GitHub Configuration
.github/skills/flutter-expert/SKILL.md, .github/workflows/test.yml
Added Flutter expert skill definition and GitHub Actions test workflow with Flutter setup, analysis, and test execution on push/PR/release to main branch.
Domain Models
workout-logger/lib/models/models.dart
Added five new training program domain classes: ProgramExerciseSlot, ProgramDay, ProgramWeek, TrainingPhase, and TrainingProgram with serialization, copyWith methods, and phase/week mapping utilities.
Services & Managers
workout-logger/lib/services/settings_provider.dart, workout-logger/lib/services/managers/program_manager.dart, workout-logger/lib/services/managers/managers.dart, workout-logger/lib/services/interfaces/storage_service_interface.dart, workout-logger/lib/services/storage_service.dart
Introduced SettingsProvider for weight unit management, new ProgramManager for training program CRUD operations, expanded IStorageService interface and StorageService implementation with program persistence methods, and added manager exports.
Workout Provider & Initialization
workout-logger/lib/services/workout_provider.dart, workout-logger/lib/main.dart
Added programManager dependency to WorkoutProvider, methods for 1RM estimation and best 1RM lookup, and navigation to exercises; updated app initialization to load ProgramManager and SettingsProvider as DI singletons.
Program Management Screens
workout-logger/lib/screens/programs/programs_screen.dart, workout-logger/lib/screens/programs/program_designer_screen.dart, workout-logger/lib/screens/programs/program_detail_screen.dart, workout-logger/lib/screens/programs/import_program_screen.dart
Added four new screens for program management: list view with empty state, multi-step designer wizard for creating/editing programs with phases and exercises, detailed view with week/day/exercise rendering and export/delete actions, and JSON import flow with validation.
Core App Screens
workout-logger/lib/screens/home_screen.dart, workout-logger/lib/screens/profile_screen.dart, workout-logger/lib/screens/analytics_screen.dart, workout-logger/lib/screens/settings_screen.dart, workout-logger/lib/screens/routines_screen.dart, workout-logger/lib/screens/workout_flow_screen.dart
Added ProfileScreen for user preferences, data export/import, and cloud backup; extended RoutinesScreen with Programs tab; updated WorkoutFlowScreen with program mode (superset cycling, program metadata display, weight unit conversion); integrated SettingsProvider in analytics and settings screens; replaced settings navigation with profile in home screen.
Project Configuration
workout-logger/pubspec.yaml
Constrained Flutter SDK version to 3.41.5 in environment section.
Test Coverage
workout-logger/test/program_manager_test.dart, workout-logger/test/test_utils/mock_storage_service.dart, workout-logger/test/add_custom_exercise_screen_test.dart, workout-logger/test/exercise_library_screen_test.dart, workout-logger/test/workout_provider_test.dart
Added comprehensive unit tests for ProgramManager (CRUD, import/export, loading), extended MockStorageService with training program persistence, and updated existing widget/provider tests to inject ProgramManager dependency.

Possibly related PRs

  • PR #16: Implements SOLID architecture recommendations through new ProgramManager service and storage interface extensions that centralize training program responsibility management.
  • PR #14: Directly modifies WorkoutProvider constructor and adds new public methods (goToExercise, estimateOneRM, getBestOneRM) that extend its capabilities.
  • PR #13: Updates WorkoutFlowScreen with superset cycling logic, program metadata display, and weight unit conversion—overlapping modifications to the same screen file.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title claims to add CLAUDE.md documentation, but the raw_summary shows the actual changes include Training Program Planner models, UI screens, managers, settings provider, weight units support, and comprehensive feature additions—not just documentation. Update the title to reflect the primary changes: 'Add Training Program Planner with weight unit settings' or 'Implement training programs, weight units, and preferences management' to accurately represent the substantial feature additions.
✅ Passed checks (2 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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

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

Caution

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

⚠️ Outside diff range comments (2)
workout-logger/lib/screens/workout_flow_screen.dart (2)

589-591: ⚠️ Potential issue | 🟠 Major

Seed the dropset text fields in the display unit, not storage kg.

_currentWeight and newWeight are stored in kg, but these controller values are written straight into fields labeled with settings.unitLabel. In lbs mode the user sees the wrong number, and any edit then gets converted again via toStorage(). Initialize the controllers with settings.toDisplay(...) here.

Also applies to: 800-802

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/lib/screens/workout_flow_screen.dart` around lines 589 - 591,
The controllers are being seeded with storage-kg values so users in lbs see
incorrect numbers; update the seeding to use the display-converted values by
calling settings.toDisplay(...) for weight before assigning to
_mainWeightController.text (and likewise use settings.toDisplay(...) wherever
_currentWeight or newWeight are written into UI controllers, e.g., the other
occurrences around lines 800-802); keep _mainRepsController.text as-is for reps,
and ensure you convert only the weight value to display units rather than
writing the raw storage kg.

403-405: ⚠️ Potential issue | 🟡 Minor

Recommendation text is still pinned to kg.

The rest of this screen is unit-aware now, but this card always renders rec.weight as kg. In lbs mode the workout flow mixes units within the same exercise, which is easy to misread. Use SettingsProvider.formatWeight(rec.weight) for display and keep the stored value in kg internally.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/lib/screens/workout_flow_screen.dart` around lines 403 - 405,
The Text widget rendering the weight uses a hardcoded "kg" string
('${rec.weight}kg × ${rec.reps} reps') which breaks unit-awareness; replace the
literal with the unit-aware formatter (use
SettingsProvider.formatWeight(rec.weight) × ${rec.reps} reps) so the UI shows
the correct units while keeping rec.weight stored in kg internally, and remove
the hardcoded "kg" suffix. Locate this in workout_flow_screen.dart where the
Text is built for the record and swap to the formatter so lbs mode displays
correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/skills/flutter-expert/SKILL.md:
- Around line 196-208: Add a blank line before the fenced code block that begins
with "```json" under the "Progress tracking:" heading so the JSON block is
separated by an empty line (per MD031); locate the "Progress tracking:"
paragraph and insert a single empty line immediately before the ```json fence to
surround the code block with blank lines.
- Around line 133-142: Add a blank line before the fenced code block that begins
with the JSON payload under the "Flutter context query:" heading so the code
block is separated from the preceding text (fix the MarkdownLint MD031
violation); locate the fenced block starting with ```json followed by the JSON
object containing "requesting_agent": "flutter-expert" and insert a single empty
line immediately above the opening ```json fence.
- Line 287: Add a single trailing newline character to the end of the SKILL.md
file (the file content that ends with "Always prioritize native performance,
beautiful UI, and consistent experience while building Flutter applications that
delight users across all platforms.") so the file terminates with a single
newline to satisfy markdownlint MD047.

In @.github/workflows/test.yml:
- Around line 35-45: The current Analyze step uses tail -n 1 on
analyze_output.txt which can miss the real summary if the last line is blank or
the summary isn’t the final line; change the summary extraction to search
analyze_output.txt for the actual flutter analyze summary pattern (e.g., lines
containing "issues" or "No issues found") instead of using tail, assign that
match to SUMMARY (falling back to the last non-empty line if no pattern match),
and keep writing SUMMARY to $GITHUB_STEP_SUMMARY so the Analyze job and the
flutter analyze invocation remain unchanged.

In `@workout-logger/lib/main.dart`:
- Around line 66-69: ProgramManager is being provided twice which creates
ambiguity: remove the duplicate or document intended usage—either delete the
direct ChangeNotifierProvider<ProgramManager>.value(value: _programManager) and
rely on WorkoutProvider.programManager as the single source of truth, or keep
the direct provider and add a comment clarifying that ProgramsScreen (and its
ListenableBuilder) should access ProgramManager via the direct
ChangeNotifierProvider rather than WorkoutProvider.programManager; update any
imports/usages (ProgramsScreen, ListenableBuilder) to match the chosen pattern
and ensure only one provider supplies ProgramManager at runtime.

In `@workout-logger/lib/screens/analytics_screen.dart`:
- Around line 788-818: The Builder is redundantly watching SettingsProvider
inside _buildSessionHistory; instead accept SettingsProvider as a parameter
(e.g., add a settings parameter to _buildSessionHistory and pass the existing
settings from _ExerciseProgressView) and remove the internal context.watch call
and Builder widget; update calls to _buildSessionHistory to pass the settings
instance so the widget tree uses the already-obtained SettingsProvider
consistently.

In `@workout-logger/lib/screens/home_screen.dart`:
- Around line 161-165: The code currently reaches into the parent using
findAncestorStateOfType<_HomeScreenState>() and sets homeState._currentIndex
directly which breaks encapsulation and is fragile; add a public method on
_HomeScreenState (e.g., navigateToTab(int index)) that wraps setState(() =>
_currentIndex = index) and then replace the ancestor lookup + direct mutation
with a safe callback or provider/inherited access that calls navigateToTab(4)
instead of touching _currentIndex or relying on findAncestorStateOfType.

In `@workout-logger/lib/screens/profile_screen.dart`:
- Around line 61-124: The _importFromFile method touches state and context after
multiple awaits; add mounted guards immediately after each async boundary (after
await showDialog(...), after await FilePicker.platform.pickFiles(...), and after
await provider.importData(jsonString)) to return early if (!mounted) before
calling setState, context.read/using provider, or _showSnack; ensure every
setState or context.read in _importFromFile is preceded by a mounted check so no
state/context is accessed on a disposed widget.

In `@workout-logger/lib/screens/programs/import_program_screen.dart`:
- Around line 267-285: In _pickFile(), avoid calling setState or mutating _ctrl
after async awaits when the State may be disposed: after each await (the
FilePicker.platform.pickFiles call and the File(...).readAsString call) check if
the State is still mounted and return early if not; specifically guard before
assigning to _ctrl.text and before calling setState to update
_validationState/_validationError/_parsed so you never call setState on a
disposed object.
- Around line 316-327: The current validation only checks top-level keys and
weeks[0] with _requireField, which can miss malformed later weeks/days; instead,
after the lightweight checks run the decoded Map through the same parser used
during import (e.g., TrainingProgram.fromMap or the ProgramManager.parse/import
routine) to fully validate structure before showing "Valid JSON" or calling
_import(); replace or augment the final validation step to call the real parser
(TrainingProgram / ProgramManager methods) with the decoded value and surface
any parser errors to the user so validation and _import() use the identical code
path.

In `@workout-logger/lib/screens/programs/program_designer_screen.dart`:
- Around line 506-780: The functions _buildDayExerciseEditor, _buildSlotEditor,
_showSlotDialog, and _updateDayExercises are using 3+ positional parameters
which makes calls error-prone; change their signatures to use named parameters
(e.g. replace int weekIdx, int dayIdx, int slotIdx, ProgramExerciseSlot slot
with {required int weekIdx, required int dayIdx, required int slotIdx, required
ProgramExerciseSlot slot}) and update every call site (_buildDayExerciseEditor
calls, places calling _buildSlotEditor, calls to _showSlotDialog from
_addExerciseSlot/_editSlot, and where _updateDayExercises is invoked) to pass
arguments by name; preserve existing defaults/nullable types (use required where
previously non-null) and keep logic unchanged.
- Around line 621-750: The dialog never exposes or mutates supersetGroupId so
new ProgramExerciseSlot instances are always null for supersetGroupId; add a
local state variable (e.g., int? supersetGroupId = existing?.supersetGroupId)
inside the dialog's builder and render a small control (toggle, dropdown, or
chip list) below the exercise picker to choose/create a superset group (source
options from the enclosing Program's superset groups or a simple "New group"
incrementer), update that state with setDlg when the user picks/creates a group,
and include supersetGroupId when constructing the ProgramExerciseSlot in the
ElevatedButton onPressed so edits and new slots persist superset membership;
ensure the control preserves existing?.supersetGroupId when editing and allows
clearing the group.

In `@workout-logger/lib/screens/programs/program_detail_screen.dart`:
- Around line 234-241: The fraction calculation can divide by zero when
_program.totalWeeks is 0; update the code in the mapping over _program.phases to
guard the denominator: compute a safeDenominator = (_program.totalWeeks == 0) ?
1 : _program.totalWeeks (or set fraction = 0.0 when totalWeeks == 0) and then
calculate fraction = (phase.endWeek - phase.startWeek + 1) / safeDenominator
before computing flex; keep the existing clamp to guarantee a minimum flex and
reference the variables _program.totalWeeks, _program.phases, fraction and the
Expanded(flex: ...) expression when making the change.
- Around line 600-605: The TextStyle instance used in program_detail_screen.dart
is not declared as const even though all its fields (fontSize, color,
fontWeight, letterSpacing) are compile-time constants; update the TextStyle(...)
expression to const TextStyle(...) so the style becomes immutable and allows
compile-time const folding (locate the TextStyle creation in the widget tree
where the style: property is set and change it to const TextStyle(...)).

In `@workout-logger/lib/screens/programs/programs_screen.dart`:
- Around line 278-279: The computation of fraction uses (phase.endWeek -
phase.startWeek + 1) / program.totalWeeks and can divide by zero if
program.totalWeeks == 0; update the code around fraction to guard against
zero/negative totalWeeks (e.g., if program.totalWeeks <= 0 set fraction = 0.0)
and optionally clamp the result to a valid range (0.0..1.0) so that fraction is
always a finite double; adjust any UI logic that consumes fraction accordingly.
- Around line 29-53: The ProgramsScreen currently returns a full Scaffold which
nests inside the parent screen’s Scaffold and causes FAB conflicts; remove the
inner Scaffold and return only the body content (use the result of
programs.isEmpty ? _buildEmptyState(context) : _buildList(context, programs)) so
_buildEmptyState and _buildList render the page content without a Scaffold, and
move the FAB widgets (those created with FloatingActionButton.small and
FloatingActionButton.extended that call _openImport and _openDesigner) up to the
parent screen so the parent composes and coordinates FABs for both tabs; ensure
any heroTag usage and callbacks (_openImport, _openDesigner) remain accessible
to the parent (e.g., expose callbacks or pass context) when refactoring.
- Around line 23-27: The code redundantly calls context.read<WorkoutProvider>()
twice inside the ListenableBuilder; cache the provider once instead: in the
builder, assign final workoutProvider = context.read<WorkoutProvider>() and then
use workoutProvider.programManager for the listenable and
workoutProvider.programManager.programs for the programs variable to improve
clarity and avoid duplicate reads (referencing ListenableBuilder,
WorkoutProvider, programManager, and programs).

In `@workout-logger/lib/screens/routines_screen.dart`:
- Around line 16-39: The children of the TabBarView (_RoutinesTab and
ProgramsScreen) currently contain their own Scaffold instances which causes
nested scaffolds and layout/FAB/back-button issues; remove the inner Scaffold
wrappers from _RoutinesTab and from ProgramsScreen so they return plain widgets
(e.g., Container, Column, ListView or CustomScrollView/SliverToBoxAdapter) and
move any floatingActionButton or top AppBar behavior into the parent
RoutinesScreen's Scaffold (or implement a Stack at RoutinesScreen to position a
shared FAB), ensuring AppBar/TabBar remain in RoutinesScreen and navigation/back
handling is provided by the single outer Scaffold.

In `@workout-logger/lib/screens/settings_screen.dart`:
- Around line 548-550: Remove the accidental blank line between the onPressed
and style properties in the ElevatedButton widget: collapse the empty line so
the onPressed: _isBackingUp ? null : _performBackup, and style:
ElevatedButton.styleFrom( appear consecutively; locate the ElevatedButton
construction that references _isBackingUp and _performBackup and delete the
stray newline to restore correct formatting.

In `@workout-logger/lib/screens/workout_flow_screen.dart`:
- Around line 147-154: The prefilled weight and number picker currently format
displayWeight with a hardcoded 1 decimal; instead derive the decimal precision
from the weight increment configured in SettingsProvider (use the increment used
by settings.toDisplay / settings.weightIncrement) and use that computed
decimalPlaces when formatting displayWeight and wiring the number picker so
values like 21.25 round-trip exactly; update the formatting in the block that
sets _currentWeight/_currentReps and sets _mainWeightController.text (and the
similar code around the 444-450 region) to compute decimalPlaces = max(0,
-log10(increment)) or otherwise derive digits from the increment and call
toStringAsFixed(decimalPlaces) and configure the number picker to use the same
decimalPlaces.

In `@workout-logger/lib/services/managers/program_manager.dart`:
- Around line 77-89: The importFromJson method currently casts
jsonDecode(jsonString) to Map<String, dynamic> which will throw a TypeError for
non-object JSON; instead check the decoded value returned from jsonDecode and if
it's not a Map<String, dynamic> throw a FormatException with a clear message;
after verifying the type, assign raw['id'], raw['isImported'], raw['createdAt']
as before, construct the TrainingProgram via TrainingProgram.fromJson(raw), and
then call saveProgram(program); reference the importFromJson function, the raw
variable, jsonDecode call, TrainingProgram.fromJson, saveProgram, and _uuid when
making this change.
- Around line 99-105: The getProgramById function currently uses a try/catch
around _programs.firstWhere(...) to return null on miss; replace this with the
collection package's firstWhereOrNull for clarity: import the collection
extension and change the body of getProgramById to return
_programs.firstWhereOrNull((p) => p.id == id) (removing the try/catch). If you
prefer to keep consistency with WorkoutProvider.getExercise, you may leave the
try/catch, but the preferred refactor is to use firstWhereOrNull in
getProgramById.

In `@workout-logger/lib/services/settings_provider.dart`:
- Around line 32-37: The setter setWeightUnit currently resets and persists
changes even when the selected unit equals the current _weightUnit; modify
setWeightUnit to return immediately if the incoming unit equals the existing
_weightUnit (i.e., add a guard if (unit == _weightUnit) return;) so it does not
reset _weightIncrement to _defaultIncrement, call _storage.saveSetting, or
notifyListeners on no-op taps; keep the rest of the logic (updating _weightUnit,
resetting _weightIncrement, persisting via _storage.saveSetting('weightUnit'...)
and 'weightIncrement', and notifyListeners()) unchanged for real changes.
- Around line 58-68: The current formatWeight(double kg) always uses one decimal
which rounds values like 21.25 to 21.3; change formatWeight to choose decimal
precision based on the current availableIncrements so supported increments are
represented exactly: compute d = toDisplay(kg), determine requiredDecimals by
inspecting availableIncrements (e.g., if any increment has hundredths (.25/.75)
use 2 decimals, else if any has tenths (.5) use 1, otherwise 0), then format d
with toStringAsFixed(requiredDecimals) and return '$str $unitLabel'; update
formatWeight (and use availableIncrements) so displayed values exactly match
supported increments.

In `@workout-logger/lib/services/storage_service.dart`:
- Around line 451-481: The export/import flow is missing training programs;
update exportAllData() to include a "trainingPrograms" key whose value is the
list returned by getAllTrainingPrograms() converted to JSON maps (use
program.toJson()), and update importData() to read the "trainingPrograms" array
from the imported payload and persist each entry by calling
saveTrainingProgram(TrainingProgram.fromJson(...)) (ensure you handle existing
IDs/overwrites consistently with other entities). Reference the TrainingProgram
CRUD helpers saveTrainingProgram, getAllTrainingPrograms, getTrainingProgram,
and deleteTrainingProgram when locating where to add serialization and
deserialization logic.

In `@workout-logger/pubspec.yaml`:
- Line 23: The Flutter SDK constraint is pinned exactly as "flutter: 3.41.5"
which blocks compatible upgrades; update the pubspec.yaml Flutter constraint
(the line with flutter: 3.41.5) to an inclusive version range such as "flutter:
^3.41.0" or "flutter: >=3.41.0 <4.0.0" so minor/patch updates are allowed while
preserving compatibility with the Dart SDK constraint.

In `@workout-logger/test/test_utils/mock_storage_service.dart`:
- Line 22: Add a public getter to expose the private list _trainingPrograms for
test assertions, matching the pattern used for
customExercises/sessions/routines/targets; implement a getter named
trainingPrograms that returns _trainingPrograms so tests can access the
collection and maintain consistency with the other getters in
mock_storage_service.dart.

---

Outside diff comments:
In `@workout-logger/lib/screens/workout_flow_screen.dart`:
- Around line 589-591: The controllers are being seeded with storage-kg values
so users in lbs see incorrect numbers; update the seeding to use the
display-converted values by calling settings.toDisplay(...) for weight before
assigning to _mainWeightController.text (and likewise use
settings.toDisplay(...) wherever _currentWeight or newWeight are written into UI
controllers, e.g., the other occurrences around lines 800-802); keep
_mainRepsController.text as-is for reps, and ensure you convert only the weight
value to display units rather than writing the raw storage kg.
- Around line 403-405: The Text widget rendering the weight uses a hardcoded
"kg" string ('${rec.weight}kg × ${rec.reps} reps') which breaks unit-awareness;
replace the literal with the unit-aware formatter (use
SettingsProvider.formatWeight(rec.weight) × ${rec.reps} reps) so the UI shows
the correct units while keeping rec.weight stored in kg internally, and remove
the hardcoded "kg" suffix. Locate this in workout_flow_screen.dart where the
Text is built for the record and swap to the formatter so lbs mode displays
correctly.
🪄 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

Run ID: 893a3de5-c7e3-4369-bbdb-ec1bbb1e7169

📥 Commits

Reviewing files that changed from the base of the PR and between 893c9ea and c3951d9.

📒 Files selected for processing (27)
  • .github/skills/flutter-expert/SKILL.md
  • .github/workflows/test.yml
  • docs/example_12_week_program.json
  • workout-logger/lib/main.dart
  • workout-logger/lib/models/models.dart
  • workout-logger/lib/screens/analytics_screen.dart
  • workout-logger/lib/screens/home_screen.dart
  • workout-logger/lib/screens/profile_screen.dart
  • workout-logger/lib/screens/programs/import_program_screen.dart
  • workout-logger/lib/screens/programs/program_designer_screen.dart
  • workout-logger/lib/screens/programs/program_detail_screen.dart
  • workout-logger/lib/screens/programs/programs_screen.dart
  • workout-logger/lib/screens/routines_screen.dart
  • workout-logger/lib/screens/settings_screen.dart
  • workout-logger/lib/screens/workout_flow_screen.dart
  • workout-logger/lib/services/interfaces/storage_service_interface.dart
  • workout-logger/lib/services/managers/managers.dart
  • workout-logger/lib/services/managers/program_manager.dart
  • workout-logger/lib/services/settings_provider.dart
  • workout-logger/lib/services/storage_service.dart
  • workout-logger/lib/services/workout_provider.dart
  • workout-logger/pubspec.yaml
  • workout-logger/test/add_custom_exercise_screen_test.dart
  • workout-logger/test/exercise_library_screen_test.dart
  • workout-logger/test/program_manager_test.dart
  • workout-logger/test/test_utils/mock_storage_service.dart
  • workout-logger/test/workout_provider_test.dart

Comment on lines +133 to +142
Flutter context query:
```json
{
"requesting_agent": "flutter-expert",
"request_type": "get_flutter_context",
"payload": {
"query": "Flutter context needed: target platforms, app type, state management preference, native features required, and deployment strategy."
}
}
```

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.

🧹 Nitpick | 🔵 Trivial

Add blank line before fenced code block.

Per markdownlint MD031, fenced code blocks should be surrounded by blank lines for proper rendering across all Markdown parsers.

📝 Proposed fix
 Flutter context query:
+
 ```json
 {
   "requesting_agent": "flutter-expert",
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 134-134: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/skills/flutter-expert/SKILL.md around lines 133 - 142, Add a blank
line before the fenced code block that begins with the JSON payload under the
"Flutter context query:" heading so the code block is separated from the
preceding text (fix the MarkdownLint MD031 violation); locate the fenced block
starting with ```json followed by the JSON object containing "requesting_agent":
"flutter-expert" and insert a single empty line immediately above the opening
```json fence.

Comment on lines +196 to +208
Progress tracking:
```json
{
"agent": "flutter-expert",
"status": "implementing",
"progress": {
"screens_completed": 32,
"custom_widgets": 45,
"test_coverage": "82%",
"performance_score": "60fps"
}
}
```

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.

🧹 Nitpick | 🔵 Trivial

Add blank line before fenced code block.

Per markdownlint MD031, fenced code blocks should be surrounded by blank lines.

📝 Proposed fix
 Progress tracking:
+
 ```json
 {
   "agent": "flutter-expert",
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 197-197: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/skills/flutter-expert/SKILL.md around lines 196 - 208, Add a blank
line before the fenced code block that begins with "```json" under the "Progress
tracking:" heading so the JSON block is separated by an empty line (per MD031);
locate the "Progress tracking:" paragraph and insert a single empty line
immediately before the ```json fence to surround the code block with blank
lines.

- Partner with backend-developer on API integration
- Coordinate with ios-developer on iOS specifics

Always prioritize native performance, beautiful UI, and consistent experience while building Flutter applications that delight users across all platforms. No newline at end of file

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.

🧹 Nitpick | 🔵 Trivial

Add trailing newline at end of file.

Per markdownlint MD047, files should end with a single newline character. This is a minor formatting fix.

📝 Proposed fix
 Always prioritize native performance, beautiful UI, and consistent experience while building Flutter applications that delight users across all platforms.
+
📝 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
Always prioritize native performance, beautiful UI, and consistent experience while building Flutter applications that delight users across all platforms.
Always prioritize native performance, beautiful UI, and consistent experience while building Flutter applications that delight users across all platforms.
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 287-287: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/skills/flutter-expert/SKILL.md at line 287, Add a single trailing
newline character to the end of the SKILL.md file (the file content that ends
with "Always prioritize native performance, beautiful UI, and consistent
experience while building Flutter applications that delight users across all
platforms.") so the file terminates with a single newline to satisfy
markdownlint MD047.

Comment on lines +35 to +45
- name: Analyze
working-directory: ./workout-logger
run: |
# Only fail on errors, ignore warnings and info messages
flutter analyze --no-fatal-infos --no-fatal-warnings | tee analyze_output.txt

# Extract and display the summary of issues
SUMMARY=$(tail -n 1 analyze_output.txt)
echo "Analysis Summary: $SUMMARY"
echo "### Analysis Summary" >> $GITHUB_STEP_SUMMARY
echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY

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.

🧹 Nitpick | 🔵 Trivial

tail -n 1 may not capture the actual summary line.

The flutter analyze output format may vary. If there are trailing blank lines or the summary isn't on the last line, tail -n 1 will capture incorrect content. Consider using grep to find the actual summary pattern.

🔧 More robust summary extraction
       - name: Analyze
         working-directory: ./workout-logger
         run: |
           # Only fail on errors, ignore warnings and info messages
           flutter analyze --no-fatal-infos --no-fatal-warnings | tee analyze_output.txt
           
-          # Extract and display the summary of issues
-          SUMMARY=$(tail -n 1 analyze_output.txt)
+          # Extract the summary line (e.g., "No issues found!" or "X issues found")
+          SUMMARY=$(grep -E "(No issues found|[0-9]+ issues? found)" analyze_output.txt | tail -n 1 || echo "Analysis completed")
           echo "Analysis Summary: $SUMMARY"
           echo "### Analysis Summary" >> $GITHUB_STEP_SUMMARY
           echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY
📝 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: Analyze
working-directory: ./workout-logger
run: |
# Only fail on errors, ignore warnings and info messages
flutter analyze --no-fatal-infos --no-fatal-warnings | tee analyze_output.txt
# Extract and display the summary of issues
SUMMARY=$(tail -n 1 analyze_output.txt)
echo "Analysis Summary: $SUMMARY"
echo "### Analysis Summary" >> $GITHUB_STEP_SUMMARY
echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY
- name: Analyze
working-directory: ./workout-logger
run: |
# Only fail on errors, ignore warnings and info messages
flutter analyze --no-fatal-infos --no-fatal-warnings | tee analyze_output.txt
# Extract the summary line (e.g., "No issues found!" or "X issues found")
SUMMARY=$(grep -E "(No issues found|[0-9]+ issues? found)" analyze_output.txt | tail -n 1 || echo "Analysis completed")
echo "Analysis Summary: $SUMMARY"
echo "### Analysis Summary" >> $GITHUB_STEP_SUMMARY
echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/test.yml around lines 35 - 45, The current Analyze step
uses tail -n 1 on analyze_output.txt which can miss the real summary if the last
line is blank or the summary isn’t the final line; change the summary extraction
to search analyze_output.txt for the actual flutter analyze summary pattern
(e.g., lines containing "issues" or "No issues found") instead of using tail,
assign that match to SUMMARY (falling back to the last non-empty line if no
pattern match), and keep writing SUMMARY to $GITHUB_STEP_SUMMARY so the Analyze
job and the flutter analyze invocation remain unchanged.

Comment on lines +66 to +69
// ProgramManager passed to tree directly
ChangeNotifierProvider<ProgramManager>.value(value: _programManager),
// SettingsProvider for user preferences (weight unit, increments)
ChangeNotifierProvider<SettingsProvider>.value(value: _settingsProvider),

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.

🧹 Nitpick | 🔵 Trivial

ProgramManager is provided twice—clarify intended access pattern.

ProgramManager is exposed both:

  1. Directly via ChangeNotifierProvider<ProgramManager>.value (line 67)
  2. Indirectly via WorkoutProvider.programManager (line 75)

This could confuse developers about which to use. If direct access is intended (e.g., for ListenableBuilder in ProgramsScreen), document this. Otherwise, consider removing the direct provider if all access should go through WorkoutProvider.

Also applies to: 71-76

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/lib/main.dart` around lines 66 - 69, ProgramManager is being
provided twice which creates ambiguity: remove the duplicate or document
intended usage—either delete the direct
ChangeNotifierProvider<ProgramManager>.value(value: _programManager) and rely on
WorkoutProvider.programManager as the single source of truth, or keep the direct
provider and add a comment clarifying that ProgramsScreen (and its
ListenableBuilder) should access ProgramManager via the direct
ChangeNotifierProvider rather than WorkoutProvider.programManager; update any
imports/usages (ProgramsScreen, ListenableBuilder) to match the chosen pattern
and ensure only one provider supplies ProgramManager at runtime.

Comment on lines +32 to +37
Future<void> setWeightUnit(WeightUnit unit) async {
_weightUnit = unit;
_weightIncrement = _defaultIncrement;
await _storage.saveSetting('weightUnit', unit == WeightUnit.kg ? 'kg' : 'lbs');
await _storage.saveSetting('weightIncrement', _weightIncrement.toString());
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.

⚠️ Potential issue | 🟡 Minor

Ignore no-op unit selections.

workout-logger/lib/screens/profile_screen.dart calls this setter on every tap, including taps on the already-selected chip. Right now that silently resets a custom increment back to the default and overwrites storage, so a stray tap on kg will discard a 1.25 kg preference.

Suggested fix
 Future<void> setWeightUnit(WeightUnit unit) async {
+  if (unit == _weightUnit) return;
   _weightUnit = unit;
   _weightIncrement = _defaultIncrement;
   await _storage.saveSetting('weightUnit', unit == WeightUnit.kg ? 'kg' : 'lbs');
   await _storage.saveSetting('weightIncrement', _weightIncrement.toString());
   notifyListeners();
 }
📝 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<void> setWeightUnit(WeightUnit unit) async {
_weightUnit = unit;
_weightIncrement = _defaultIncrement;
await _storage.saveSetting('weightUnit', unit == WeightUnit.kg ? 'kg' : 'lbs');
await _storage.saveSetting('weightIncrement', _weightIncrement.toString());
notifyListeners();
Future<void> setWeightUnit(WeightUnit unit) async {
if (unit == _weightUnit) return;
_weightUnit = unit;
_weightIncrement = _defaultIncrement;
await _storage.saveSetting('weightUnit', unit == WeightUnit.kg ? 'kg' : 'lbs');
await _storage.saveSetting('weightIncrement', _weightIncrement.toString());
notifyListeners();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/lib/services/settings_provider.dart` around lines 32 - 37, The
setter setWeightUnit currently resets and persists changes even when the
selected unit equals the current _weightUnit; modify setWeightUnit to return
immediately if the incoming unit equals the existing _weightUnit (i.e., add a
guard if (unit == _weightUnit) return;) so it does not reset _weightIncrement to
_defaultIncrement, call _storage.saveSetting, or notifyListeners on no-op taps;
keep the rest of the logic (updating _weightUnit, resetting _weightIncrement,
persisting via _storage.saveSetting('weightUnit'...) and 'weightIncrement', and
notifyListeners()) unchanged for real changes.

Comment on lines +58 to +68
/// Format a kg weight value with the correct unit label.
String formatWeight(double kg) {
final d = toDisplay(kg);
final str = d == d.truncateToDouble() ? d.toStringAsFixed(0) : d.toStringAsFixed(1);
return '$str $unitLabel';
}

/// Available weight increments for the current unit.
List<double> get availableIncrements => _weightUnit == WeightUnit.kg
? [1.25, 2.5, 5.0, 10.0]
: [2.5, 5.0, 10.0, 25.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.

⚠️ Potential issue | 🟠 Major

formatWeight() rounds away supported increments.

This provider exposes 1.25 kg increments, but every non-integer weight is formatted with a single decimal. Values like 21.25 therefore render as 21.3, which will leak into analytics and set history.

Suggested fix
 String formatWeight(double kg) {
   final d = toDisplay(kg);
-  final str = d == d.truncateToDouble() ? d.toStringAsFixed(0) : d.toStringAsFixed(1);
+  final str = d
+      .toStringAsFixed(2)
+      .replaceFirst(RegExp(r'\.?0+$'), '');
   return '$str $unitLabel';
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/lib/services/settings_provider.dart` around lines 58 - 68, The
current formatWeight(double kg) always uses one decimal which rounds values like
21.25 to 21.3; change formatWeight to choose decimal precision based on the
current availableIncrements so supported increments are represented exactly:
compute d = toDisplay(kg), determine requiredDecimals by inspecting
availableIncrements (e.g., if any increment has hundredths (.25/.75) use 2
decimals, else if any has tenths (.5) use 1, otherwise 0), then format d with
toStringAsFixed(requiredDecimals) and return '$str $unitLabel'; update
formatWeight (and use availableIncrements) so displayed values exactly match
supported increments.

Comment on lines +451 to +481
// ==================== TRAINING PROGRAMS ====================

@override
Future<void> saveTrainingProgram(TrainingProgram program) async {
await _trainingProgramsBoxInstance.put(
program.id,
jsonEncode(program.toJson()),
);
}

@override
Future<List<TrainingProgram>> getAllTrainingPrograms() async {
final programs = <TrainingProgram>[];
for (final json in _trainingProgramsBoxInstance.values) {
programs.add(TrainingProgram.fromJson(jsonDecode(json)));
}
programs.sort((a, b) => b.createdAt.compareTo(a.createdAt));
return programs;
}

@override
Future<TrainingProgram?> getTrainingProgram(String id) async {
final json = _trainingProgramsBoxInstance.get(id);
if (json == null) return null;
return TrainingProgram.fromJson(jsonDecode(json));
}

@override
Future<void> deleteTrainingProgram(String id) async {
await _trainingProgramsBoxInstance.delete(id);
}

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify if training programs are mentioned anywhere in export/import context
rg -n "trainingProgram|training_program" workout-logger/lib/services/storage_service.dart | grep -i "export\|import" || echo "No export/import references found for training programs"

Repository: Devasy/Workout-logger

Length of output: 120


🏁 Script executed:

sed -n '332,363p' workout-logger/lib/services/storage_service.dart

Repository: Devasy/Workout-logger

Length of output: 1159


🏁 Script executed:

sed -n '366,449p' workout-logger/lib/services/storage_service.dart

Repository: Devasy/Workout-logger

Length of output: 2942


🏁 Script executed:

# Check if there are any TODOs or comments about training programs in the file
rg -n "TODO|FIXME|training.?program" workout-logger/lib/services/storage_service.dart -A 2 -B 2

Repository: Devasy/Workout-logger

Length of output: 292


🏁 Script executed:

rg -n "TODO|FIXME|training.?program|trainingProgram" workout-logger/lib/services/storage_service.dart -B 3 -A 3

Repository: Devasy/Workout-logger

Length of output: 1983


🏁 Script executed:

# Check if training programs are referenced/imported in other parts of the codebase
rg -n "trainingProgram|training_program" workout-logger/lib --type dart | head -20

Repository: Devasy/Workout-logger

Length of output: 902


Add training programs to export/import methods.

Training programs have complete CRUD methods but are missing from exportAllData() and importData(). Users will lose their training programs when exporting and re-importing data. Include trainingPrograms in the export/import flow alongside the other entities (sessions, routines, targets, muscle groups, custom exercises).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/lib/services/storage_service.dart` around lines 451 - 481, The
export/import flow is missing training programs; update exportAllData() to
include a "trainingPrograms" key whose value is the list returned by
getAllTrainingPrograms() converted to JSON maps (use program.toJson()), and
update importData() to read the "trainingPrograms" array from the imported
payload and persist each entry by calling
saveTrainingProgram(TrainingProgram.fromJson(...)) (ensure you handle existing
IDs/overwrites consistently with other entities). Reference the TrainingProgram
CRUD helpers saveTrainingProgram, getAllTrainingPrograms, getTrainingProgram,
and deleteTrainingProgram when locating where to add serialization and
deserialization logic.


environment:
sdk: ^3.9.2
flutter: 3.41.5

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

What is the latest stable version of Flutter SDK as of April 2026?

💡 Result:

The latest stable version of the Flutter SDK as of April 3, 2026, is 3.41.5.

Citations:


Consider using a version range for Flutter SDK constraint instead of exact pinning.

The Flutter SDK is pinned to exact version 3.41.5, which prevents developers from using compatible newer versions. This is inconsistent with the Dart SDK constraint on line 22 (^3.9.2), which allows compatible versions.

Consider using flutter: ^3.41.0 or flutter: ">=3.41.0 <4.0.0" to allow patch and minor version updates while maintaining consistency with the Dart SDK constraint style.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/pubspec.yaml` at line 23, The Flutter SDK constraint is pinned
exactly as "flutter: 3.41.5" which blocks compatible upgrades; update the
pubspec.yaml Flutter constraint (the line with flutter: 3.41.5) to an inclusive
version range such as "flutter: ^3.41.0" or "flutter: >=3.41.0 <4.0.0" so
minor/patch updates are allowed while preserving compatibility with the Dart SDK
constraint.

final List<Target> _targets = [];
final List<MuscleGroup> _muscleGroups = [];
final Map<String, String> _settings = {};
final List<TrainingProgram> _trainingPrograms = [];

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.

🧹 Nitpick | 🔵 Trivial

Consider adding a public getter for test assertions.

Other collections (customExercises, sessions, routines, targets) have public getters (lines 28-31) for test assertions. Adding one for _trainingPrograms would maintain consistency.

📝 Proposed addition after line 31
  List<TrainingProgram> get trainingPrograms => _trainingPrograms;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workout-logger/test/test_utils/mock_storage_service.dart` at line 22, Add a
public getter to expose the private list _trainingPrograms for test assertions,
matching the pattern used for customExercises/sessions/routines/targets;
implement a getter named trainingPrograms that returns _trainingPrograms so
tests can access the collection and maintain consistency with the other getters
in mock_storage_service.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.

2 participants