Skip to content

Commit 8294d66

Browse files
authored
Merge pull request #791 from wger-project/fix/delete-workout-logs
Properly update the UI when deleting workout logs
2 parents c2280aa + 9d05c9e commit 8294d66

25 files changed

+172
-200
lines changed

lib/helpers/colors.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'dart:ui';
1+
import 'package:flutter/material.dart';
22

33
const LIST_OF_COLORS8 = [
44
Color(0xFF2A4C7D),
@@ -41,4 +41,9 @@ Iterable<Color> generateChartColors(int nrOfItems) sync* {
4141
for (final color in colors) {
4242
yield color;
4343
}
44+
45+
// Always return black after generating nrOfItems colors
46+
while (true) {
47+
yield Colors.black;
48+
}
4449
}

lib/helpers/ui.dart

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import 'package:logging/logging.dart';
2121
import 'package:provider/provider.dart';
2222
import 'package:wger/exceptions/http_exception.dart';
2323
import 'package:wger/l10n/generated/app_localizations.dart';
24-
import 'package:wger/models/exercises/exercise.dart';
25-
import 'package:wger/models/exercises/translation.dart';
2624
import 'package:wger/models/workouts/log.dart';
2725
import 'package:wger/providers/routines.dart';
2826

@@ -108,13 +106,7 @@ void showHttpExceptionErrorDialog(
108106
showDialog(context: context, builder: (context) => Container());
109107
}
110108

111-
dynamic showDeleteDialog(
112-
BuildContext context,
113-
String confirmDeleteName,
114-
Log log,
115-
Translation exercise,
116-
Map<Exercise, List<Log>> exerciseData,
117-
) async {
109+
void showDeleteDialog(BuildContext context, String confirmDeleteName, Log log) async {
118110
final res = await showDialog(
119111
context: context,
120112
builder: (BuildContext contextDialog) {
@@ -124,19 +116,18 @@ dynamic showDeleteDialog(
124116
),
125117
actions: [
126118
TextButton(
119+
key: const ValueKey('cancel-button'),
127120
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
128121
onPressed: () => Navigator.of(contextDialog).pop(),
129122
),
130123
TextButton(
124+
key: const ValueKey('delete-button'),
131125
child: Text(
132126
AppLocalizations.of(context).delete,
133127
style: TextStyle(color: Theme.of(context).colorScheme.error),
134128
),
135129
onPressed: () {
136-
exerciseData[exercise]!.removeWhere((el) => el.id == log.id);
137-
Provider.of<RoutinesProvider>(context, listen: false).deleteLog(
138-
log,
139-
);
130+
context.read<RoutinesProvider>().deleteLog(log.id!, log.routineId);
140131

141132
Navigator.of(contextDialog).pop();
142133

lib/models/workouts/routine.dart

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import 'package:json_annotation/json_annotation.dart';
2020
import 'package:wger/helpers/json.dart';
2121
import 'package:wger/helpers/misc.dart';
22-
import 'package:wger/models/exercises/exercise.dart';
2322
import 'package:wger/models/workouts/day.dart';
2423
import 'package:wger/models/workouts/day_data.dart';
2524
import 'package:wger/models/workouts/log.dart';
@@ -177,28 +176,4 @@ class Routine {
177176

178177
return groupedLogs;
179178
}
180-
181-
/// Massages the log data to more easily present on the log overview
182-
///
183-
Map<DateTime, Map<String, dynamic>> get logData {
184-
final out = <DateTime, Map<String, dynamic>>{};
185-
for (final sessionData in sessions) {
186-
final date = sessionData.session.date;
187-
if (!out.containsKey(date)) {
188-
out[date] = {
189-
'session': sessionData.session,
190-
'exercises': <Exercise, List<Log>>{},
191-
};
192-
}
193-
194-
for (final log in sessionData.logs) {
195-
final exercise = log.exercise;
196-
if (!out[date]!['exercises']!.containsKey(exercise)) {
197-
out[date]!['exercises']![exercise] = <Log>[];
198-
}
199-
out[date]!['exercises']![exercise].add(log);
200-
}
201-
}
202-
return out;
203-
}
204179
}

lib/models/workouts/session_api.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
import 'package:json_annotation/json_annotation.dart';
20+
import 'package:wger/models/exercises/exercise.dart';
2021
import 'package:wger/models/workouts/log.dart';
2122
import 'package:wger/models/workouts/session.dart';
2223

@@ -32,6 +33,17 @@ class WorkoutSessionApi {
3233

3334
WorkoutSessionApi({required this.session, this.logs = const []});
3435

36+
/// Returns all different exercises in the session
37+
///
38+
/// This is used to display the exercises in the session
39+
List<Exercise> get exercises {
40+
final Set<Exercise> exerciseSet = {};
41+
for (final log in logs) {
42+
exerciseSet.add(log.exercise);
43+
}
44+
return exerciseSet.toList();
45+
}
46+
3547
// Boilerplate
3648
factory WorkoutSessionApi.fromJson(Map<String, dynamic> json) =>
3749
_$WorkoutSessionApiFromJson(json);

lib/providers/routines.dart

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -673,13 +673,9 @@ class RoutinesProvider with ChangeNotifier {
673673
notifyListeners();
674674
}*/
675675

676-
Future<void> deleteLog(Log log) async {
677-
await baseProvider.deleteRequest(_logsUrlPath, log.id!);
678-
for (final workout in _routines) {
679-
for (final sessionData in workout.sessions) {
680-
sessionData.session.logs.removeWhere((element) => element.id == log.id);
681-
}
682-
}
683-
notifyListeners();
676+
Future<void> deleteLog(int logId, int routineId) async {
677+
_logger.fine('Deleting log ${logId}');
678+
await baseProvider.deleteRequest(_logsUrlPath, logId);
679+
await fetchAndSetRoutineFull(routineId);
684680
}
685681
}

lib/screens/routine_logs_screen.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@
1818

1919
import 'package:flutter/material.dart';
2020
import 'package:provider/provider.dart';
21-
import 'package:wger/models/workouts/routine.dart';
2221
import 'package:wger/providers/routines.dart';
23-
import 'package:wger/widgets/routines/app_bar.dart';
22+
import 'package:wger/widgets/core/app_bar.dart';
2423
import 'package:wger/widgets/routines/workout_logs.dart';
2524

2625
class WorkoutLogsScreen extends StatelessWidget {
@@ -30,13 +29,12 @@ class WorkoutLogsScreen extends StatelessWidget {
3029

3130
@override
3231
Widget build(BuildContext context) {
33-
final routine = ModalRoute.of(context)!.settings.arguments as Routine;
32+
final routineId = ModalRoute.of(context)!.settings.arguments as int;
33+
final routine = Provider.of<RoutinesProvider>(context).findById(routineId);
3434

3535
return Scaffold(
36-
appBar: RoutineDetailAppBar(routine),
37-
body: Consumer<RoutinesProvider>(
38-
builder: (context, value, child) => WorkoutLogs(routine),
39-
),
36+
appBar: EmptyAppBar(routine.name),
37+
body: WorkoutLogs(routine),
4038
);
4139
}
4240
}

lib/widgets/nutrition/meal.dart

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,15 +238,10 @@ class MealItemEditableFullTile extends StatelessWidget {
238238

239239
return NutritionTile(
240240
leading: IngredientAvatar(ingredient: _item.ingredient),
241-
title: Row(
242-
mainAxisSize: MainAxisSize.max,
243-
children: [
244-
Text(
245-
'${_item.amount.toStringAsFixed(0)}$unit ${_item.ingredient.name}',
246-
overflow: TextOverflow.ellipsis,
247-
textAlign: TextAlign.left,
248-
),
249-
],
241+
title: Text(
242+
'${_item.amount.toStringAsFixed(0)}$unit ${_item.ingredient.name}',
243+
overflow: TextOverflow.ellipsis,
244+
textAlign: TextAlign.left,
250245
),
251246
subtitle: (_viewMode != viewMode.withAllDetails && !_editing)
252247
? null

lib/widgets/routines/app_bar.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class RoutineDetailAppBar extends StatelessWidget implements PreferredSizeWidget
122122
Navigator.pushNamed(
123123
context,
124124
WorkoutLogsScreen.routeName,
125-
arguments: routine,
125+
arguments: routine.id,
126126
);
127127

128128
case _RoutineDetailBarOptions.delete:

lib/widgets/routines/log.dart

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import 'package:wger/helpers/colors.dart';
2222
import 'package:wger/helpers/misc.dart';
2323
import 'package:wger/helpers/ui.dart';
2424
import 'package:wger/l10n/generated/app_localizations.dart';
25-
import 'package:wger/models/exercises/exercise.dart';
2625
import 'package:wger/models/workouts/log.dart';
2726
import 'package:wger/models/workouts/routine.dart';
2827
import 'package:wger/models/workouts/session.dart';
@@ -116,18 +115,22 @@ class ExerciseLogChart extends StatelessWidget {
116115
mainAxisSize: MainAxisSize.max,
117116
children: [
118117
LogChartWidgetFl(_logs, _selectedDate),
119-
Row(
120-
mainAxisAlignment: MainAxisAlignment.center,
121-
children: [
122-
..._logs.keys.map((reps) {
123-
colors.moveNext();
124-
return Indicator(
125-
color: colors.current,
126-
text: formatNum(reps).toString(),
127-
isSquare: false,
128-
);
129-
}),
130-
],
118+
SingleChildScrollView(
119+
scrollDirection: Axis.horizontal,
120+
child: Row(
121+
mainAxisAlignment: MainAxisAlignment.center,
122+
children: [
123+
..._logs.keys.map((reps) {
124+
colors.moveNext();
125+
126+
return Indicator(
127+
color: colors.current,
128+
text: formatNum(reps).toString(),
129+
isSquare: false,
130+
);
131+
}),
132+
],
133+
),
131134
),
132135
const SizedBox(height: 15),
133136
],
@@ -139,49 +142,42 @@ class DayLogWidget extends StatelessWidget {
139142
final DateTime _date;
140143
final Routine _routine;
141144

142-
final WorkoutSession _session;
143-
final Map<Exercise, List<Log>> _exerciseMap;
144-
145-
const DayLogWidget(this._date, this._exerciseMap, this._session, this._routine);
145+
const DayLogWidget(this._date, this._routine);
146146

147147
@override
148148
Widget build(BuildContext context) {
149+
final sessionApi =
150+
_routine.sessions.firstWhere((sessionApi) => sessionApi.session.date.isSameDayAs(_date));
151+
final exercises = sessionApi.exercises;
152+
149153
return Card(
150154
child: Column(
151155
children: [
152-
SessionInfo(_session),
153-
..._exerciseMap.keys.map((exercise) {
156+
SessionInfo(sessionApi.session),
157+
...exercises.map((exercise) {
154158
final translation =
155159
exercise.getTranslation(Localizations.localeOf(context).languageCode);
156160
return Column(
157161
children: [
158-
if (_exerciseMap[exercise]!.isNotEmpty)
159-
Text(
160-
translation.name,
161-
style: Theme.of(context).textTheme.headlineSmall,
162-
)
163-
else
164-
Container(),
165-
..._exerciseMap[exercise]!.map(
166-
(log) => Row(
167-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
168-
children: [
169-
Text(log.singleLogRepTextNoNl),
170-
IconButton(
171-
icon: const Icon(Icons.delete),
172-
onPressed: () {
173-
showDeleteDialog(
174-
context,
175-
translation.name,
176-
log,
177-
translation,
178-
_exerciseMap,
179-
);
180-
},
181-
),
182-
],
183-
),
162+
Text(
163+
translation.name,
164+
style: Theme.of(context).textTheme.titleMedium,
184165
),
166+
...sessionApi.logs.where((l) => l.exerciseId == exercise.id).map(
167+
(log) => Row(
168+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
169+
children: [
170+
Text(log.singleLogRepTextNoNl),
171+
IconButton(
172+
icon: const Icon(Icons.delete),
173+
key: ValueKey('delete-log-${log.id}'),
174+
onPressed: () {
175+
showDeleteDialog(context, translation.name, log);
176+
},
177+
),
178+
],
179+
),
180+
),
185181
Padding(
186182
padding: const EdgeInsets.symmetric(horizontal: 15),
187183
child: ExerciseLogChart(

0 commit comments

Comments
 (0)