diff --git a/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/ActiveSessionEngine.kt b/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/ActiveSessionEngine.kt index da94c4146..1f62e68f8 100644 --- a/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/ActiveSessionEngine.kt +++ b/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/ActiveSessionEngine.kt @@ -4444,6 +4444,8 @@ class ActiveSessionEngine( isAMRAP = nextIsAMRAP, stallDetectionEnabled = exerciseForNextSet.stallDetectionEnabled, warmupReps = if (nextExerciseIsBodyweight) 0 else Constants.DEFAULT_WARMUP_REPS, + stopAtTop = exerciseForNextSet.stopAtTop, + repCountTiming = exerciseForNextSet.repCountTiming, ) Logger.d { "startRestTimer: Issue #203 - Updated params for next set: ${exerciseForNextSet.exercise.name}, setIdx=$nextSetIdx, isAMRAP=$nextIsAMRAP, nextSetReps=$nextSetReps" } } @@ -4850,6 +4852,8 @@ class ActiveSessionEngine( isAMRAP = nextIsAMRAP, stallDetectionEnabled = nextExercise.stallDetectionEnabled, warmupReps = if (nextIsBodyweight) 0 else Constants.DEFAULT_WARMUP_REPS, + stopAtTop = nextExercise.stopAtTop, + repCountTiming = nextExercise.repCountTiming, ) Logger.d { "startNextSetOrExercise: Issue #203 - progressionKg=${nextExercise.progressionKg}kg for " + diff --git a/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/DefaultWorkoutSessionManager.kt b/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/DefaultWorkoutSessionManager.kt index 3ac1acb72..e63fc8461 100644 --- a/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/DefaultWorkoutSessionManager.kt +++ b/shared/src/commonMain/kotlin/com/devil/phoenixproject/presentation/manager/DefaultWorkoutSessionManager.kt @@ -937,6 +937,8 @@ class DefaultWorkoutSessionManager( selectedExerciseId = nextExercise.exercise.id, isAMRAP = nextIsAMRAP, stallDetectionEnabled = nextExercise.stallDetectionEnabled, + stopAtTop = nextExercise.stopAtTop, + repCountTiming = nextExercise.repCountTiming, ) Logger.d { "proceedFromSummary: Issue #203 - Updated params for next set: ${nextExercise.exercise.name}, setIdx=$nextSetIdx, isAMRAP=$nextIsAMRAP" diff --git a/shared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/manager/DWSMRoutineFlowTest.kt b/shared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/manager/DWSMRoutineFlowTest.kt index a403e4a72..e3b1060cc 100644 --- a/shared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/manager/DWSMRoutineFlowTest.kt +++ b/shared/src/commonTest/kotlin/com/devil/phoenixproject/presentation/manager/DWSMRoutineFlowTest.kt @@ -3,6 +3,7 @@ package com.devil.phoenixproject.presentation.manager import com.devil.phoenixproject.domain.model.AppliedRoutineModifier import com.devil.phoenixproject.domain.model.PRType import com.devil.phoenixproject.domain.model.PersonalRecord +import com.devil.phoenixproject.domain.model.RepCountTiming import com.devil.phoenixproject.domain.model.ProgramMode import com.devil.phoenixproject.domain.model.Routine import com.devil.phoenixproject.domain.model.RoutineExercise @@ -856,6 +857,85 @@ class DWSMRoutineFlowTest { harness.cleanup() } + /** + * Issue #689: Regression test for the autoplay exercise-boundary transition. + * + * ActiveSessionEngine.startNextSetOrExercise must replace the preceding exercise's + * stopAtTop and repCountTiming values with the next RoutineExercise's values. + */ + @Test + fun startNextSet_propagatesPerExerciseStopAtTopAndRepCountTiming() = runTest { + val harness = DWSMTestHarness(this) + val exercise0 = TestFixtures.allExercises[0] + val exercise1 = TestFixtures.allExercises[1] + val routine = Routine( + id = "test-689-autoplay-stopAtTop-repCountTiming", + name = "Issue689 Autoplay Regression", + exercises = listOf( + RoutineExercise( + id = "re-0-stopAtTop-true", + exercise = exercise0, + orderIndex = 0, + setReps = listOf(10), + weightPerCableKg = 25f, + stopAtTop = true, + repCountTiming = RepCountTiming.TOP, + ), + RoutineExercise( + id = "re-1-stopAtTop-false", + exercise = exercise1, + orderIndex = 1, + setReps = listOf(12), + weightPerCableKg = 15f, + stopAtTop = false, + repCountTiming = RepCountTiming.BOTTOM, + ), + ), + ) + routine.exercises.forEach { harness.fakeExerciseRepo.addExercise(it.exercise) } + advanceUntilIdle() + + harness.dwsm.loadRoutine(routine) + advanceUntilIdle() + + // Exercise 0 has the values that the report says leaked into later exercises. + assertEquals(true, harness.dwsm.coordinator.workoutParameters.value.stopAtTop) + assertEquals(RepCountTiming.TOP, harness.dwsm.coordinator.workoutParameters.value.repCountTiming) + + // Simulate a completed rest countdown advancing from exercise 0 to exercise 1. + harness.setActiveSummaryCountdownSeconds(0) + harness.dwsm.coordinator._currentExerciseIndex.value = 0 + harness.dwsm.coordinator._currentSetIndex.value = 0 + harness.dwsm.coordinator._workoutState.value = WorkoutState.Resting( + restSecondsRemaining = 0, + nextExerciseName = exercise1.displayName, + isLastExercise = false, + currentSet = 1, + totalSets = 1, + ) + + harness.dwsm.startNextSet() + advanceUntilIdle() + + val params = harness.dwsm.coordinator.workoutParameters.value + assertEquals( + false, + params.stopAtTop, + "stopAtTop must not leak from exercise 0 to exercise 1 (Issue #689 regression)", + ) + assertEquals( + RepCountTiming.BOTTOM, + params.repCountTiming, + "repCountTiming must not leak from exercise 0 to exercise 1 (Issue #689 regression)", + ) + assertEquals( + exercise1.id, + params.selectedExerciseId, + "Selected exercise should advance to exercise 1", + ) + harness.cleanup() + } + @Test fun goToPreviousExercise_navigatesBackward() = runTest { val harness = DWSMTestHarness(this)