From 033213abbb4b2a74cac3ae04bd3725ca62704cec Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 15 Nov 2025 18:10:14 +0100 Subject: [PATCH] Allow opening the workout progress dialog from the progress indicator This is easier to open with the thumbs and also makes logical sense. When opening the workout menu from here, the default tab is the progress one, not the overview. --- lib/widgets/routines/gym_mode/navigation.dart | 141 +++++++----------- .../routines/gym_mode/workout_menu.dart | 60 +++++++- 2 files changed, 113 insertions(+), 88 deletions(-) diff --git a/lib/widgets/routines/gym_mode/navigation.dart b/lib/widgets/routines/gym_mode/navigation.dart index 7f8ec093..d2572b52 100644 --- a/lib/widgets/routines/gym_mode/navigation.dart +++ b/lib/widgets/routines/gym_mode/navigation.dart @@ -19,11 +19,51 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:wger/helpers/consts.dart'; -import 'package:wger/l10n/generated/app_localizations.dart'; import 'package:wger/providers/gym_state.dart'; import 'package:wger/theme/theme.dart'; import 'package:wger/widgets/routines/gym_mode/workout_menu.dart'; +class NavigationHeader extends StatelessWidget { + final PageController _controller; + final String _title; + final bool showEndWorkoutButton; + + const NavigationHeader(this._title, this._controller, {this.showEndWorkoutButton = true}); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + IconButton( + icon: const Icon(Icons.close), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + _title, + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + ), + ), + IconButton( + icon: const Icon(Icons.menu), + onPressed: () { + showDialog( + context: context, + builder: (ctx) => WorkoutMenuDialog(_controller), + ); + }, + ), + ], + ); + } +} + class NavigationFooter extends ConsumerWidget { final PageController _controller; final bool showPrevious; @@ -54,10 +94,19 @@ class NavigationFooter extends ConsumerWidget { else const SizedBox(width: 48), Expanded( - child: LinearProgressIndicator( - minHeight: 3, - value: gymState.ratioCompleted, - valueColor: const AlwaysStoppedAnimation(wgerPrimaryColor), + child: GestureDetector( + onTap: () => showDialog( + context: context, + builder: (ctx) => WorkoutMenuDialog(_controller, initialIndex: 1), + ), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 15), + child: LinearProgressIndicator( + minHeight: 3, + value: gymState.ratioCompleted, + valueColor: const AlwaysStoppedAnimation(wgerPrimaryColor), + ), + ), ), ), if (showNext) @@ -76,85 +125,3 @@ class NavigationFooter extends ConsumerWidget { ); } } - -class NavigationHeader extends ConsumerWidget { - final PageController _controller; - final String _title; - final bool showEndWorkoutButton; - - const NavigationHeader(this._title, this._controller, {this.showEndWorkoutButton = true}); - - Widget getDialog(BuildContext context, int totalPages, List pages) { - final endWorkoutButton = showEndWorkoutButton - ? TextButton( - child: Text(AppLocalizations.of(context).endWorkout), - onPressed: () { - _controller.animateToPage( - totalPages, - duration: DEFAULT_ANIMATION_DURATION, - curve: DEFAULT_ANIMATION_CURVE, - ); - - Navigator.of(context).pop(); - }, - ) - : null; - - return AlertDialog( - title: Text( - AppLocalizations.of(context).jumpTo, - textAlign: TextAlign.center, - ), - contentPadding: EdgeInsets.zero, - content: SizedBox( - height: double.maxFinite, - width: double.maxFinite, - child: WorkoutMenu(_controller), - ), - actions: [ - ?endWorkoutButton, - TextButton( - child: Text(MaterialLocalizations.of(context).closeButtonLabel), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final gymState = ref.watch(gymStateProvider); - - return Row( - children: [ - IconButton( - icon: const Icon(Icons.close), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - _title, - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - ), - ), - IconButton( - icon: const Icon(Icons.menu), - onPressed: () { - showDialog( - context: context, - builder: (ctx) => getDialog(ctx, gymState.totalPages, gymState.pages), - ); - }, - ), - ], - ); - } -} diff --git a/lib/widgets/routines/gym_mode/workout_menu.dart b/lib/widgets/routines/gym_mode/workout_menu.dart index 772aaced..9c556284 100644 --- a/lib/widgets/routines/gym_mode/workout_menu.dart +++ b/lib/widgets/routines/gym_mode/workout_menu.dart @@ -20,17 +20,20 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; import 'package:wger/helpers/consts.dart'; +import 'package:wger/l10n/generated/app_localizations.dart'; import 'package:wger/providers/gym_state.dart'; import 'package:wger/widgets/exercises/autocompleter.dart'; class WorkoutMenu extends StatelessWidget { final PageController _controller; + final int initialIndex; - const WorkoutMenu(this._controller); + const WorkoutMenu(this._controller, {this.initialIndex = 0, super.key}); @override Widget build(BuildContext context) { return DefaultTabController( + initialIndex: initialIndex, length: 2, child: Column( children: [ @@ -288,3 +291,58 @@ class ExerciseSwapWidget extends ConsumerWidget { ); } } + +class WorkoutMenuDialog extends ConsumerWidget { + final PageController controller; + final bool showEndWorkoutButton; + final int initialIndex; + + const WorkoutMenuDialog( + this.controller, { + super.key, + this.showEndWorkoutButton = true, + this.initialIndex = 0, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final gymState = ref.watch(gymStateProvider); + + final endWorkoutButton = true + ? TextButton( + child: Text(AppLocalizations.of(context).endWorkout), + onPressed: () { + controller.animateToPage( + gymState.totalPages, + duration: DEFAULT_ANIMATION_DURATION, + curve: DEFAULT_ANIMATION_CURVE, + ); + + Navigator.of(context).pop(); + }, + ) + : null; + + return AlertDialog( + title: Text( + AppLocalizations.of(context).jumpTo, + textAlign: TextAlign.center, + ), + contentPadding: EdgeInsets.zero, + content: SizedBox( + height: double.maxFinite, + width: double.maxFinite, + child: WorkoutMenu(controller, initialIndex: initialIndex), + ), + actions: [ + ?endWorkoutButton, + TextButton( + child: Text(MaterialLocalizations.of(context).closeButtonLabel), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + } +}