@@ -47,6 +47,7 @@ import {
4747 matchesExerciseFilter ,
4848} from '../utils/exerciseFilters' ;
4949import { resolveExerciseProfile } from '../domain/intelligence/exerciseProfileEngine' ;
50+ import { formatVolumeFromKg , formatWeightFromKg } from '../utils/weightUnits' ;
5051
5152function genId ( ) { return Date . now ( ) . toString ( 36 ) + Math . random ( ) . toString ( 36 ) . slice ( 2 , 6 ) ; }
5253
@@ -66,7 +67,7 @@ function getExerciseMuscles(exercise) {
6667 return getExerciseFilterSummary ( exercise , 6 ) ;
6768}
6869
69- function getPlateText ( targetKg , barWeight , profilePlates ) {
70+ function getPlateText ( targetKg , barWeight , profilePlates , weightUnit = 'kg' ) {
7071 const perSide = ( targetKg - barWeight ) / 2 ;
7172 if ( perSide <= 0 ) return 'Bar only' ;
7273 const plates = profilePlates ?. length
@@ -78,7 +79,7 @@ function getPlateText(targetKg, barWeight, profilePlates) {
7879 while ( rem >= p - 0.001 ) { result . push ( p ) ; rem = Math . round ( ( rem - p ) * 100 ) / 100 ; }
7980 }
8081 if ( result . length === 0 ) return 'Bar only' ;
81- return result . map ( p => p + 'kg' ) . join ( ' + ' ) + ' each side' ;
82+ return result . map ( p => formatWeightFromKg ( p , weightUnit ) ) . join ( ' + ' ) + ' each side' ;
8283}
8384
8485function parseRepTarget ( value , fallback = 8 ) {
@@ -191,29 +192,29 @@ const rt = StyleSheet.create({
191192
192193// ─── PLATE MODAL ─────────────────────────────────────────────────────────────
193194
194- function PlateModal ( { visible, targetKg, barWeight, onClose } ) {
195+ function PlateModal ( { visible, targetKg, barWeight, onClose, weightUnit = 'kg' } ) {
195196 const result = calcPlates ( targetKg , barWeight ) ;
196197 return (
197198 < Modal visible = { visible } transparent animationType = "slide" onRequestClose = { onClose } >
198199 < View style = { pm . overlay } >
199200 < View style = { pm . sheet } >
200201 < Text style = { pm . title } > PLATE CALCULATOR</ Text >
201- < Text style = { pm . target } > { targetKg } kg total</ Text >
202+ < Text style = { pm . target } > { formatWeightFromKg ( targetKg , weightUnit ) } total</ Text >
202203 { result . valid ? (
203204 < >
204205 < Text style = { pm . label } > Each side:</ Text >
205206 { result . each . length === 0
206- ? < Text style = { pm . noPlates } > Bar only ({ barWeight } kg )</ Text >
207+ ? < Text style = { pm . noPlates } > Bar only ({ formatWeightFromKg ( barWeight , weightUnit ) } )</ Text >
207208 : result . each . map ( ( p , i ) => (
208209 < View key = { i } style = { pm . plateRow } >
209210 < View style = { [ pm . plateVis , { width : 20 + p . kg * 2 } ] } />
210- < Text style = { pm . plateText } > { p . kg } kg x { p . count } </ Text >
211+ < Text style = { pm . plateText } > { formatWeightFromKg ( p . kg , weightUnit ) } x { p . count } </ Text >
211212 </ View >
212213 ) ) }
213- < Text style = { pm . sub } > Bar: { barWeight } kg · Total: { result . total } kg </ Text >
214+ < Text style = { pm . sub } > Bar: { formatWeightFromKg ( barWeight , weightUnit ) } · Total: { formatWeightFromKg ( result . total , weightUnit ) } </ Text >
214215 </ >
215216 ) : (
216- < Text style = { { color : '#FF4500' , textAlign : 'center' } } > Cannot load { targetKg } kg with available plates.</ Text >
217+ < Text style = { { color : '#FF4500' , textAlign : 'center' } } > Cannot load { formatWeightFromKg ( targetKg , weightUnit ) } with available plates.</ Text >
217218 ) }
218219 < TouchableOpacity style = { pm . close } onPress = { ( ) => { triggerHaptic ( 'selection' ) . catch ( ( ) => { } ) ; onClose ( ) ; } } >
219220 < Text style = { { color : '#f0f0f0' , fontWeight : '700' , letterSpacing : 2 } } > CLOSE</ Text >
@@ -842,7 +843,7 @@ function WorkoutContent({ plan, day, planIndex, dayIndex, navigation }) {
842843
843844 if ( weight > 0 && ( ! pb [ key ] || weight > pb [ key ] ) ) {
844845 updatePb ( key , weight ) ;
845- dispatch ( { type : 'SET_PB_NOTIF' , message : 'NEW PB: ' + ex . name + ' — ' + weight + 'kg' } ) ;
846+ dispatch ( { type : 'SET_PB_NOTIF' , message : 'NEW PB: ' + ex . name + ' — ' + formatWeightFromKg ( weight , settings ?. weightUnit || 'kg' ) } ) ;
846847 setTimeout ( ( ) => dispatch ( { type : 'SET_PB_NOTIF' , message : null } ) , 3000 ) ;
847848 primarySetEvent = 'prUnlocked' ;
848849 }
@@ -1128,7 +1129,7 @@ function WorkoutContent({ plan, day, planIndex, dayIndex, navigation }) {
11281129 } ) . filter ( Boolean ) ;
11291130 if ( targets . length > 0 ) setNextTargets ( targets ) ;
11301131 } catch ( _ ) { }
1131- const completionLine = summaryText || `You lifted ${ Math . round ( totalVolume ) . toLocaleString ( ) } kg total.` ;
1132+ const completionLine = summaryText || `You lifted ${ formatVolumeFromKg ( totalVolume , settings ?. weightUnit || 'kg' ) } total.` ;
11321133 const prLine = prEvents . length ? ` ${ prEvents . length } PR event${ prEvents . length > 1 ? 's' : '' } .` : '' ;
11331134 const milestoneLine = addResult ?. unlockedMilestones ?. length
11341135 ? ` ${ addResult . unlockedMilestones . length } milestone unlocked.`
@@ -1304,7 +1305,7 @@ function WorkoutContent({ plan, day, planIndex, dayIndex, navigation }) {
13041305 < Text style = { s . exTarget } > { ex . primary || ( ex . primaryMuscles || [ ] ) [ 0 ] || '—' } · { workingExercises [ exIndex ] . sets } x{ workingExercises [ exIndex ] . reps } </ Text >
13051306 { suggestion ? (
13061307 < Text style = { [ s . exTargetHint , { color : suggestion . action === 'reduce' ? '#FF8E8E' : colors . subtext } ] } >
1307- Next target { suggestion . targetWeight } kg x { suggestion . targetReps }
1308+ Next target { Number ( suggestion . targetWeight || 0 ) > 0 ? formatWeightFromKg ( suggestion . targetWeight , settings ?. weightUnit || 'kg' ) : 'BW' } x { Math . max ( 1 , Number ( suggestion . targetReps || 0 ) ) }
13081309 { suggestion . plateauSignal ? ` · Plateau: ${ suggestion . plateauSignal . recommendation } ` : '' }
13091310 { suggestion . deloadSignal ? ` · ${ suggestion . deloadSignal . recommendation } ` : '' }
13101311 </ Text >
@@ -1319,27 +1320,38 @@ function WorkoutContent({ plan, day, planIndex, dayIndex, navigation }) {
13191320 < TouchableOpacity style = { s . ghostContainer } onPress = { ( ) => { triggerHaptic ( 'selection' , { enabled : haptic } ) . catch ( ( ) => { } ) ; const fs = ghost . sets [ 0 ] ; if ( fs ) dispatch ( { type : 'SET_INPUT' , exIndex, weight : String ( fs . weight ) , reps : String ( fs . reps ) } ) ; } } >
13201321 < Text style = { s . ghostLabel } > LAST · { ghost . date } · tap to fill</ Text >
13211322 < View style = { { flexDirection : 'row' , flexWrap : 'wrap' , gap : 8 } } >
1322- { ghost . sets . map ( ( gs , gi ) => < Text key = { gi } style = { s . ghostSet } > { gs . weight > 0 ? ` ${ gs . weight } kg` : 'BW' } ×{ gs . reps } </ Text > ) }
1323+ { ghost . sets . map ( ( gs , gi ) => < Text key = { gi } style = { s . ghostSet } > { gs . weight > 0 ? formatWeightFromKg ( gs . weight , settings ?. weightUnit || 'kg' ) : 'BW' } ×{ gs . reps } </ Text > ) }
13231324 </ View >
13241325 </ TouchableOpacity >
13251326 ) : null }
13261327 { logged . length > 0 && (
13271328 < View style = { s . loggedSets } >
13281329 { logged . map ( ( ls , si ) => (
13291330 < View key = { ls . id } >
1330- < SetRow set = { ls } setIndex = { si } exIndex = { exIndex } dispatch = { dispatch } effortTracking = { settings . effortTracking || 'off' } hapticFeedback = { haptic } />
1331+ < SetRow set = { ls } setIndex = { si } exIndex = { exIndex } dispatch = { dispatch } effortTracking = { settings . effortTracking || 'off' } hapticFeedback = { haptic } weightUnit = { settings ?. weightUnit || 'kg' } />
13311332 { showPlateUi && ls . type === 'warmup' && ls . weight > 0 && (
13321333 < Text style = { s . plateHint } >
1333- { getPlateText ( ls . weight , activeGymProfile ?. barWeight || settings . barWeight || 20 , activeGymProfile ?. plates ) }
1334+ { getPlateText ( ls . weight , activeGymProfile ?. barWeight || settings . barWeight || 20 , activeGymProfile ?. plates , settings ?. weightUnit || 'kg' ) }
13341335 </ Text >
13351336 ) }
13361337 </ View >
13371338 ) ) }
13381339 </ View >
13391340 ) }
1341+ { showPlateUi ? (
1342+ < TouchableOpacity
1343+ style = { s . quickAddBtn }
1344+ onPress = { ( ) => {
1345+ triggerHaptic ( 'selection' , { enabled : haptic } ) . catch ( ( ) => { } ) ;
1346+ generateWarmups ( exIndex ) ;
1347+ } }
1348+ >
1349+ < Text style = { s . quickAddText } > GENERATE WARM-UP SETS</ Text >
1350+ </ TouchableOpacity >
1351+ ) : null }
13401352 < View style = { s . inputRow } >
13411353 < View style = { s . inputGroup } >
1342- < Text style = { s . inputLabel } > KG </ Text >
1354+ < Text style = { s . inputLabel } > { String ( settings ?. weightUnit || 'kg' ) . toUpperCase ( ) } </ Text >
13431355 < View style = { { flexDirection : 'row' , alignItems : 'center' } } >
13441356 < TextInput style = { s . input } value = { inp . weight } onChangeText = { t => dispatch ( { type : 'SET_INPUT' , exIndex, weight : t } ) } keyboardType = "decimal-pad" placeholder = "0" placeholderTextColor = "#222" />
13451357 { showPlateUi ? (
@@ -1375,7 +1387,13 @@ function WorkoutContent({ plan, day, planIndex, dayIndex, navigation }) {
13751387 </ View >
13761388
13771389 { /* Modals */ }
1378- < PlateModal visible = { showPlates } targetKg = { platesTarget } barWeight = { activeGymProfile ?. barWeight || settings . barWeight || 20 } onClose = { ( ) => setShowPlates ( false ) } />
1390+ < PlateModal
1391+ visible = { showPlates }
1392+ targetKg = { platesTarget }
1393+ barWeight = { activeGymProfile ?. barWeight || settings . barWeight || 20 }
1394+ weightUnit = { settings ?. weightUnit || 'kg' }
1395+ onClose = { ( ) => setShowPlates ( false ) }
1396+ />
13791397
13801398 < RestOverrideModal
13811399 visible = { showRestOverride }
@@ -1497,7 +1515,7 @@ function WorkoutContent({ plan, day, planIndex, dayIndex, navigation }) {
14971515 { t . action ? `${ String ( t . action ) . toUpperCase ( ) } · ` : '' } { t . rationale || ( t . plateau ? `Plateau: ${ t . plateau } ` : t . deload ? t . deload : 'Keep the trend moving' ) }
14981516 </ Text >
14991517 </ View >
1500- < Text style = { [ s . targetVal , { color : t . action === 'reduce' ? '#FF8E8E' : colors . accent } ] } > { t . weight } kg × { t . reps } </ Text >
1518+ < Text style = { [ s . targetVal , { color : t . action === 'reduce' ? '#FF8E8E' : colors . accent } ] } > { Number ( t . weight || 0 ) > 0 ? formatWeightFromKg ( t . weight , settings ?. weightUnit || 'kg' ) : 'BW' } × { Math . max ( 1 , Number ( t . reps || 0 ) ) } </ Text >
15011519 </ View >
15021520 ) ) }
15031521 </ ScrollView >
0 commit comments