Feat/v0.9.0 enhancement sweep - #406
Conversation
Phase 37: Foundation (#323) Wave: 1 Requirements: FOUND-01 Create WeightDisplayFormatter utility for cable-aware total weight display. Update primary surfaces (WorkoutHud, HistoryTab, SetSummaryCard) to show total weight instead of per-cable values. 14 unit tests pass covering all cable/unit/edge case combinations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ssion Tests Phase 37: Foundation (#323) Wave: 2 Requirements: FOUND-01 Migrate secondary display surfaces (DashboardComponents, AnalyticsScreen, ExerciseDetailScreen, ExercisesTab, HomeScreen, ActiveWorkoutScreen) to WeightDisplayFormatter. Add 9 guard tests protecting sync/health/BLE paths from double-multiplication and 30 regression tests covering all cable/unit combinations. 53 total weight display tests pass. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 37: Foundation (#323) Fixed 8 issues: tautological guard tests rewritten with source scanning, CompletedSetsSection cable-aware display, CountdownCard total weight, ModeConfirmationScreen unit conversion, weak test assertions replaced with exact values, negative/unusual cableCount edge case tests added. Unresolved: PersonalRecord cableCount data model gap (requires schema migration). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…idMain Phase 37: Foundation (#323) Fixed guard test for HealthIntegration.android.kt to scan androidMain source set where the actual file lives, not just commonMain. Guard now checks both source sets matching the iOS guard pattern. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 38: Weight-Dependent Features Wave: 1 Requirements: WEIGHT-01 Wire pre-built weight increment preference into all weight control surfaces. Settings UI picker for 0.1–5.0 lb/kg increments. WeightAdjustmentControls, CompactWeightAdjustment, WeightPickerDialog, WeightStepper all use configured increment. Slider capped at 200 steps. Preset % buttons round to machine increment. Routine.kt duplicate roundToIncrement deprecated. 18 unit tests covering increment wiring, conversion, and reset behavior. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 38: Weight-Dependent Features Wave: 2 Requirements: WEIGHT-02 BulkWeightAdjustDialog with percentage and absolute modes, preview section showing current → new weight per exercise. PR-scaled exercises skipped with indicator. All weights clamped [0, MAX_WEIGHT_KG] and rounded to 0.5kg machine increment. Per-set weights (setWeightsPerCableKg) also adjusted. Integrated into RoutineEditorScreen overflow menu (all exercises) and SelectionActionBar (selected exercises). 25 unit tests for pure logic. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 38: Weight-Dependent Features Wave: 3 Requirements: WEIGHT-01, WEIGHT-02 9 structural boundary guards verifying BulkWeightAdjust and weight increment preferences don't leak into BLE, sync, or health integration layers. Follows Phase 37 WeightDisplayGuardTest pattern — scans real source directories. 1 edge case added to BulkWeightAdjustTest (zero-weight percentage). 114 total weight-related tests across all phases, zero failures. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All plans executed. 3/3 passed. Overall progress: 5/21 (24%) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 38: Weight-Dependent Features Fixed 4 issues: duplicate constants consolidated to Constants/UnitConverter, formatWeight toInt() truncation replaced with formatDecimal, lb-to-kg conversion tests added, hardcoded contentDescription replaced with string resource (5 locales). WeightStepper rounding responsibility documented. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Review passed after 1 cycle. 4 warning(s) fixed, 0 blocker(s). Reviewers: testing-qa-verification-specialist, engineering-senior-developer Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 39: Routine Cluster Wave: 1 Requirements: ROUTINE-01 - Extract normalizeRoutine() to RoutineUtils.kt (top-level, testable) - Add reorderExercisesInSuperset() utility function - Wire ReorderableColumn inside superset containers for nested drag-and-drop - Add drag handles on exercises within supersets - preserveIntraSupersetOrder flag prevents normalizeRoutine() clobber Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 39: Routine Cluster Wave: 1 Requirements: ROUTINE-02 - Add RoutineGroup domain model + groupId on Routine - SQLDelight migration 27: RoutineGroup table, groupId FK with ON DELETE SET NULL - Fix pre-existing migration 26 gap in MigrationStatements.kt - RoutineGroup CRUD in SqlDelightWorkoutRepository - RoutineGroupHeader + MoveToGroupDialog composables - Transform RoutinesTab from flat list to grouped collapsible sections - Backup/restore includes RoutineGroup data (version 3) - Wire ViewModel + RoutineFlowManager for group operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2/2 plans completed Progress: 7/21 (33%) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 39: Routine Cluster Wave: 2 Requirements: ROUTINE-01, ROUTINE-02 - SupersetReorderTest: 7 tests for intra-superset reorder ordering - RoutineGroupTest: 10 tests for group CRUD and routine-group associations - RoutineRegressionGuardTest: 5 regression guards for existing routine ops - Fix SchemaManifest: add RoutineGroup table, groupId column, index - Fix SchemaParityTest: bump CURRENT_VERSION 26->27 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All plans executed. 3/3 passed. Overall progress: 8/21 (38%) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 39: Routine Cluster (#365, #307) Fixed 8 issues found by 4-agent review panel: BLOCKER: groupId missing from insertRoutine/upsertRoutine SQL queries - VitruvianDatabase.sq: added groupId to insert + upsert queries - SqlDelightWorkoutRepository: pass groupId in saveRoutine - DataBackupManager: pass groupId in backup import - SqlDelightSyncRepository: preserve groupId in 3 sync upsert paths - SchemaManifest: add groupId to Routine table definition BLOCKER: "New Group..." flow creates group but doesn't move routines - RoutinesTab: wire pendingMoveRoutineIds + LaunchedEffect chain WARNING: groupRepo unsafe cast to SqlDelightWorkoutRepository - RoutineFlowManager: safe cast with null-safe calls WARNING: Group collector lacks retry logic - RoutineFlowManager: 3-retry exponential backoff matching Collector #1 WARNING: Selection mode not exited when last item deselected - RoutinesTab: auto-exit when selectedIds empty WARNING: Test coverage gaps (3) - SchemaParityTest: update stale version comments - RoutineRegressionGuardTest: add backup v3 compat test - SupersetReorderTest: add out-of-bounds + orderInSuperset assertions - RoutineGroupTest: add ON DELETE SET NULL coverage note Pre-existing: added groupId = null to 5 test files using insertRoutine Reviewers: testing-qa-verification-specialist, engineering-backend-architect, testing-test-results-analyzer, engineering-mobile-app-builder Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review passed after 1 cycle. 2 blocker(s) fixed, 6 warning(s) fixed. Reviewers: testing-qa-verification-specialist, engineering-backend-architect, testing-test-results-analyzer, engineering-mobile-app-builder Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 40: Analytics Wave: 1 Requirements: ANALYTICS-01 Wire BodyweightVolumeCalculator into ActiveSessionEngine at all 3 set completion paths. Add body weight input to Settings with kg/lbs support. Add bodyweight exercise variant picker to SetReadyScreen. Migrate RoutineFlowManager callers to Exercise.isBodyweight property. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nt (#225) Phase 40: Analytics Wave: 1 Requirements: ANALYTICS-02 Fix RoutineTimeEstimator: profileId parameter (no hardcoded "default"), AMRAP 1.5x multiplier with range output, warmup sets at 0.7x, superset- aware traversal via getItems(), 30s exercise transitions, 3-session minimum threshold. Register in Koin. Wire to RoutineOverviewScreen and RoutinesTab with clock badge. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation Phase 40: Analytics Wave: 2 Requirements: ANALYTICS-01, ANALYTICS-02 Add 17 new tests: 7 bodyweight volume (decline, pull-up, edge cases), 3 sync push (bodyweight volume survives push, cable division), 7 time estimator (multi-exercise, warmup combo, AMRAP range, long routine). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All plans executed. 3/3 passed. Overall progress: 14/21 (67%) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review passed after 1 cycle(s). 0 blocker(s) fixed, 5 warning(s) accepted as documented limitations. Reviewers: testing-qa-verification-specialist, engineering-senior-developer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 41: Quick Wins Wave: 1 Requirements: UX-01 (#190), UX-02 (#228) - Wire autoStartRoutine preference with LaunchedEffect redirect in RoutineOverviewScreen - Add exercise timer pause/resume/reset for TUT/Echo timed exercises - Timer controls are pure state manipulation — no BLE side effects - Settings toggle for auto-start in Workout section - 13 new tests (5 auto-start, 8 timer controls) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 41: Quick Wins Wave: 2 Requirements: AUDIO-01 (#100) - Add FINAL_REP HapticEvent with distinct boopbeepbeep sound + strong haptic - Switch REP_COMPLETED from quiet beep to louder chirpchirp - Gate warmup rep chirps by repSoundEnabled (was ungated) - Priority chain: audioRepCount > FINAL_REP > REP_COMPLETED - Both TOP and BOTTOM rep timing paths handle final rep detection - iOS sound mapping + TODO for .ogg-to-.caf conversion - 28 new tests (event identity, final rep detection, preference gating) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All plans executed. 2/2 passed. Overall progress: 16/21 (76%) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review passed after 1 cycle(s). 0 blocker(s) fixed, 5 warnings accepted as design trade-offs. Reviewers: testing-qa-verification-specialist, testing-test-results-analyzer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… Pickers Phase 42: Platform Wave: 1 Requirements: PLATFORM-01 - BackupDestination sealed class with Default/Custom variants, iOS bookmark support - PreferencesManager persistence with JSON serialization and graceful fallback - BackupLocationPicker expect/actual: Android SAF OpenDocumentTree + iOS UIDocumentPicker - Added androidx-documentfile dependency for Android directory name extraction Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 42: Platform Wave: 2 Requirements: PLATFORM-01 - BackupDestinationResolver interface with Android/iOS implementations - Android: DocumentFile + persistable URI permission checks - iOS: Security-scoped bookmark resolution via Base64 decode - DataBackupManager routing: custom destination with fallback to default - SettingsTab: backup location display, change/reset controls, picker integration - Wired through SettingsManager → MainViewModel → NavGraph → SettingsTab Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 42: Platform Wave: 3 Requirements: PLATFORM-01 - BackupDestinationTest: 15 tests (serialization, round-trip, error resilience, forward compat) - BackupRoutingTest: 9 tests (resolver accessibility, write capture, fallback, edge cases) - FakeBackupDestinationResolver: test double with configurable results - Fixed FakePreferencesManager missing setBackupDestination() override (compilation blocker) - 24 new tests total, all pass. 1612 tests in suite. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SchemaManifest CREATE TABLE and heal operations must stay in sync with migrations. Missing cable_count from migration 28. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PersonalRecord stored weightPerCableKg but lacked cableCount, so all PR displays defaulted to single-cable weight. Added cable_count column via migration 28, threaded through repository, sync DTO, backup/restore, migration manager, and updated 4 display surfaces. Legacy PRs default to null (formatter shows per-cable as before). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify cableCount defaults to null for legacy data and correctly stores single/dual cable values. Also fix pre-existing compilation failures in FakePersonalRecordRepository, ConflictResolutionTest, MigrationManagerTest, SqlDelightPersonalRecordRepositoryTest, and ExerciseConfigViewModelTest caused by the cableCount parameter being added to the PersonalRecordRepository interface and insertRecord/ insertPRIgnore SQLDelight queries but not propagated to test fakes and call sites. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 .caf files exist in iosApp/VitruvianPhoenix/ bundle. The TODO was left behind after conversion was completed via convert_sounds.sh. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dual-cable exercises with individual handles (HANDLES, ROPE, etc.) now show per-cable weight. Only BAR and BELT exercises show combined weight. Adds display_multiplier column (migration 29) to WorkoutSession, threads through SetSummary, backup, sync, and all display surfaces. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Thread display_multiplier = null through 9 test call sites that broke after migration 29 added the column to WorkoutSession. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mits Introduce visual delta tracking to show weight changes relative to routine baselines. Standardize hardware weight limits across the workout flow using centralized constants. - Add `MAX_WEIGHT_PER_CABLE_KG` (110kg) to `Constants`. - Enhance `SliderWithButtons` to support optional, color-coded `deltaText` (tertiary for increase, error for decrease). - Implement baseline delta calculation logic in `RoutineOverviewScreen`, `SetReadyScreen`, and `RestTimerCard`. - Refactor weight adjusters to use shared hardware constants and standardize on a 0.25kg weight step. - Update `RoutineFlowManager` to enforce weight clamping using `coerceIn`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge main into feat/v0.9.0-enhancement-sweep to bring in bug fixes that landed after the branch diverged: - #388: V-Form legacy rep packet parsing (6..23 byte range) - #357: warmupOverrideParams for rep counter configuration - #402: EccentricOnly BLE NON_OVERLAP variant override - #393: Routine complete navigation race (Idle before Complete) - #392: Session ID leak on routine switch - #395: Aggregate health writes for routine workouts Conflict resolution highlights: - 27.sqm: Combined RoutineGroup + TrainingCycle deletedAt - MigrationStatements: v27 combined, v28-29 added with v29 fix - VitruvianDatabase.sq: upsertRoutine gets both updatedAt + groupId - DataBackupManager: v1 backup import nullable defaults for new cols - ActiveSessionEngine: VBT threshold code kept, duplicate removed - PortalApiClient: JWT prefix leak downgraded to Logger.d Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile-side design for exercise ID-first sync resolution, resolving GitHub issue #404 (exercise identity lost during sync round-trip). Covers: displayName field, sync DTO changes, ID-first pull resolution, trailing-space name cleanup. Depends on portal-side catalog deployment. Companion spec in phoenix-portal for Supabase/edge function changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Part of exercise catalog ID-first resolution (#404). Adds displayName TEXT column for disambiguation of same-name exercises. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Was a computed property returning name. Now a constructor parameter that defaults to name, populated from the DB displayName column. All insertExercise call sites pass null for now (Task 3 will generate display names). Mapper falls back to base name when column is NULL. Part of exercise catalog ID-first resolution (#404). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds exerciseId to PortalExerciseDto and PortalRoutineExerciseSyncDto. Adds displayName and exerciseEquipment to PortalRoutineExerciseSyncDto. Adds displayName to CustomExerciseSyncDto. Part of exercise catalog ID-first resolution (#404). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exercises with duplicate names get equipment-suffixed display names (e.g. 'Bicep Curl (Long Bar)'). All exercise names are trimmed on import to remove trailing-space disambiguation hacks. Part of exercise catalog ID-first resolution (#404). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Session exercises and routine exercises now carry the catalog exercise ID, display name, and equipment in their push DTOs. Part of exercise catalog ID-first resolution (#404). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exercise resolution now checks exerciseId first (direct catalog lookup), falling back to name-based resolution only for legacy data without IDs. Fixes the core identity loss bug (#404). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rectness - Add displayName to SchemaManifest CREATE TABLE and heal operations - Register migration 30 in MigrationStatements resilient fallback - Fix 7 test compilation errors (missing displayName/cable_count params) - Wire exerciseId through session pull for ID-first resolution - Fix telemetry cable values from "left"/"right" to canonical "A"/"B" - Raise weight clamp from MAX_WEIGHT_KG (100) to MAX_WEIGHT_PER_CABLE_KG (110) - Extract WeightStepper labels to localizable string resources - Remove dead legacy HapticFeedbackEffect in androidApp/ui/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughRemoved the Android haptic/audio composable; introduced two-cable weight UI/localization changes and per-cable clamping; propagated portal exercise IDs through sync lookup and updated telemetry cable labels; added schema heal for Exercise.displayName and test adjustments (cable_count, clamping expectations, fake repo ID resolution). ChangesTwo‑Cable Weight System
Sync & Exercise ID Propagation
Haptic Feedback Removal
Sequence Diagram(s)sequenceDiagram
participant Portal as Portal API
participant SyncMgr as SyncManager
participant PullAdapter as PortalPullAdapter
participant Repo as SyncRepository
Portal->>SyncMgr: deliver PullWorkoutSessionDto (includes exerciseId)
SyncMgr->>PullAdapter: toWorkoutSessionsWithLookup(portalSession,..., lookup)
PullAdapter->>Lookup: lookup(name, muscleGroup, exerciseId)
activate Repo
Lookup->>Repo: findExerciseId(name, muscleGroup, existingExerciseId)
Repo-->>Lookup: resolvedExerciseId (uses exerciseId-first)
Lookup-->>PullAdapter: resolvedExerciseId
PullAdapter-->>SyncMgr: WorkoutSession with resolvedExerciseId
SyncMgr->>Repo: persist/merge sessions
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 2/5 reviews remaining, refill in 30 minutes and 19 seconds. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 122b9527a0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| profile_id = routine.profileId ?: "default", | ||
| groupId = null, | ||
| ) |
There was a problem hiding this comment.
Preserve routine group assignment in streaming imports
In the streaming import path (importFromStream), routines are always inserted with groupId = null, so backups larger than the streaming threshold lose all routine-to-group links even when the backup contains valid groupId values. This silently flattens grouped routines after restore for large backups, while non-streaming import preserves the field.
Useful? React with 👍 / 👎.
| profile_id = session.profileId ?: "default", | ||
| display_multiplier = null, | ||
| ) |
There was a problem hiding this comment.
Keep display multiplier when streaming session backups
The streaming import branch hard-codes display_multiplier = null when restoring workout sessions, which drops newly added display metadata from v3 backups. For imports that take the streaming path, restored history can render weights differently than before export because the formatter must fall back to heuristics/legacy fields.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR is a broad “enhancement sweep” across the shared KMP module and both platforms, adding new workout UX signals (haptics/VBT), routine grouping + backup schema updates, and improving weight display semantics (cable-aware presentation) alongside sync/backup plumbing updates.
Changes:
- Adds new haptic events (FINAL_REP, VELOCITY_THRESHOLD_REACHED) and threads VBT settings through coordinator/engine/preferences.
- Introduces cable-/equipment-aware weight display via
displayMultiplier, plus DB + backup + sync DTO schema updates. - Adds custom backup destination support (model/picker/resolver) and routine grouping support (model/UI/backup/migration).
Reviewed changes
Copilot reviewed 180 out of 277 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| shared/src/iosMain/kotlin/com/devil/phoenixproject/presentation/components/HapticFeedbackEffect.ios.kt | iOS sound + haptic routing for new haptic events |
| shared/src/iosMain/kotlin/com/devil/phoenixproject/di/PlatformModule.ios.kt | iOS DI wiring for backup destination resolver + updated backup manager deps |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/testutil/FakeWorkoutRepository.kt | Test fake updated for new repository API |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/testutil/FakeSyncRepository.kt | Test fake updated for ID-first exercise resolution |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/testutil/FakePreferencesManager.kt | Test fake updated for backup + VBT prefs setters |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/testutil/FakePersonalRecordRepository.kt | Test fake updated for PR cableCount parameter |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/testutil/FakeBackupDestinationResolver.kt | New test double for backup destination I/O |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/util/WeightDisplayGuardTest.kt | Reflection-based guard test for formatter layering |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/manager/WorkoutCoordinatorEventTest.kt | New tests for haptic event coexistence/routing |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/domain/model/WorkoutMetricTest.kt | Extends singleton equality test coverage for new haptic event |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/data/sync/PortalSyncAdapterTest.kt | Adds bodyweight volume sync push regression tests |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/data/sync/ConflictResolutionTest.kt | Updates fixtures for new nullable DB columns |
| shared/src/commonTest/kotlin/com/devil/phoenixproject/data/repository/PersonalRecordCableCountTest.kt | New unit tests for PR cableCount backward compat |
| shared/src/commonMain/sqldelight/com/devil/phoenixproject/database/migrations/30.sqm | Adds Exercise.displayName column |
| shared/src/commonMain/sqldelight/com/devil/phoenixproject/database/migrations/29.sqm | Adds WorkoutSession.display_multiplier column |
| shared/src/commonMain/sqldelight/com/devil/phoenixproject/database/migrations/28.sqm | Adds PersonalRecord.cable_count column |
| shared/src/commonMain/sqldelight/com/devil/phoenixproject/database/migrations/27.sqm | Expands migration 27 to include RoutineGroup + Routine.groupId FK |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/util/Constants.kt | Updates app version + adjusts weight constants surface |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/util/BackupModels.kt | Backup schema v3: routine groups + new fields (displayMultiplier, cableCount, etc.) |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/util/BackupLocationPicker.kt | expect API for directory picking (custom backup destination) |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/util/BackupDestinationResolver.kt | New interface for platform-specific directory access |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/util/BackupDestination.kt | New serializable preference model for backup destination |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/viewmodel/MainViewModel.kt | Exposes routine groups + new settings setters + exercise timer controls |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/util/WeightDisplayFormatter.kt | New centralized display-only weight formatting (cable-aware) |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/WorkoutUiState.kt | Adds exercise timer pause state + VBT threshold in UI state/actions |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/WorkoutTab.kt | Threads exercise timer controls + applies display multiplier in countdown card |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/TrainingCyclesScreen.kt | Wires user preference increment into cycle mode confirmation |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/RoutineGroupHeader.kt | New composable for collapsible routine group headers |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/ModeConfirmationScreen.kt | Displays per-cable weight in user unit + configurable weight step |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/HomeScreen.kt | Uses WeightDisplayFormatter for recent activity weights |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/ExercisesTab.kt | Updates best-weight/1RM computations for cable awareness |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/ExerciseDetailScreen.kt | Updates 1RM + trends + tables to be cable-aware |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/DailyRoutinesScreen.kt | Wires routine group CRUD into routines UI |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/AnalyticsScreen.kt | Uses WeightDisplayFormatter for PR display |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/screen/ActiveWorkoutScreen.kt | Threads exercise timer pause + uses WeightDisplayFormatter in PR dialog |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/navigation/NavGraph.kt | Wires new settings: backup destination, weight increment, body weight, VBT |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/WorkoutCoordinator.kt | Adds routineGroups state + VBT threshold/config plumbing + timer pause state |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/SettingsManager.kt | Adds setters for backup destination + VBT prefs |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/GamificationManager.kt | Threads cableCount into PR persistence + celebration event |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/DefaultWorkoutSessionManager.kt | Constructs coordinator with VBT prefs + collects updates; delegates group CRUD and timer controls |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/WeightStepper.kt | i18n string resources + clarifies BLE rounding responsibilities |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/SliderWithButtons.kt | Adds optional delta indicator for sliders |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/SelectionActionBar.kt | Adds “bulk weight adjust” action button with localized a11y text |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/ExerciseConfigModal.kt | Threads configurable weight step into mode config panels |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/DashboardComponents.kt | Uses WeightDisplayFormatter for PR/top-exercise displays |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/usecase/BodyweightVolumeCalculator.kt | Adds more variants + variant picker support |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/premium/BiomechanicsEngine.kt | Makes velocity loss threshold mutable at runtime |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/model/UserPreferences.kt | Adds backup destination + VBT preferences |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/model/Routine.kt | Adds RoutineGroup + Routine.groupId; deprecates duplicate roundToIncrement |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/model/Models.kt | Adds PR cableCount, session displayMultiplier, new haptic events, PR celebration cableCount |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/model/Exercise.kt | Adds Exercise.displayName + isBodyweight + displayMultiplier logic |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/di/DomainModule.kt | Registers RoutineTimeEstimator use case |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/SyncModels.kt | Adds sync DTO fields: displayMultiplier, PR cableCount, exercise displayName |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/SyncManager.kt | Updates pull exercise lookup to support ID-first resolution |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/PortalSyncDtos.kt | Adds exerciseId/displayName/equipment snapshot fields; documents canonical cable A/B |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/PortalSyncAdapter.kt | Includes catalog IDs in portal DTOs + uses canonical cable A/B telemetry |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/PortalPullAdapter.kt | Adds exerciseId-aware lookup on pull |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/PortalApiClient.kt | Reduces auth logging verbosity (token prefix removed) |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/repository/WorkoutRepository.kt | Adds session-count API for time estimation |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/repository/SyncRepository.kt | Extends findExerciseId signature with optional exerciseId |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/repository/SqlDelightPersonalRecordRepository.kt | Threads cableCount through PR persistence and mapping |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/repository/SqlDelightExerciseRepository.kt | Maps Exercise.displayName from DB |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/repository/PersonalRecordRepository.kt | Adds optional cableCount params to PR update APIs |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/preferences/PreferencesManager.kt | Adds backup destination + VBT preference persistence |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/migration/MigrationManager.kt | Carries PR cable_count through profile migrations |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/local/MigrationStatements.kt | Adds statement lists for migrations 27–30 (resilient executor) |
| shared/src/commonMain/kotlin/com/devil/phoenixproject/data/local/ExerciseImporter.kt | Generates disambiguated display names during import |
| shared/src/commonMain/composeResources/values/strings.xml | Adds new string keys for weight stepper + adjust weights |
| shared/src/commonMain/composeResources/values-nl/strings.xml | Adds localized cd_adjust_weights |
| shared/src/commonMain/composeResources/values-fr/strings.xml | Adds localized cd_adjust_weights (currently English) |
| shared/src/commonMain/composeResources/values-es/strings.xml | Adds localized cd_adjust_weights (currently English) |
| shared/src/commonMain/composeResources/values-de/strings.xml | Adds localized cd_adjust_weights (currently English) |
| shared/src/androidMain/kotlin/com/devil/phoenixproject/util/BackupLocationPicker.android.kt | Android directory picker implementation (SAF + persistable permissions) |
| shared/src/androidMain/kotlin/com/devil/phoenixproject/util/BackupDestinationResolver.android.kt | Android resolver implementation (DocumentFile I/O + permission validation) |
| shared/src/androidMain/kotlin/com/devil/phoenixproject/di/PlatformModule.android.kt | Android DI wiring for resolver + updated backup manager deps |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/util/DataBackupManagerRoutineNameTest.kt | Updates fixtures for new nullable columns (groupId/display_multiplier) |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/util/BackupJsonNavigatorTest.kt | Adds cable_count fixture for round-trip |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/presentation/viewmodel/ExerciseConfigViewModelTest.kt | Updates fixtures for new Exercise.displayName + PR cable_count |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightUserProfileRepositoryTest.kt | Updates session fixture for display_multiplier |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightTrainingCycleRepositoryTest.kt | Updates routine fixture for groupId |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightSmartSuggestionsRepositoryTest.kt | Updates session fixture for display_multiplier |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightPersonalRecordRepositoryTest.kt | Updates fixtures for Exercise.displayName + PR cable_count |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightGamificationRepositoryTest.kt | Updates session fixture for display_multiplier |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightExerciseRepositoryTest.kt | Updates insertExercise fixture for displayName |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/repository/SqlDelightCompletedSetRepositoryTest.kt | Updates routine/session fixtures for groupId/display_multiplier |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/migration/MigrationManagerTest.kt | Updates fixtures for new nullable columns |
| shared/src/androidHostTest/kotlin/com/devil/phoenixproject/data/local/SchemaParityTest.kt | Updates schema parity docs/version constant (but not yet to latest migrations) |
| shared/build.gradle.kts | Bumps compileSdk and updates dependency management + SQLDelight schema version |
| iosApp/VitruvianPhoenix/VitruvianPhoenix.xcodeproj/project.pbxproj | Updates iOS marketing version |
| gradle/libs.versions.toml | Adds DocumentFile and Health Connect coordinates |
| audit/AUDIT-SUMMARY.md | Updates audit summary reporting table and totals |
| androidApp/src/androidTest/kotlin/com/devil/phoenixproject/testutil/FakeWorkoutRepository.kt | Android test fake updated for new repository API |
| androidApp/build.gradle.kts | Bumps compileSdk/versionName and enables resource shrinking for release |
| .planning/phases/44-integration-validation/44-REVIEW.md | Adds validation review notes and verdict |
| .planning/phases/44-integration-validation/44-02-SUMMARY.md | Adds regression suite/build verification summary |
| .planning/phases/44-integration-validation/44-01-SUMMARY.md | Adds integration test plan summary |
| .planning/phases/43-advanced-vbt/43-REVIEW.md | Adds VBT phase review summary |
| .planning/phases/43-advanced-vbt/43-03-SUMMARY.md | Adds VBT tests/integration validation summary |
| .planning/phases/43-advanced-vbt/43-02-SUMMARY.md | Adds VBT real-time tracking/auto-end summary |
| .planning/phases/43-advanced-vbt/43-01-SUMMARY.md | Adds VBT settings/threshold model summary |
| .planning/phases/42-platform/42-REVIEW.md | Adds platform phase review summary |
| .planning/phases/42-platform/42-03-SUMMARY.md | Adds platform tests/fixtures summary |
| .planning/phases/42-platform/42-02-SUMMARY.md | Adds platform UI integration + backup routing summary |
| .planning/phases/42-platform/42-01-SUMMARY.md | Adds backup destination model + picker summary |
| .planning/phases/41-quick-wins/41-REVIEW.md | Adds quick wins phase review summary |
| .planning/phases/40-analytics/40-REVIEW.md | Adds analytics phase review summary |
| .planning/phases/40-analytics/40-02-SUMMARY.md | Adds routine time estimate enhancement summary |
| .planning/phases/40-analytics/40-01-SUMMARY.md | Adds bodyweight volume integration summary |
| .planning/memory/RETRO.md | Adds retrospective/action items log |
| .planning/phases/36-integration-validation/36-CONTEXT.md | Removes obsolete phase context |
| .planning/phases/36-integration-validation/36-03-PLAN.md | Removes obsolete plan doc |
| .planning/phases/36-integration-validation/36-02-PLAN.md | Removes obsolete plan doc |
| .planning/phases/36-integration-validation/36-01-PLAN.md | Removes obsolete plan doc |
| .planning/phases/35-ios-platform-parity/35-CONTEXT.md | Removes obsolete phase context |
| .planning/phases/35-ios-platform-parity/35-03-PLAN.md | Removes obsolete plan doc |
| .planning/phases/35-ios-platform-parity/35-02-PLAN.md | Removes obsolete plan doc |
| .planning/phases/35-ios-platform-parity/35-01-PLAN.md | Removes obsolete plan doc |
| .planning/phases/34-lifecycle-security/34-REVIEW.md | Removes obsolete phase review doc |
| .planning/phases/34-lifecycle-security/34-CONTEXT.md | Removes obsolete phase context |
| .planning/phases/34-lifecycle-security/34-03-PLAN.md | Removes obsolete plan doc |
| .planning/phases/34-lifecycle-security/34-02-PLAN.md | Removes obsolete plan doc |
| .planning/phases/33-sync-data-integrity/33-REVIEW.md | Removes obsolete phase review doc |
| .planning/phases/33-sync-data-integrity/33-CONTEXT.md | Removes obsolete phase context |
| .planning/phases/33-sync-data-integrity/33-03-SUMMARY.md | Removes obsolete summary doc |
| .planning/phases/33-sync-data-integrity/33-03-PLAN.md | Removes obsolete plan doc |
| .planning/phases/33-sync-data-integrity/33-02-SUMMARY.md | Removes obsolete summary doc |
| .planning/phases/33-sync-data-integrity/33-01-SUMMARY.md | Removes obsolete summary doc |
| .planning/phases/32-ble-reliability/32-REVIEW.md | Removes obsolete phase review doc |
| .planning/phases/32-ble-reliability/32-CONTEXT.md | Removes obsolete phase context |
| .planning/phases/32-ble-reliability/32-03-SUMMARY.md | Removes obsolete summary doc |
| .planning/phases/32-ble-reliability/32-02-SUMMARY.md | Removes obsolete summary doc |
| .planning/phases/32-ble-reliability/32-01-SUMMARY.md | Removes obsolete summary doc |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Version 30 = initial schema (1) + 29 migrations (1.sqm through 29.sqm). | ||
| version = 30 | ||
| } |
| bestOneRepMax = calculateBestOneRepMax(sessions), | ||
| bestWeight = sessions.maxOf { it.weightPerCableKg }, | ||
| bestWeight = sessions.maxOf { it.weightPerCableKg * (it.cableCount ?: 1) }, | ||
| lastPerformed = sessions.maxOf { it.timestamp }, |
| override suspend fun getSessionCountForExercise(exerciseId: String, profileId: String): Long = | ||
| sessions.values.count { it.exerciseId == exerciseId }.toLong() |
| if (session.weightPerCableKg > 0) { | ||
| session.timestamp to session.weightPerCableKg | ||
| val totalWeight = session.weightPerCableKg * (session.cableCount ?: 1) | ||
| session.timestamp to totalWeight | ||
| } else { |
| companion object { | ||
| private const val CURRENT_VERSION = 26L | ||
| private const val CURRENT_VERSION = 27L | ||
|
|
| if (session.workingReps > 0) { | ||
| val oneRm = calculateOneRepMax(session.weightPerCableKg, session.workingReps) | ||
| val totalWeight = session.weightPerCableKg * (session.cableCount ?: 1) | ||
| val oneRm = calculateOneRepMax(totalWeight, session.workingReps) | ||
| session.timestamp to oneRm |
| override suspend fun getSessionCountForExercise(exerciseId: String, profileId: String): Long = | ||
| sessions.values.count { it.exerciseId == exerciseId }.toLong() | ||
|
|
| object Constants { | ||
| // App version | ||
| const val APP_VERSION = "0.7.0" | ||
| const val APP_VERSION = "0.8.0" | ||
|
|
| val job = launch(UnconfinedTestDispatcher(testScheduler)) { | ||
| coordinator.hapticEvents.toList(collected) | ||
| } | ||
|
|
||
| hapticFlow.emit(HapticEvent.FINAL_REP) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0b9d521c42
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| onClick = { onWeightChange((currentWeightKg + incrementKg).coerceAtMost(Constants.MAX_WEIGHT_PER_CABLE_KG)) }, | ||
| enabled = enabled && currentWeightKg < Constants.MAX_WEIGHT_PER_CABLE_KG, |
There was a problem hiding this comment.
Align all weight-entry paths to the same max limit
Updating the + buttons to allow MAX_WEIGHT_PER_CABLE_KG here introduces inconsistent behavior because other paths in the same component still clamp to MAX_WEIGHT_KG (e.g., WeightPresets and WeightPickerDialog). After a user increments above 100 kg, using +5% or opening the picker can silently force the value back to 100 kg, making 100–110 kg settings unstable and surprising.
Useful? React with 👍 / 👎.
Code Review SummaryStatus: Issues Found | Recommendation: Address before merge Overview
Other Observations (not in diff)
Files Reviewed (1 file in increment)
Reviewed by step-3.5-flash · 295,222 tokens |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
shared/src/androidHostTest/kotlin/com/devil/phoenixproject/util/BackupJsonNavigatorTest.kt (1)
530-543:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAssert
cable_countin the round-trip, not just the record count.This test now seeds
cable_count = 2, but it never verifies that the value survives export → import → re-export. A regression that drops the new field would still pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/WeightAdjustmentControls.kt`:
- Around line 111-113: The picker and preset paths are still using
Constants.MAX_WEIGHT_KG while the +/- buttons and allowed UI range use
Constants.MAX_WEIGHT_PER_CABLE_KG (110kg); update any usage of
WeightPickerDialog(...) and the "+5%" preset calculation in
WeightAdjustmentControls (including the handler that clamps values for presets)
to use Constants.MAX_WEIGHT_PER_CABLE_KG instead of Constants.MAX_WEIGHT_KG, and
ensure onWeightChange calls and any coerceAtMost/coerceIn clamping logic
reference Constants.MAX_WEIGHT_PER_CABLE_KG so all adjustment paths (buttons,
preset, picker) share the same ceiling.
🪄 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: 722ece41-dadb-40ae-b744-f0f38dd03673
📒 Files selected for processing (12)
androidApp/src/main/kotlin/com/devil/phoenixproject/ui/HapticFeedbackEffect.ktshared/src/androidHostTest/kotlin/com/devil/phoenixproject/util/BackupJsonNavigatorTest.ktshared/src/commonMain/composeResources/values/strings.xmlshared/src/commonMain/kotlin/com/devil/phoenixproject/data/local/SchemaManifest.ktshared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/PortalPullAdapter.ktshared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/PortalSyncAdapter.ktshared/src/commonMain/kotlin/com/devil/phoenixproject/data/sync/SyncManager.ktshared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/BulkWeightAdjustDialog.ktshared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/WeightAdjustmentControls.ktshared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/WeightStepper.ktshared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/components/BulkWeightAdjustTest.ktshared/src/commonTest/kotlin/com/devil/phoenixproject/testutil/FakeSyncRepository.kt
💤 Files with no reviewable changes (1)
- androidApp/src/main/kotlin/com/devil/phoenixproject/ui/HapticFeedbackEffect.kt
| icon = Icons.Default.Add, | ||
| onClick = { onWeightChange((currentWeightKg + incrementKg).coerceAtMost(Constants.MAX_WEIGHT_KG)) }, | ||
| enabled = enabled && currentWeightKg < Constants.MAX_WEIGHT_KG, | ||
| onClick = { onWeightChange((currentWeightKg + incrementKg).coerceAtMost(Constants.MAX_WEIGHT_PER_CABLE_KG)) }, | ||
| enabled = enabled && currentWeightKg < Constants.MAX_WEIGHT_PER_CABLE_KG, |
There was a problem hiding this comment.
Align the picker/preset paths with the new 110kg ceiling.
These buttons now allow 100f..110f, but WeightPickerDialog(...) and the +5% preset in this same file still cap at Constants.MAX_WEIGHT_KG. That leaves the component internally inconsistent: once a user reaches, say, 105kg via the buttons, opening the picker can feed an out-of-range value into the slider and any picker interaction will clamp it back to 100kg.
♻️ Minimal follow-up to keep all weight-adjustment paths consistent
- val maxWeightDisplay = if (isLbs) UnitConverter.kgToLb(Constants.MAX_WEIGHT_KG).toInt() else Constants.MAX_WEIGHT_KG.toInt()
+ val maxWeightDisplay = if (isLbs) {
+ UnitConverter.kgToLb(Constants.MAX_WEIGHT_PER_CABLE_KG).toInt()
+ } else {
+ Constants.MAX_WEIGHT_PER_CABLE_KG.toInt()
+ }
- .coerceAtMost(Constants.MAX_WEIGHT_KG)
+ .coerceAtMost(Constants.MAX_WEIGHT_PER_CABLE_KG)
- .coerceIn(0f, Constants.MAX_WEIGHT_KG)
+ .coerceIn(0f, Constants.MAX_WEIGHT_PER_CABLE_KG)
- ).coerceIn(0f, Constants.MAX_WEIGHT_KG)
+ ).coerceIn(0f, Constants.MAX_WEIGHT_PER_CABLE_KG)Also applies to: 511-512
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/components/WeightAdjustmentControls.kt`
around lines 111 - 113, The picker and preset paths are still using
Constants.MAX_WEIGHT_KG while the +/- buttons and allowed UI range use
Constants.MAX_WEIGHT_PER_CABLE_KG (110kg); update any usage of
WeightPickerDialog(...) and the "+5%" preset calculation in
WeightAdjustmentControls (including the handler that clamps values for presets)
to use Constants.MAX_WEIGHT_PER_CABLE_KG instead of Constants.MAX_WEIGHT_KG, and
ensure onWeightChange calls and any coerceAtMost/coerceIn clamping logic
reference Constants.MAX_WEIGHT_PER_CABLE_KG so all adjustment paths (buttons,
preset, picker) share the same ceiling.
Summary by CodeRabbit
New Features
Bug Fixes
Changes