Skip to content

feat(#674): Add eccentric load option for Old School mode#683

Closed
9thLevelSoftware wants to merge 56 commits into
mainfrom
enhancement/issue-674-old-school-eccentric
Closed

feat(#674): Add eccentric load option for Old School mode#683
9thLevelSoftware wants to merge 56 commits into
mainfrom
enhancement/issue-674-old-school-eccentric

Conversation

@9thLevelSoftware

Copy link
Copy Markdown
Owner

Summary

Adds eccentric load percentage support (110%–150%) to Old School mode by reusing the proven Echo 0x4E BLE packet mechanism. When eccentric load > 100%, the app dispatches the 0x4E packet with EchoLevel.HARDER and warmupReps = 3 (Constants.DEFAULT_WARMUP_REPS). isEchoMode stays false — PR tracking, gamification, and Old School behavior are preserved.

Closes #674

Changes

Source (7 files)

File Change
Models.kt Add hasEccentricOverload computed property
ActiveSessionEngine.kt Dispatch 0x4E for Old School+ecc>100, remove isEchoMode gate on defaults save, skip deload stall detection
JustLiftScreen.kt Remove isEchoMode guard on LaunchedEffect, split Card to show eccentric dropdown for Old School
SetReadyScreen.kt Split guard for eccentric slider (Echo+OldSchool), keep EchoLevel/AMRAP Echo-only
ExerciseEditBottomSheet.kt Show EccentricLoadSelector for Old School
RoutineOverviewScreen.kt Show eccentric load slider for Old School
RoutineFlowManager.kt Populate eccentricLoadPercent for Old School mode

Tests (1 file, 4 new tests)

  • hasEccentricOverload true for Old School + LOAD_130
  • hasEccentricOverload false for Old School + LOAD_100
  • hasEccentricOverload false for Echo + LOAD_100
  • hasEccentricOverload true for Echo + LOAD_130

Behavior

  • 100% (default): Normal Old School behavior — 0x04 packet, no change
  • 110%–150%: 0x4E packet dispatched with HARDER level and 3-rep warmup buffer
  • isEchoMode remains false — PR tracking, gamification, and app-side Old School behavior preserved
  • Echo mode unchanged — all existing Echo behavior identical
  • Zero schema migration, zero portal changes

User Instructions

Old School mode now shows an Eccentric Load dropdown in Just Lift, Set Ready, and the Routine Editor. Select 110%–150% to increase resistance during the lowering phase. PR tracking and gamification continue based on concentric weight.

Hardware Validation Gate

This implementation covers app-side changes only. Before production release, hardware validation must confirm:

  1. 0x4E with HARDER EchoLevel doesn't change Old School concentric feel
  2. Rep count events are identical in format/timing (0x4E vs 0x04)
  3. eccentricMaxVelocity = -200.0 produces correct eccentric limits

Devil added 30 commits July 16, 2026 15:47
Devil added 21 commits July 17, 2026 07:13
Reuse the Echo 0x4E BLE packet for Old School exercises with eccentric
load > 100%. isEchoMode stays false — PR tracking, gamification, and
Old School behavior are preserved. EchoLevel.HARDER and warmupReps=3
(Constants.DEFAULT_WARMUP_REPS) are used for the Old School 0x4E path.

Changes:
- Models.kt: add hasEccentricOverload computed property
- ActiveSessionEngine.kt: dispatch 0x4E for Old School+ecc>100,
  remove isEchoMode gate on defaults save, skip deload stall for ecc>100
- JustLiftScreen.kt: remove isEchoMode guard on LaunchedEffect, split
  Card to show eccentric dropdown for Old School (no EchoLevel)
- SetReadyScreen.kt: split guard for eccentric slider (Echo+OldSchool),
  keep EchoLevel/AMRAP reps Echo-only
- ExerciseEditBottomSheet.kt: show EccentricLoadSelector for Old School
- RoutineOverviewScreen.kt: show eccentric load slider for Old School
- RoutineFlowManager.kt: populate eccentricLoadPercent for Old School
- WorkoutParametersTest.kt: 4 new hasEccentricOverload tests

Closes #674

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28355e4df5

ℹ️ 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".

}

val commandValidation = if (bleParams.isEchoMode) {
val hasEccentricOverload = bleParams.eccentricLoad.percentage > 100

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restrict overload dispatch to Old School mode

When a user selects an overload above 100% in Echo or Old School and then switches to Pump, TUT, TUT Beast, or Eccentric Only, both JustLiftScreen and ExerciseConfigViewModel.onSelectedModeChange retain the previous eccentric value. This mode-agnostic check consequently sends the 0x4E Echo control packet instead of that mode's program packet and also disables deload auto-stop. Require ProgramMode.OldSchool here in addition to the percentage check.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in commit 1a02b59: hasEccentricOverload now requires ProgramMode.OldSchool in addition to eccentricLoad.percentage > 100. This prevents the 0x4E Echo packet from being dispatched when a user switches from Old School+130% to Pump/TUT/TUTBeast/EccentricOnly. The ActiveSessionEngine now uses the model property instead of an inline percentage-only check.

Comment on lines +419 to 423
if (isEchoMode || isOldSchool) {
EccentricLoadSelector(
eccentricLoad = eccentricLoad,
onLoadChange = viewModel::onEccentricLoadChange,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve Old School overload in portal routine sync

Old School routines can now save a selected overload locally, but PortalSyncAdapter.toPortalRoutine still emits eccentricLoad = null for every non-Echo exercise. After the routine is pushed and restored on another device, PortalPullAdapter.parseEccentricLoad(null) converts it to 100%, silently removing the configured overload and changing the workout behavior. Serialize this field for Old School as well as Echo.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in commit 1a02b59: PortalSyncAdapter.toPortalRoutine now serializes eccentricLoad for both ProgramMode.Echo and ProgramMode.OldSchool. Previously it was Echo-only, which silently dropped the Old School overload setting during portal sync and restore.

…ngs label

The enhancement added an Old School-specific settings label. Update the
source-level wiring test to match the new conditional pattern.
9thLevelSoftware pushed a commit that referenced this pull request Jul 25, 2026
…al sync

- hasEccentricOverload now requires ProgramMode.OldSchool (not just ecc%>100)
  so switching from Old School+130% to Pump/TUT doesn't dispatch 0x4E packet
- ActiveSessionEngine uses the model property instead of inline percentage check
- PortalSyncAdapter serializes eccentricLoad for Old School routines (not just Echo)
- Updated tests: Echo+LOAD_130 now false; added Pump+LOAD_130 regression test

Addresses Codex review P1s on PR #683

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a02b592ca

ℹ️ 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".

Comment on lines +2854 to 2855
val command = if (bleParams.isEchoMode || hasEccentricOverload) {
BlePacketFactory.createEchoControl(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the configured Old School weight in overload packets

When an Old School set uses more than 100% eccentric load, this branch replaces the 96-byte program frame with createEchoControl(). That 32-byte frame serializes reps, Echo timing/velocity, and eccentric percentage, but neither weightPerCableKg, progression, nor the Old School phase profile, so a freshly connected machine cannot receive the user's selected concentric weight and is configured as Echo rather than Old School. The overload path needs a protocol sequence or packet that retains the Old School force configuration instead of sending only the Echo frame.

Useful? React with 👍 / 👎.

Comment on lines +679 to 682
if (isEchoMode || isOldSchool) {
OverviewEccentricLoadSlider(
percent = eccentricLoadPercent,
onPercentChange = onEccentricLoadChange,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Apply the overview eccentric adjustment when starting

For an Old School routine, changing this newly visible slider only updates ExerciseOverviewAdjustments; startCurrentExercise() passes only adjusted weight and reps to enterSetReadyWithAdjustments(), which then restores both the SetReady percentage and WorkoutParameters.eccentricLoad from the saved exercise. Consequently, selecting (for example) 130% on the overview and pressing Start silently begins with the routine's original percentage. Pass the adjusted eccentric value through the start path alongside weight and reps.

Useful? React with 👍 / 👎.

Comment on lines +583 to +586
val isOldSchool = selectedMode is WorkoutMode.OldSchool
val showEccentricLoad = isEchoMode || isOldSchool

if (showEccentricLoad) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict Old School choices to supported overload values

When Old School is selected, this exposes the existing dropdown containing 0%, 50%, and 75% as well as overload values; the routine editor does the same, and the SetReady/overview sliders expose the full 0–150% range. However, hasEccentricOverload dispatches eccentric behavior only above 100%, so selecting any sub-100 value displays and persists an asymmetric-load choice while the machine receives the ordinary symmetric Old School program. Filter Old School controls to the supported 100%/110–150% choices or implement the advertised underload behavior.

Useful? React with 👍 / 👎.

…al sync

- hasEccentricOverload now requires ProgramMode.OldSchool (not just ecc%>100)
  so switching from Old School+130% to Pump/TUT doesn't dispatch 0x4E packet
- ActiveSessionEngine uses the model property instead of inline percentage check
- PortalSyncAdapter serializes eccentricLoad for Old School only when > 100%
- Updated tests: Echo+LOAD_130 now false; added Pump+LOAD_130 regression test

Addresses Codex review P1s on PR #683
@9thLevelSoftware
9thLevelSoftware force-pushed the enhancement/issue-674-old-school-eccentric branch from 1a02b59 to b5097ad Compare July 25, 2026 03:20
@9thLevelSoftware
9thLevelSoftware deleted the enhancement/issue-674-old-school-eccentric branch July 25, 2026 14:19
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.

Add eccentric weight increase option to Old School mode

1 participant