Merge branch 'feature/flexible-routines' into Jackpkn-fix/gym-provider-navigation

This commit is contained in:
Roland Geider
2025-02-21 22:16:25 +01:00
48 changed files with 3553 additions and 440 deletions

View File

@@ -24,33 +24,35 @@ import 'package:wger/models/workouts/weight_unit.dart';
/// Returns the text representation for a single setting, used in the gym mode
String repText(
num? reps,
RepetitionUnit repetitionUnitObj,
num? repetitions,
RepetitionUnit? repetitionUnitObj,
num? weight,
WeightUnit weightUnitObj,
WeightUnit? weightUnitObj,
String? rir,
) {
// TODO(x): how to (easily?) translate strings like the units or 'RiR'
final List<String> out = [];
if (reps != null) {
out.add(formatNum(reps).toString());
if (repetitions != null) {
out.add(formatNum(repetitions).toString());
// The default repetition unit is 'reps', which we don't show unless there
// is no weight defined so that we don't just output something like "8" but
// rather "8 repetitions". If there is weight we want to output "8 x 50kg",
// since the repetitions are implied. If other units are used, we always
// print them
if (repetitionUnitObj.id != REP_UNIT_REPETITIONS_ID || weight == 0 || weight == null) {
out.add(repetitionUnitObj.name);
if (repetitionUnitObj != null && repetitionUnitObj.id != REP_UNIT_REPETITIONS_ID ||
weight == 0 ||
weight == null) {
out.add(repetitionUnitObj!.name);
}
}
if (weight != null && weight != 0) {
out.add('×');
out.add(formatNum(weight).toString());
out.add(weightUnitObj.name);
out.add(weightUnitObj!.name);
}
if (rir != null && rir != '') {

View File

@@ -11,7 +11,7 @@ import 'package:wger/models/exercises/video.dart';
part 'exercise_api.freezed.dart';
part 'exercise_api.g.dart';
/// Model for an exercise as returned from the exercisebaseinfo endpoint
/// Model for an exercise as returned from the exerciseinfo endpoint
///
/// Basically this is just used as a convenience to create "real" exercise
/// objects and nothing more

View File

@@ -44,9 +44,6 @@ class BaseConfig {
@JsonKey(required: true)
late String step;
@JsonKey(required: true, name: 'need_log_to_apply')
late bool needLogToApply;
@JsonKey(required: true, name: 'repeat')
late bool repeat;
@@ -61,7 +58,6 @@ class BaseConfig {
required this.value,
this.operation = 'r',
this.step = 'abs',
this.needLogToApply = false,
this.requirements = null,
});
@@ -69,7 +65,6 @@ class BaseConfig {
iteration = 1;
operation = 'r';
step = 'abs';
needLogToApply = false;
requirements = null;
repeat = false;
}

View File

@@ -16,7 +16,6 @@ BaseConfig _$BaseConfigFromJson(Map<String, dynamic> json) {
'value',
'operation',
'step',
'need_log_to_apply',
'repeat',
'requirements'
],
@@ -29,7 +28,6 @@ BaseConfig _$BaseConfigFromJson(Map<String, dynamic> json) {
value: stringOrIntToNum(json['value']),
operation: json['operation'] as String? ?? 'r',
step: json['step'] as String? ?? 'abs',
needLogToApply: json['need_log_to_apply'] as bool? ?? false,
requirements: json['requirements'] ?? null,
);
}
@@ -40,7 +38,6 @@ Map<String, dynamic> _$BaseConfigToJson(BaseConfig instance) => <String, dynamic
'value': instance.value,
'operation': instance.operation,
'step': instance.step,
'need_log_to_apply': instance.needLogToApply,
'repeat': instance.repeat,
'requirements': instance.requirements,
};

View File

@@ -62,10 +62,10 @@ class Log {
num? repetitionsTarget;
@JsonKey(required: true, name: 'repetitions_unit')
late int repetitionsUnitId;
late int? repetitionsUnitId;
@JsonKey(includeFromJson: false, includeToJson: false)
late RepetitionUnit repetitionsUnitObj;
late RepetitionUnit? repetitionsUnitObj;
@JsonKey(required: true, fromJson: stringToNum, toJson: numToString)
late num? weight;
@@ -74,10 +74,10 @@ class Log {
num? weightTarget;
@JsonKey(required: true, name: 'weight_unit')
late int weightUnitId;
late int? weightUnitId;
@JsonKey(includeFromJson: false, includeToJson: false)
late WeightUnit weightUnitObj;
late WeightUnit? weightUnitObj;
@JsonKey(required: true, toJson: dateToYYYYMMDD)
late DateTime date;
@@ -111,14 +111,14 @@ class Log {
exerciseId = base.id!;
}
set weightUnit(WeightUnit weightUnit) {
set weightUnit(WeightUnit? weightUnit) {
weightUnitObj = weightUnit;
weightUnitId = weightUnit.id;
weightUnitId = weightUnit?.id;
}
set repetitionUnit(RepetitionUnit repetitionUnit) {
set repetitionUnit(RepetitionUnit? repetitionUnit) {
repetitionsUnitObj = repetitionUnit;
repetitionsUnitId = repetitionUnit.id;
repetitionsUnitId = repetitionUnit?.id;
}
void setRir(String rir) {

View File

@@ -18,6 +18,7 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:wger/helpers/json.dart';
import 'package:wger/helpers/misc.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/day_data.dart';
@@ -69,12 +70,6 @@ class Routine {
@JsonKey(includeFromJson: false, includeToJson: false)
List<DayData> dayDataGym = [];
@JsonKey(includeFromJson: false, includeToJson: false)
List<DayData> dayDataCurrentIteration = [];
@JsonKey(includeFromJson: false, includeToJson: false)
List<DayData> dayDataCurrentIterationGym = [];
@JsonKey(required: false, includeToJson: false, defaultValue: [])
List<WorkoutSessionApi> sessions = [];
@@ -89,8 +84,6 @@ class Routine {
this.days = const [],
this.dayData = const [],
this.dayDataGym = const [],
this.dayDataCurrentIteration = const [],
this.dayDataCurrentIterationGym = const [],
this.sessions = const [],
}) {
this.created = created ?? DateTime.now();
@@ -121,6 +114,29 @@ class Routine {
return out;
}
int? getIteration({DateTime? date}) {
if (date == null) {
return null;
}
for (final data in dayData) {
if (data.date.isSameDayAs(date)) {
return data.iteration;
}
}
return null;
}
List<DayData> get dayDataCurrentIteration {
final iteration = getIteration() ?? 1;
return dayData.where((data) => data.iteration == iteration).toList();
}
List<DayData> get dayDataCurrentIterationGym {
final iteration = getIteration() ?? 1;
return dayDataGym.where((data) => data.iteration == iteration).toList();
}
/// Filters the workout logs by exercise and sorts them by date
///
/// Optionally, filters list so that only unique logs are returned. "Unique"

View File

@@ -58,24 +58,24 @@ class SetConfigData {
late int? weightUnitId;
@JsonKey(includeToJson: false, includeFromJson: false)
late WeightUnit weightUnit;
late WeightUnit? weightUnit;
@JsonKey(required: true, name: 'weight_rounding', fromJson: stringToNumNull)
late num? weightRounding;
@JsonKey(required: true, fromJson: stringToNumNull, name: 'reps')
@JsonKey(required: true, fromJson: stringToNumNull, name: 'repetitions')
late num? repetitions;
@JsonKey(required: true, name: 'max_reps', fromJson: stringToNumNull)
@JsonKey(required: true, name: 'max_repetitions', fromJson: stringToNumNull)
late num? maxRepetitions;
@JsonKey(required: true, name: 'reps_unit')
@JsonKey(required: true, name: 'repetitions_unit')
late int? repetitionsUnitId;
@JsonKey(includeToJson: false, includeFromJson: false)
late RepetitionUnit repetitionsUnit;
late RepetitionUnit? repetitionsUnit;
@JsonKey(required: true, name: 'reps_rounding', fromJson: stringToNumNull)
@JsonKey(required: true, name: 'repetitions_rounding', fromJson: stringToNumNull)
late num? repetitionsRounding;
@JsonKey(required: true)
@@ -119,7 +119,7 @@ class SetConfigData {
this.textRepr = '',
Exercise? exercise,
WeightUnit? weightUnit,
RepetitionUnit? repsUnit,
RepetitionUnit? repetitionsUnit,
}) {
if (exercise != null) {
this.exercise = exercise;
@@ -127,8 +127,8 @@ class SetConfigData {
if (weightUnit != null) {
this.weightUnit = weightUnit;
}
if (repsUnit != null) {
this.repetitionsUnit = repsUnit;
if (repetitionsUnit != null) {
this.repetitionsUnit = repetitionsUnit;
}
}

View File

@@ -20,10 +20,10 @@ SetConfigData _$SetConfigDataFromJson(Map<String, dynamic> json) {
'max_weight',
'weight_unit',
'weight_rounding',
'reps',
'max_reps',
'reps_unit',
'reps_rounding',
'repetitions',
'max_repetitions',
'repetitions_unit',
'repetitions_rounding',
'rir',
'max_rir',
'rpe',
@@ -44,11 +44,12 @@ SetConfigData _$SetConfigDataFromJson(Map<String, dynamic> json) {
weightRounding: json['weight_rounding'] == null
? 1.25
: stringToNumNull(json['weight_rounding'] as String?),
repetitions: stringToNumNull(json['reps'] as String?),
maxRepetitions: stringToNumNull(json['max_reps'] as String?),
repetitionsUnitId: (json['reps_unit'] as num?)?.toInt() ?? REP_UNIT_REPETITIONS_ID,
repetitionsRounding:
json['reps_rounding'] == null ? 1 : stringToNumNull(json['reps_rounding'] as String?),
repetitions: stringToNumNull(json['repetitions'] as String?),
maxRepetitions: stringToNumNull(json['max_repetitions'] as String?),
repetitionsUnitId: (json['repetitions_unit'] as num?)?.toInt() ?? REP_UNIT_REPETITIONS_ID,
repetitionsRounding: json['repetitions_rounding'] == null
? 1
: stringToNumNull(json['repetitions_rounding'] as String?),
rir: json['rir'] as String?,
maxRir: json['max_rir'] as String?,
rpe: json['rpe'] as String?,
@@ -70,10 +71,10 @@ Map<String, dynamic> _$SetConfigDataToJson(SetConfigData instance) => <String, d
'max_weight': instance.maxWeight,
'weight_unit': instance.weightUnitId,
'weight_rounding': instance.weightRounding,
'reps': instance.repetitions,
'max_reps': instance.maxRepetitions,
'reps_unit': instance.repetitionsUnitId,
'reps_rounding': instance.repetitionsRounding,
'repetitions': instance.repetitions,
'max_repetitions': instance.maxRepetitions,
'repetitions_unit': instance.repetitionsUnitId,
'repetitions_rounding': instance.repetitionsRounding,
'rir': instance.rir,
'max_rir': instance.maxRir,
'rpe': instance.rpe,

View File

@@ -29,8 +29,8 @@ part 'slot_entry.g.dart';
enum ConfigType {
weight,
maxWeight,
reps,
maxReps,
repetitions,
maxRepetitions,
sets,
maxSets,
rir,
@@ -68,25 +68,25 @@ class SlotEntry {
late int exerciseId;
@JsonKey(required: true, name: 'repetition_unit')
late int repetitionUnitId;
late int? repetitionUnitId;
@JsonKey(includeFromJson: false, includeToJson: false)
late RepetitionUnit repetitionUnitObj;
late RepetitionUnit? repetitionUnitObj;
@JsonKey(required: true, name: 'repetition_rounding', fromJson: stringToNum)
late num repetitionRounding;
@JsonKey(required: false, name: 'reps_configs', includeToJson: false, defaultValue: [])
late List<BaseConfig> repsConfigs = [];
@JsonKey(required: false, name: 'repetitions_configs', includeToJson: false, defaultValue: [])
late List<BaseConfig> repetitionsConfigs = [];
@JsonKey(required: false, name: 'max_reps_configs', includeToJson: false, defaultValue: [])
late List<BaseConfig> maxRepsConfigs = [];
@JsonKey(required: false, name: 'max_repetitions_configs', includeToJson: false, defaultValue: [])
late List<BaseConfig> maxRepetitionsConfigs = [];
@JsonKey(required: true, name: 'weight_unit')
late int weightUnitId;
late int? weightUnitId;
@JsonKey(includeFromJson: false, includeToJson: false)
late WeightUnit weightUnitObj;
late WeightUnit? weightUnitObj;
@JsonKey(required: true, name: 'weight_rounding', fromJson: stringToNum)
late num weightRounding;
@@ -137,8 +137,8 @@ class SlotEntry {
this.maxRirConfigs = const [],
this.restTimeConfigs = const [],
this.maxRestTimeConfigs = const [],
this.repsConfigs = const [],
this.maxRepsConfigs = const [],
this.repetitionsConfigs = const [],
this.maxRepetitionsConfigs = const [],
RepetitionUnit? repetitionUnit,
WeightUnit? weightUnit,
Exercise? exercise,
@@ -186,8 +186,8 @@ class SlotEntry {
bool get hasProgressionRules {
return weightConfigs.length > 1 ||
repsConfigs.length > 1 ||
maxRepsConfigs.length > 1 ||
repetitionsConfigs.length > 1 ||
maxRepetitionsConfigs.length > 1 ||
nrOfSetsConfigs.length > 1 ||
maxNrOfSetsConfigs.length > 1 ||
rirConfigs.length > 1 ||
@@ -208,10 +208,10 @@ class SlotEntry {
return nrOfSetsConfigs;
case ConfigType.maxSets:
return maxNrOfSetsConfigs;
case ConfigType.reps:
return repsConfigs;
case ConfigType.maxReps:
return maxRepsConfigs;
case ConfigType.repetitions:
return repetitionsConfigs;
case ConfigType.maxRepetitions:
return maxRepetitionsConfigs;
case ConfigType.rir:
return rirConfigs;
case ConfigType.maxRir:

View File

@@ -29,9 +29,9 @@ SlotEntry _$SlotEntryFromJson(Map<String, dynamic> json) {
order: (json['order'] as num).toInt(),
type: json['type'] as String,
exerciseId: (json['exercise'] as num).toInt(),
repetitionUnitId: (json['repetition_unit'] as num).toInt(),
repetitionUnitId: (json['repetition_unit'] as num?)?.toInt(),
repetitionRounding: stringToNum(json['repetition_rounding'] as String?),
weightUnitId: (json['weight_unit'] as num).toInt(),
weightUnitId: (json['weight_unit'] as num?)?.toInt(),
weightRounding: stringToNum(json['weight_rounding'] as String?),
comment: json['comment'] as String,
weightConfigs: (json['weight_configs'] as List<dynamic>?)
@@ -66,11 +66,11 @@ SlotEntry _$SlotEntryFromJson(Map<String, dynamic> json) {
?.map((e) => BaseConfig.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
repsConfigs: (json['reps_configs'] as List<dynamic>?)
repetitionsConfigs: (json['repetitions_configs'] as List<dynamic>?)
?.map((e) => BaseConfig.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
maxRepsConfigs: (json['max_reps_configs'] as List<dynamic>?)
maxRepetitionsConfigs: (json['max_repetitions_configs'] as List<dynamic>?)
?.map((e) => BaseConfig.fromJson(e as Map<String, dynamic>))
.toList() ??
[],

View File

@@ -37,7 +37,7 @@ class AddExerciseProvider with ChangeNotifier {
List<Muscle> _primaryMuscles = [];
List<Muscle> _secondaryMuscles = [];
static const _exerciseUrlPath = 'exercise-base';
static const _exerciseUrlPath = 'exercise';
static const _imagesUrlPath = 'exerciseimage';
static const _exerciseTranslationUrlPath = 'exercise-translation';
static const _exerciseAliasPath = 'exercisealias';

View File

@@ -48,7 +48,7 @@ class ExercisesProvider with ChangeNotifier {
static const EXERCISE_CACHE_DAYS = 7;
static const CACHE_VERSION = 4;
static const exerciseInfoUrlPath = 'exercisebaseinfo';
static const exerciseInfoUrlPath = 'exerciseinfo';
static const exerciseSearchPath = 'exercise/search';
static const categoriesUrlPath = 'exercisecategory';

View File

@@ -45,8 +45,6 @@ class RoutinesProvider with ChangeNotifier {
static const _routinesLogsSubpath = 'logs';
static const _routinesDateSequenceDisplaySubpath = 'date-sequence-display';
static const _routinesDateSequenceGymSubpath = 'date-sequence-gym';
static const _routinesCurrentIterationDisplaySubpath = 'current-iteration-display';
static const _routinesCurrentIterationGymSubpath = 'current-iteration-gym';
static const _daysUrlPath = 'day';
static const _slotsUrlPath = 'slot';
static const _slotEntriesUrlPath = 'slot-entry';
@@ -58,15 +56,15 @@ class RoutinesProvider with ChangeNotifier {
static const _routineConfigMaxSets = 'max-sets-config';
static const _routineConfigWeights = 'weight-config';
static const _routineConfigMaxWeights = 'max-weight-config';
static const _routineConfigReps = 'reps-config';
static const _routineConfigMaxReps = 'max-reps-config';
static const _routineConfigRepetitions = 'repetitions-config';
static const _routineConfigMaxRepetitions = 'max-repetitions-config';
static const _routineConfigRir = 'rir-config';
static const _routineConfigMaxRir = 'rest-config';
static const _routineConfigRestTime = 'rest-config';
static const _routineConfigMaxRestTime = 'max-rest-config';
Routine? _currentRoutine;
late ExercisesProvider _exercises;
late ExercisesProvider _exerciseProvider;
final WgerBaseProvider baseProvider;
List<Routine> _routines = [];
List<WeightUnit> _weightUnits = [];
@@ -79,7 +77,7 @@ class RoutinesProvider with ChangeNotifier {
List<WeightUnit>? weightUnits,
List<RepetitionUnit>? repetitionUnits,
}) {
_exercises = exercises;
_exerciseProvider = exercises;
_routines = entries;
_weightUnits = weightUnits ?? [];
_repetitionUnits = repetitionUnits ?? [];
@@ -93,6 +91,10 @@ class RoutinesProvider with ChangeNotifier {
return [..._weightUnits];
}
set weightUnits(List<WeightUnit> weightUnits) {
_weightUnits = weightUnits;
}
/// Clears all lists
void clear() {
_currentRoutine = null;
@@ -112,6 +114,10 @@ class RoutinesProvider with ChangeNotifier {
return [..._repetitionUnits];
}
set repetitionUnits(List<RepetitionUnit> repetitionUnits) {
_repetitionUnits = repetitionUnits;
}
RepetitionUnit findRepetitionUnitById(int id) =>
_repetitionUnits.firstWhere((element) => element.id == id);
@@ -196,7 +202,7 @@ class RoutinesProvider with ChangeNotifier {
for (final entry in entries) {
for (final slot in entry.slots) {
for (final setConfig in slot.setConfigs) {
setConfig.exercise = (await _exercises.fetchAndSetExercise(setConfig.exerciseId))!;
setConfig.exercise = (await _exerciseProvider.fetchAndSetExercise(setConfig.exerciseId))!;
setConfig.repetitionsUnit = _repetitionUnits.firstWhere(
(e) => e.id == setConfig.repetitionsUnitId,
@@ -249,20 +255,6 @@ class RoutinesProvider with ChangeNotifier {
objectMethod: _routinesDateSequenceGymSubpath,
),
),
baseProvider.fetch(
baseProvider.makeUrl(
_routinesUrlPath,
id: routineId,
objectMethod: _routinesCurrentIterationDisplaySubpath,
),
),
baseProvider.fetch(
baseProvider.makeUrl(
_routinesUrlPath,
id: routineId,
objectMethod: _routinesCurrentIterationGymSubpath,
),
),
baseProvider.fetch(
baseProvider.makeUrl(
_routinesUrlPath,
@@ -276,9 +268,7 @@ class RoutinesProvider with ChangeNotifier {
final dayData = results[1] as List<dynamic>;
final dayDataGym = results[2] as List<dynamic>;
final currentIterationDayData = results[3] as List<dynamic>;
final currentIterationDayDataGym = results[4] as List<dynamic>;
final sessionData = results[5] as List<dynamic>;
final sessionData = results[3] as List<dynamic>;
/*
* Set exercise, repetition and weight unit objects
@@ -291,21 +281,14 @@ class RoutinesProvider with ChangeNotifier {
final dayDataEntriesGym = dayDataGym.map((entry) => DayData.fromJson(entry)).toList();
setExercisesAndUnits(dayDataEntriesGym);
final currentIteration =
currentIterationDayData.map((entry) => DayData.fromJson(entry)).toList();
setExercisesAndUnits(currentIteration);
final currentIterationGym =
currentIterationDayDataGym.map((entry) => DayData.fromJson(entry)).toList();
setExercisesAndUnits(currentIterationGym);
final sessionDataEntries =
sessionData.map((entry) => WorkoutSessionApi.fromJson(entry)).toList();
for (final day in routine.days) {
for (final slot in day.slots) {
for (final slotEntry in slot.entries) {
slotEntry.exerciseObj = (await _exercises.fetchAndSetExercise(slotEntry.exerciseId))!;
slotEntry.exerciseObj =
(await _exerciseProvider.fetchAndSetExercise(slotEntry.exerciseId))!;
slotEntry.repetitionUnitObj = _repetitionUnits.firstWhere(
(e) => e.id == slotEntry.repetitionUnitId,
);
@@ -318,8 +301,6 @@ class RoutinesProvider with ChangeNotifier {
routine.dayData = dayDataEntriesDisplay;
routine.dayDataGym = dayDataEntriesGym;
routine.dayDataCurrentIteration = currentIteration;
routine.dayDataCurrentIterationGym = currentIterationGym;
// Logs
routine.sessions = List<WorkoutSessionApi>.from(sessionDataEntries);
@@ -327,7 +308,7 @@ class RoutinesProvider with ChangeNotifier {
for (final log in session.logs) {
log.weightUnit = _weightUnits.firstWhere((e) => e.id == log.weightUnitId);
log.repetitionUnit = _repetitionUnits.firstWhere((e) => e.id == log.repetitionsUnitId);
log.exerciseBase = (await _exercises.fetchAndSetExercise(log.exerciseId))!;
log.exerciseBase = (await _exerciseProvider.fetchAndSetExercise(log.exerciseId))!;
}
}
@@ -535,7 +516,7 @@ class RoutinesProvider with ChangeNotifier {
baseProvider.makeUrl(_slotEntriesUrlPath),
);
final newEntry = SlotEntry.fromJson(data);
newEntry.exerciseObj = (await _exercises.fetchAndSetExercise(newEntry.exerciseId))!;
newEntry.exerciseObj = (await _exerciseProvider.fetchAndSetExercise(newEntry.exerciseId))!;
for (final routine in _routines) {
for (final day in routine.days) {
@@ -584,10 +565,10 @@ class RoutinesProvider with ChangeNotifier {
return _routineConfigWeights;
case ConfigType.maxWeight:
return _routineConfigMaxWeights;
case ConfigType.reps:
return _routineConfigReps;
case ConfigType.maxReps:
return _routineConfigMaxReps;
case ConfigType.repetitions:
return _routineConfigRepetitions;
case ConfigType.maxRepetitions:
return _routineConfigMaxRepetitions;
case ConfigType.rir:
return _routineConfigRir;
case ConfigType.maxRir:
@@ -696,7 +677,7 @@ class RoutinesProvider with ChangeNotifier {
newLog.weightUnit = _weightUnits.firstWhere((e) => e.id == log.weightUnitId);
newLog.repetitionUnit = _repetitionUnits.firstWhere((e) => e.id == log.weightUnitId);
newLog.exerciseBase = (await _exercises.fetchAndSetExercise(log.exerciseId))!;
newLog.exerciseBase = (await _exerciseProvider.fetchAndSetExercise(log.exerciseId))!;
final plan = findById(newLog.routineId);
final session = plan.sessions.firstWhere((element) => element.session.id == newLog.sessionId);

View File

@@ -19,7 +19,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:wger/providers/routines.dart';
import 'package:wger/widgets/routines/app_bar.dart';
import 'package:wger/widgets/core/app_bar.dart';
import 'package:wger/widgets/routines/routine_edit.dart';
class RoutineEditScreen extends StatelessWidget {
@@ -34,7 +34,7 @@ class RoutineEditScreen extends StatelessWidget {
final routine = Provider.of<RoutinesProvider>(context).findById(routineId);
return Scaffold(
appBar: RoutineDetailAppBar(routine),
appBar: EmptyAppBar(routine.name),
body: RoutineEdit(routine),
);
}

View File

@@ -132,7 +132,7 @@ class _ReorderableDaysListState extends State<ReorderableDaysList> {
),
onTap: () async {
final day = Day.empty();
day.name = i18n.newDay;
day.name = '${i18n.newDay} ${widget.days.length + 1}';
day.routineId = widget.routineId;
final newDay = await provider.addDay(day);

View File

@@ -20,12 +20,12 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wger/models/workouts/slot_entry.dart';
class RepsInputWidget extends StatelessWidget {
final _repsController = TextEditingController();
class RepetitionsInputWidget extends StatelessWidget {
final _repetitionsController = TextEditingController();
final SlotEntry _setting;
final bool _detailed;
RepsInputWidget(this._setting, this._detailed);
RepetitionsInputWidget(this._setting, this._detailed);
@override
Widget build(BuildContext context) {
@@ -34,7 +34,7 @@ class RepsInputWidget extends StatelessWidget {
labelText: _detailed ? AppLocalizations.of(context).repetitions : '',
errorMaxLines: 2,
),
controller: _repsController,
controller: _repetitionsController,
keyboardType: TextInputType.number,
validator: (value) {
try {

View File

@@ -26,12 +26,11 @@ import 'package:wger/providers/routines.dart';
///
/// Can be used with a Setting or a Log object
class RepetitionUnitInputWidget extends StatefulWidget {
final int _initialValue;
late int selectedRepetitionUnit;
final ValueChanged<int> onChanged;
late int? selectedRepetitionUnit;
final ValueChanged<int?> onChanged;
RepetitionUnitInputWidget(this._initialValue, {required this.onChanged}) {
selectedRepetitionUnit = _initialValue;
RepetitionUnitInputWidget(initialValue, {required this.onChanged}) {
selectedRepetitionUnit = initialValue;
}
@override
@@ -43,7 +42,9 @@ class _RepetitionUnitInputWidgetState extends State<RepetitionUnitInputWidget> {
Widget build(BuildContext context) {
final unitProvider = context.read<RoutinesProvider>();
RepetitionUnit selectedWeightUnit = unitProvider.findRepetitionUnitById(widget._initialValue);
RepetitionUnit? selectedWeightUnit = widget.selectedRepetitionUnit != null
? unitProvider.findRepetitionUnitById(widget.selectedRepetitionUnit!)
: null;
return DropdownButtonFormField(
value: selectedWeightUnit,

View File

@@ -78,8 +78,8 @@ class _SlotEntryFormState extends State<SlotEntryForm> {
final weightController = TextEditingController();
final maxWeightController = TextEditingController();
final repsController = TextEditingController();
final maxRepsController = TextEditingController();
final repetitionsController = TextEditingController();
final maxRepetitionsController = TextEditingController();
final restController = TextEditingController();
final maxRestController = TextEditingController();
final rirController = TextEditingController();
@@ -102,11 +102,12 @@ class _SlotEntryFormState extends State<SlotEntryForm> {
maxWeightController.text = widget.entry.maxWeightConfigs.first.value.toString();
}
if (widget.entry.repsConfigs.isNotEmpty) {
repsController.text = widget.entry.repsConfigs.first.value.round().toString();
if (widget.entry.repetitionsConfigs.isNotEmpty) {
repetitionsController.text = widget.entry.repetitionsConfigs.first.value.round().toString();
}
if (widget.entry.maxRepsConfigs.isNotEmpty) {
maxRepsController.text = widget.entry.maxRepsConfigs.first.value.round().toString();
if (widget.entry.maxRepetitionsConfigs.isNotEmpty) {
maxRepetitionsController.text =
widget.entry.maxRepetitionsConfigs.first.value.round().toString();
}
if (widget.entry.restTimeConfigs.isNotEmpty) {
@@ -126,8 +127,8 @@ class _SlotEntryFormState extends State<SlotEntryForm> {
weightController.dispose();
maxWeightController.dispose();
repsController.dispose();
maxRepsController.dispose();
repetitionsController.dispose();
maxRepetitionsController.dispose();
restController.dispose();
maxRestController.dispose();
@@ -252,7 +253,7 @@ class _SlotEntryFormState extends State<SlotEntryForm> {
children: [
Flexible(
child: TextFormField(
controller: repsController,
controller: repetitionsController,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: i18n.repetitions),
validator: (value) {
@@ -266,7 +267,7 @@ class _SlotEntryFormState extends State<SlotEntryForm> {
if (!widget.simpleMode)
Flexible(
child: TextFormField(
controller: maxRepsController,
controller: maxRepetitionsController,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: i18n.max),
validator: (value) {
@@ -348,13 +349,13 @@ class _SlotEntryFormState extends State<SlotEntryForm> {
provider.handleConfig(
widget.entry,
repsController.text,
ConfigType.reps,
repetitionsController.text,
ConfigType.repetitions,
);
provider.handleConfig(
widget.entry,
maxRepsController.text,
ConfigType.maxReps,
maxRepetitionsController.text,
ConfigType.maxRepetitions,
);
provider.handleConfig(

View File

@@ -26,12 +26,11 @@ import 'package:wger/providers/routines.dart';
///
/// Can be used with a Setting or a Log object
class WeightUnitInputWidget extends StatefulWidget {
final int _initialValue;
late int selectedWeightUnit;
final ValueChanged<int> onChanged;
late int? selectedWeightUnit;
final ValueChanged<int?> onChanged;
WeightUnitInputWidget(this._initialValue, {required this.onChanged}) {
selectedWeightUnit = _initialValue;
WeightUnitInputWidget(initialValue, {required this.onChanged}) {
selectedWeightUnit = initialValue;
}
@override
@@ -43,7 +42,9 @@ class _WeightUnitInputWidgetState extends State<WeightUnitInputWidget> {
Widget build(BuildContext context) {
final unitProvider = context.read<RoutinesProvider>();
WeightUnit selectedWeightUnit = unitProvider.findWeightUnitById(widget._initialValue);
WeightUnit? selectedWeightUnit = widget.selectedWeightUnit != null
? unitProvider.findWeightUnitById(widget.selectedWeightUnit!)
: null;
return DropdownButtonFormField(
value: selectedWeightUnit,

View File

@@ -311,7 +311,7 @@ class LogPage extends StatefulWidget {
class _LogPageState extends State<LogPage> {
final _form = GlobalKey<FormState>();
String rirValue = SlotEntry.DEFAULT_RIR;
final _repsController = TextEditingController();
final _repetitionsController = TextEditingController();
final _weightController = TextEditingController();
var _detailed = false;
bool _isSaving = false;
@@ -325,7 +325,7 @@ class _LogPageState extends State<LogPage> {
focusNode = FocusNode();
if (widget._configData.repetitions != null) {
_repsController.text = widget._configData.repetitions!.toString();
_repetitionsController.text = widget._configData.repetitions!.toString();
}
if (widget._configData.weight != null) {
@@ -336,7 +336,7 @@ class _LogPageState extends State<LogPage> {
@override
void dispose() {
focusNode.dispose();
_repsController.dispose();
_repetitionsController.dispose();
_weightController.dispose();
super.dispose();
}
@@ -348,9 +348,9 @@ class _LogPageState extends State<LogPage> {
icon: const Icon(Icons.remove, color: Colors.black),
onPressed: () {
try {
final int newValue = int.parse(_repsController.text) - 1;
final int newValue = int.parse(_repetitionsController.text) - 1;
if (newValue > 0) {
_repsController.text = newValue.toString();
_repetitionsController.text = newValue.toString();
}
} on FormatException {}
},
@@ -361,7 +361,7 @@ class _LogPageState extends State<LogPage> {
labelText: AppLocalizations.of(context).repetitions,
),
enabled: true,
controller: _repsController,
controller: _repetitionsController,
keyboardType: TextInputType.number,
focusNode: focusNode,
onFieldSubmitted: (_) {},
@@ -383,8 +383,8 @@ class _LogPageState extends State<LogPage> {
icon: const Icon(Icons.add, color: Colors.black),
onPressed: () {
try {
final int newValue = int.parse(_repsController.text) + 1;
_repsController.text = newValue.toString();
final int newValue = int.parse(_repetitionsController.text) + 1;
_repetitionsController.text = newValue.toString();
} on FormatException {}
},
),
@@ -585,7 +585,7 @@ class _LogPageState extends State<LogPage> {
onTap: () {
setState(() {
// Text field
_repsController.text = log.repetitions.toString();
_repetitionsController.text = log.repetitions.toString();
_weightController.text = log.weight.toString();
// Drop downs