mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
If there is a rest time, show a countdown timer in the gym mode
This commit is contained in:
@@ -145,6 +145,7 @@ class DayHeader extends StatelessWidget {
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
subtitle: Text(_dayData.day!.description),
|
||||
leading: _viewMode ? null : const Icon(Icons.play_arrow),
|
||||
trailing: _dayData.date.isSameDayAs(DateTime.now()) ? const Icon(Icons.today) : null,
|
||||
minLeadingWidth: 8,
|
||||
|
||||
@@ -167,7 +167,19 @@ class _GymModeState extends ConsumerState<GymMode> {
|
||||
state.exercisePages,
|
||||
widget._iteration,
|
||||
));
|
||||
out.add(TimerWidget(_controller, ratioCompleted, state.exercisePages));
|
||||
|
||||
// If there is a rest time, add a countdown timer
|
||||
if (config.restTime != null) {
|
||||
out.add(TimerCountdownWidget(
|
||||
_controller,
|
||||
config.restTime!.toInt(),
|
||||
ratioCompleted,
|
||||
state.exercisePages,
|
||||
));
|
||||
} else {
|
||||
out.add(TimerWidget(_controller, ratioCompleted, state.exercisePages));
|
||||
}
|
||||
|
||||
firstPage = false;
|
||||
}
|
||||
}
|
||||
@@ -1026,22 +1038,16 @@ class _TimerWidgetState extends State<TimerWidget> {
|
||||
DateTime today = DateTime(2000, 1, 1, 0, 0, 0);
|
||||
|
||||
void startTimer() {
|
||||
setState(() {
|
||||
_seconds = 0;
|
||||
});
|
||||
setState(() => _seconds = 0);
|
||||
|
||||
_timer?.cancel();
|
||||
|
||||
const oneSecond = Duration(seconds: 1);
|
||||
_timer = Timer.periodic(oneSecond, (Timer timer) {
|
||||
if (_seconds == _maxSeconds) {
|
||||
setState(() {
|
||||
timer.cancel();
|
||||
});
|
||||
setState(() => timer.cancel());
|
||||
} else {
|
||||
setState(() {
|
||||
_seconds++;
|
||||
});
|
||||
setState(() => _seconds++);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1081,6 +1087,79 @@ class _TimerWidgetState extends State<TimerWidget> {
|
||||
}
|
||||
}
|
||||
|
||||
class TimerCountdownWidget extends StatefulWidget {
|
||||
final PageController _controller;
|
||||
final double _ratioCompleted;
|
||||
final int _seconds;
|
||||
final Map<Exercise, int> _exercisePages;
|
||||
|
||||
const TimerCountdownWidget(
|
||||
this._controller,
|
||||
this._seconds,
|
||||
this._ratioCompleted,
|
||||
this._exercisePages,
|
||||
);
|
||||
|
||||
@override
|
||||
_TimerCountdownWidgetState createState() => _TimerCountdownWidgetState();
|
||||
}
|
||||
|
||||
class _TimerCountdownWidgetState extends State<TimerCountdownWidget> {
|
||||
// See https://stackoverflow.com/questions/54610121/flutter-countdown-timer
|
||||
|
||||
Timer? _timer;
|
||||
late int _seconds;
|
||||
DateTime today = DateTime(2000, 1, 1, 0, 0, 0);
|
||||
|
||||
void startTimer() {
|
||||
_timer?.cancel();
|
||||
|
||||
const oneSecond = Duration(seconds: 1);
|
||||
_timer = Timer.periodic(oneSecond, (Timer timer) {
|
||||
if (_seconds == 0) {
|
||||
setState(() => timer.cancel());
|
||||
} else {
|
||||
setState(() => _seconds--);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_seconds = widget._seconds;
|
||||
startTimer();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
NavigationHeader(
|
||||
AppLocalizations.of(context).pause,
|
||||
widget._controller,
|
||||
exercisePages: widget._exercisePages,
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Text(
|
||||
DateFormat('m:ss').format(today.add(Duration(seconds: _seconds))),
|
||||
style: Theme.of(context).textTheme.displayLarge!.copyWith(color: wgerPrimaryColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
NavigationFooter(widget._controller, widget._ratioCompleted),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NavigationFooter extends StatelessWidget {
|
||||
final PageController _controller;
|
||||
final double _ratioCompleted;
|
||||
|
||||
@@ -148,7 +148,7 @@ void main() {
|
||||
// Bench press - pause
|
||||
//
|
||||
expect(find.text('Pause'), findsOneWidget);
|
||||
expect(find.byType(TimerWidget), findsOneWidget);
|
||||
expect(find.byType(TimerCountdownWidget), findsOneWidget);
|
||||
expect(find.byIcon(Icons.close), findsOneWidget);
|
||||
expect(find.byIcon(Icons.toc), findsOneWidget);
|
||||
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
|
||||
@@ -169,7 +169,7 @@ void main() {
|
||||
// Pause
|
||||
//
|
||||
expect(find.text('Pause'), findsOneWidget);
|
||||
expect(find.byType(TimerWidget), findsOneWidget);
|
||||
expect(find.byType(TimerCountdownWidget), findsOneWidget);
|
||||
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
|
||||
expect(find.byIcon(Icons.close), findsOneWidget);
|
||||
expect(find.byIcon(Icons.chevron_right), findsOneWidget);
|
||||
@@ -189,7 +189,7 @@ void main() {
|
||||
// Pause
|
||||
//
|
||||
expect(find.text('Pause'), findsOneWidget);
|
||||
expect(find.byType(TimerWidget), findsOneWidget);
|
||||
expect(find.byType(TimerCountdownWidget), findsOneWidget);
|
||||
await tester.tap(find.byIcon(Icons.chevron_right));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
||||
@@ -65,9 +65,7 @@ void main() {
|
||||
),
|
||||
child: const SizedBox(),
|
||||
),
|
||||
routes: {
|
||||
RoutineScreen.routeName: (ctx) => const RoutineScreen(),
|
||||
},
|
||||
routes: {RoutineScreen.routeName: (ctx) => const RoutineScreen()},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -83,6 +81,7 @@ void main() {
|
||||
expect(find.text('3 day workout'), findsOneWidget);
|
||||
|
||||
expect(find.text('first day'), findsOneWidget);
|
||||
debugDumpApp();
|
||||
expect(find.text('chest, shoulders'), findsOneWidget);
|
||||
|
||||
expect(find.text('second day'), findsOneWidget);
|
||||
|
||||
@@ -56,7 +56,7 @@ void main() {
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
navigatorKey: key,
|
||||
home: Scaffold(body: SlotEntryForm(slotEntry, simpleMode: simpleMode)),
|
||||
home: Scaffold(body: SlotEntryForm(slotEntry, 1, simpleMode: simpleMode)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ void main() {
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verify(mockRoutinesProvider.editSlotEntry(any)).called(1);
|
||||
verify(mockRoutinesProvider.editSlotEntry(any, any)).called(1);
|
||||
verify(mockRoutinesProvider.handleConfig(any, any, any)).called(8);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ Routine getTestRoutine({List<Exercise>? exercises}) {
|
||||
repetitionsUnit: testRepetitionUnit1,
|
||||
weight: 10,
|
||||
weightUnit: testWeightUnit1,
|
||||
restTime: 60,
|
||||
restTime: null,
|
||||
rir: '',
|
||||
rpe: '',
|
||||
textRepr: '12x10kg',
|
||||
@@ -310,7 +310,7 @@ Routine getTestRoutine({List<Exercise>? exercises}) {
|
||||
repetitionsUnit: testRepetitionUnit1,
|
||||
weight: 10,
|
||||
weightUnit: testWeightUnit1,
|
||||
restTime: 60,
|
||||
restTime: null,
|
||||
rir: '',
|
||||
rpe: '',
|
||||
textRepr: '12x10kg',
|
||||
@@ -324,7 +324,7 @@ Routine getTestRoutine({List<Exercise>? exercises}) {
|
||||
repetitionsUnit: testRepetitionUnit1,
|
||||
weight: 10,
|
||||
weightUnit: testWeightUnit1,
|
||||
restTime: 60,
|
||||
restTime: null,
|
||||
rir: '',
|
||||
rpe: '',
|
||||
textRepr: '12x10kg',
|
||||
|
||||
Reference in New Issue
Block a user