Skip to content

Commit

Permalink
Allow setting the day order per drag and drop
Browse files Browse the repository at this point in the history
  • Loading branch information
rolandgeider committed Nov 12, 2024
1 parent 1d93b2f commit 9e9fa6b
Show file tree
Hide file tree
Showing 20 changed files with 281 additions and 268 deletions.
2 changes: 1 addition & 1 deletion integration_test/2_workout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Widget createWorkoutDetailScreen({locale = 'en'}) {
final mockWorkoutProvider = MockRoutinesProvider();
final workout = getWorkout(exercises: getScreenshotExercises());
when(mockWorkoutProvider.activePlan).thenReturn(workout);
when(mockWorkoutProvider.fetchAndSetWorkoutPlanFull(1)).thenAnswer((_) => Future.value(workout));
when(mockWorkoutProvider.fetchAndSetRoutineFull(1)).thenAnswer((_) => Future.value(workout));

return MultiProvider(
providers: [
Expand Down
14 changes: 14 additions & 0 deletions lib/models/workouts/day.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class Day {
@JsonKey(required: true)
late String type;

@JsonKey(required: true)
late num order;

@JsonKey(required: true)
late Object? config;

Expand All @@ -62,6 +65,17 @@ class Day {
slots = [];
}

Day.empty() {
name = 'new day';
description = '';
type = 'custom';
isRest = false;
needLogsToAdvance = false;
order = 0;
config = {};
slots = [];
}

// Boilerplate
factory Day.fromJson(Map<String, dynamic> json) => _$DayFromJson(json);

Expand Down
3 changes: 3 additions & 0 deletions lib/models/workouts/day.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

87 changes: 43 additions & 44 deletions lib/providers/routines.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/helpers/consts.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/exercises/translation.dart';
import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/day_data.dart';
import 'package:wger/models/workouts/log.dart';
Expand Down Expand Up @@ -54,7 +53,7 @@ class RoutinesProvider with ChangeNotifier {
Routine? _currentPlan;
final ExercisesProvider _exercises;
final WgerBaseProvider baseProvider;
List<Routine> _workoutPlans = [];
List<Routine> _routines = [];
List<WeightUnit> _weightUnits = [];
List<RepetitionUnit> _repetitionUnit = [];

Expand All @@ -63,10 +62,10 @@ class RoutinesProvider with ChangeNotifier {
ExercisesProvider exercises,
List<Routine> entries,
) : _exercises = exercises,
_workoutPlans = entries;
_routines = entries;

List<Routine> get items {
return [..._workoutPlans];
return [..._routines];
}

List<WeightUnit> get weightUnits {
Expand All @@ -76,7 +75,7 @@ class RoutinesProvider with ChangeNotifier {
/// Clears all lists
void clear() {
_currentPlan = null;
_workoutPlans = [];
_routines = [];
_weightUnits = [];
_repetitionUnit = [];
}
Expand All @@ -96,15 +95,15 @@ class RoutinesProvider with ChangeNotifier {
}

List<Routine> getPlans() {
return _workoutPlans;
return _routines;
}

Routine findById(int id) {
return _workoutPlans.firstWhere((workoutPlan) => workoutPlan.id == id);
return _routines.firstWhere((workoutPlan) => workoutPlan.id == id);
}

int findIndexById(int id) {
return _workoutPlans.indexWhere((workoutPlan) => workoutPlan.id == id);
return _routines.indexWhere((workoutPlan) => workoutPlan.id == id);
}

/// Set the currently "active" workout plan
Expand All @@ -125,8 +124,8 @@ class RoutinesProvider with ChangeNotifier {
/// Returns the current active workout plan. At the moment this is just
/// the latest, but this might change in the future.
Routine? get activePlan {
if (_workoutPlans.isNotEmpty) {
return _workoutPlans.first;
if (_routines.isNotEmpty) {
return _routines.first;
}
return null;
}
Expand All @@ -137,15 +136,15 @@ class RoutinesProvider with ChangeNotifier {

/// Fetches and sets all workout plans fully, i.e. with all corresponding child
/// attributes
Future<void> fetchAndSetAllPlansFull() async {
Future<void> fetchAndSetAllRoutinesFull() async {
final data = await baseProvider.fetch(
baseProvider.makeUrl(
_routinesUrlPath,
query: {'ordering': '-creation_date', 'limit': '1000'},
),
);
for (final entry in data['results']) {
await fetchAndSetWorkoutPlanFull(entry['id']);
await fetchAndSetRoutineFull(entry['id']);
}

notifyListeners();
Expand All @@ -157,10 +156,10 @@ class RoutinesProvider with ChangeNotifier {
final data = await baseProvider.fetch(
baseProvider.makeUrl(_routinesUrlPath, query: {'limit': '1000'}),
);
_workoutPlans = [];
_routines = [];
for (final workoutPlanData in data['results']) {
final plan = Routine.fromJson(workoutPlanData);
_workoutPlans.add(plan);
_routines.add(plan);
}

// _workoutPlans.sort((a, b) => b.created.compareTo(a.created));
Expand All @@ -187,20 +186,20 @@ class RoutinesProvider with ChangeNotifier {

/// Fetches a workout plan sparsely, i.e. only with the data on the plan
/// object itself and no child attributes
Future<Routine> fetchAndSetPlanSparse(int planId) async {
Future<Routine> fetchAndSetRoutineSparse(int planId) async {
final fullPlanData = await baseProvider.fetch(
baseProvider.makeUrl(_routinesUrlPath, id: planId),
);
final plan = Routine.fromJson(fullPlanData);
_workoutPlans.add(plan);
_workoutPlans.sort((a, b) => b.created.compareTo(a.created));
_routines.add(plan);
_routines.sort((a, b) => b.created.compareTo(a.created));

notifyListeners();
return plan;
}

/// Fetches a workout plan fully, i.e. with all corresponding child attributes
Future<Routine> fetchAndSetWorkoutPlanFull(int routineId) async {
Future<Routine> fetchAndSetRoutineFull(int routineId) async {
// Fetch structure and computed data
final results = await Future.wait([
baseProvider.fetch(
Expand Down Expand Up @@ -295,8 +294,8 @@ class RoutinesProvider with ChangeNotifier {
}

// ... and done
final routineIndex = _workoutPlans.indexWhere((r) => r.id == routineId);
_workoutPlans.replaceRange(routineIndex, routineIndex + 1, [routine]);
final routineIndex = _routines.indexWhere((r) => r.id == routineId);
_routines.replaceRange(routineIndex, routineIndex + 1, [routine]);

notifyListeners();
return routine;
Expand All @@ -308,7 +307,7 @@ class RoutinesProvider with ChangeNotifier {
baseProvider.makeUrl(_routinesUrlPath),
);
final plan = Routine.fromJson(data);
_workoutPlans.insert(0, plan);
_routines.insert(0, plan);
notifyListeners();
return plan;
}
Expand All @@ -322,15 +321,15 @@ class RoutinesProvider with ChangeNotifier {
}

Future<void> deleteRoutine(int id) async {
final existingWorkoutIndex = _workoutPlans.indexWhere((element) => element.id == id);
final existingWorkout = _workoutPlans[existingWorkoutIndex];
_workoutPlans.removeAt(existingWorkoutIndex);
final existingWorkoutIndex = _routines.indexWhere((element) => element.id == id);
final existingWorkout = _routines[existingWorkoutIndex];
_routines.removeAt(existingWorkoutIndex);
notifyListeners();

final response = await baseProvider.deleteRequest(_routinesUrlPath, id);

if (response.statusCode >= 400) {
_workoutPlans.insert(existingWorkoutIndex, existingWorkout);
_routines.insert(existingWorkoutIndex, existingWorkout);
notifyListeners();
throw WgerHttpException(response.body);
}
Expand Down Expand Up @@ -405,18 +404,21 @@ class RoutinesProvider with ChangeNotifier {
/*
* Days
*/
Future<Day> addDay(Day day, Routine workout) async {
Future<Day> addDay(Day day, {refresh = false}) async {
/*
* Saves a new day instance to the DB and adds it to the given workout
*/
day.routineId = workout.id!;
final data = await baseProvider.post(
day.toJson(),
baseProvider.makeUrl(_daysUrlPath),
);
day = Day.fromJson(data);
day.slots = [];
workout.days.insert(0, day);
final routine = findById(day.routineId);
routine.days.insert(0, day);
if (refresh) {
fetchAndSetRoutineFull(day.routineId);
}
notifyListeners();
return day;
}
Expand All @@ -429,9 +431,19 @@ class RoutinesProvider with ChangeNotifier {
notifyListeners();
}

Future<void> editDays(List<Day> days) async {
for (final day in days) {
await baseProvider.patch(
day.toJson(),
baseProvider.makeUrl(_daysUrlPath, id: day.id),
);
}
notifyListeners();
}

Future<void> deleteDay(Day day) async {
await baseProvider.deleteRequest(_daysUrlPath, day.id!);
for (final workout in _workoutPlans) {
for (final workout in _routines) {
workout.days.removeWhere((element) => element.id == day.id);
}
notifyListeners();
Expand Down Expand Up @@ -496,23 +508,10 @@ class RoutinesProvider with ChangeNotifier {
notifyListeners();
}

Future<String> fetchSmartText(Slot workoutSet, Translation exercise) async {
final data = await baseProvider.fetch(
baseProvider.makeUrl(
_slotsUrlPath,
id: workoutSet.id,
objectMethod: 'smart_text',
query: {'exercise': exercise.id.toString()},
),
);

return data['results'];
}

Future<void> deleteSet(int setId) async {
await baseProvider.deleteRequest(_slotsUrlPath, setId);

for (final workout in _workoutPlans) {
for (final workout in _routines) {
for (final day in workout.days) {
day.slots.removeWhere((element) => element.id == setId);
}
Expand Down Expand Up @@ -581,7 +580,7 @@ class RoutinesProvider with ChangeNotifier {

Future<void> deleteLog(Log log) async {
await baseProvider.deleteRequest(_logsUrlPath, log.id!);
for (final workout in _workoutPlans) {
for (final workout in _routines) {
workout.logs.removeWhere((element) => element.id == log.id);
}
notifyListeners();
Expand Down
2 changes: 1 addition & 1 deletion lib/screens/home_tabs_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class _HomeTabsScreenState extends State<HomeTabsScreen> with SingleTickerProvid
log('Loading current workout plan');
if (workoutPlansProvider.activePlan != null) {
final planId = workoutPlansProvider.activePlan!.id!;
await workoutPlansProvider.fetchAndSetWorkoutPlanFull(planId);
await workoutPlansProvider.fetchAndSetRoutineFull(planId);
workoutPlansProvider.setCurrentPlan(planId);
}
}
Expand Down
7 changes: 5 additions & 2 deletions lib/screens/routine_edit_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
*/

import 'package:flutter/material.dart';
import 'package:wger/models/workouts/routine.dart';
import 'package:provider/provider.dart';
import 'package:wger/providers/routines.dart';
import 'package:wger/widgets/routines/app_bar.dart';
import 'package:wger/widgets/routines/routine_edit.dart';

Expand All @@ -28,7 +29,9 @@ class RoutineEditScreen extends StatelessWidget {

@override
Widget build(BuildContext context) {
final routine = ModalRoute.of(context)!.settings.arguments as Routine;
final routineId = ModalRoute.of(context)!.settings.arguments as int;

final routine = Provider.of<RoutinesProvider>(context).findById(routineId);

return Scaffold(
appBar: RoutineDetailAppBar(routine),
Expand Down
3 changes: 1 addition & 2 deletions lib/screens/routine_logs_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ class WorkoutLogsScreen extends StatelessWidget {
static const routeName = '/workout-logs';

Future<Routine> _loadFullWorkout(BuildContext context, int routineId) {
return Provider.of<RoutinesProvider>(context, listen: false)
.fetchAndSetWorkoutPlanFull(routineId);
return Provider.of<RoutinesProvider>(context, listen: false).fetchAndSetRoutineFull(routineId);
}

@override
Expand Down
3 changes: 1 addition & 2 deletions lib/screens/routine_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ class RoutineScreen extends StatelessWidget {
static const routeName = '/routine-detail';

Future<Routine> _loadFullWorkout(BuildContext context, int routineId) {
return Provider.of<RoutinesProvider>(context, listen: false)
.fetchAndSetWorkoutPlanFull(routineId);
return Provider.of<RoutinesProvider>(context, listen: false).fetchAndSetRoutineFull(routineId);
}

@override
Expand Down
11 changes: 10 additions & 1 deletion lib/widgets/routines/app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum _RoutineDetailBarOptions {
edit,
delete,
logs,
reload,
}

class RoutineListAppBar extends StatelessWidget implements PreferredSizeWidget {
Expand Down Expand Up @@ -90,6 +91,10 @@ class RoutineDetailAppBar extends StatelessWidget implements PreferredSizeWidget
PopupMenuButton(
itemBuilder: (context) {
return [
PopupMenuItem<_RoutineDetailBarOptions>(
value: _RoutineDetailBarOptions.reload,
child: Text('debug / reload'),
),
PopupMenuItem<_RoutineDetailBarOptions>(
value: _RoutineDetailBarOptions.logs,
child: Text(AppLocalizations.of(context).labelWorkoutLogs),
Expand All @@ -110,7 +115,7 @@ class RoutineDetailAppBar extends StatelessWidget implements PreferredSizeWidget
Navigator.pushNamed(
context,
RoutineEditScreen.routeName,
arguments: routine,
arguments: routine.id,
);

case _RoutineDetailBarOptions.logs:
Expand All @@ -123,6 +128,10 @@ class RoutineDetailAppBar extends StatelessWidget implements PreferredSizeWidget
case _RoutineDetailBarOptions.delete:
Provider.of<RoutinesProvider>(context, listen: false).deleteRoutine(routine.id!);
Navigator.of(context).pop();

case _RoutineDetailBarOptions.reload:
Provider.of<RoutinesProvider>(context, listen: false)
.fetchAndSetRoutineFull(routine.id!);
}
},
),
Expand Down
Loading

0 comments on commit 9e9fa6b

Please sign in to comment.