mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Add image upload methods
We use the "manual" way as it was before, since there were some problems making this work and most of the errors were happening during the exercise creation itself.
This commit is contained in:
@@ -50,7 +50,6 @@ abstract mixin class $ExerciseAliasSubmissionApiCopyWith<$Res> {
|
||||
factory $ExerciseAliasSubmissionApiCopyWith(
|
||||
ExerciseAliasSubmissionApi value, $Res Function(ExerciseAliasSubmissionApi) _then) =
|
||||
_$ExerciseAliasSubmissionApiCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({String alias});
|
||||
}
|
||||
@@ -236,7 +235,6 @@ extension ExerciseAliasSubmissionApiPatterns on ExerciseAliasSubmissionApi {
|
||||
@JsonSerializable()
|
||||
class _ExerciseAliasSubmissionApi implements ExerciseAliasSubmissionApi {
|
||||
const _ExerciseAliasSubmissionApi({required this.alias});
|
||||
|
||||
factory _ExerciseAliasSubmissionApi.fromJson(Map<String, dynamic> json) =>
|
||||
_$ExerciseAliasSubmissionApiFromJson(json);
|
||||
|
||||
@@ -282,7 +280,6 @@ abstract mixin class _$ExerciseAliasSubmissionApiCopyWith<$Res>
|
||||
factory _$ExerciseAliasSubmissionApiCopyWith(
|
||||
_ExerciseAliasSubmissionApi value, $Res Function(_ExerciseAliasSubmissionApi) _then) =
|
||||
__$ExerciseAliasSubmissionApiCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String alias});
|
||||
@@ -350,7 +347,6 @@ abstract mixin class $ExerciseCommentSubmissionApiCopyWith<$Res> {
|
||||
factory $ExerciseCommentSubmissionApiCopyWith(
|
||||
ExerciseCommentSubmissionApi value, $Res Function(ExerciseCommentSubmissionApi) _then) =
|
||||
_$ExerciseCommentSubmissionApiCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call({String alias});
|
||||
}
|
||||
@@ -536,7 +532,6 @@ extension ExerciseCommentSubmissionApiPatterns on ExerciseCommentSubmissionApi {
|
||||
@JsonSerializable()
|
||||
class _ExerciseCommentSubmissionApi implements ExerciseCommentSubmissionApi {
|
||||
const _ExerciseCommentSubmissionApi({required this.alias});
|
||||
|
||||
factory _ExerciseCommentSubmissionApi.fromJson(Map<String, dynamic> json) =>
|
||||
_$ExerciseCommentSubmissionApiFromJson(json);
|
||||
|
||||
@@ -582,7 +577,6 @@ abstract mixin class _$ExerciseCommentSubmissionApiCopyWith<$Res>
|
||||
factory _$ExerciseCommentSubmissionApiCopyWith(
|
||||
_ExerciseCommentSubmissionApi value, $Res Function(_ExerciseCommentSubmissionApi) _then) =
|
||||
__$ExerciseCommentSubmissionApiCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String alias});
|
||||
@@ -615,16 +609,11 @@ class __$ExerciseCommentSubmissionApiCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
mixin _$ExerciseTranslationSubmissionApi {
|
||||
String get name;
|
||||
|
||||
String get description;
|
||||
|
||||
int get language;
|
||||
|
||||
@JsonKey(name: 'license_author')
|
||||
String get author;
|
||||
|
||||
List<ExerciseAliasSubmissionApi> get aliases;
|
||||
|
||||
List<ExerciseCommentSubmissionApi> get comments;
|
||||
|
||||
/// Create a copy of ExerciseTranslationSubmissionApi
|
||||
@@ -667,7 +656,6 @@ abstract mixin class $ExerciseTranslationSubmissionApiCopyWith<$Res> {
|
||||
factory $ExerciseTranslationSubmissionApiCopyWith(ExerciseTranslationSubmissionApi value,
|
||||
$Res Function(ExerciseTranslationSubmissionApi) _then) =
|
||||
_$ExerciseTranslationSubmissionApiCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call(
|
||||
{String name,
|
||||
@@ -916,7 +904,6 @@ class _ExerciseTranslationSubmissionApi implements ExerciseTranslationSubmission
|
||||
final List<ExerciseCommentSubmissionApi> comments = const []})
|
||||
: _aliases = aliases,
|
||||
_comments = comments;
|
||||
|
||||
factory _ExerciseTranslationSubmissionApi.fromJson(Map<String, dynamic> json) =>
|
||||
_$ExerciseTranslationSubmissionApiFromJson(json);
|
||||
|
||||
@@ -930,7 +917,6 @@ class _ExerciseTranslationSubmissionApi implements ExerciseTranslationSubmission
|
||||
@JsonKey(name: 'license_author')
|
||||
final String author;
|
||||
final List<ExerciseAliasSubmissionApi> _aliases;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
List<ExerciseAliasSubmissionApi> get aliases {
|
||||
@@ -940,7 +926,6 @@ class _ExerciseTranslationSubmissionApi implements ExerciseTranslationSubmission
|
||||
}
|
||||
|
||||
final List<ExerciseCommentSubmissionApi> _comments;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
List<ExerciseCommentSubmissionApi> get comments {
|
||||
@@ -1001,7 +986,6 @@ abstract mixin class _$ExerciseTranslationSubmissionApiCopyWith<$Res>
|
||||
factory _$ExerciseTranslationSubmissionApiCopyWith(_ExerciseTranslationSubmissionApi value,
|
||||
$Res Function(_ExerciseTranslationSubmissionApi) _then) =
|
||||
__$ExerciseTranslationSubmissionApiCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
@@ -1065,20 +1049,14 @@ class __$ExerciseTranslationSubmissionApiCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
mixin _$ExerciseSubmissionApi {
|
||||
int get category;
|
||||
|
||||
List<int> get muscles;
|
||||
|
||||
@JsonKey(name: 'muscles_secondary')
|
||||
List<int> get musclesSecondary;
|
||||
|
||||
List<int> get equipment;
|
||||
|
||||
@JsonKey(name: 'license_author')
|
||||
String get author;
|
||||
|
||||
@JsonKey(includeToJson: false)
|
||||
int? get variation;
|
||||
|
||||
List<ExerciseTranslationSubmissionApi> get translations;
|
||||
|
||||
/// Create a copy of ExerciseSubmissionApi
|
||||
@@ -1129,7 +1107,6 @@ abstract mixin class $ExerciseSubmissionApiCopyWith<$Res> {
|
||||
factory $ExerciseSubmissionApiCopyWith(
|
||||
ExerciseSubmissionApi value, $Res Function(ExerciseSubmissionApi) _then) =
|
||||
_$ExerciseSubmissionApiCopyWithImpl;
|
||||
|
||||
@useResult
|
||||
$Res call(
|
||||
{int category,
|
||||
@@ -1389,14 +1366,12 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi {
|
||||
_musclesSecondary = musclesSecondary,
|
||||
_equipment = equipment,
|
||||
_translations = translations;
|
||||
|
||||
factory _ExerciseSubmissionApi.fromJson(Map<String, dynamic> json) =>
|
||||
_$ExerciseSubmissionApiFromJson(json);
|
||||
|
||||
@override
|
||||
final int category;
|
||||
final List<int> _muscles;
|
||||
|
||||
@override
|
||||
List<int> get muscles {
|
||||
if (_muscles is EqualUnmodifiableListView) return _muscles;
|
||||
@@ -1405,7 +1380,6 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi {
|
||||
}
|
||||
|
||||
final List<int> _musclesSecondary;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'muscles_secondary')
|
||||
List<int> get musclesSecondary {
|
||||
@@ -1415,7 +1389,6 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi {
|
||||
}
|
||||
|
||||
final List<int> _equipment;
|
||||
|
||||
@override
|
||||
List<int> get equipment {
|
||||
if (_equipment is EqualUnmodifiableListView) return _equipment;
|
||||
@@ -1430,7 +1403,6 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi {
|
||||
@JsonKey(includeToJson: false)
|
||||
final int? variation;
|
||||
final List<ExerciseTranslationSubmissionApi> _translations;
|
||||
|
||||
@override
|
||||
List<ExerciseTranslationSubmissionApi> get translations {
|
||||
if (_translations is EqualUnmodifiableListView) return _translations;
|
||||
@@ -1491,7 +1463,6 @@ abstract mixin class _$ExerciseSubmissionApiCopyWith<$Res>
|
||||
factory _$ExerciseSubmissionApiCopyWith(
|
||||
_ExerciseSubmissionApi value, $Res Function(_ExerciseSubmissionApi) _then) =
|
||||
__$ExerciseSubmissionApiCopyWithImpl;
|
||||
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
|
||||
@@ -2,6 +2,8 @@ import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/models/exercises/category.dart';
|
||||
import 'package:wger/models/exercises/equipment.dart';
|
||||
import 'package:wger/models/exercises/exercise.dart';
|
||||
@@ -36,6 +38,7 @@ class AddExerciseProvider with ChangeNotifier {
|
||||
List<Muscle> _secondaryMuscles = [];
|
||||
|
||||
static const _exerciseSubmissionUrlPath = 'exercise-submission';
|
||||
static const _imagesUrlPath = 'exerciseimage';
|
||||
static const _checkLanguageUrlPath = 'check-language';
|
||||
|
||||
void clear() {
|
||||
@@ -190,6 +193,21 @@ class AddExerciseProvider with ChangeNotifier {
|
||||
return result['id'];
|
||||
}
|
||||
|
||||
Future<void> addImages(int exerciseId) async {
|
||||
for (final image in _exerciseImages) {
|
||||
final request = http.MultipartRequest('POST', baseProvider.makeUrl(_imagesUrlPath));
|
||||
request.headers.addAll(baseProvider.getDefaultHeaders(includeAuth: true));
|
||||
|
||||
request.files.add(await http.MultipartFile.fromPath('image', image.path));
|
||||
request.fields['exercise'] = exerciseId.toString();
|
||||
request.fields['style'] = EXERCISE_IMAGE_ART_STYLE.PHOTO.index.toString();
|
||||
|
||||
await request.send();
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<bool> validateLanguage(String input, String languageCode) async {
|
||||
final Map<String, dynamic> result = await baseProvider.post(
|
||||
{'input': input, 'language_code': languageCode},
|
||||
|
||||
@@ -86,21 +86,24 @@ class _AddExerciseStepperState extends State<AddExerciseStepper> {
|
||||
Exercise? exercise;
|
||||
try {
|
||||
final exerciseId = await addExerciseProvider.addExercise();
|
||||
await addExerciseProvider.addImages(exerciseId);
|
||||
exercise = await exerciseProvider.fetchAndSetExercise(exerciseId);
|
||||
addExerciseProvider.clear();
|
||||
} on WgerHttpException catch (error) {
|
||||
if (context.mounted) {
|
||||
setState(() {
|
||||
errorWidget = FormHttpErrorsWidget(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (exercise == null) {
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (exercise == null || !context.mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,16 +111,6 @@ class _AddExerciseStepperState extends State<AddExerciseStepper> {
|
||||
.getTranslation(Localizations.localeOf(context).languageCode)
|
||||
.name;
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (!context.mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
||||
@@ -7,9 +7,11 @@ import 'package:wger/providers/add_exercise.dart';
|
||||
import 'mixins/image_picker_mixin.dart';
|
||||
|
||||
class PreviewExerciseImages extends StatelessWidget with ExerciseImagePickerMixin {
|
||||
const PreviewExerciseImages({super.key, required this.selectedImages});
|
||||
|
||||
final List<File> selectedImages;
|
||||
final bool allowEdit;
|
||||
|
||||
const PreviewExerciseImages({super.key, required this.selectedImages, this.allowEdit = true});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
@@ -23,46 +25,48 @@ class PreviewExerciseImages extends StatelessWidget with ExerciseImagePickerMixi
|
||||
child: Stack(
|
||||
children: [
|
||||
Image.file(file),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.withValues(alpha: 0.5),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: IconButton(
|
||||
iconSize: 20,
|
||||
onPressed: () =>
|
||||
context.read<AddExerciseProvider>().removeExercise(file.path),
|
||||
color: Colors.white,
|
||||
icon: const Icon(Icons.delete),
|
||||
if (allowEdit)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.withValues(alpha: 0.5),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: IconButton(
|
||||
iconSize: 20,
|
||||
onPressed: () =>
|
||||
context.read<AddExerciseProvider>().removeExercise(file.path),
|
||||
color: Colors.white,
|
||||
icon: const Icon(Icons.delete),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: Colors.grey,
|
||||
height: 200,
|
||||
width: 100,
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () => pickImages(context),
|
||||
if (allowEdit)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: Colors.grey,
|
||||
height: 200,
|
||||
width: 100,
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () => pickImages(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,89 +34,89 @@ class Step1Basics extends StatelessWidget {
|
||||
|
||||
return Form(
|
||||
key: formkey,
|
||||
child: Column(
|
||||
children: [
|
||||
AddExerciseTextArea(
|
||||
onChange: (value) => {},
|
||||
title: '${AppLocalizations.of(context).name}*',
|
||||
helperText: AppLocalizations.of(context).baseNameEnglish,
|
||||
isRequired: true,
|
||||
validator: (name) => validateName(name, context),
|
||||
onSaved: (String? name) => addExerciseProvider.exerciseNameEn = name!,
|
||||
),
|
||||
AddExerciseTextArea(
|
||||
onChange: (value) => {},
|
||||
title: AppLocalizations.of(context).alternativeNames,
|
||||
isMultiline: true,
|
||||
helperText: AppLocalizations.of(context).oneNamePerLine,
|
||||
onSaved: (String? alternateName) =>
|
||||
addExerciseProvider.alternateNamesEn = alternateName!.split('\n'),
|
||||
),
|
||||
ExerciseCategoryInputWidget<ExerciseCategory>(
|
||||
key: const Key('category-dropdown'),
|
||||
entries: categories,
|
||||
title: '${AppLocalizations.of(context).category}*',
|
||||
callback: (ExerciseCategory newValue) {
|
||||
addExerciseProvider.category = newValue;
|
||||
},
|
||||
validator: (ExerciseCategory? category) {
|
||||
if (category == null) {
|
||||
return AppLocalizations.of(context).selectEntry;
|
||||
}
|
||||
},
|
||||
displayName: (ExerciseCategory c) => getTranslation(c.name, context),
|
||||
),
|
||||
AddExerciseMultiselectButton<Equipment>(
|
||||
key: const Key('equipment-multiselect'),
|
||||
title: AppLocalizations.of(context).equipment,
|
||||
items: equipment,
|
||||
initialItems: addExerciseProvider.equipment,
|
||||
onChange: (dynamic entries) {
|
||||
addExerciseProvider.equipment = entries.cast<Equipment>();
|
||||
},
|
||||
onSaved: (dynamic entries) {
|
||||
addExerciseProvider.equipment = entries.cast<Equipment>();
|
||||
},
|
||||
displayName: (Equipment e) => getTranslation(e.name, context),
|
||||
),
|
||||
AddExerciseMultiselectButton<Muscle>(
|
||||
key: const Key('primary-muscles-multiselect'),
|
||||
title: AppLocalizations.of(context).muscles,
|
||||
items: muscles,
|
||||
initialItems: addExerciseProvider.primaryMuscles,
|
||||
onChange: (dynamic muscles) {
|
||||
addExerciseProvider.primaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
onSaved: (dynamic muscles) {
|
||||
addExerciseProvider.primaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
displayName: (Muscle e) =>
|
||||
e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''),
|
||||
),
|
||||
AddExerciseMultiselectButton<Muscle>(
|
||||
key: const Key('secondary-muscles-multiselect'),
|
||||
title: AppLocalizations.of(context).musclesSecondary,
|
||||
items: muscles,
|
||||
initialItems: addExerciseProvider.secondaryMuscles,
|
||||
onChange: (dynamic muscles) {
|
||||
addExerciseProvider.secondaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
onSaved: (dynamic muscles) {
|
||||
addExerciseProvider.secondaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
displayName: (Muscle e) =>
|
||||
e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''),
|
||||
),
|
||||
Consumer<AddExerciseProvider>(
|
||||
builder: (context, value, child) => MuscleRowWidget(
|
||||
muscles: value.primaryMuscles,
|
||||
musclesSecondary: value.secondaryMuscles,
|
||||
child: Consumer<AddExerciseProvider>(
|
||||
builder: (context, provider, child) => Column(
|
||||
children: [
|
||||
AddExerciseTextArea(
|
||||
onChange: (value) => {},
|
||||
title: '${AppLocalizations.of(context).name}*',
|
||||
helperText: AppLocalizations.of(context).baseNameEnglish,
|
||||
isRequired: true,
|
||||
validator: (name) => validateName(name, context),
|
||||
onSaved: (String? name) => addExerciseProvider.exerciseNameEn = name!,
|
||||
),
|
||||
),
|
||||
const MuscleColorHelper(main: true),
|
||||
const SizedBox(height: 5),
|
||||
const MuscleColorHelper(main: false),
|
||||
],
|
||||
AddExerciseTextArea(
|
||||
onChange: (value) => {},
|
||||
title: AppLocalizations.of(context).alternativeNames,
|
||||
isMultiline: true,
|
||||
helperText: AppLocalizations.of(context).oneNamePerLine,
|
||||
onSaved: (String? alternateName) =>
|
||||
addExerciseProvider.alternateNamesEn = alternateName!.split('\n'),
|
||||
),
|
||||
ExerciseCategoryInputWidget<ExerciseCategory>(
|
||||
key: const Key('category-dropdown'),
|
||||
entries: categories,
|
||||
title: '${AppLocalizations.of(context).category}*',
|
||||
callback: (ExerciseCategory newValue) {
|
||||
addExerciseProvider.category = newValue;
|
||||
},
|
||||
validator: (ExerciseCategory? category) {
|
||||
if (category == null) {
|
||||
return AppLocalizations.of(context).selectEntry;
|
||||
}
|
||||
},
|
||||
displayName: (ExerciseCategory c) => getTranslation(c.name, context),
|
||||
),
|
||||
AddExerciseMultiselectButton<Equipment>(
|
||||
key: const Key('equipment-multiselect'),
|
||||
title: AppLocalizations.of(context).equipment,
|
||||
items: equipment,
|
||||
initialItems: addExerciseProvider.equipment,
|
||||
onChange: (dynamic entries) {
|
||||
addExerciseProvider.equipment = entries.cast<Equipment>();
|
||||
},
|
||||
onSaved: (dynamic entries) {
|
||||
addExerciseProvider.equipment = entries.cast<Equipment>();
|
||||
},
|
||||
displayName: (Equipment e) => getTranslation(e.name, context),
|
||||
),
|
||||
AddExerciseMultiselectButton<Muscle>(
|
||||
key: const Key('primary-muscles-multiselect'),
|
||||
title: AppLocalizations.of(context).muscles,
|
||||
items: muscles,
|
||||
initialItems: addExerciseProvider.primaryMuscles,
|
||||
onChange: (dynamic muscles) {
|
||||
addExerciseProvider.primaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
onSaved: (dynamic muscles) {
|
||||
addExerciseProvider.primaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
displayName: (Muscle e) =>
|
||||
e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''),
|
||||
),
|
||||
AddExerciseMultiselectButton<Muscle>(
|
||||
key: const Key('secondary-muscles-multiselect'),
|
||||
title: AppLocalizations.of(context).musclesSecondary,
|
||||
items: muscles,
|
||||
initialItems: addExerciseProvider.secondaryMuscles,
|
||||
onChange: (dynamic muscles) {
|
||||
addExerciseProvider.secondaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
onSaved: (dynamic muscles) {
|
||||
addExerciseProvider.secondaryMuscles = muscles.cast<Muscle>();
|
||||
},
|
||||
displayName: (Muscle e) =>
|
||||
e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''),
|
||||
),
|
||||
MuscleRowWidget(
|
||||
muscles: provider.primaryMuscles,
|
||||
musclesSecondary: provider.secondaryMuscles,
|
||||
),
|
||||
const MuscleColorHelper(main: true),
|
||||
const SizedBox(height: 5),
|
||||
const MuscleColorHelper(main: false),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,129 +2,136 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/providers/add_exercise.dart';
|
||||
import 'package:wger/widgets/add_exercise/preview_images.dart';
|
||||
import 'package:wger/widgets/core/cards.dart';
|
||||
|
||||
class Step6Overview extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context);
|
||||
final addExerciseProvider = context.read<AddExerciseProvider>();
|
||||
|
||||
return Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text(
|
||||
i18n.baseData,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FlexColumnWidth(2),
|
||||
1: FlexColumnWidth(3),
|
||||
},
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.name),
|
||||
Text(addExerciseProvider.exerciseNameEn ?? '...'),
|
||||
],
|
||||
return Consumer<AddExerciseProvider>(
|
||||
builder: (ctx, provider, __) => Column(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text(
|
||||
i18n.baseData,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FlexColumnWidth(2),
|
||||
1: FlexColumnWidth(3),
|
||||
},
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.name),
|
||||
Text(provider.exerciseNameEn ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.alternativeNames),
|
||||
Text(
|
||||
provider.alternateNamesEn.isNotEmpty
|
||||
? provider.alternateNamesEn.join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.description),
|
||||
Text(provider.descriptionEn ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.category),
|
||||
Text(provider.category?.name ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.muscles),
|
||||
Text(
|
||||
provider.primaryMuscles.isNotEmpty
|
||||
? provider.primaryMuscles.map((m) => m.name).join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.musclesSecondary),
|
||||
Text(
|
||||
provider.secondaryMuscles.isNotEmpty
|
||||
? provider.secondaryMuscles.map((m) => m.name).join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.equipment),
|
||||
Text(
|
||||
provider.equipment.isNotEmpty
|
||||
? provider.equipment.map((m) => m.name).join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
i18n.translation,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FlexColumnWidth(2),
|
||||
1: FlexColumnWidth(3),
|
||||
},
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.name),
|
||||
Text(provider.exerciseNameTrans ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.alternativeNames),
|
||||
Text(
|
||||
provider.alternateNamesTrans.isNotEmpty
|
||||
? provider.alternateNamesTrans.join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.description),
|
||||
Text(provider.descriptionTrans ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.language),
|
||||
Text(provider.languageTranslation?.fullName ?? '...'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (provider.exerciseImages.isNotEmpty)
|
||||
PreviewExerciseImages(
|
||||
selectedImages: provider.exerciseImages,
|
||||
allowEdit: false,
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.alternativeNames),
|
||||
Text(
|
||||
addExerciseProvider.alternateNamesEn.isNotEmpty
|
||||
? addExerciseProvider.alternateNamesEn.join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.description),
|
||||
Text(addExerciseProvider.descriptionEn ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.category),
|
||||
Text(addExerciseProvider.category?.name ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.muscles),
|
||||
Text(
|
||||
addExerciseProvider.primaryMuscles.isNotEmpty
|
||||
? addExerciseProvider.primaryMuscles.map((m) => m.name).join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.musclesSecondary),
|
||||
Text(
|
||||
addExerciseProvider.secondaryMuscles.isNotEmpty
|
||||
? addExerciseProvider.secondaryMuscles.map((m) => m.name).join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.equipment),
|
||||
Text(
|
||||
addExerciseProvider.equipment.isNotEmpty
|
||||
? addExerciseProvider.equipment.map((m) => m.name).join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
i18n.translation,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
Table(
|
||||
columnWidths: const {
|
||||
0: FlexColumnWidth(2),
|
||||
1: FlexColumnWidth(3),
|
||||
},
|
||||
children: [
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.name),
|
||||
Text(addExerciseProvider.exerciseNameTrans ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.alternativeNames),
|
||||
Text(
|
||||
addExerciseProvider.alternateNamesTrans.isNotEmpty
|
||||
? addExerciseProvider.alternateNamesTrans.join('\n')
|
||||
: '...',
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.description),
|
||||
Text(addExerciseProvider.descriptionTrans ?? '...'),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Text(i18n.language),
|
||||
Text(addExerciseProvider.languageTranslation?.fullName ?? '...'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
InfoCard(text: i18n.checkInformationBeforeSubmitting)
|
||||
],
|
||||
InfoCard(text: i18n.checkInformationBeforeSubmitting)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,6 +153,18 @@ class MockAddExerciseProvider extends _i1.Mock implements _i11.AddExerciseProvid
|
||||
returnValue: <_i12.File>[],
|
||||
) as List<_i12.File>);
|
||||
|
||||
@override
|
||||
List<String> get alternateNamesEn => (super.noSuchMethod(
|
||||
Invocation.getter(#alternateNamesEn),
|
||||
returnValue: <String>[],
|
||||
) as List<String>);
|
||||
|
||||
@override
|
||||
List<String> get alternateNamesTrans => (super.noSuchMethod(
|
||||
Invocation.getter(#alternateNamesTrans),
|
||||
returnValue: <String>[],
|
||||
) as List<String>);
|
||||
|
||||
@override
|
||||
List<_i8.Equipment> get equipment => (super.noSuchMethod(
|
||||
Invocation.getter(#equipment),
|
||||
@@ -195,6 +207,42 @@ class MockAddExerciseProvider extends _i1.Mock implements _i11.AddExerciseProvid
|
||||
),
|
||||
) as _i13.ExerciseSubmissionApi);
|
||||
|
||||
@override
|
||||
set exerciseNameEn(String? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#exerciseNameEn,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set exerciseNameTrans(String? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#exerciseNameTrans,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set descriptionEn(String? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#descriptionEn,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set descriptionTrans(String? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#descriptionTrans,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set languageEn(_i10.Language? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
@@ -214,64 +262,28 @@ class MockAddExerciseProvider extends _i1.Mock implements _i11.AddExerciseProvid
|
||||
);
|
||||
|
||||
@override
|
||||
set category(_i7.ExerciseCategory? value) => super.noSuchMethod(
|
||||
set alternateNamesEn(List<String>? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#category,
|
||||
#alternateNamesEn,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set exerciseNameEn(String? name) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#exerciseNameEn,
|
||||
name,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set exerciseNameTrans(String? name) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#exerciseNameTrans,
|
||||
name,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set descriptionEn(String? description) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#descriptionEn,
|
||||
description,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set descriptionTrans(String? description) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#descriptionTrans,
|
||||
description,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set alternateNamesEn(List<String>? names) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#alternateNamesEn,
|
||||
names,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set alternateNamesTrans(List<String>? names) => super.noSuchMethod(
|
||||
set alternateNamesTrans(List<String>? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#alternateNamesTrans,
|
||||
names,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set category(_i7.ExerciseCategory? value) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#category,
|
||||
value,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@@ -381,6 +393,32 @@ class MockAddExerciseProvider extends _i1.Mock implements _i11.AddExerciseProvid
|
||||
returnValue: _i15.Future<int>.value(0),
|
||||
) as _i15.Future<int>);
|
||||
|
||||
@override
|
||||
_i15.Future<void> addImages(int? exerciseId) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#addImages,
|
||||
[exerciseId],
|
||||
),
|
||||
returnValue: _i15.Future<void>.value(),
|
||||
returnValueForMissingStub: _i15.Future<void>.value(),
|
||||
) as _i15.Future<void>);
|
||||
|
||||
@override
|
||||
_i15.Future<bool> validateLanguage(
|
||||
String? input,
|
||||
String? languageCode,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#validateLanguage,
|
||||
[
|
||||
input,
|
||||
languageCode,
|
||||
],
|
||||
),
|
||||
returnValue: _i15.Future<bool>.value(false),
|
||||
) as _i15.Future<bool>);
|
||||
|
||||
@override
|
||||
void addListener(_i16.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
||||
Reference in New Issue
Block a user