From 833d4796bbce0566c138d63e5bdc2aa2ffec17fd Mon Sep 17 00:00:00 2001 From: Benjamin Carayon Date: Wed, 4 Mar 2026 10:57:41 +0100 Subject: [PATCH 1/2] automatic fixes --- integration_test/3_gym_mode.dart | 2 +- lib/helpers/i18n.dart | 1 + lib/models/exercises/exercise.dart | 2 +- lib/models/measurements/measurement_category.dart | 2 +- lib/models/workouts/base_config.dart | 2 +- lib/providers/nutrition.dart | 2 +- lib/providers/routines.dart | 2 +- lib/widgets/add_exercise/add_exercise_dropdown_button.dart | 2 +- lib/widgets/add_exercise/license_info_widget.dart | 2 +- lib/widgets/add_exercise/preview_images.dart | 2 +- lib/widgets/add_exercise/steps/step_2_variations.dart | 4 ++-- lib/widgets/add_exercise/steps/step_4_translations.dart | 6 +++--- lib/widgets/add_exercise/steps/step_5_images.dart | 2 +- lib/widgets/dashboard/widgets/measurements.dart | 2 +- lib/widgets/exercises/forms.dart | 2 +- lib/widgets/measurements/charts.dart | 3 +-- lib/widgets/nutrition/charts.dart | 4 ++-- lib/widgets/nutrition/nutrition_tile.dart | 4 ++-- lib/widgets/routines/logs/session_info.dart | 2 +- test/exercises/contribute_exercise_test.dart | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) diff --git a/integration_test/3_gym_mode.dart b/integration_test/3_gym_mode.dart index 16fdfbdda..7e14c3d4d 100644 --- a/integration_test/3_gym_mode.dart +++ b/integration_test/3_gym_mode.dart @@ -92,7 +92,7 @@ Widget createGymModeResultsScreen({String locale = 'en'}) { gymStateProvider.overrideWithValue( GymModeState( routine: routine, - dayId: routine.days.first.id!, + dayId: routine.days.first.id, iteration: 1, showExercisePages: true, showTimerPages: true, diff --git a/lib/helpers/i18n.dart b/lib/helpers/i18n.dart index 4da3c04d4..b1732d396 100644 --- a/lib/helpers/i18n.dart +++ b/lib/helpers/i18n.dart @@ -1,4 +1,5 @@ /// This code is autogenerated in the backend repo in extract-i18n.py do not edit! +library; /// Translate dynamic strings that are returned from the server /// These strings such as categories or equipment are returned by the server diff --git a/lib/models/exercises/exercise.dart b/lib/models/exercises/exercise.dart index dca5341d0..30f95d47b 100644 --- a/lib/models/exercises/exercise.dart +++ b/lib/models/exercises/exercise.dart @@ -205,7 +205,7 @@ class Exercise extends Equatable { (e) => e.languageObj.shortName == LANGUAGE_SHORT_ENGLISH, orElse: () { _logger.info( - 'Could not find fallback english translation for exercise-ID ${id}, returning ' + 'Could not find fallback english translation for exercise-ID $id, returning ' 'first language (${translations.first.languageObj.shortName}) instead.', ); return translations.first; diff --git a/lib/models/measurements/measurement_category.dart b/lib/models/measurements/measurement_category.dart index e5c8cdfd3..6328c986f 100644 --- a/lib/models/measurements/measurement_category.dart +++ b/lib/models/measurements/measurement_category.dart @@ -58,5 +58,5 @@ class MeasurementCategory extends Equatable { // Helper function which makes the entries list of the toJson output null, as it isn't needed //ignore: always_declare_return_types - static _nullValue(_) => null; + static Null _nullValue(_) => null; } diff --git a/lib/models/workouts/base_config.dart b/lib/models/workouts/base_config.dart index a7ffbd7bb..f195ffbbc 100644 --- a/lib/models/workouts/base_config.dart +++ b/lib/models/workouts/base_config.dart @@ -55,7 +55,7 @@ class BaseConfig { required this.value, this.operation = 'r', this.step = 'abs', - this.requirements = null, + this.requirements, }); BaseConfig.firstIteration(this.value, this.slotEntryId) { diff --git a/lib/providers/nutrition.dart b/lib/providers/nutrition.dart index 12435e372..7ae238dd3 100644 --- a/lib/providers/nutrition.dart +++ b/lib/providers/nutrition.dart @@ -360,7 +360,7 @@ class NutritionPlansProvider with ChangeNotifier { (database.delete(database.ingredients)..where((i) => i.id.equals(ingredientId))).go(); } } else { - _logger.info("Fetching ingredient ID $ingredientId from server"); + _logger.info('Fetching ingredient ID $ingredientId from server'); final data = await baseProvider.fetch( baseProvider.makeUrl(_ingredientInfoPath, id: ingredientId), ); diff --git a/lib/providers/routines.dart b/lib/providers/routines.dart index 692c36ceb..7072afe66 100644 --- a/lib/providers/routines.dart +++ b/lib/providers/routines.dart @@ -691,7 +691,7 @@ class RoutinesProvider with ChangeNotifier { }*/ Future deleteLog(int logId, int routineId) async { - _logger.fine('Deleting log ${logId}'); + _logger.fine('Deleting log $logId'); await baseProvider.deleteRequest(_logsUrlPath, logId); await fetchAndSetRoutineFull(routineId); } diff --git a/lib/widgets/add_exercise/add_exercise_dropdown_button.dart b/lib/widgets/add_exercise/add_exercise_dropdown_button.dart index 7b8d71dd7..2b82ff0c1 100644 --- a/lib/widgets/add_exercise/add_exercise_dropdown_button.dart +++ b/lib/widgets/add_exercise/add_exercise_dropdown_button.dart @@ -37,7 +37,7 @@ class _AddExerciseDropdownButtonState extends State { }); widget.onChange(value); }, - value: _selectedItem, + initialValue: _selectedItem, decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), border: const OutlineInputBorder( diff --git a/lib/widgets/add_exercise/license_info_widget.dart b/lib/widgets/add_exercise/license_info_widget.dart index 59e9609b2..9324df7af 100644 --- a/lib/widgets/add_exercise/license_info_widget.dart +++ b/lib/widgets/add_exercise/license_info_widget.dart @@ -11,7 +11,7 @@ import 'package:wger/l10n/generated/app_localizations.dart'; /// Being a separate widget allows Flutter to optimize rendering since /// this content never changes. class LicenseInfoWidget extends StatelessWidget { - const LicenseInfoWidget({Key? key}) : super(key: key); + const LicenseInfoWidget({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/widgets/add_exercise/preview_images.dart b/lib/widgets/add_exercise/preview_images.dart index 3da95b587..60de475b9 100644 --- a/lib/widgets/add_exercise/preview_images.dart +++ b/lib/widgets/add_exercise/preview_images.dart @@ -89,7 +89,7 @@ class PreviewExerciseImages extends StatelessWidget { height: 120, margin: const EdgeInsets.only(right: 8), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceVariant, + color: Theme.of(context).colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(8), border: Border.all( color: Theme.of(context).colorScheme.outline, diff --git a/lib/widgets/add_exercise/steps/step_2_variations.dart b/lib/widgets/add_exercise/steps/step_2_variations.dart index 4fcb639ba..3ab25e65d 100644 --- a/lib/widgets/add_exercise/steps/step_2_variations.dart +++ b/lib/widgets/add_exercise/steps/step_2_variations.dart @@ -50,7 +50,7 @@ class Step2Variations extends StatelessWidget { ), ), Consumer( - builder: (ctx, provider, __) => Switch( + builder: (ctx, provider, _) => Switch( value: provider.variationId == key, onChanged: (state) => provider.variationId = key, ), @@ -83,7 +83,7 @@ class Step2Variations extends StatelessWidget { ), ), Consumer( - builder: (ctx, provider, __) => Switch( + builder: (ctx, provider, _) => Switch( value: provider.variationConnectToExercise == base.id, onChanged: (state) => provider.variationConnectToExercise = base.id, ), diff --git a/lib/widgets/add_exercise/steps/step_4_translations.dart b/lib/widgets/add_exercise/steps/step_4_translations.dart index d8f4a778f..fdfc6d559 100644 --- a/lib/widgets/add_exercise/steps/step_4_translations.dart +++ b/lib/widgets/add_exercise/steps/step_4_translations.dart @@ -61,7 +61,7 @@ class _Step4TranslationState extends State { AddExerciseTextArea( title: '${i18n.name}*', validator: (name) => validateName(name, context), - onSaved: (String? name) => addExerciseProvider.exerciseNameTrans = name!, + onSaved: (String? name) => addExerciseProvider.exerciseNameTrans = name, ), AddExerciseTextArea( title: i18n.alternativeNames, @@ -86,14 +86,14 @@ class _Step4TranslationState extends State { addExerciseProvider.alternateNamesTrans = alternateName!.split('\n'), ), Consumer( - builder: (ctx, provider, __) => AddExerciseTextArea( + builder: (ctx, provider, _) => AddExerciseTextArea( onChange: (value) => {}, title: '${i18n.description}*', helperText: i18n.enterTextInLanguage, isMultiline: true, validator: (name) => validateExerciseDescription(name, context), onSaved: (String? description) => - addExerciseProvider.descriptionTrans = description!, + addExerciseProvider.descriptionTrans = description, ), ), ], diff --git a/lib/widgets/add_exercise/steps/step_5_images.dart b/lib/widgets/add_exercise/steps/step_5_images.dart index 6d4361225..95246139e 100644 --- a/lib/widgets/add_exercise/steps/step_5_images.dart +++ b/lib/widgets/add_exercise/steps/step_5_images.dart @@ -179,7 +179,7 @@ class _Step5ImagesState extends State with ExerciseImagePickerMixin // Image picker or preview - shown when not entering metadata if (_currentImageToAdd == null) Consumer( - builder: (ctx, provider, __) { + builder: (ctx, provider, _) { if (provider.exerciseImages.isNotEmpty) { // Show preview of images that have been added with metadata return Column( diff --git a/lib/widgets/dashboard/widgets/measurements.dart b/lib/widgets/dashboard/widgets/measurements.dart index ed7fbd8f9..c38124803 100644 --- a/lib/widgets/dashboard/widgets/measurements.dart +++ b/lib/widgets/dashboard/widgets/measurements.dart @@ -55,7 +55,7 @@ class _DashboardMeasurementWidgetState extends State ); } return Consumer( - builder: (context, _, __) => Card( + builder: (context, _, _) => Card( child: Column( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/widgets/exercises/forms.dart b/lib/widgets/exercises/forms.dart index d07577280..0465e7061 100644 --- a/lib/widgets/exercises/forms.dart +++ b/lib/widgets/exercises/forms.dart @@ -58,7 +58,7 @@ class _ExerciseCategoryInputWidgetState extends State { return BarChart( BarChartData( alignment: BarChartAlignment.center, - barTouchData: BarTouchData(enabled: false), + barTouchData: const BarTouchData(enabled: false), titlesData: FlTitlesData( show: true, bottomTitles: AxisTitles( diff --git a/lib/widgets/nutrition/nutrition_tile.dart b/lib/widgets/nutrition/nutrition_tile.dart index 4e1cc5b48..22de42b3c 100644 --- a/lib/widgets/nutrition/nutrition_tile.dart +++ b/lib/widgets/nutrition/nutrition_tile.dart @@ -32,8 +32,8 @@ class NutritionTile extends StatelessWidget { Expanded( child: Column( children: [ - if (title != null) title!, - if (subtitle != null) subtitle!, + ?title, + ?subtitle, ], ), ), diff --git a/lib/widgets/routines/logs/session_info.dart b/lib/widgets/routines/logs/session_info.dart index a8293010f..4110d26be 100644 --- a/lib/widgets/routines/logs/session_info.dart +++ b/lib/widgets/routines/logs/session_info.dart @@ -57,7 +57,7 @@ class _SessionInfoState extends State { ), if (editMode) SessionForm( - widget._session.routineId!, + widget._session.routineId, onSaved: () => setState(() => editMode = false), session: widget._session, ) diff --git a/test/exercises/contribute_exercise_test.dart b/test/exercises/contribute_exercise_test.dart index df1c3b4ba..3c303130e 100644 --- a/test/exercises/contribute_exercise_test.dart +++ b/test/exercises/contribute_exercise_test.dart @@ -284,7 +284,7 @@ void main() { await tester.pumpAndSettle(); // Verify initial step is 0 - var stepper = tester.widget(find.byType(Stepper)); + final stepper = tester.widget(find.byType(Stepper)); expect(stepper.currentStep, equals(0)); // Get localized text for UI elements From eff66ff0a05b564b0f60d7156b77d4db25443315 Mon Sep 17 00:00:00 2001 From: Benjamin Carayon Date: Wed, 4 Mar 2026 13:57:57 +0100 Subject: [PATCH 2/2] Implementation of a custom barweight setting (TextField instead of predefined dropdown list with fixed values). In the Log Page, increasing the weight with the quick add and remove buttons now use the minimum weight plate available. --- .../measurements/measurement_category.dart | 4 +-- lib/providers/plate_weights.dart | 7 ---- lib/widgets/routines/forms/weight.dart | 2 ++ lib/widgets/routines/gym_mode/log_page.dart | 31 +++++++++++------ lib/widgets/routines/plate_calculator.dart | 34 ++++++++++--------- 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/lib/models/measurements/measurement_category.dart b/lib/models/measurements/measurement_category.dart index 6328c986f..526a8e044 100644 --- a/lib/models/measurements/measurement_category.dart +++ b/lib/models/measurements/measurement_category.dart @@ -57,6 +57,6 @@ class MeasurementCategory extends Equatable { List get props => [id, name, unit, entries]; // Helper function which makes the entries list of the toJson output null, as it isn't needed - //ignore: always_declare_return_types - static Null _nullValue(_) => null; + static List? _nullValue(_) => null; } + diff --git a/lib/providers/plate_weights.dart b/lib/providers/plate_weights.dart index 493bad04c..7df2f97a4 100644 --- a/lib/providers/plate_weights.dart +++ b/lib/providers/plate_weights.dart @@ -55,9 +55,6 @@ class PlateCalculatorState { final List availablePlatesKg = const [0.5, 1, 1.25, 2, 2.5, 5, 10, 15, 20, 25]; final List availablePlatesLb = const [2.5, 5, 10, 25, 35, 45]; - final availableBarWeightsKg = [10, 15, 20]; - final availableBarWeightsLb = [15, 20, 25, 33, 45]; - PlateCalculatorState({ this.useColors = true, num? barWeight, @@ -106,10 +103,6 @@ class PlateCalculatorState { return isMetric ? availablePlatesKg : availablePlatesLb; } - List get availableBarsWeights { - return isMetric ? availableBarWeightsKg : availableBarWeightsLb; - } - List get platesList { return plateCalculator(totalWeight, barWeight, selectedPlates); } diff --git a/lib/widgets/routines/forms/weight.dart b/lib/widgets/routines/forms/weight.dart index 51987ce96..4c49ee14d 100644 --- a/lib/widgets/routines/forms/weight.dart +++ b/lib/widgets/routines/forms/weight.dart @@ -139,6 +139,7 @@ class _WeightInputWidgetState extends ConsumerState { final base = currentWeight ?? 0; final newValue = base - widget.valueChange; if (newValue >= 0 && log != null) { + plateProvider.setWeight(newValue); logProvider.setWeight(newValue); } }, @@ -181,6 +182,7 @@ class _WeightInputWidgetState extends ConsumerState { final base = currentWeight ?? 0; final newValue = base + widget.valueChange; if (log != null) { + plateProvider.setWeight(newValue); logProvider.setWeight(newValue); } }, diff --git a/lib/widgets/routines/gym_mode/log_page.dart b/lib/widgets/routines/gym_mode/log_page.dart index cd0eef568..2ffeff95e 100644 --- a/lib/widgets/routines/gym_mode/log_page.dart +++ b/lib/widgets/routines/gym_mode/log_page.dart @@ -61,6 +61,17 @@ class LogPage extends ConsumerWidget { } final setConfigData = slotEntryPage.setConfigData!; + // Calculate weightRounding as 2 times the smallest available plate weight + final plateProvider = ref.read(plateCalculatorProvider.notifier); + final selectedPlates = plateProvider.state.selectedPlates; + final minPlate = selectedPlates.isNotEmpty ? selectedPlates.reduce((a, b) => a < b ? a : b) : 1.25; + final calculatedWeightRounding = 2 * minPlate; + + // Create a new SetConfigData with the calculated weightRounding + final updatedConfigData = setConfigData.copyWith( + weightRounding: calculatedWeightRounding, + ); + final log = ref.read(gymLogProvider); // Mark done sets @@ -84,17 +95,17 @@ class LogPage extends ConsumerWidget { children: [ Column( children: [ - Text( - setConfigData.textRepr, - textAlign: TextAlign.center, + Text( + updatedConfigData.textRepr, + textAlign: TextAlign.center, style: theme.textTheme.headlineMedium?.copyWith( color: Theme.of(context).colorScheme.primary, decoration: decorationStyle, - ), - ), - if (setConfigData.type != SlotEntryType.normal) + ), + ), + if (updatedConfigData.type != SlotEntryType.normal) Text( - setConfigData.type.name.toUpperCase(), + updatedConfigData.type.name.toUpperCase(), textAlign: TextAlign.center, style: theme.textTheme.headlineSmall?.copyWith( color: Theme.of(context).colorScheme.primary, @@ -115,8 +126,8 @@ class LogPage extends ConsumerWidget { ), ), if (log.exercise.showPlateCalculator) const LogsPlatesWidget(), - if (slotEntryPage.setConfigData!.comment.isNotEmpty) - Text(slotEntryPage.setConfigData!.comment, textAlign: TextAlign.center), + if (updatedConfigData.comment.isNotEmpty) + Text(updatedConfigData.comment, textAlign: TextAlign.center), const SizedBox(height: 10), Expanded( child: (gymState.routine.filterLogsByExercise(log.exerciseId).isNotEmpty) @@ -135,7 +146,7 @@ class LogPage extends ConsumerWidget { padding: const EdgeInsets.symmetric(vertical: 5), child: LogFormWidget( controller: _controller, - configData: setConfigData, + configData: updatedConfigData, key: ValueKey('log-form-${slotEntryPage.uuid}'), ), ), diff --git a/lib/widgets/routines/plate_calculator.dart b/lib/widgets/routines/plate_calculator.dart index 4e5c06b73..c8778c969 100644 --- a/lib/widgets/routines/plate_calculator.dart +++ b/lib/widgets/routines/plate_calculator.dart @@ -108,24 +108,26 @@ class _AddPlateWeightsState extends ConsumerState { ), Padding( padding: const EdgeInsets.all(10), - child: DropdownMenu( - key: const ValueKey('barWeightDropdown'), - width: double.infinity, - initialSelection: plateWeightsState.barWeight, - requestFocusOnTap: true, - label: Text(i18n.barWeight), - onSelected: (num? value) { - if (value == null) { - return; + child: TextField( + key: const ValueKey('barWeightTextField'), + controller: TextEditingController(text: plateWeightsState.barWeight.toString()), + keyboardType: TextInputType.number, + decoration: InputDecoration( + labelText: i18n.barWeight, + suffix: Text(plateWeightsState.isMetric ? i18n.kg : i18n.lb), + ), + onChanged: (text) { + final parsed = num.tryParse(text); + if (parsed != null) { + plateWeightsNotifier.setBarWeight(parsed); + } + }, + onSubmitted: (text) { + final parsed = num.tryParse(text); + if (parsed != null) { + plateWeightsNotifier.setBarWeight(parsed); } - plateWeightsNotifier.setBarWeight(value); }, - dropdownMenuEntries: plateWeightsState.availableBarsWeights.map((value) { - return DropdownMenuEntry( - value: value, - label: value.toString(), - ); - }).toList(), ), ), SwitchListTile(