From ba34570a3da4e5571e335a3a3a61cb4e1a4c2f5c Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 19 Sep 2025 22:27:04 +0200 Subject: [PATCH] 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. --- .../exercise_submission.freezed.dart | 29 --- lib/providers/add_exercise.dart | 18 ++ lib/screens/add_exercise_screen.dart | 19 +- lib/widgets/add_exercise/preview_images.dart | 64 ++--- .../add_exercise/steps/step1basics.dart | 164 ++++++------ .../add_exercise/steps/step6Overview.dart | 237 +++++++++--------- .../contribute_exercise_test.mocks.dart | 136 ++++++---- 7 files changed, 349 insertions(+), 318 deletions(-) diff --git a/lib/models/exercises/exercise_submission.freezed.dart b/lib/models/exercises/exercise_submission.freezed.dart index e156ae41..c5da9843 100644 --- a/lib/models/exercises/exercise_submission.freezed.dart +++ b/lib/models/exercises/exercise_submission.freezed.dart @@ -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 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 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 get aliases; - List 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 comments = const []}) : _aliases = aliases, _comments = comments; - factory _ExerciseTranslationSubmissionApi.fromJson(Map json) => _$ExerciseTranslationSubmissionApiFromJson(json); @@ -930,7 +917,6 @@ class _ExerciseTranslationSubmissionApi implements ExerciseTranslationSubmission @JsonKey(name: 'license_author') final String author; final List _aliases; - @override @JsonKey() List get aliases { @@ -940,7 +926,6 @@ class _ExerciseTranslationSubmissionApi implements ExerciseTranslationSubmission } final List _comments; - @override @JsonKey() List 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 get muscles; - @JsonKey(name: 'muscles_secondary') List get musclesSecondary; - List get equipment; - @JsonKey(name: 'license_author') String get author; - @JsonKey(includeToJson: false) int? get variation; - List 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 json) => _$ExerciseSubmissionApiFromJson(json); @override final int category; final List _muscles; - @override List get muscles { if (_muscles is EqualUnmodifiableListView) return _muscles; @@ -1405,7 +1380,6 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi { } final List _musclesSecondary; - @override @JsonKey(name: 'muscles_secondary') List get musclesSecondary { @@ -1415,7 +1389,6 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi { } final List _equipment; - @override List get equipment { if (_equipment is EqualUnmodifiableListView) return _equipment; @@ -1430,7 +1403,6 @@ class _ExerciseSubmissionApi implements ExerciseSubmissionApi { @JsonKey(includeToJson: false) final int? variation; final List _translations; - @override List 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( diff --git a/lib/providers/add_exercise.dart b/lib/providers/add_exercise.dart index baace514..a0ddf5ef 100644 --- a/lib/providers/add_exercise.dart +++ b/lib/providers/add_exercise.dart @@ -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 _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 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 validateLanguage(String input, String languageCode) async { final Map result = await baseProvider.post( {'input': input, 'language_code': languageCode}, diff --git a/lib/screens/add_exercise_screen.dart b/lib/screens/add_exercise_screen.dart index 688e4045..591e938e 100644 --- a/lib/screens/add_exercise_screen.dart +++ b/lib/screens/add_exercise_screen.dart @@ -86,21 +86,24 @@ class _AddExerciseStepperState extends State { 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 { .getTranslation(Localizations.localeOf(context).languageCode) .name; - if (mounted) { - setState(() { - _isLoading = false; - }); - } - - if (!context.mounted) { - return; - } - return showDialog( context: context, builder: (BuildContext context) { diff --git a/lib/widgets/add_exercise/preview_images.dart b/lib/widgets/add_exercise/preview_images.dart index 32cd2d23..23f7660c 100644 --- a/lib/widgets/add_exercise/preview_images.dart +++ b/lib/widgets/add_exercise/preview_images.dart @@ -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 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().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().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), + ), ), ), ), - ), ]), ); } diff --git a/lib/widgets/add_exercise/steps/step1basics.dart b/lib/widgets/add_exercise/steps/step1basics.dart index bb0eb52a..761a2411 100644 --- a/lib/widgets/add_exercise/steps/step1basics.dart +++ b/lib/widgets/add_exercise/steps/step1basics.dart @@ -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( - 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( - key: const Key('equipment-multiselect'), - title: AppLocalizations.of(context).equipment, - items: equipment, - initialItems: addExerciseProvider.equipment, - onChange: (dynamic entries) { - addExerciseProvider.equipment = entries.cast(); - }, - onSaved: (dynamic entries) { - addExerciseProvider.equipment = entries.cast(); - }, - displayName: (Equipment e) => getTranslation(e.name, context), - ), - AddExerciseMultiselectButton( - key: const Key('primary-muscles-multiselect'), - title: AppLocalizations.of(context).muscles, - items: muscles, - initialItems: addExerciseProvider.primaryMuscles, - onChange: (dynamic muscles) { - addExerciseProvider.primaryMuscles = muscles.cast(); - }, - onSaved: (dynamic muscles) { - addExerciseProvider.primaryMuscles = muscles.cast(); - }, - displayName: (Muscle e) => - e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''), - ), - AddExerciseMultiselectButton( - key: const Key('secondary-muscles-multiselect'), - title: AppLocalizations.of(context).musclesSecondary, - items: muscles, - initialItems: addExerciseProvider.secondaryMuscles, - onChange: (dynamic muscles) { - addExerciseProvider.secondaryMuscles = muscles.cast(); - }, - onSaved: (dynamic muscles) { - addExerciseProvider.secondaryMuscles = muscles.cast(); - }, - displayName: (Muscle e) => - e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''), - ), - Consumer( - builder: (context, value, child) => MuscleRowWidget( - muscles: value.primaryMuscles, - musclesSecondary: value.secondaryMuscles, + child: Consumer( + 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( + 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( + key: const Key('equipment-multiselect'), + title: AppLocalizations.of(context).equipment, + items: equipment, + initialItems: addExerciseProvider.equipment, + onChange: (dynamic entries) { + addExerciseProvider.equipment = entries.cast(); + }, + onSaved: (dynamic entries) { + addExerciseProvider.equipment = entries.cast(); + }, + displayName: (Equipment e) => getTranslation(e.name, context), + ), + AddExerciseMultiselectButton( + key: const Key('primary-muscles-multiselect'), + title: AppLocalizations.of(context).muscles, + items: muscles, + initialItems: addExerciseProvider.primaryMuscles, + onChange: (dynamic muscles) { + addExerciseProvider.primaryMuscles = muscles.cast(); + }, + onSaved: (dynamic muscles) { + addExerciseProvider.primaryMuscles = muscles.cast(); + }, + displayName: (Muscle e) => + e.name + (e.nameEn.isNotEmpty ? '\n(${getTranslation(e.nameEn, context)})' : ''), + ), + AddExerciseMultiselectButton( + key: const Key('secondary-muscles-multiselect'), + title: AppLocalizations.of(context).musclesSecondary, + items: muscles, + initialItems: addExerciseProvider.secondaryMuscles, + onChange: (dynamic muscles) { + addExerciseProvider.secondaryMuscles = muscles.cast(); + }, + onSaved: (dynamic muscles) { + addExerciseProvider.secondaryMuscles = muscles.cast(); + }, + 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), + ], + ), ), ); } diff --git a/lib/widgets/add_exercise/steps/step6Overview.dart b/lib/widgets/add_exercise/steps/step6Overview.dart index 1aa5d01a..95fdb89d 100644 --- a/lib/widgets/add_exercise/steps/step6Overview.dart +++ b/lib/widgets/add_exercise/steps/step6Overview.dart @@ -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(); - 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( + 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) + ], + ), ); } } diff --git a/test/exercises/contribute_exercise_test.mocks.dart b/test/exercises/contribute_exercise_test.mocks.dart index 04da213b..25cee87e 100644 --- a/test/exercises/contribute_exercise_test.mocks.dart +++ b/test/exercises/contribute_exercise_test.mocks.dart @@ -153,6 +153,18 @@ class MockAddExerciseProvider extends _i1.Mock implements _i11.AddExerciseProvid returnValue: <_i12.File>[], ) as List<_i12.File>); + @override + List get alternateNamesEn => (super.noSuchMethod( + Invocation.getter(#alternateNamesEn), + returnValue: [], + ) as List); + + @override + List get alternateNamesTrans => (super.noSuchMethod( + Invocation.getter(#alternateNamesTrans), + returnValue: [], + ) as List); + @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? 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? names) => super.noSuchMethod( - Invocation.setter( - #alternateNamesEn, - names, - ), - returnValueForMissingStub: null, - ); - - @override - set alternateNamesTrans(List? names) => super.noSuchMethod( + set alternateNamesTrans(List? 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.value(0), ) as _i15.Future); + @override + _i15.Future addImages(int? exerciseId) => (super.noSuchMethod( + Invocation.method( + #addImages, + [exerciseId], + ), + returnValue: _i15.Future.value(), + returnValueForMissingStub: _i15.Future.value(), + ) as _i15.Future); + + @override + _i15.Future validateLanguage( + String? input, + String? languageCode, + ) => + (super.noSuchMethod( + Invocation.method( + #validateLanguage, + [ + input, + languageCode, + ], + ), + returnValue: _i15.Future.value(false), + ) as _i15.Future); + @override void addListener(_i16.VoidCallback? listener) => super.noSuchMethod( Invocation.method(