Skip to content

Commit 07f38a8

Browse files
authored
Merge pull request #794 from wger-project/fix/gym-mode-time
Fix gym mode start time problem
2 parents 8294d66 + 1ecbfa8 commit 07f38a8

File tree

12 files changed

+676
-33
lines changed

12 files changed

+676
-33
lines changed

lib/helpers/json.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ TimeOfDay stringToTime(String? time) {
6262
return TimeOfDay.fromDateTime(DateTime.parse('2020-01-01 $out'));
6363
}
6464

65+
TimeOfDay? stringToTimeNull(String? time) {
66+
if (time == null) {
67+
return null;
68+
}
69+
70+
return TimeOfDay.fromDateTime(DateTime.parse('2020-01-01 $time'));
71+
}
72+
6573
/*
6674
* Converts a datetime to time.
6775
*/

lib/models/nutrition/meal.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class Meal {
3535
@JsonKey(name: 'plan')
3636
late int planId;
3737

38-
@JsonKey(toJson: timeToString, fromJson: stringToTime)
38+
@JsonKey(toJson: timeToString, fromJson: stringToTimeNull)
3939
TimeOfDay? time;
4040

4141
@JsonKey(name: 'name')

lib/models/nutrition/meal.g.dart

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/models/workouts/session.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ class WorkoutSession {
3636
@JsonKey(required: true, toJson: dateToYYYYMMDD)
3737
late DateTime date;
3838

39-
@JsonKey(required: true, fromJson: stringToNum, toJson: numToString)
40-
late num impression;
39+
@JsonKey(required: true, fromJson: int.parse, toJson: numToString)
40+
late int impression;
4141

4242
@JsonKey(required: false, defaultValue: '')
4343
late String notes;
4444

45-
@JsonKey(required: true, name: 'time_start', toJson: timeToString, fromJson: stringToTime)
45+
@JsonKey(required: true, name: 'time_start', toJson: timeToString, fromJson: stringToTimeNull)
4646
late TimeOfDay? timeStart;
4747

48-
@JsonKey(required: true, name: 'time_end', toJson: timeToString, fromJson: stringToTime)
48+
@JsonKey(required: true, name: 'time_end', toJson: timeToString, fromJson: stringToTimeNull)
4949
late TimeOfDay? timeEnd;
5050

5151
@JsonKey(required: false, includeToJson: false, defaultValue: [])

lib/models/workouts/session.g.dart

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/providers/gym_state.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flutter/material.dart';
12
import 'package:flutter_riverpod/flutter_riverpod.dart';
23
import 'package:logging/logging.dart';
34
import 'package:wger/models/exercises/exercise.dart';
@@ -14,15 +15,18 @@ class GymState {
1415
final bool showExercisePages;
1516
final int currentPage;
1617
final int? dayId;
18+
late TimeOfDay startTime;
1719
late DateTime validUntil;
1820

1921
GymState(
2022
{this.exercisePages = const {},
2123
this.showExercisePages = true,
2224
this.currentPage = 0,
2325
this.dayId,
24-
DateTime? validUntil}) {
26+
DateTime? validUntil,
27+
TimeOfDay? startTime}) {
2528
this.validUntil = validUntil ?? DateTime.now().add(DEFAULT_DURATION);
29+
this.startTime = startTime ?? TimeOfDay.now();
2630
}
2731

2832
GymState copyWith({
@@ -31,13 +35,15 @@ class GymState {
3135
int? currentPage,
3236
int? dayId,
3337
DateTime? validUntil,
38+
TimeOfDay? startTime,
3439
}) {
3540
return GymState(
3641
exercisePages: exercisePages ?? this.exercisePages,
3742
showExercisePages: showExercisePages ?? this.showExercisePages,
3843
currentPage: currentPage ?? this.currentPage,
3944
dayId: dayId ?? this.dayId,
4045
validUntil: validUntil ?? this.validUntil.add(DEFAULT_DURATION),
46+
startTime: startTime ?? this.startTime,
4147
);
4248
}
4349

@@ -49,6 +55,7 @@ class GymState {
4955
'exercisePages: ${exercisePages.length} exercises, '
5056
'dayId: $dayId, '
5157
'validUntil: $validUntil '
58+
'startTime: $startTime, '
5259
')';
5360
}
5461
}
@@ -86,6 +93,7 @@ class GymStateNotifier extends StateNotifier<GymState> {
8693
currentPage: 0,
8794
dayId: null,
8895
validUntil: DateTime.now().add(DEFAULT_DURATION),
96+
startTime: TimeOfDay.now(),
8997
);
9098
}
9199
}

lib/widgets/nutrition/forms.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class MealForm extends StatelessWidget {
7474
}
7575
},
7676
onSaved: (newValue) {
77-
_meal.time = stringToTime(newValue);
77+
_meal.time = stringToTimeNull(newValue);
7878
},
7979
),
8080
TextFormField(

lib/widgets/routines/gym_mode/gym_mode.dart

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,9 @@ class GymMode extends ConsumerStatefulWidget {
3636
final DayData _dayDataGym;
3737
final DayData _dayDataDisplay;
3838
final int _iteration;
39-
late final TimeOfDay _start;
4039
final _logger = Logger('GymMode');
4140

42-
GymMode(this._dayDataGym, this._dayDataDisplay, this._iteration) {
43-
_start = TimeOfDay.now();
44-
}
41+
GymMode(this._dayDataGym, this._dayDataDisplay, this._iteration);
4542

4643
@override
4744
ConsumerState<GymMode> createState() => _GymModeState();
@@ -78,11 +75,12 @@ class _GymModeState extends ConsumerState<GymMode> {
7875
final validUntil = ref.read(gymStateProvider).validUntil;
7976
final currentPage = ref.read(gymStateProvider).currentPage;
8077
final savedDayId = ref.read(gymStateProvider).dayId;
81-
8278
final newDayId = widget._dayDataGym.day!.id!;
83-
final shouldReset =
84-
widget._dayDataGym.day!.id != savedDayId || validUntil.isBefore(DateTime.now());
85-
widget._logger.fine('Day ID mismatch or expired validUntil date. Resetting to page 0.');
79+
80+
final shouldReset = newDayId != savedDayId || validUntil.isBefore(DateTime.now());
81+
if (shouldReset) {
82+
widget._logger.fine('Day ID mismatch or expired validUntil date. Resetting to page 0.');
83+
}
8684
final initialPage = shouldReset ? 0 : currentPage;
8785

8886
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -118,8 +116,8 @@ class _GymModeState extends ConsumerState<GymMode> {
118116

119117
List<Widget> getContent() {
120118
final state = ref.watch(gymStateProvider);
121-
final exerciseProvider = provider.Provider.of<ExercisesProvider>(context, listen: false);
122-
final workoutProvider = provider.Provider.of<RoutinesProvider>(context, listen: false);
119+
final exerciseProvider = context.read<ExercisesProvider>();
120+
final routinesProvider = context.read<RoutinesProvider>();
123121
var currentElement = 1;
124122
final List<Widget> out = [];
125123

@@ -144,7 +142,7 @@ class _GymModeState extends ConsumerState<GymMode> {
144142
config,
145143
slotData,
146144
exercise,
147-
workoutProvider.findById(widget._dayDataGym.day!.routineId),
145+
routinesProvider.findById(widget._dayDataGym.day!.routineId),
148146
ratioCompleted,
149147
state.exercisePages,
150148
widget._iteration,
@@ -192,10 +190,9 @@ class _GymModeState extends ConsumerState<GymMode> {
192190
StartPage(_controller, widget._dayDataDisplay, _exercisePages),
193191
...getContent(),
194192
SessionPage(
195-
provider.Provider.of<RoutinesProvider>(context, listen: false)
196-
.findById(widget._dayDataGym.day!.routineId),
193+
context.read<RoutinesProvider>().findById(widget._dayDataGym.day!.routineId),
197194
_controller,
198-
widget._start,
195+
ref.read(gymStateProvider).startTime,
199196
_exercisePages,
200197
),
201198
];

lib/widgets/routines/gym_mode/session_page.dart

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* You should have received a copy of the GNU Affero General Public License
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
18+
import 'package:clock/clock.dart';
1819
import 'package:flutter/material.dart';
1920
import 'package:provider/provider.dart' as provider;
2021
import 'package:wger/exceptions/http_exception.dart';
@@ -33,8 +34,8 @@ class SessionPage extends StatefulWidget {
3334
final Routine _routine;
3435
late WorkoutSession _session;
3536
final PageController _controller;
36-
final TimeOfDay _start;
3737
final Map<Exercise, int> _exercisePages;
38+
final TimeOfDay _start;
3839

3940
SessionPage(
4041
this._routine,
@@ -43,11 +44,11 @@ class SessionPage extends StatefulWidget {
4344
this._exercisePages,
4445
) {
4546
_session = _routine.sessions.map((sessionApi) => sessionApi.session).firstWhere(
46-
(session) => session.date.isSameDayAs(DateTime.now()),
47+
(session) => session.date.isSameDayAs(clock.now()),
4748
orElse: () => WorkoutSession(
4849
routineId: _routine.id!,
4950
impression: DEFAULT_IMPRESSION,
50-
date: DateTime.now(),
51+
date: clock.now(),
5152
timeEnd: TimeOfDay.now(),
5253
timeStart: _start,
5354
),
@@ -65,17 +66,18 @@ class _SessionPageState extends State<SessionPage> {
6566
final timeStartController = TextEditingController();
6667
final timeEndController = TextEditingController();
6768

68-
// final _session = WorkoutSession.now();
69-
7069
/// Selected impression: bad, neutral, good
71-
var selectedImpression = [false, true, false];
70+
var selectedImpression = [false, false, false];
7271

7372
@override
7473
void initState() {
7574
super.initState();
7675

77-
timeStartController.text = timeToString(widget._session.timeStart)!;
78-
timeEndController.text = timeToString(widget._session.timeEnd)!;
76+
timeStartController.text = timeToString(widget._session.timeStart ?? widget._start)!;
77+
timeEndController.text = timeToString(widget._session.timeEnd ?? TimeOfDay.now())!;
78+
notesController.text = widget._session.notes;
79+
80+
selectedImpression[widget._session.impression - 1] = true;
7981
}
8082

8183
@override
@@ -212,6 +214,7 @@ class _SessionPageState extends State<SessionPage> {
212214
],
213215
),
214216
ElevatedButton(
217+
key: const ValueKey('save-button'),
215218
child: Text(AppLocalizations.of(context).save),
216219
onPressed: () async {
217220
// Validate and save the current values to the weightEntry

test/workout/gym_mode_screen_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import 'package:flutter_test/flutter_test.dart';
2222
import 'package:mockito/annotations.dart';
2323
import 'package:mockito/mockito.dart';
2424
import 'package:provider/provider.dart';
25+
import 'package:wger/helpers/json.dart';
2526
import 'package:wger/l10n/generated/app_localizations.dart';
2627
import 'package:wger/providers/base_provider.dart';
2728
import 'package:wger/providers/exercises.dart';
@@ -263,6 +264,13 @@ void main() {
263264
expect(find.byIcon(Icons.sentiment_very_dissatisfied), findsOneWidget);
264265
expect(find.byIcon(Icons.sentiment_neutral), findsOneWidget);
265266
expect(find.byIcon(Icons.sentiment_very_satisfied), findsOneWidget);
267+
expect(
268+
find.text(timeToString(TimeOfDay.now())!),
269+
findsNWidgets(2),
270+
reason: 'start and end time are the same',
271+
);
272+
final toggleButtons = tester.widget<ToggleButtons>(find.byType(ToggleButtons));
273+
expect(toggleButtons.isSelected[1], isTrue);
266274
expect(find.byIcon(Icons.chevron_left), findsOneWidget);
267275
expect(find.byIcon(Icons.close), findsOneWidget);
268276
expect(find.byIcon(Icons.chevron_right), findsNothing);

0 commit comments

Comments
 (0)