mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Add bar weight and color options to the plate calculator provider
This commit is contained in:
@@ -37,7 +37,9 @@
|
||||
"@passwordTooShort": {
|
||||
"description": "Error message when the user a password that is too short"
|
||||
},
|
||||
"selectAvailablePlates": "Select Available Plates",
|
||||
"selectAvailablePlates": "Select available plates",
|
||||
"barWeight": "Bar weight",
|
||||
"useColors": "Use colors",
|
||||
"password": "Password",
|
||||
"@password": {},
|
||||
"confirmPassword": "Confirm password",
|
||||
|
||||
@@ -90,20 +90,20 @@ void main() async {
|
||||
await PreferenceHelper.instance.migrationSupportFunctionForSharedPreferences();
|
||||
|
||||
// Catch errors from Flutter itself (widget build, layout, paint, etc.)
|
||||
FlutterError.onError = (FlutterErrorDetails details) {
|
||||
final stack = details.stack ?? StackTrace.empty;
|
||||
if (kDebugMode) {
|
||||
FlutterError.dumpErrorToConsole(details);
|
||||
}
|
||||
|
||||
// Don't show the full error dialog for network image loading errors.
|
||||
if (details.exception is NetworkImageLoadException) {
|
||||
return;
|
||||
}
|
||||
|
||||
showGeneralErrorDialog(details.exception, stack);
|
||||
// throw details.exception;
|
||||
};
|
||||
// FlutterError.onError = (FlutterErrorDetails details) {
|
||||
// final stack = details.stack ?? StackTrace.empty;
|
||||
// if (kDebugMode) {
|
||||
// FlutterError.dumpErrorToConsole(details);
|
||||
// }
|
||||
//
|
||||
// // Don't show the full error dialog for network image loading errors.
|
||||
// if (details.exception is NetworkImageLoadException) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // showGeneralErrorDialog(details.exception, stack);
|
||||
// // throw details.exception;
|
||||
// };
|
||||
|
||||
// Catch errors that happen outside of the Flutter framework (e.g., in async operations)
|
||||
PlatformDispatcher.instance.onError = (error, stack) {
|
||||
|
||||
@@ -11,6 +11,9 @@ import 'package:wger/helpers/shared_preferences.dart';
|
||||
const DEFAULT_KG_PLATES = [2.5, 5, 10, 15, 20, 25];
|
||||
const DEFAULT_LB_PLATES = [2.5, 5, 10, 25, 35, 45];
|
||||
|
||||
const DEFAULT_BAR_WEIGHT_KG = 20;
|
||||
const DEFAULT_BAR_WEIGHT_LB = 45;
|
||||
|
||||
const PREFS_KEY_PLATES = 'selectedPlates';
|
||||
|
||||
final plateCalculatorProvider =
|
||||
@@ -21,9 +24,6 @@ final plateCalculatorProvider =
|
||||
class PlateCalculatorState {
|
||||
final _logger = Logger('PlateWeightsState');
|
||||
|
||||
final barWeightKg = 20;
|
||||
final barWeightLb = 45;
|
||||
|
||||
// https://en.wikipedia.org/wiki/Barbell#Bumper_plates
|
||||
final Map<double, Color> plateColorMapKg = {
|
||||
25: Colors.red,
|
||||
@@ -48,26 +48,68 @@ class PlateCalculatorState {
|
||||
1.25: Colors.white,
|
||||
};
|
||||
|
||||
final bool useColors;
|
||||
final bool isMetric;
|
||||
final num totalWeight;
|
||||
final num barWeight;
|
||||
final List<num> selectedPlates;
|
||||
final List<num> availablePlatesKg = const [0.5, 1, 1.25, 2, 2.5, 5, 10, 15, 20, 25];
|
||||
final List<num> 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,
|
||||
this.isMetric = true,
|
||||
this.totalWeight = 0,
|
||||
List<num>? selectedPlates,
|
||||
}) : selectedPlates = selectedPlates ?? [...DEFAULT_KG_PLATES];
|
||||
}) : barWeight = barWeight ?? (isMetric ? DEFAULT_BAR_WEIGHT_KG : DEFAULT_BAR_WEIGHT_LB),
|
||||
selectedPlates =
|
||||
selectedPlates ?? (isMetric ? [...DEFAULT_KG_PLATES] : [...DEFAULT_LB_PLATES]);
|
||||
|
||||
num get barWeight {
|
||||
return isMetric ? barWeightKg : barWeightLb;
|
||||
PlateCalculatorState.fromJson(Map<String, dynamic> plateData)
|
||||
: useColors = plateData['useColors'] ?? true,
|
||||
isMetric = plateData['isMetric'] ?? true,
|
||||
selectedPlates = plateData['selectedPlates']?.cast<num>() ?? [...DEFAULT_KG_PLATES],
|
||||
barWeight = plateData['barWeight'] ??
|
||||
((plateData['isMetric'] ?? true) ? DEFAULT_BAR_WEIGHT_KG : DEFAULT_BAR_WEIGHT_LB),
|
||||
totalWeight = 0;
|
||||
|
||||
PlateCalculatorState copyWith({
|
||||
bool? useColors,
|
||||
bool? isMetric,
|
||||
num? totalWeight,
|
||||
num? barWeight,
|
||||
List<num>? selectedPlates,
|
||||
}) {
|
||||
return PlateCalculatorState(
|
||||
useColors: useColors ?? this.useColors,
|
||||
isMetric: isMetric ?? this.isMetric,
|
||||
totalWeight: totalWeight ?? this.totalWeight,
|
||||
barWeight: barWeight ?? this.barWeight,
|
||||
selectedPlates: selectedPlates ?? this.selectedPlates,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'useColors': useColors,
|
||||
'isMetric': isMetric,
|
||||
'selectedPlates': selectedPlates,
|
||||
'barWeight': barWeight,
|
||||
};
|
||||
}
|
||||
|
||||
List<num> get availablePlates {
|
||||
return isMetric ? availablePlatesKg : availablePlatesLb;
|
||||
}
|
||||
|
||||
List<num> get availableBarsWeights {
|
||||
return isMetric ? availableBarWeightsKg : availableBarWeightsLb;
|
||||
}
|
||||
|
||||
List<num> get platesList {
|
||||
return plateCalculator(totalWeight, barWeight, selectedPlates);
|
||||
}
|
||||
@@ -81,27 +123,15 @@ class PlateCalculatorState {
|
||||
}
|
||||
|
||||
Color getColor(num plate) {
|
||||
if (!useColors) {
|
||||
return Colors.grey;
|
||||
}
|
||||
|
||||
if (isMetric) {
|
||||
return plateColorMapKg[plate.toDouble()] ?? Colors.grey;
|
||||
}
|
||||
return plateColorMapLb[plate.toDouble()] ?? Colors.grey;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'isMetric': isMetric, 'selectedPlates': selectedPlates};
|
||||
}
|
||||
|
||||
PlateCalculatorState copyWith({
|
||||
bool? isMetric,
|
||||
num? totalWeight,
|
||||
List<num>? selectedPlates,
|
||||
}) {
|
||||
return PlateCalculatorState(
|
||||
isMetric: isMetric ?? this.isMetric,
|
||||
totalWeight: totalWeight ?? this.totalWeight,
|
||||
selectedPlates: selectedPlates ?? this.selectedPlates,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PlateCalculatorNotifier extends StateNotifier<PlateCalculatorState> {
|
||||
@@ -125,13 +155,11 @@ class PlateCalculatorNotifier extends StateNotifier<PlateCalculatorState> {
|
||||
|
||||
if (prefsData != null) {
|
||||
try {
|
||||
final plateData = json.decode(prefsData);
|
||||
state = state.copyWith(
|
||||
isMetric: plateData['isMetric'] ?? true,
|
||||
selectedPlates: plateData['selectedPlates'].cast<num>() ?? [...DEFAULT_KG_PLATES],
|
||||
);
|
||||
state = PlateCalculatorState.fromJson(json.decode(prefsData));
|
||||
_logger.fine('Plate data loaded from SharedPreferences: ${state.toJson()}');
|
||||
} catch (e) {
|
||||
_logger.fine('Error decoding plate data from SharedPreferences: $e');
|
||||
state = PlateCalculatorState();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +175,15 @@ class PlateCalculatorNotifier extends StateNotifier<PlateCalculatorState> {
|
||||
await saveToSharedPrefs();
|
||||
}
|
||||
|
||||
void setBarWeight(num x) {
|
||||
_logger.fine('Setting bar weight to $x');
|
||||
state = state.copyWith(barWeight: x);
|
||||
}
|
||||
|
||||
void setUseColors(bool value) {
|
||||
state = state.copyWith(useColors: value);
|
||||
}
|
||||
|
||||
void unitChange({WeightUnitEnum? unit}) {
|
||||
final WeightUnitEnum changeTo =
|
||||
unit ?? (state.isMetric ? WeightUnitEnum.lb : WeightUnitEnum.kg);
|
||||
@@ -155,6 +192,7 @@ class PlateCalculatorNotifier extends StateNotifier<PlateCalculatorState> {
|
||||
state = state.copyWith(
|
||||
isMetric: true,
|
||||
totalWeight: 0,
|
||||
barWeight: DEFAULT_BAR_WEIGHT_KG,
|
||||
selectedPlates: [...DEFAULT_KG_PLATES],
|
||||
);
|
||||
}
|
||||
@@ -163,6 +201,7 @@ class PlateCalculatorNotifier extends StateNotifier<PlateCalculatorState> {
|
||||
state = state.copyWith(
|
||||
isMetric: false,
|
||||
totalWeight: 0,
|
||||
barWeight: DEFAULT_BAR_WEIGHT_LB,
|
||||
selectedPlates: [...DEFAULT_LB_PLATES],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:provider/provider.dart' as provider;
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/providers/plate_weights.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
import 'package:wger/widgets/routines/plate_calculator.dart';
|
||||
|
||||
class AddPlateWeights extends ConsumerStatefulWidget {
|
||||
const AddPlateWeights({super.key});
|
||||
class ConfigureAvailablePlates extends ConsumerStatefulWidget {
|
||||
const ConfigureAvailablePlates({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<AddPlateWeights> createState() => _AddPlateWeightsState();
|
||||
ConsumerState<ConfigureAvailablePlates> createState() => _AddPlateWeightsState();
|
||||
}
|
||||
|
||||
class _AddPlateWeightsState extends ConsumerState<AddPlateWeights>
|
||||
with SingleTickerProviderStateMixin {
|
||||
final _unitController = TextEditingController();
|
||||
|
||||
class _AddPlateWeightsState extends ConsumerState<ConfigureAvailablePlates> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -26,19 +21,13 @@ class _AddPlateWeightsState extends ConsumerState<AddPlateWeights>
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_unitController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context);
|
||||
|
||||
final plateWeightsState = ref.watch(plateCalculatorProvider);
|
||||
final plateWeightsNotifier = ref.read(plateCalculatorProvider.notifier);
|
||||
final userProvider = provider.Provider.of<UserProvider>(context);
|
||||
// final userProvider = provider.Provider.of<UserProvider>(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Select Available Plates')),
|
||||
@@ -50,7 +39,6 @@ class _AddPlateWeightsState extends ConsumerState<AddPlateWeights>
|
||||
child: DropdownMenu<WeightUnitEnum>(
|
||||
width: double.infinity,
|
||||
initialSelection: plateWeightsState.isMetric ? WeightUnitEnum.kg : WeightUnitEnum.lb,
|
||||
controller: _unitController,
|
||||
requestFocusOnTap: true,
|
||||
label: Text(i18n.unit),
|
||||
onSelected: (WeightUnitEnum? unit) {
|
||||
@@ -69,6 +57,32 @@ class _AddPlateWeightsState extends ConsumerState<AddPlateWeights>
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: DropdownMenu<num>(
|
||||
width: double.infinity,
|
||||
initialSelection: plateWeightsState.barWeight,
|
||||
requestFocusOnTap: true,
|
||||
label: Text(i18n.barWeight),
|
||||
onSelected: (num? value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
plateWeightsNotifier.setBarWeight(value);
|
||||
},
|
||||
dropdownMenuEntries: plateWeightsState.availableBarsWeights.map((value) {
|
||||
return DropdownMenuEntry<num>(
|
||||
value: value,
|
||||
label: value.toString(),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(i18n.useColors),
|
||||
value: plateWeightsState.useColors,
|
||||
onChanged: (state) => plateWeightsNotifier.setUseColors(state),
|
||||
),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
const double widthThreshold = 450.0;
|
||||
@@ -47,6 +47,8 @@ class GymModeScreen extends StatelessWidget {
|
||||
.first;
|
||||
|
||||
return Scaffold(
|
||||
// backgroundColor: Theme.of(context).cardColor,
|
||||
// primary: false,
|
||||
body: SafeArea(
|
||||
child: Consumer<RoutinesProvider>(
|
||||
builder: (context, value, child) => GymMode(dayDataGym, dayDataDisplay, args.iteration),
|
||||
|
||||
@@ -42,7 +42,6 @@ class ExerciseOverview extends StatelessWidget {
|
||||
_controller,
|
||||
exercisePages: _exercisePages,
|
||||
),
|
||||
const Divider(),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
|
||||
@@ -29,7 +29,7 @@ import 'package:wger/models/workouts/set_config_data.dart';
|
||||
import 'package:wger/models/workouts/slot_data.dart';
|
||||
import 'package:wger/providers/plate_weights.dart';
|
||||
import 'package:wger/providers/routines.dart';
|
||||
import 'package:wger/screens/add_plate_weights.dart';
|
||||
import 'package:wger/screens/configure_plates.dart';
|
||||
import 'package:wger/widgets/core/core.dart';
|
||||
import 'package:wger/widgets/core/progress_indicator.dart';
|
||||
import 'package:wger/widgets/routines/forms/reps_unit.dart';
|
||||
@@ -260,6 +260,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
onChanged: (v) => {},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
if (_detailed)
|
||||
@@ -271,6 +272,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
Flexible(
|
||||
child: WeightUnitInputWidget(widget._log.weightUnitId, onChanged: (v) => {}),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
if (_detailed)
|
||||
@@ -285,6 +287,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
},
|
||||
),
|
||||
SwitchListTile(
|
||||
dense: true,
|
||||
title: Text(AppLocalizations.of(context).setUnitsAndRir),
|
||||
value: _detailed,
|
||||
onChanged: (value) {
|
||||
@@ -293,7 +296,7 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
});
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
FilledButton(
|
||||
onPressed: _isSaving
|
||||
? null
|
||||
: () async {
|
||||
@@ -340,98 +343,119 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
}
|
||||
|
||||
Widget getPastLogs() {
|
||||
return ListView(
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).labelWorkoutLogs,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
...widget._workoutPlan.filterLogsByExercise(widget._exercise.id!, unique: true).map((log) {
|
||||
return ListTile(
|
||||
title: Text(log.singleLogRepTextNoNl),
|
||||
subtitle: Text(
|
||||
DateFormat.yMd(Localizations.localeOf(context).languageCode).format(log.date),
|
||||
),
|
||||
trailing: const Icon(Icons.copy),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
// Text field
|
||||
_repetitionsController.text = log.repetitions?.toString() ?? '';
|
||||
_weightController.text = log.weight?.toString() ?? '';
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
// color: Theme.of(context).secondaryHeaderColor,
|
||||
// color: Theme.of(context).splashColor,
|
||||
// color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
// border: Border.all(color: Colors.black, width: 1),
|
||||
),
|
||||
child: ListView(
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).labelWorkoutLogs,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
...widget._workoutPlan
|
||||
.filterLogsByExercise(widget._exercise.id!, unique: true)
|
||||
.map((log) {
|
||||
return ListTile(
|
||||
title: Text(log.singleLogRepTextNoNl),
|
||||
subtitle: Text(
|
||||
DateFormat.yMd(Localizations.localeOf(context).languageCode).format(log.date),
|
||||
),
|
||||
trailing: const Icon(Icons.copy),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
// Text field
|
||||
_repetitionsController.text = log.repetitions?.toString() ?? '';
|
||||
_weightController.text = log.weight?.toString() ?? '';
|
||||
|
||||
// Drop downs
|
||||
widget._log.rir = log.rir;
|
||||
widget._log.repetitionUnit = log.repetitionsUnitObj;
|
||||
widget._log.weightUnit = log.weightUnitObj;
|
||||
// Drop downs
|
||||
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations.of(context).dataCopied),
|
||||
));
|
||||
});
|
||||
},
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
);
|
||||
}),
|
||||
],
|
||||
widget._log.rir = log.rir;
|
||||
widget._log.repetitionUnit = log.repetitionsUnitObj;
|
||||
widget._log.weightUnit = log.weightUnitObj;
|
||||
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(AppLocalizations.of(context).dataCopied),
|
||||
));
|
||||
});
|
||||
},
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getPlates() {
|
||||
final plateWeightsState = ref.watch(plateCalculatorProvider);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).plateCalculator,
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (context) => const AddPlateWeights()));
|
||||
},
|
||||
icon: const Icon(Icons.settings),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
child: plateWeightsState.hasPlates
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
...plateWeightsState.calculatePlates.entries.map(
|
||||
(entry) => Row(
|
||||
children: [
|
||||
Text(entry.value.toString()),
|
||||
const Text('×'),
|
||||
PlateWeight(
|
||||
value: entry.key,
|
||||
size: 37,
|
||||
padding: 2,
|
||||
margin: 0,
|
||||
color: ref.read(plateCalculatorProvider).getColor(entry.key),
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
child: Column(
|
||||
children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// Text(
|
||||
// AppLocalizations.of(context).plateCalculator,
|
||||
// style: Theme.of(context).textTheme.titleMedium,
|
||||
// ),
|
||||
// IconButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context)
|
||||
// .push(MaterialPageRoute(builder: (context) => const AddPlateWeights()));
|
||||
// },
|
||||
// icon: const Icon(Icons.settings, size: 16),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (context) => const ConfigureAvailablePlates()));
|
||||
},
|
||||
child: SizedBox(
|
||||
child: plateWeightsState.hasPlates
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
...plateWeightsState.calculatePlates.entries.map(
|
||||
(entry) => Row(
|
||||
children: [
|
||||
Text(entry.value.toString()),
|
||||
const Text('×'),
|
||||
PlateWeight(
|
||||
value: entry.key,
|
||||
size: 37,
|
||||
padding: 2,
|
||||
margin: 0,
|
||||
color: ref.read(plateCalculatorProvider).getColor(entry.key),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: MutedText(
|
||||
AppLocalizations.of(context).plateCalculatorNotDivisible,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: MutedText(
|
||||
AppLocalizations.of(context).plateCalculatorNotDivisible,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -444,27 +468,43 @@ class _LogPageState extends ConsumerState<LogPage> {
|
||||
widget._controller,
|
||||
exercisePages: widget._exercisePages,
|
||||
),
|
||||
Center(
|
||||
child: Text(
|
||||
widget._configData.textRepr,
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
textAlign: TextAlign.center,
|
||||
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Center(
|
||||
child: Text(
|
||||
widget._configData.textRepr,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineMedium
|
||||
?.copyWith(color: Theme.of(context).colorScheme.primary),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget._slotData.comment != '')
|
||||
if (widget._slotData.comment.isNotEmpty)
|
||||
Text(widget._slotData.comment, textAlign: TextAlign.center),
|
||||
// Only show calculator for barbell
|
||||
if (widget._log.exercise.equipment.map((e) => e.id).contains(ID_EQUIPMENT_BARBELL))
|
||||
getPlates(),
|
||||
const SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: (widget._workoutPlan.filterLogsByExercise(widget._exercise.id!).isNotEmpty)
|
||||
? getPastLogs()
|
||||
: Container(),
|
||||
),
|
||||
// Only show calculator for barbell
|
||||
if (widget._log.exercise.equipment.map((e) => e.id).contains(ID_EQUIPMENT_BARBELL))
|
||||
getPlates(),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: Card(child: getForm()),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Card(
|
||||
color: Theme.of(context).colorScheme.inversePrimary,
|
||||
// color: Theme.of(context).secondaryHeaderColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5),
|
||||
child: getForm(),
|
||||
),
|
||||
),
|
||||
),
|
||||
NavigationFooter(widget._controller, widget._ratioCompleted),
|
||||
],
|
||||
|
||||
@@ -52,7 +52,7 @@ class NavigationFooter extends StatelessWidget {
|
||||
const SizedBox(width: 48),
|
||||
Expanded(
|
||||
child: LinearProgressIndicator(
|
||||
minHeight: 1.5,
|
||||
minHeight: 3,
|
||||
value: _ratioCompleted,
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(wgerPrimaryColor),
|
||||
),
|
||||
|
||||
@@ -59,7 +59,6 @@ class SessionPage extends StatelessWidget {
|
||||
_controller,
|
||||
exercisePages: _exercisePages,
|
||||
),
|
||||
const Divider(),
|
||||
Expanded(child: Container()),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
|
||||
@@ -21,7 +21,6 @@ class StartPage extends StatelessWidget {
|
||||
_controller,
|
||||
exercisePages: _exercisePages,
|
||||
),
|
||||
const Divider(),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
|
||||
@@ -31,7 +31,7 @@ class PlateWeight extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? color : Colors.black12,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.black, width: isSelected ? 1 : 0),
|
||||
border: Border.all(color: Colors.black, width: isSelected ? 2 : 0),
|
||||
),
|
||||
child: Text(
|
||||
value.toString(),
|
||||
|
||||
@@ -39,7 +39,7 @@ void main() {
|
||||
expect(notifier.state.isMetric, false);
|
||||
expect(notifier.state.totalWeight, 0);
|
||||
expect(notifier.state.selectedPlates, DEFAULT_LB_PLATES);
|
||||
expect(notifier.state.barWeight, notifier.state.barWeightLb);
|
||||
expect(notifier.state.barWeight, DEFAULT_BAR_WEIGHT_LB);
|
||||
expect(notifier.state.availablePlates, notifier.state.availablePlatesLb);
|
||||
|
||||
// Change back to metric
|
||||
@@ -48,7 +48,7 @@ void main() {
|
||||
expect(notifier.state.isMetric, true);
|
||||
expect(notifier.state.totalWeight, 0);
|
||||
expect(notifier.state.selectedPlates, DEFAULT_KG_PLATES);
|
||||
expect(notifier.state.barWeight, notifier.state.barWeightKg);
|
||||
expect(notifier.state.barWeight, DEFAULT_BAR_WEIGHT_KG);
|
||||
expect(notifier.state.availablePlates, notifier.state.availablePlatesKg);
|
||||
});
|
||||
|
||||
@@ -64,10 +64,12 @@ void main() {
|
||||
final updatedState = initialState.copyWith(
|
||||
isMetric: false,
|
||||
totalWeight: 100,
|
||||
barWeight: 15,
|
||||
selectedPlates: [1, 2, 3],
|
||||
);
|
||||
|
||||
expect(updatedState.isMetric, false);
|
||||
expect(updatedState.barWeight, 15);
|
||||
expect(updatedState.totalWeight, 100);
|
||||
expect(updatedState.selectedPlates, [1, 2, 3]);
|
||||
});
|
||||
@@ -76,18 +78,19 @@ void main() {
|
||||
final state = PlateCalculatorState(isMetric: false, selectedPlates: [10, 20]);
|
||||
final json = state.toJson();
|
||||
expect(json['isMetric'], false);
|
||||
expect(json['barWeight'], DEFAULT_BAR_WEIGHT_LB);
|
||||
expect(json['selectedPlates'], [10, 20]);
|
||||
});
|
||||
|
||||
test('barWeight returns correct value based on isMetric', () {
|
||||
test('barWeight returns correct default value based on isMetric', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true);
|
||||
expect(metricState.barWeight, metricState.barWeightKg);
|
||||
expect(metricState.barWeight, DEFAULT_BAR_WEIGHT_KG);
|
||||
|
||||
final imperialState = PlateCalculatorState(isMetric: false);
|
||||
expect(imperialState.barWeight, imperialState.barWeightLb);
|
||||
expect(imperialState.barWeight, DEFAULT_BAR_WEIGHT_LB);
|
||||
});
|
||||
|
||||
test('availablePlates returns correct list based on isMetric', () {
|
||||
test('availablePlates returns correct default list based on isMetric', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true);
|
||||
expect(metricState.availablePlates, metricState.availablePlatesKg);
|
||||
|
||||
@@ -95,14 +98,26 @@ void main() {
|
||||
expect(imperialState.availablePlates, metricState.availablePlatesLb);
|
||||
});
|
||||
|
||||
test('getColor returns correct color', () {
|
||||
test('getColor returns correct color - 1', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true);
|
||||
expect(metricState.getColor(20), Colors.blue);
|
||||
expect(metricState.getColor(10), Colors.green);
|
||||
expect(metricState.getColor(0.1), Colors.grey, reason: 'Fallback color');
|
||||
|
||||
final imperialState = PlateCalculatorState(isMetric: false);
|
||||
expect(imperialState.getColor(45), Colors.blue);
|
||||
expect(imperialState.getColor(35), Colors.yellow);
|
||||
expect(imperialState.getColor(0.1), Colors.grey, reason: 'Fallback color');
|
||||
});
|
||||
|
||||
test('getColor returns correct color - 2', () {
|
||||
final metricState = PlateCalculatorState(isMetric: true, useColors: false);
|
||||
expect(metricState.getColor(20), Colors.grey);
|
||||
expect(metricState.getColor(10), Colors.grey);
|
||||
|
||||
final imperialState = PlateCalculatorState(isMetric: false, useColors: false);
|
||||
expect(imperialState.getColor(45), Colors.grey);
|
||||
expect(imperialState.getColor(25), Colors.grey);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -53,9 +53,11 @@ void main() {
|
||||
final testRoutine = getTestRoutine();
|
||||
final testExercises = getTestExercises();
|
||||
|
||||
Widget renderGymMode({locale = 'en'}) {
|
||||
setUp(() {
|
||||
SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty();
|
||||
});
|
||||
|
||||
Widget renderGymMode({locale = 'en'}) {
|
||||
return ChangeNotifierProvider<RoutinesProvider>(
|
||||
create: (context) => RoutinesProvider(
|
||||
mockBaseProvider,
|
||||
|
||||
Reference in New Issue
Block a user