diff --git a/stronglift_replacement/workout_app/lib/models/exercise_state.dart b/stronglift_replacement/workout_app/lib/models/exercise_state.dart index adc3bfe..5fd5f67 100644 --- a/stronglift_replacement/workout_app/lib/models/exercise_state.dart +++ b/stronglift_replacement/workout_app/lib/models/exercise_state.dart @@ -200,23 +200,10 @@ DateTime? parsePauseDate(Object? raw) { return parsed; } -const _months = [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', -]; - -/// `11 Oct`: how a pause's end date is shown. -String formatShortDate(DateTime d) => '${d.day} ${_months[d.month - 1]}'; +/// `11.10`: how a pause's end date is shown (textgate: numerals, no month +/// word; was `11 Oct`). +String formatShortDate(DateTime d) => + '${d.day}.${d.month.toString().padLeft(2, '0')}'; /// `3:00`: how a rest length is shown. String formatRest(int secs) => diff --git a/stronglift_replacement/workout_app/lib/models/progression.dart b/stronglift_replacement/workout_app/lib/models/progression.dart index 1ab56cd..aa4e11a 100644 --- a/stronglift_replacement/workout_app/lib/models/progression.dart +++ b/stronglift_replacement/workout_app/lib/models/progression.dart @@ -125,15 +125,19 @@ ProgressionTarget targetAfterFailure(ProgressionInputs s) { } } -/// Short label for moving from [from] to [to]: `25 kg`, `13 reps`, -/// `25 kg × 6`, or `same` when the rule has nowhere left to go. +/// What [describeTargetChange] returns when the rule has nowhere to go. +const kNoTargetChange = '='; + +/// Short label for moving from [from] to [to]: `25 kg`, `×13` (reps), +/// `25 kg × 6`, or [kNoTargetChange]. textgate: numerals and symbols only +/// (was `13 reps` / `same`). String describeTargetChange(ProgressionInputs from, ProgressionTarget to) { final weightChanged = to.weight != from.weight; final repsChanged = to.reps != from.reps; if (weightChanged && repsChanged) return '${_kg(to.weight)} kg × ${to.reps}'; if (weightChanged) return '${_kg(to.weight)} kg'; - if (repsChanged) return '${to.reps} reps'; - return 'same'; + if (repsChanged) return '×${to.reps}'; + return kNoTargetChange; } /// `25` for 25.0, `27.5` for 27.5 — no trailing `.0` noise in tight rows. diff --git a/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_deload.dart b/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_deload.dart index 29a6efc..4721208 100644 --- a/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_deload.dart +++ b/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_deload.dart @@ -18,7 +18,7 @@ class _DeloadRow extends StatelessWidget { Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final change = describeTargetChange(state, targetAfterFailure(state)); - final canDeload = change != 'same'; + final canDeload = change != kNoTargetChange; return SizedBox( height: 40, child: Row( diff --git a/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_rows.dart b/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_rows.dart index 48c3c32..9f3b80c 100644 --- a/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_rows.dart +++ b/stronglift_replacement/workout_app/lib/widgets/exercise_settings_sheet_rows.dart @@ -207,16 +207,17 @@ class _PauseRow extends StatelessWidget { ), ] : [ + // textgate: was "Paused — back on 11 Oct". Icon( Icons.pause_circle_outline, size: 18, color: colorScheme.error, + semanticLabel: 'Paused', ), const SizedBox(width: 8), - Text( - 'Paused — back on ${formatShortDate(until)}', - style: style, - ), + Icon(Icons.arrow_forward, size: 16, color: colorScheme.error), + const SizedBox(width: 4), + Text(formatShortDate(until), style: style), const Spacer(), TextButton( onPressed: onResume, diff --git a/stronglift_replacement/workout_app/lib/widgets/exercise_tile_rows.dart b/stronglift_replacement/workout_app/lib/widgets/exercise_tile_rows.dart index 71f0279..1816a4e 100644 --- a/stronglift_replacement/workout_app/lib/widgets/exercise_tile_rows.dart +++ b/stronglift_replacement/workout_app/lib/widgets/exercise_tile_rows.dart @@ -20,10 +20,12 @@ class _ModeChip extends StatelessWidget { static const double width = 64; - String get _text => switch (state.mode) { - ProgressionMode.weight => 'kg', - ProgressionMode.reps => 'reps', - ProgressionMode.doubleProgression => '${state.repsLow}→${state.repsHigh}', + // textgate: was 'kg' / 'reps'. The same mode glyphs as the settings + // sheet's segmented control; double progression keeps its rep range. + IconData? get _modeIcon => switch (state.mode) { + ProgressionMode.weight => Icons.fitness_center, + ProgressionMode.reps => Icons.repeat, + ProgressionMode.doubleProgression => null, }; @override @@ -52,12 +54,17 @@ class _ModeChip extends StatelessWidget { Icon(Icons.tune, size: 13, color: color), const SizedBox(width: 3), Flexible( - child: Text( - _text, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: color, fontSize: AppTextSize.caption), - ), + child: _modeIcon == null + ? Text( + '${state.repsLow}→${state.repsHigh}', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: color, + fontSize: AppTextSize.caption, + ), + ) + : Icon(_modeIcon, size: 14, color: color), ), ], ), @@ -204,16 +211,24 @@ class _PausedRow extends StatelessWidget { height: ExerciseTile.setRowHeight, child: Row( children: [ - Icon(Icons.pause_circle_outline, size: 20, color: color), - const SizedBox(width: 8), - Expanded( - child: Text( - 'Paused — back on ${formatShortDate(until)} · counts as failed', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: color, fontSize: AppTextSize.label), - ), + // textgate: was "Paused — back on 11 Oct · counts as failed". + // Now: pause glyph, the return date, and the failed-set cross. + Icon( + Icons.pause_circle_outline, + size: 20, + color: color, + semanticLabel: 'Paused — counts as failed', ), + const SizedBox(width: 8), + Icon(Icons.arrow_forward, size: 16, color: color), + const SizedBox(width: 4), + Text( + formatShortDate(until), + key: const Key('paused_until'), + style: TextStyle(color: color, fontSize: AppTextSize.label), + ), + const SizedBox(width: 8), + Icon(Icons.close, size: 16, color: color), ], ), ); diff --git a/stronglift_replacement/workout_app/test/models/exercise_state_test.dart b/stronglift_replacement/workout_app/test/models/exercise_state_test.dart index 881c213..7bc3fe9 100644 --- a/stronglift_replacement/workout_app/test/models/exercise_state_test.dart +++ b/stronglift_replacement/workout_app/test/models/exercise_state_test.dart @@ -62,9 +62,9 @@ void main() { }); test('formatShortDate', () { - expect(formatShortDate(DateTime(2026, 10, 11)), '11 Oct'); - expect(formatShortDate(DateTime(2026, 1, 1)), '1 Jan'); - expect(formatShortDate(DateTime(2026, 12, 31)), '31 Dec'); + expect(formatShortDate(DateTime(2026, 10, 11)), '11.10'); + expect(formatShortDate(DateTime(2026, 1, 1)), '1.01'); + expect(formatShortDate(DateTime(2026, 12, 31)), '31.12'); }); }); } diff --git a/stronglift_replacement/workout_app/test/models/progression_test.dart b/stronglift_replacement/workout_app/test/models/progression_test.dart index 46389b0..f8de366 100644 --- a/stronglift_replacement/workout_app/test/models/progression_test.dart +++ b/stronglift_replacement/workout_app/test/models/progression_test.dart @@ -153,16 +153,13 @@ void main() { }); test('reps only', () { - expect( - describeTargetChange(from, const ProgressionTarget(20, 9)), - '9 reps', - ); + expect(describeTargetChange(from, const ProgressionTarget(20, 9)), '×9'); }); test('no change', () { expect( describeTargetChange(from, const ProgressionTarget(20, 8)), - 'same', + kNoTargetChange, ); }); diff --git a/stronglift_replacement/workout_app/test/screens/workout_pause_test.dart b/stronglift_replacement/workout_app/test/screens/workout_pause_test.dart index 5d1a925..6fc6a42 100644 --- a/stronglift_replacement/workout_app/test/screens/workout_pause_test.dart +++ b/stronglift_replacement/workout_app/test/screens/workout_pause_test.dart @@ -18,6 +18,7 @@ import '../fake_audio_platform.dart'; import '../fake_break_service.dart'; import '../fake_secure_storage.dart'; import '_workout_screen_test_fixtures.dart'; +import '../icon_finders.dart'; // Real plan names, so each has a progression-state row to pause. const _lunge = Exercise(name: 'Dumbbell Lunge', sets: 2, reps: 5, weight: 10); @@ -63,7 +64,7 @@ void main() { testWidgets('the paused exercise shows no sets and says so', (tester) async { await pumpPausedSitup(tester); expect(find.byType(RepCircle), findsNWidgets(_lunge.sets)); - expect(find.textContaining('Paused — back on'), findsOneWidget); + expect(iconLabeled('Paused — counts as failed'), findsOneWidget); }); testWidgets('Finish unlocks without it, and it is recorded as failed', ( diff --git a/stronglift_replacement/workout_app/test/widgets/exercise_settings_sheet_test.dart b/stronglift_replacement/workout_app/test/widgets/exercise_settings_sheet_test.dart index adb9d6b..63c113a 100644 --- a/stronglift_replacement/workout_app/test/widgets/exercise_settings_sheet_test.dart +++ b/stronglift_replacement/workout_app/test/widgets/exercise_settings_sheet_test.dart @@ -155,7 +155,7 @@ void main() { edits.last.pausedUntil, pauseEnd(DateTime.now(), kDefaultPauseDays + 1), ); - expect(find.textContaining('Paused — back on'), findsOneWidget); + expect(iconLabeled('Paused'), findsOneWidget); await tester.tap(iconLabeled('Resume')); await tester.pump(); diff --git a/stronglift_replacement/workout_app/test/widgets/exercise_tile_test.dart b/stronglift_replacement/workout_app/test/widgets/exercise_tile_test.dart index e438633..91ca919 100644 --- a/stronglift_replacement/workout_app/test/widgets/exercise_tile_test.dart +++ b/stronglift_replacement/workout_app/test/widgets/exercise_tile_test.dart @@ -134,17 +134,17 @@ void main() { await tester.pumpWidget( _wrap(_tile(state: _state.copyWith(mode: ProgressionMode.reps))), ); - expect(find.text('0/3 → 6 reps'), findsOneWidget); - expect(find.text('0/2 → 4 reps'), findsOneWidget); + expect(find.text('0/3 → ×6'), findsOneWidget); + expect(find.text('0/2 → ×4'), findsOneWidget); }); - testWidgets('mode chip names the mode', (tester) async { + testWidgets('mode chip shows the mode glyph', (tester) async { await tester.pumpWidget(_wrap(_tile())); - expect(find.text('kg'), findsOneWidget); + expect(find.byIcon(Icons.fitness_center), findsOneWidget); await tester.pumpWidget( _wrap(_tile(state: _state.copyWith(mode: ProgressionMode.reps))), ); - expect(find.text('reps'), findsOneWidget); + expect(find.byIcon(Icons.repeat), findsOneWidget); await tester.pumpWidget( _wrap( _tile( @@ -184,10 +184,8 @@ void main() { ); expect(find.byType(RepCircle), findsNothing); expect(find.bySemanticsLabel('Squat warmup'), findsNothing); - expect( - find.textContaining('back on ${formatShortDate(until)}'), - findsOneWidget, - ); + expect(find.text(formatShortDate(until)), findsOneWidget); + expect(iconLabeled('Paused — counts as failed'), findsOneWidget); expect(tester.getSize(find.byType(ExerciseTile)), size); expect(_cardColor(tester), idle); });