import 'dart:convert'; import 'package:drift/drift.dart' hide Column; import 'package:flutter/material.dart' hide Action; import 'package:provider/provider.dart'; import 'package:sendtrain/daos/actions_dao.dart'; import 'package:sendtrain/daos/activity_actions_dao.dart'; import 'package:sendtrain/database/database.dart'; import 'package:sendtrain/helpers/widget_helpers.dart'; import 'package:sendtrain/widgets/generic/elements/form_drop_down.dart'; import 'package:sendtrain/widgets/generic/elements/form_text_input.dart'; class ActivityActionEditor extends StatefulWidget { const ActivityActionEditor( {super.key, required this.session, required this.activity, this.action, this.callback}); final Session session; final Activity activity; final Action? action; final Function? callback; @override State createState() => _ActivityActionEditorState(); } class _ActivityActionEditorState extends State { final GlobalKey _formKey = GlobalKey(); final Map actionEditController = { 'sets': TextEditingController(), 'reps': TextEditingController(), 'weight': TextEditingController(), 'repLength': TextEditingController(), 'preparation': TextEditingController(), 'setRest': TextEditingController(), 'repRest': TextEditingController(), 'cooldown': TextEditingController(), 'type': TextEditingController(), 'alternating': TextEditingController(), }; late final AppDatabase db; bool isAlternating = false; bool isTimed = false; String editorType = 'Create'; @override void initState() { super.initState(); db = Provider.of(context, listen: false); // if we're editing a session, we'll want to populate it with the appropriate values if (widget.action != null) { final Action action = widget.action!; editorType = 'Edit'; isAlternating = action.isAlternating; isTimed = action.repType == RepType.time ? true : false; actionEditController['sets']?.text = action.totalSets.toString(); actionEditController['reps']?.text = json.decode(action.totalReps)[0].toString(); actionEditController['weight']?.text = json.decode(action.repWeights ?? "")[0].toString(); actionEditController['repLength']?.text = ((action.repLength ?? 0) ~/ 1000).toString(); actionEditController['preparation']?.text = ((action.restBeforeSets ?? 0) ~/ 1000).toString(); actionEditController['setRest']?.text = ((action.restBetweenSets ?? 0) ~/ 1000).toString(); actionEditController['repRest']?.text = ((action.restBetweenReps ?? 0) ~/ 1000).toString(); actionEditController['cooldown']?.text = ((action.restAfterSets ?? 0) ~/ 1000).toString(); actionEditController['isTimed']?.text = isTimed.toString(); actionEditController['alternating']?.text = isAlternating.toString(); } } @override Widget build(BuildContext context) { if (widget.action != null) { editorType = 'Edit'; } return Padding( padding: EdgeInsets.fromLTRB(15, 0, 15, 15), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding( padding: EdgeInsets.only(top: 10, bottom: 10), child: Text('$editorType Action', textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge)), Row(children: [ formItemWrapper( CheckboxListTile( title: Text("Reps alternate? (eg. Left/Right Hand)"), value: isAlternating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), ), onChanged: (bool? value) { setState(() { isAlternating = value!; }); }, ), EdgeInsets.fromLTRB(10, 10, 10, 10)), ]), Row(children: [ formItemWrapper( CheckboxListTile( title: Text("Are reps timed?"), value: isTimed, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), ), onChanged: (bool? value) { setState(() { isTimed = value!; }); }, ), EdgeInsets.fromLTRB(10, 10, 10, 15)) ]), Row(children: [ FormDropDown( title: 'Sets', entries: numericDropDownItems('Set', 50), controller: actionEditController['sets']!), FormDropDown( title: 'Reps', entries: numericDropDownItems('Rep', 100), controller: actionEditController['reps']!, ) ]), Row(children: [ formItemWrapper( FormTextInput( type: InputTypes.number, controller: actionEditController['preparation']!, title: 'Preparation (sec)', hint: 'time before start', requiresValidation: false), EdgeInsets.fromLTRB(10, 5, 10, 0)), formItemWrapper( FormTextInput( type: InputTypes.number, controller: actionEditController['cooldown']!, title: 'Cooldown (sec)', hint: 'rest after completion', requiresValidation: false), EdgeInsets.fromLTRB(10, 5, 10, 0)), ]), Row(children: [ formItemWrapper( FormTextInput( type: InputTypes.number, controller: actionEditController['setRest']!, title: 'Set Rest (sec)', hint: 'Rest between sets', requiresValidation: false), EdgeInsets.only(left: 10, right: 10)), formItemWrapper( FormTextInput( type: InputTypes.number, controller: actionEditController['repRest']!, title: 'Rep Rest (sec)', hint: 'Rest between reps', requiresValidation: false), EdgeInsets.only(left: 10, right: 10)), ]), Row(children: [ formItemWrapper( FormTextInput( type: InputTypes.number, controller: actionEditController['repLength']!, title: 'Rep Length (sec)', hint: 'Total rep time (not required)', requiresValidation: false), EdgeInsets.only(left: 10, right: 10)), formItemWrapper( FormTextInput( type: InputTypes.number, controller: actionEditController['weight']!, title: 'Weight', hint: 'Weight for reps', requiresValidation: false), EdgeInsets.only(left: 10, right: 10)), ]), Row(mainAxisAlignment: MainAxisAlignment.end, children: [ Padding( padding: EdgeInsets.only(top: 10, right: 10), child: FilledButton( onPressed: () async { if (_formKey.currentState!.validate()) { if (widget.action != null) { Action newAction = widget.action!.copyWith( totalSets: int.parse( actionEditController['sets']!.text), totalReps: json.encode([ int.parse( actionEditController['reps']!.text) ]), repLength: Value(int.parse( actionEditController['repLength']! .text) * 1000), restBeforeSets: Value(int.parse( actionEditController['preparation']! .text) * 1000), restBetweenSets: Value(int.parse( actionEditController['setRest']! .text) * 1000), restBetweenReps: Value(int.parse( actionEditController['repRest']! .text) * 1000), restAfterSets: Value(int.parse( actionEditController['cooldown']! .text) * 1000), repType: int.parse(actionEditController[ 'repLength']! .text) > 0 ? RepType.time : RepType.count, repWeights: Value(json.encode([ int.parse( actionEditController['weight']!.text) ])), // setWeights: Value(json.encode([actionEditController['setWeights']!.text])), isAlternating: isAlternating, ); // var result = await ActionsDao(db).createOrUpdate( // newAction.toCompanion(true)); await ActionsDao(db).replace(newAction); } else { // create action await ActionsDao(db) .createOrUpdate(ActionsCompanion( title: Value('title'), description: Value('description'), totalSets: Value(int.parse( actionEditController['sets']! .text)), totalReps: Value(json.encode( [int.parse(actionEditController['reps']!.text)])), repLength: Value( int.parse(actionEditController['repLength']!.text) * 1000), restBeforeSets: Value( int.parse(actionEditController['preparation']!.text) * 1000), restBetweenSets: Value( int.parse(actionEditController['setRest']!.text) * 1000), restBetweenReps: Value(int.parse(actionEditController['repRest']!.text) * 1000), restAfterSets: Value(int.parse(actionEditController['cooldown']!.text) * 1000), repType: Value(int.parse(actionEditController['repLength']!.text) > 0 ? RepType.time : RepType.count), repWeights: Value(json.encode([int.parse(actionEditController['weight']!.text)])), // setWeights: Value(json.encode([actionEditController['setWeights']!.text])), isAlternating: Value(isAlternating), // repType: RepType.values.firstWhere((e) => e.toString() == "RepType.${actionEditController['repType']!.text}"), set: Value(""))) .then((actionId) { ActivityActionsDao(db).createOrUpdate( ActivityActionsCompanion( activityId: Value(widget.activity.id), sessionId: Value(widget.session.id), actionId: Value(actionId), position: Value(0))); }); } Navigator.pop( _formKey.currentContext!, 'Submit'); if (widget.callback != null) { await widget.callback!(); } } }, child: Text('Submit'))) ]) ]))); } }