Skip to content

Commit

Permalink
Show workout session information
Browse files Browse the repository at this point in the history
  • Loading branch information
rolandgeider committed Jan 26, 2025
1 parent 51ed2ef commit 7c6fbeb
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 51 deletions.
19 changes: 9 additions & 10 deletions lib/models/workouts/routine.dart
Original file line number Diff line number Diff line change
Expand Up @@ -158,24 +158,23 @@ class Routine {
///
Map<DateTime, Map<String, dynamic>> get logData {
final out = <DateTime, Map<String, dynamic>>{};
for (final log in logs) {
final exercise = log.exercise;
final date = log.date;

for (final sessionData in sessions) {
final date = sessionData.session.date;
if (!out.containsKey(date)) {
out[date] = {
'session': null,
'session': sessionData.session,
'exercises': <Exercise, List<Log>>{},
};
}

if (!out[date]!['exercises']!.containsKey(exercise)) {
out[date]!['exercises']![exercise] = <Log>[];
for (final log in sessionData.logs) {
final exercise = log.exercise;
if (!out[date]!['exercises']!.containsKey(exercise)) {
out[date]!['exercises']![exercise] = <Log>[];
}
out[date]!['exercises']![exercise].add(log);
}

out[date]!['exercises']![exercise].add(log);
}

return out;
}
}
8 changes: 4 additions & 4 deletions lib/models/workouts/session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ class WorkoutSession {
late String notes;

@JsonKey(required: true, name: 'time_start', toJson: timeToString, fromJson: stringToTime)
late TimeOfDay timeStart;
late TimeOfDay? timeStart;

@JsonKey(required: true, name: 'time_end', toJson: timeToString, fromJson: stringToTime)
late TimeOfDay timeEnd;
late TimeOfDay? timeEnd;

@JsonKey(required: false, includeToJson: false, defaultValue: [])
List<Log> logs = [];
Expand Down Expand Up @@ -74,7 +74,7 @@ class WorkoutSession {

Map<String, dynamic> toJson() => _$WorkoutSessionToJson(this);

String? get impressionAsString {
return IMPRESSION_MAP[impression];
String get impressionAsString {
return IMPRESSION_MAP[impression]!;
}
}
2 changes: 1 addition & 1 deletion lib/providers/exercises.dart
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ class ExercisesProvider with ChangeNotifier {
// Note: no await since we don't care for the updated data right now. It
// will be written to the db whenever the request finishes and we will get
// the updated exercise the next time
//handleUpdateExerciseFromApi(database, exerciseId);
handleUpdateExerciseFromApi(database, exerciseId);

return exercise;
} on NoSuchEntryException {
Expand Down
31 changes: 15 additions & 16 deletions lib/providers/routines.dart
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,6 @@ class RoutinesProvider with ChangeNotifier {
objectMethod: _routinesLogsSubpath,
),
),
baseProvider.fetchPaginated(
baseProvider.makeUrl(
_logsUrlPath,
query: {'routine': routineId.toString(), 'limit': '900'},
),
),
]);

final routine = Routine.fromJson(results[0] as Map<String, dynamic>);
Expand All @@ -285,7 +279,6 @@ class RoutinesProvider with ChangeNotifier {
final currentIterationDayData = results[3] as List<dynamic>;
final currentIterationDayDataGym = results[4] as List<dynamic>;
final sessionData = results[5] as List<dynamic>;
final logData = results[6] as List<dynamic>;

/*
* Set exercise, repetition and weight unit objects
Expand Down Expand Up @@ -329,18 +322,24 @@ class RoutinesProvider with ChangeNotifier {
routine.dayDataCurrentIterationGym = currentIterationGym;

// Logs
routine.sessions = sessionDataEntries;
// routine.sessions = sessionDataEntries;
routine.sessions = List<WorkoutSessionApi>.from(sessionDataEntries);

for (final logEntry in logData) {
// TODO: workaround, routine.logs is marked as an unmodifiable list
routine.logs = [];
for (final sessionData in routine.sessions) {
try {
final log = Log.fromJson(logEntry);
log.weightUnit = _weightUnits.firstWhere((e) => e.id == log.weightUnitId);
log.repetitionUnit = _repetitionUnits.firstWhere((e) => e.id == log.weightUnitId);
log.exerciseBase = (await _exercises.fetchAndSetExercise(log.exerciseId))!;
routine.logs.add(log);
} catch (e) {
_logger.warning('Error while processing the logs for a routine!');
for (final log in sessionData.logs) {
log.weightUnit = _weightUnits.firstWhere((e) => e.id == log.weightUnitId);
log.repetitionUnit = _repetitionUnits.firstWhere((e) => e.id == log.weightUnitId);
log.exerciseBase = (await _exercises.fetchAndSetExercise(log.exerciseId))!;

routine.logs.add(log);
}
} catch (e, stackTrace) {
_logger.warning('Error while processing the session data for a routine!');
_logger.warning(e.toString());
_logger.warning(stackTrace.toString());
}
}

Expand Down
13 changes: 10 additions & 3 deletions lib/widgets/routines/charts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,16 @@ class _LogChartWidgetFlState extends State<LogChartWidgetFl> {
);
},
interval: chartGetInterval(
// TODO: make sure this works when the data is empty etc
widget._data[widget._data.keys.first]!.first.date,
widget._data[widget._data.keys.last]!.first.date,
widget._data.containsKey(widget._data.keys.first) &&
widget._data[widget._data.keys.first]!.isNotEmpty
? widget._data[widget._data.keys.first]!.first.date
: DateTime.now(),
widget._data.containsKey(widget._data.keys.last) &&
widget._data[widget._data.keys.last]!.isNotEmpty
? widget._data[widget._data.keys.last]!.first.date
: DateTime.now(),
// widget._data[widget._data.keys.first]!.first.date,
// widget._data[widget._data.keys.last]!.first.date,
),
),
),
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/routines/gym_mode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ class _SessionPageState extends State<SessionPage> {
// Open time picker
final pickedTime = await showTimePicker(
context: context,
initialTime: widget._session.timeStart,
initialTime: widget._session.timeStart ?? TimeOfDay.now(),
);

if (pickedTime != null) {
Expand Down Expand Up @@ -893,7 +893,7 @@ class _SessionPageState extends State<SessionPage> {
// Open time picker
final pickedTime = await showTimePicker(
context: context,
initialTime: widget._session.timeEnd,
initialTime: widget._session.timeEnd ?? TimeOfDay.now(),
);

if (pickedTime != null) {
Expand Down
99 changes: 85 additions & 14 deletions lib/widgets/routines/log.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,89 @@
*/

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
import 'package:wger/helpers/colors.dart';
import 'package:wger/helpers/misc.dart';
import 'package:wger/helpers/ui.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/workouts/log.dart';
import 'package:wger/models/workouts/routine.dart';
import 'package:wger/models/workouts/session.dart';
import 'package:wger/widgets/measurements/charts.dart';
import 'package:wger/widgets/routines/charts.dart';

class SessionInfo extends StatelessWidget {
final WorkoutSession _session;

const SessionInfo(this._session);

@override
Widget build(BuildContext context) {
final i18n = AppLocalizations.of(context);

return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
i18n.workoutSession,
style: Theme.of(context).textTheme.headlineSmall,
),
Text(
DateFormat.yMd(Localizations.localeOf(context).languageCode).format(_session.date),
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 8.0),
_buildInfoRow(
context,
i18n.timeStart,
_session.timeStart != null
? MaterialLocalizations.of(context).formatTimeOfDay(_session.timeStart!)
: '-/-',
),
_buildInfoRow(
context,
i18n.timeEnd,
_session.timeEnd != null
? MaterialLocalizations.of(context).formatTimeOfDay(_session.timeEnd!)
: '-/-',
),
_buildInfoRow(
context,
i18n.impression,
_session.impressionAsString,
),
_buildInfoRow(
context,
i18n.notes,
_session.notes.isNotEmpty ? _session.notes : '-/-',
),
],
),
);
}

Widget _buildInfoRow(BuildContext context, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$label: ',
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
Expanded(
child: Text(
value,
style: Theme.of(context).textTheme.titleMedium,
),
),
],
),
);
}
}

class ExerciseLogChart extends StatelessWidget {
final Map<num, List<Log>> _logs;
Expand All @@ -40,7 +114,8 @@ class ExerciseLogChart extends StatelessWidget {
return Column(
mainAxisSize: MainAxisSize.max,
children: [
LogChartWidgetFl(_logs, _selectedDate),
// TODO: why does this not work??? 😫
// LogChartWidgetFl(_logs, _selectedDate),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expand All @@ -64,34 +139,30 @@ class DayLogWidget extends StatelessWidget {
final DateTime _date;
final Routine _routine;

final WorkoutSession? _session;
final Map<Exercise, List<Log>> _exerciseData;
final WorkoutSession _session;
final Map<Exercise, List<Log>> _exerciseMap;

const DayLogWidget(this._date, this._exerciseData, this._session, this._routine);
const DayLogWidget(this._date, this._exerciseMap, this._session, this._routine);

@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
Text(
DateFormat.yMd(Localizations.localeOf(context).languageCode).format(_date),
style: Theme.of(context).textTheme.headlineSmall,
),
if (_session != null) const Text('Session data here'),
..._exerciseData.keys.map((exercise) {
SessionInfo(_session),
..._exerciseMap.keys.map((exercise) {
final translation =
exercise.getTranslation(Localizations.localeOf(context).languageCode);
return Column(
children: [
if (_exerciseData[exercise]!.isNotEmpty)
if (_exerciseMap[exercise]!.isNotEmpty)
Text(
translation.name,
style: Theme.of(context).textTheme.headlineSmall,
)
else
Container(),
..._exerciseData[exercise]!.map(
..._exerciseMap[exercise]!.map(
(log) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expand All @@ -104,7 +175,7 @@ class DayLogWidget extends StatelessWidget {
translation.name,
log,
translation,
_exerciseData,
_exerciseMap,
);
},
),
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/routines/workout_logs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class _WorkoutLogsState extends State<WorkoutLogs> {
/// An event in the workout log calendar
class WorkoutLogEvent {
final DateTime dateTime;
final WorkoutSession? session;
final WorkoutSession session;
final Map<Exercise, List<Log>> exercises;

const WorkoutLogEvent(this.dateTime, this.session, this.exercises);
Expand Down

0 comments on commit 7c6fbeb

Please sign in to comment.