mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Merge pull request #125 from agwanyaseen/feature/exercise-crowdsourcing
feat: Form Related Changes in Add Exercise Screen
This commit is contained in:
@@ -2,9 +2,31 @@ import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:wger/models/exercises/muscle.dart';
|
||||
|
||||
class AddExcerciseProvider with ChangeNotifier {
|
||||
List<File> get excerciseImages => [..._excerciseImages];
|
||||
final List<File> _excerciseImages = [];
|
||||
String? _name;
|
||||
String? _alternativeName;
|
||||
String? _targetArea;
|
||||
List<String?>? _primaryMuscles = [];
|
||||
List<String?>? _secondaryMuscles = [];
|
||||
|
||||
set exerciseName(String name) => _name = name;
|
||||
set alternateName(String? name) => _alternativeName = name;
|
||||
set targetArea(String target) => _targetArea = target;
|
||||
set primaryMuclses(List<String?>? muscles) {
|
||||
if (muscles?.isNotEmpty ?? false) {
|
||||
_primaryMuscles = muscles;
|
||||
}
|
||||
}
|
||||
|
||||
set secondayMuclses(List<String?>? muscles) {
|
||||
if (muscles?.isNotEmpty ?? false) {
|
||||
_secondaryMuscles = muscles;
|
||||
}
|
||||
}
|
||||
|
||||
void addExcerciseImages(List<File> excercizes) {
|
||||
_excerciseImages.addAll(excercizes);
|
||||
@@ -16,4 +38,23 @@ class AddExcerciseProvider with ChangeNotifier {
|
||||
_excerciseImages.remove(file);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
//Just to Debug Provider
|
||||
printValues() {
|
||||
print('Name ${_name}');
|
||||
print('alternate name : ${_alternativeName}');
|
||||
print('target area : ${_targetArea}');
|
||||
print('primary mucsles');
|
||||
if (_primaryMuscles != null) {
|
||||
for (final a in _primaryMuscles!) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
print('seconday mucsles');
|
||||
if (_secondaryMuscles != null) {
|
||||
for (final a in _secondaryMuscles!) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ class ExercisesProvider with ChangeNotifier {
|
||||
|
||||
List<Exercise> get items => [..._exercises];
|
||||
List<ExerciseCategory> get categories => [..._categories];
|
||||
List<Muscle> get muscles => [..._muscles];
|
||||
|
||||
// Initialize filters for exercises search in exercises list
|
||||
void _initFilters() {
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/providers/add_excercise_provider.dart';
|
||||
import 'package:wger/providers/exercises.dart';
|
||||
import 'package:wger/widgets/add_exercise/add_exercise_dropdown_button.dart';
|
||||
import 'package:wger/widgets/add_exercise/add_exercise_multiselect_button.dart';
|
||||
import 'package:wger/widgets/add_exercise/add_exercise_text_area.dart';
|
||||
@@ -19,10 +20,19 @@ class AddExerciseScreen extends StatefulWidget {
|
||||
_AddExerciseScreenState createState() => _AddExerciseScreenState();
|
||||
}
|
||||
|
||||
abstract class ValidateStep {
|
||||
abstract VoidCallback _submit;
|
||||
}
|
||||
|
||||
class _AddExerciseScreenState extends State<AddExerciseScreen> {
|
||||
int _currentStep = 0;
|
||||
int lastStepIndex = AddExerciseScreen.STEPS_IN_FORM - 1;
|
||||
|
||||
final List<GlobalKey<FormState>> _keys = [
|
||||
GlobalKey<FormState>(),
|
||||
GlobalKey<FormState>(),
|
||||
GlobalKey<FormState>(),
|
||||
GlobalKey<FormState>()
|
||||
];
|
||||
Widget _controlsBuilder(
|
||||
BuildContext context, {
|
||||
VoidCallback? onStepCancel,
|
||||
@@ -55,7 +65,9 @@ class _AddExerciseScreenState extends State<AddExerciseScreen> {
|
||||
steps: [
|
||||
Step(
|
||||
title: const Text('Basics'),
|
||||
content: _BasicStepContent(),
|
||||
content: _BasicStepContent(
|
||||
formkey: _keys[0],
|
||||
),
|
||||
),
|
||||
Step(
|
||||
title: const Text('Duplicates and variations'),
|
||||
@@ -75,9 +87,13 @@ class _AddExerciseScreenState extends State<AddExerciseScreen> {
|
||||
if (_currentStep == lastStepIndex) {
|
||||
_addExercise();
|
||||
} else {
|
||||
setState(() {
|
||||
_currentStep += 1;
|
||||
});
|
||||
if (_keys[_currentStep].currentState?.validate() ?? false) {
|
||||
_keys[_currentStep].currentState?.save();
|
||||
context.read<AddExcerciseProvider>().printValues();
|
||||
setState(() {
|
||||
_currentStep += 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
onStepCancel: () => setState(() {
|
||||
@@ -89,38 +105,51 @@ class _AddExerciseScreenState extends State<AddExerciseScreen> {
|
||||
}
|
||||
|
||||
class _BasicStepContent extends StatelessWidget {
|
||||
final GlobalKey<FormState> _basicStepFormKey = GlobalKey<FormState>();
|
||||
// final GlobalKey<FormState> _basicStepFormKey = GlobalKey<FormState>();
|
||||
final GlobalKey<FormState> formkey;
|
||||
_BasicStepContent({required this.formkey});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final addExercideProvider = context.read<AddExcerciseProvider>();
|
||||
final exerciseProvider = context.read<ExercisesProvider>();
|
||||
final categories = exerciseProvider.categories;
|
||||
final muscles = exerciseProvider.muscles;
|
||||
return Form(
|
||||
key: _basicStepFormKey,
|
||||
key: formkey,
|
||||
child: Column(
|
||||
children: [
|
||||
AddExerciseTextArea(
|
||||
onChange: (value) => print(value),
|
||||
title: AppLocalizations.of(context).name,
|
||||
title: '${AppLocalizations.of(context).name}*',
|
||||
isRequired: true,
|
||||
validator: (name) => name?.isEmpty ?? true ? 'Name is required' : null,
|
||||
onSaved: (String? name) => addExercideProvider.exerciseName = name!,
|
||||
),
|
||||
AddExerciseTextArea(
|
||||
onChange: (value) => print(value),
|
||||
title: 'Alternative names',
|
||||
isMultiline: true,
|
||||
helperText: 'One name per line',
|
||||
onSaved: (String? alternateName) => addExercideProvider.alternateName = alternateName,
|
||||
),
|
||||
AddExerciseDropdownButton(
|
||||
title: 'Target area',
|
||||
items: ['Arms'],
|
||||
title: 'Target area*',
|
||||
items: categories.map((e) => e.name).toList(),
|
||||
onChange: (value) => print(value),
|
||||
validator: (value) => value?.isEmpty ?? true ? 'Target Area is Required ' : null,
|
||||
onSaved: (String? targetArea) => addExercideProvider.targetArea = targetArea!,
|
||||
),
|
||||
AddExerciseMultiselectButton(
|
||||
title: AppLocalizations.of(context).muscles,
|
||||
items: ['Arms', 'Chest', 'Shoulders'],
|
||||
items: muscles.map((e) => e.name).toList(),
|
||||
onChange: (value) => print(value),
|
||||
onSaved: (List<String?>? muscles) => addExercideProvider.primaryMuclses = muscles,
|
||||
),
|
||||
AddExerciseMultiselectButton(
|
||||
title: AppLocalizations.of(context).musclesSecondary,
|
||||
items: ['Arms', 'Chest', 'Shoulders'],
|
||||
items: muscles.map((e) => e.name).toList(),
|
||||
onChange: (value) => print(value),
|
||||
onSaved: (List<String?>? muscles) => addExercideProvider.secondayMuclses = muscles,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -7,11 +7,15 @@ class AddExerciseDropdownButton extends StatefulWidget {
|
||||
required this.items,
|
||||
required this.title,
|
||||
required this.onChange,
|
||||
this.validator,
|
||||
this.onSaved,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<String> items;
|
||||
final String title;
|
||||
final ValueChanged<String?> onChange;
|
||||
final FormFieldValidator<String?>? validator;
|
||||
final FormFieldSetter<String?>? onSaved;
|
||||
|
||||
@override
|
||||
_AddExerciseDropdownButtonState createState() => _AddExerciseDropdownButtonState();
|
||||
@@ -25,7 +29,9 @@ class _AddExerciseDropdownButtonState extends State<AddExerciseDropdownButton> {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: DropdownButtonFormField<String>(
|
||||
validator: widget.validator,
|
||||
isExpanded: true,
|
||||
onSaved: widget.onSaved,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_selectedItem = value;
|
||||
|
||||
@@ -8,11 +8,13 @@ class AddExerciseMultiselectButton extends StatefulWidget {
|
||||
required this.items,
|
||||
required this.title,
|
||||
required this.onChange,
|
||||
this.onSaved,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<String> items;
|
||||
final String title;
|
||||
final ValueChanged<List<String?>> onChange;
|
||||
final FormFieldSetter<List<String?>?>? onSaved;
|
||||
|
||||
@override
|
||||
_AddExerciseMultiselectButtonState createState() => _AddExerciseMultiselectButtonState();
|
||||
@@ -25,6 +27,7 @@ class _AddExerciseMultiselectButtonState extends State<AddExerciseMultiselectBut
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MultiSelectDialogField<String?>(
|
||||
onSaved: widget.onSaved,
|
||||
items: widget.items.map((item) => MultiSelectItem<String?>(item, item)).toList(),
|
||||
onConfirm: (value) {
|
||||
setState(() {
|
||||
|
||||
@@ -8,6 +8,8 @@ class AddExerciseTextArea extends StatelessWidget {
|
||||
this.helperText = '',
|
||||
this.isRequired = true,
|
||||
this.isMultiline = false,
|
||||
this.validator,
|
||||
this.onSaved,
|
||||
}) : super(key: key);
|
||||
|
||||
final ValueChanged<String> onChange;
|
||||
@@ -15,6 +17,8 @@ class AddExerciseTextArea extends StatelessWidget {
|
||||
final bool isMultiline;
|
||||
final String title;
|
||||
final String helperText;
|
||||
final FormFieldValidator<String?>? validator;
|
||||
final FormFieldSetter<String?>? onSaved;
|
||||
|
||||
static const MULTILINE_MIN_LINES = 4;
|
||||
static const DEFAULT_LINES = 1;
|
||||
@@ -27,6 +31,8 @@ class AddExerciseTextArea extends StatelessWidget {
|
||||
keyboardType: isMultiline ? TextInputType.multiline : TextInputType.text,
|
||||
maxLines: isMultiline ? null : DEFAULT_LINES,
|
||||
minLines: isMultiline ? MULTILINE_MIN_LINES : DEFAULT_LINES,
|
||||
validator: validator,
|
||||
onSaved: onSaved,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
|
||||
border: OutlineInputBorder(
|
||||
|
||||
Reference in New Issue
Block a user