mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Polish the gym mode and other widgets
This commit is contained in:
@@ -88,7 +88,7 @@
|
||||
"@noWorkoutPlans": {
|
||||
"description": "Message shown when the user has no workout plans"
|
||||
},
|
||||
"addExercise": "Add exercise to this day",
|
||||
"addExercise": "Add exercise",
|
||||
"repetitions": "Repetitions",
|
||||
"@repetitions": {
|
||||
"description": "Repetitions for an exercise set"
|
||||
|
||||
@@ -5,6 +5,16 @@ part 'day.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Day {
|
||||
static const Map<int, String> weekdays = {
|
||||
1: 'Monday',
|
||||
2: 'Tuesday',
|
||||
3: 'Wednesday',
|
||||
4: 'Thursday',
|
||||
5: 'Friday',
|
||||
6: 'Saturday',
|
||||
7: 'Sunday',
|
||||
};
|
||||
|
||||
@JsonKey(required: true)
|
||||
int? id;
|
||||
|
||||
@@ -28,27 +38,6 @@ class Day {
|
||||
this.sets = [];
|
||||
}
|
||||
|
||||
Day.withData({
|
||||
required this.id,
|
||||
required this.workoutId,
|
||||
required this.description,
|
||||
List<int>? daysOfWeek,
|
||||
List<Set>? sets,
|
||||
}) {
|
||||
this.daysOfWeek = daysOfWeek ?? [];
|
||||
this.sets = sets ?? [];
|
||||
}
|
||||
|
||||
static const Map<int, String> weekdays = {
|
||||
1: 'Monday',
|
||||
2: 'Tuesday',
|
||||
3: 'Wednesday',
|
||||
4: 'Thursday',
|
||||
5: 'Friday',
|
||||
6: 'Saturday',
|
||||
7: 'Sunday',
|
||||
};
|
||||
|
||||
String getDayName(int weekDay) {
|
||||
return weekdays[weekDay]!;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,23 @@ class Set {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return only one setting object per exercise, this makes rendering workout
|
||||
/// plans easier and the gym mode uses the synthetic settings anyway.
|
||||
List<Setting> get settingsFiltered {
|
||||
List<Setting> out = [];
|
||||
|
||||
settings.forEach((setting) {
|
||||
final foundSettings = out.where(
|
||||
(element) => element.exerciseId == setting.exerciseId,
|
||||
);
|
||||
|
||||
if (foundSettings.length == 0) {
|
||||
out.add(setting);
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
|
||||
void addExercise(Exercise exercise) {
|
||||
exercisesObj.add(exercise);
|
||||
exercisesIds.add(exercise.id);
|
||||
|
||||
@@ -8,7 +8,8 @@ part 'setting.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Setting {
|
||||
static final possibleValues = ['1', '1.5', '2', '2.5', '3', '3.5'];
|
||||
static final possibleRiRValues = ['1', '1.5', '2', '2.5', '3', '3.5'];
|
||||
static final defaultRiR = '2';
|
||||
|
||||
@JsonKey(required: true)
|
||||
int? id;
|
||||
@@ -87,7 +88,7 @@ class Setting {
|
||||
}
|
||||
|
||||
void setRir(String rir) {
|
||||
if (possibleValues.contains(rir)) {
|
||||
if (possibleRiRValues.contains(rir)) {
|
||||
this.rir = rir;
|
||||
} else {
|
||||
throw Exception('RiR value not allowed');
|
||||
|
||||
@@ -140,6 +140,7 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier {
|
||||
final setData = await fetch(makeUrl(_setsUrlPath, query: {'exerciseday': day.id.toString()}));
|
||||
for (final setEntry in setData['results']) {
|
||||
final workoutSet = Set.fromJson(setEntry);
|
||||
fetchComputedSettings(workoutSet);
|
||||
|
||||
// Settings
|
||||
List<Setting> settings = [];
|
||||
@@ -182,18 +183,6 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> fetchAndSetWorkouts() async {
|
||||
final data = await fetch(makeUrl(_workoutPlansUrlPath, query: {'ordering': '-creation_date'}));
|
||||
final List<WorkoutPlan> loadedWorkoutPlans = [];
|
||||
|
||||
for (final entry in data['results']) {
|
||||
loadedWorkoutPlans.add(WorkoutPlan.fromJson(entry));
|
||||
}
|
||||
|
||||
_workoutPlans = loadedWorkoutPlans;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<WorkoutPlan> addWorkout(WorkoutPlan workout) async {
|
||||
final data = await post(workout.toJson(), makeUrl(_workoutPlansUrlPath));
|
||||
final plan = WorkoutPlan.fromJson(data);
|
||||
@@ -325,10 +314,38 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier {
|
||||
Future<Set> addSet(Set workoutSet) async {
|
||||
final data = await post(workoutSet.toJson(), makeUrl(_setsUrlPath));
|
||||
final set = Set.fromJson(data);
|
||||
fetchComputedSettings(set);
|
||||
notifyListeners();
|
||||
return set;
|
||||
}
|
||||
|
||||
Future<void> fetchComputedSettings(Set workoutSet) async {
|
||||
final data = await fetch(makeUrl(
|
||||
_setsUrlPath,
|
||||
id: workoutSet.id!,
|
||||
objectMethod: 'computed_settings',
|
||||
));
|
||||
|
||||
List<Setting> settings = [];
|
||||
data['results'].forEach((e) => settings.add(Setting.fromJson(e)));
|
||||
|
||||
workoutSet.settingsComputed = settings;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<String> fetchSmartText(Set workoutSet, Exercise exercise) async {
|
||||
final data = await fetch(
|
||||
makeUrl(
|
||||
_setsUrlPath,
|
||||
id: workoutSet.id!,
|
||||
objectMethod: 'smart_text',
|
||||
query: {'exercise': exercise.id.toString()},
|
||||
),
|
||||
);
|
||||
|
||||
return data['results'];
|
||||
}
|
||||
|
||||
Future<void> deleteSet(Set workoutSet) async {
|
||||
await deleteRequest(_setsUrlPath, workoutSet.id!);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class _GymModeScreenState extends State<GymModeScreen> {
|
||||
final _day = ModalRoute.of(context)!.settings.arguments as Day;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.green,
|
||||
body: Consumer<WorkoutPlans>(
|
||||
builder: (context, value, child) => GymMode(_day),
|
||||
),
|
||||
|
||||
@@ -258,7 +258,7 @@ class _DashboardWorkoutWidgetState extends State<DashboardWorkoutWidget> {
|
||||
day.sets.forEach((set) {
|
||||
out.add(Column(
|
||||
children: [
|
||||
...set.settings.map((s) {
|
||||
...set.settingsFiltered.map((s) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(s.exerciseObj.name),
|
||||
|
||||
@@ -75,7 +75,7 @@ class _WorkoutDayWidgetState extends State<WorkoutDayWidget> {
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
...set.settings
|
||||
...set.settingsFiltered
|
||||
.map(
|
||||
(setting) => SettingWidget(
|
||||
setting: setting,
|
||||
|
||||
@@ -606,13 +606,15 @@ class _RiRInputWidgetState extends State<RiRInputWidget> {
|
||||
return DropdownButtonFormField(
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.rir),
|
||||
value: dropdownValue,
|
||||
onSaved: (String? newValue) {
|
||||
widget._setting.setRir(newValue!);
|
||||
},
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
dropdownValue = newValue!;
|
||||
widget._setting.setRir(newValue);
|
||||
});
|
||||
},
|
||||
items: Setting.possibleValues.map<DropdownMenuItem<String>>((String value) {
|
||||
items: Setting.possibleRiRValues.map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
|
||||
@@ -117,7 +117,7 @@ class StartPage extends StatelessWidget {
|
||||
(set) {
|
||||
return Column(
|
||||
children: [
|
||||
...set.settings.map((s) {
|
||||
...set.settingsFiltered.map((s) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(s.exerciseObj.name, style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
@@ -142,14 +142,13 @@ class StartPage extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class LogPage extends StatelessWidget {
|
||||
class LogPage extends StatefulWidget {
|
||||
PageController _controller;
|
||||
Setting _setting;
|
||||
Exercise _exercise;
|
||||
WorkoutPlan _workoutPlan;
|
||||
Log _log = Log.empty();
|
||||
|
||||
final _form = GlobalKey<FormState>();
|
||||
final _repsController = TextEditingController();
|
||||
final _weightController = TextEditingController();
|
||||
final _rirController = TextEditingController();
|
||||
@@ -174,6 +173,14 @@ class LogPage extends StatelessWidget {
|
||||
_log.weightUnit = 1;
|
||||
}
|
||||
|
||||
@override
|
||||
_LogPageState createState() => _LogPageState();
|
||||
}
|
||||
|
||||
class _LogPageState extends State<LogPage> {
|
||||
final _form = GlobalKey<FormState>();
|
||||
String rirValue = Setting.defaultRiR;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@@ -184,7 +191,7 @@ class LogPage extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Text(
|
||||
_exercise.name,
|
||||
widget._exercise.name,
|
||||
style: Theme.of(context).textTheme.headline5,
|
||||
),
|
||||
),
|
||||
@@ -196,11 +203,28 @@ class LogPage extends StatelessWidget {
|
||||
children: [
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.repetitions),
|
||||
controller: _repsController,
|
||||
controller: widget._repsController,
|
||||
keyboardType: TextInputType.number,
|
||||
onFieldSubmitted: (_) {},
|
||||
onSaved: (newValue) {
|
||||
_log.reps = int.parse(newValue!);
|
||||
widget._log.reps = int.parse(newValue!);
|
||||
},
|
||||
validator: (value) {
|
||||
try {
|
||||
int.parse(value!);
|
||||
} catch (error) {
|
||||
return AppLocalizations.of(context)!.enterValidNumber;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.weight),
|
||||
controller: widget._weightController,
|
||||
keyboardType: TextInputType.number,
|
||||
onFieldSubmitted: (_) {},
|
||||
onSaved: (newValue) {
|
||||
widget._log.weight = double.parse(newValue!);
|
||||
},
|
||||
validator: (value) {
|
||||
try {
|
||||
@@ -211,21 +235,23 @@ class LogPage extends StatelessWidget {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.weight),
|
||||
controller: _weightController,
|
||||
keyboardType: TextInputType.number,
|
||||
onFieldSubmitted: (_) {},
|
||||
onSaved: (newValue) {
|
||||
_log.weight = double.parse(newValue!);
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
DropdownButtonFormField(
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context)!.rir),
|
||||
controller: _rirController,
|
||||
keyboardType: TextInputType.number,
|
||||
onFieldSubmitted: (_) {},
|
||||
onSaved: (newValue) {},
|
||||
value: rirValue,
|
||||
onSaved: (String? newValue) {
|
||||
widget._log.rir = newValue!;
|
||||
},
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
rirValue = newValue!;
|
||||
});
|
||||
},
|
||||
items: Setting.possibleRiRValues.map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
/*
|
||||
TextFormField(
|
||||
@@ -252,10 +278,10 @@ class LogPage extends StatelessWidget {
|
||||
|
||||
// Save the entry on the server
|
||||
try {
|
||||
await Provider.of<WorkoutPlans>(context, listen: false).addLog(_log);
|
||||
await Provider.of<WorkoutPlans>(context, listen: false).addLog(widget._log);
|
||||
//final snackBar = SnackBar(content: Text('Yay! A SnackBar!'));
|
||||
//ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
_controller.nextPage(
|
||||
widget._controller.nextPage(
|
||||
duration: Duration(milliseconds: 200),
|
||||
curve: Curves.bounceIn,
|
||||
);
|
||||
@@ -269,7 +295,7 @@ class LogPage extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
NavigationFooter(_controller),
|
||||
NavigationFooter(widget._controller),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user