mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-19 07:50:52 +01:00
feat: allow editing old sessions via popup dialog
This commit is contained in:
@@ -18,13 +18,16 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/helpers/colors.dart';
|
||||
import 'package:wger/helpers/json.dart';
|
||||
import 'package:wger/helpers/misc.dart';
|
||||
import 'package:wger/helpers/ui.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.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/providers/routines.dart';
|
||||
import 'package:wger/widgets/measurements/charts.dart';
|
||||
import 'package:wger/widgets/routines/charts.dart';
|
||||
|
||||
@@ -37,44 +40,51 @@ class SessionInfo extends StatelessWidget {
|
||||
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 : '-/-',
|
||||
),
|
||||
],
|
||||
return GestureDetector(
|
||||
onTap: (){
|
||||
final routinesProvider = context.read<RoutinesProvider>();
|
||||
showEditSessionDialog(context, _session, routinesProvider);
|
||||
|
||||
},
|
||||
child: 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 : '-/-',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -197,3 +207,114 @@ class DayLogWidget extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
void showEditSessionDialog(BuildContext context, WorkoutSession session, RoutinesProvider routinesProvider) {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final notesController = TextEditingController(text: session.notes);
|
||||
final timeStartController = TextEditingController(text: timeToString(session.timeStart ?? TimeOfDay.now())!);
|
||||
final timeEndController = TextEditingController(text: timeToString(session.timeEnd ?? TimeOfDay.now())!);
|
||||
List<bool> selectedImpression = [false, false, false];
|
||||
selectedImpression[session.impression - 1] = true;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
return AlertDialog(
|
||||
title: Text('Edit Session (${session.date.toLocal().toString().split(' ')[0]})'),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ToggleButtons(
|
||||
renderBorder: false,
|
||||
isSelected: selectedImpression,
|
||||
onPressed: (index) {
|
||||
for (int i = 0; i < selectedImpression.length; i++) {
|
||||
selectedImpression[i] = (i == index);
|
||||
}
|
||||
session.impression = index + 1;
|
||||
},
|
||||
children: const [
|
||||
Icon(Icons.sentiment_very_dissatisfied),
|
||||
Icon(Icons.sentiment_neutral),
|
||||
Icon(Icons.sentiment_very_satisfied),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(labelText: 'Notes'),
|
||||
controller: notesController,
|
||||
maxLines: 3,
|
||||
onSaved: (value) => session.notes = value ?? '',
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(labelText: 'Start Time'),
|
||||
controller: timeStartController,
|
||||
onTap: () async {
|
||||
FocusScope.of(ctx).requestFocus(FocusNode());
|
||||
final picked = await showTimePicker(
|
||||
context: ctx,
|
||||
initialTime: session.timeStart ?? TimeOfDay.now(),
|
||||
);
|
||||
if (picked != null) {
|
||||
timeStartController.text = timeToString(picked)!;
|
||||
session.timeStart = picked;
|
||||
}
|
||||
},
|
||||
validator: (_) {
|
||||
final start = stringToTime(timeStartController.text);
|
||||
final end = stringToTime(timeEndController.text);
|
||||
if (start.isAfter(end)) {
|
||||
return 'Start time cannot be after end time.';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onSaved: (val) => session.timeStart = stringToTime(val),
|
||||
),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(labelText: 'End Time'),
|
||||
controller: timeEndController,
|
||||
onTap: () async {
|
||||
FocusScope.of(ctx).requestFocus(FocusNode());
|
||||
final picked = await showTimePicker(
|
||||
context: ctx,
|
||||
initialTime: session.timeEnd ?? TimeOfDay.now(),
|
||||
);
|
||||
if (picked != null) {
|
||||
timeEndController.text = timeToString(picked)!;
|
||||
session.timeEnd = picked;
|
||||
}
|
||||
},
|
||||
onSaved: (val) => session.timeEnd = stringToTime(val),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
_formKey.currentState?.save();
|
||||
|
||||
try {
|
||||
await routinesProvider.editSession(session);
|
||||
Navigator.of(ctx).pop();
|
||||
} catch (e) {
|
||||
showErrorDialog(e, context);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Text('Save'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user