diff --git a/lib/providers/gym_state.dart b/lib/providers/gym_state.dart index 4bc7c102..22141d6f 100644 --- a/lib/providers/gym_state.dart +++ b/lib/providers/gym_state.dart @@ -39,18 +39,21 @@ class PageEntry { required this.type, required this.pageIndex, this.slotPages = const [], - }) : uuid = uuidV4(), + String? uuid, + }) : uuid = uuid ?? uuidV4(), assert( slotPages.isEmpty || type == PageType.set, 'SlotEntries can only be set for set pages', ); PageEntry copyWith({ + String? uuid, PageType? type, int? pageIndex, List? slotPages, }) { return PageEntry( + uuid: uuid ?? this.uuid, type: type ?? this.type, pageIndex: pageIndex ?? this.pageIndex, slotPages: slotPages ?? this.slotPages, @@ -58,11 +61,11 @@ class PageEntry { } List get exercises { - final ids = {}; + final exerciseSet = {}; for (final entry in slotPages) { - ids.add(entry.setConfigData!.exercise); + exerciseSet.add(entry.setConfigData!.exercise); } - return ids.toList(); + return exerciseSet.toList(); } // Whether all sub-pages (e.g. log pages) are marked as done. @@ -96,9 +99,11 @@ class SlotPageEntry { required this.setIndex, this.setConfigData, this.logDone = false, - }) : uuid = uuidV4(); + String? uuid, + }) : uuid = uuid ?? uuidV4(); SlotPageEntry copyWith({ + String? uuid, SlotPageType? type, int? exerciseId, int? setIndex, @@ -107,6 +112,7 @@ class SlotPageEntry { bool? logDone, }) { return SlotPageEntry( + uuid: uuid ?? this.uuid, type: type ?? this.type, setIndex: setIndex ?? this.setIndex, pageIndex: pageIndex ?? this.pageIndex, @@ -116,7 +122,14 @@ class SlotPageEntry { } @override - String toString() => 'SlotPageEntry(type: $type, setIndex: $setIndex, pageIndex: $pageIndex)'; + String toString() => + 'SlotPageEntry(' + 'uuid: $uuid, ' + 'type: $type, ' + 'setIndex: $setIndex, ' + 'pageIndex: $pageIndex, ' + 'logDone: $logDone' + ')'; } class GymModeState { diff --git a/lib/widgets/routines/gym_mode/navigation.dart b/lib/widgets/routines/gym_mode/navigation.dart index cffbb904..7f8ec093 100644 --- a/lib/widgets/routines/gym_mode/navigation.dart +++ b/lib/widgets/routines/gym_mode/navigation.dart @@ -146,7 +146,7 @@ class NavigationHeader extends ConsumerWidget { ), ), IconButton( - icon: const Icon(Icons.toc), + icon: const Icon(Icons.menu), onPressed: () { showDialog( context: context, diff --git a/test/routine/gym_mode_provider_test.dart b/test/routine/gym_mode_provider_test.dart index 33e6c318..206db1b9 100644 --- a/test/routine/gym_mode_provider_test.dart +++ b/test/routine/gym_mode_provider_test.dart @@ -20,28 +20,76 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:wger/providers/gym_state.dart'; +import '../../test_data/exercises.dart'; import '../../test_data/routines.dart'; void main() { - group('GymStateNotifier.calculatePages', () { - late GymStateNotifier notifier; - late ProviderContainer container; + late GymStateNotifier notifier; + late ProviderContainer container; - setUp(() { - container = ProviderContainer.test(); - notifier = container.read(gymStateProvider.notifier); + setUp(() { + container = ProviderContainer.test(); + notifier = container.read(gymStateProvider.notifier); + notifier.state = notifier.state.copyWith( + showExercisePages: true, + showTimerPages: true, + dayId: 1, + iteration: 1, + routine: getTestRoutine(), + ); + notifier.calculatePages(); + }); + + group('GymStateNotifier.markSlotPageAsDone', () { + test('Correctly changes the flag', () { + // Arrange + final slotPage = notifier.state.pages[1].slotPages[2]; + expect(slotPage.type, SlotPageType.log); + expect( + notifier.state.pages.every((p) => p.slotPages.every((s) => !s.logDone)), + true, + reason: 'All slot pages are initially not done', + ); + + // Act + notifier.markSlotPageAsDone(slotPage.uuid, isDone: true); + + // Assert + for (final page in notifier.state.pages.where((p) => p.type == PageType.set)) { + for (final slot in page.slotPages.where((s) => s.type == SlotPageType.log)) { + if (slot.uuid == slotPage.uuid) { + expect(slot.logDone, true); + } else { + expect(slot.logDone, false); + } + } + } }); + }); + group('GymStateNotifier.replaceExercises', () { + test('Correctly swaps an exercise', () { + // Arrange + final slotPage = notifier.state.pages[1].slotPages[2]; + notifier.state.pages.every((p) => p.exercises.every((s) => s.id != testSquats.id)); + expect(slotPage.type, SlotPageType.log); + + // Act + notifier.replaceExercises(slotPage.uuid, originalExerciseId: 1, newExercise: testSquats); + + // Assert + expect(notifier.state.pages[1].exercises.first.id, testSquats.id); + }); + }); + + group('GymStateNotifier.calculatePages', () { test( - 'Correctly generates pages: exercise and timer', + 'Correctly generates pages - exercise and timer', () { // Arrange notifier.state = notifier.state.copyWith( showExercisePages: true, showTimerPages: true, - dayId: 1, - iteration: 1, - routine: getTestRoutine(), ); // Act @@ -49,27 +97,35 @@ void main() { // Assert final pages = notifier.state.pages; - expect(pages.length, 4, reason: '4 PageEntries (start, set 1, set 2, session)'); - final setEntry = pages.firstWhere((p) => p.type == PageType.set); - expect(setEntry.slotPages.length, 3, reason: 'Three sets for the exercise'); - + expect(pages.length, 4, reason: '4 PageEntries (start, set 1, set 2, session)'); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.log).length, + 3, + reason: 'Three sets', + ); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.timer).length, + 3, + reason: 'One timer after each set', + ); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.exerciseOverview).length, + 1, + reason: 'One exercise overview at the start', + ); expect(setEntry.slotPages[0].type, SlotPageType.exerciseOverview); expect(setEntry.slotPages[1].type, SlotPageType.timer); expect(setEntry.slotPages[2].type, SlotPageType.log); - - expect(notifier.state.totalPages, 7); + expect(notifier.state.totalPages, 16); }, ); - test('Correctly generates pages: no exercises and no timer', () { + test('Correctly generates pages - no exercises and no timer', () { // Arrange notifier.state = notifier.state.copyWith( showExercisePages: false, showTimerPages: false, - dayId: 1, - iteration: 1, - routine: getTestRoutine(), ); // Act @@ -77,22 +133,34 @@ void main() { // Assert final pages = notifier.state.pages; - expect(pages.length, 4, reason: '4 PageEntries (start, set 1, set 2, session)'); - final setEntry = pages.firstWhere((p) => p.type == PageType.set); - expect(setEntry.slotPages.length, 1); + expect(pages.length, 4, reason: '4 PageEntries (start, set 1, set 2, session)'); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.log).length, + 3, + reason: 'Three sets', + ); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.timer).length, + 0, + reason: 'No timer', + ); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.exerciseOverview).length, + 0, + reason: 'No overview', + ); expect(setEntry.slotPages[0].type, SlotPageType.log); - expect(notifier.state.totalPages, 3); + expect(setEntry.slotPages[1].type, SlotPageType.log); + expect(setEntry.slotPages[2].type, SlotPageType.log); + expect(notifier.state.totalPages, 8); }); - test('Correctly generates pages: exercises and no timer', () { + test('Correctly generates pages - exercises and no timer', () { // Arrange notifier.state = notifier.state.copyWith( showExercisePages: true, showTimerPages: false, - dayId: 1, - iteration: 1, - routine: getTestRoutine(), ); // Act @@ -100,13 +168,29 @@ void main() { // Assert final pages = notifier.state.pages; - expect(pages.length, 4, reason: '4 PageEntries (start, set 1, set 2, session)'); - final setEntry = pages.firstWhere((p) => p.type == PageType.set); - expect(setEntry.slotPages.length, 2); + expect(pages.length, 4, reason: '4 PageEntries (start, set 1, set 2, session)'); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.log).length, + 3, + reason: 'Three sets', + ); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.timer).length, + 0, + reason: 'No timer', + ); + expect( + setEntry.slotPages.where((p) => p.type == SlotPageType.exerciseOverview).length, + 1, + reason: 'One exercise overview at the start', + ); + expect(setEntry.slotPages.length, 4); expect(setEntry.slotPages[0].type, SlotPageType.exerciseOverview); expect(setEntry.slotPages[1].type, SlotPageType.log); - expect(notifier.state.totalPages, 5); + expect(setEntry.slotPages[2].type, SlotPageType.log); + expect(setEntry.slotPages[3].type, SlotPageType.log); + expect(notifier.state.totalPages, 10); }); }); }