mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Show workout session information
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = [];
|
||||
@@ -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]!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>);
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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: [
|
||||
@@ -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: [
|
||||
@@ -104,7 +175,7 @@ class DayLogWidget extends StatelessWidget {
|
||||
translation.name,
|
||||
log,
|
||||
translation,
|
||||
_exerciseData,
|
||||
_exerciseMap,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user