diff --git a/lib/helpers/errors.dart b/lib/helpers/errors.dart index f8e2e750..a33575ce 100644 --- a/lib/helpers/errors.dart +++ b/lib/helpers/errors.dart @@ -340,30 +340,45 @@ class ApiError { } /// Extracts error messages from the server response +/// Extracts error messages from the server response, +/// including nested error structures. List extractErrors(Map errors) { final List errorList = []; - - for (final key in errors.keys) { - // Header - var header = key[0].toUpperCase() + key.substring(1, key.length); - header = header.replaceAll('_', ' '); - final error = ApiError(key: header); - - final messages = errors[key]; - - // Messages - if (messages is String) { - error.errorMessages = List.of(error.errorMessages)..add(messages); - } else { - error.errorMessages = [...error.errorMessages, ...messages]; - } - - errorList.add(error); - } - + _extractErrorsRecursive(errors, errorList); return errorList; } +void _extractErrorsRecursive(Map errors, List errorList, + [String? parentKey]) { + for (final key in errors.keys) { + final value = errors[key]; + final fullKey = parentKey != null ? '$parentKey | ${_formatHeader(key)}' : key; + + if (value is Map) { + // Nested structure, recursive call + _extractErrorsRecursive(value, errorList, fullKey); + } else { + // Endpoint, put everything together + final header = _formatHeader(fullKey); + final error = ApiError(key: header); + + if (value is String) { + error.errorMessages = [value]; + } else if (value is List) { + error.errorMessages = value.cast(); + } + + errorList.add(error); + } + } +} + +String _formatHeader(String key) { + var header = key[0].toUpperCase() + key.substring(1, key.length); + header = header.replaceAll('_', ' '); + return header.replaceAll('.', ' '); +} + /// Processes the error messages from the server and returns a list of widgets List formatApiErrors(List errors, {Color? color}) { final textColor = color ?? Colors.black; diff --git a/lib/models/exercises/exercise_submission.dart b/lib/models/exercises/exercise_submission.dart new file mode 100644 index 00000000..8bda5df5 --- /dev/null +++ b/lib/models/exercises/exercise_submission.dart @@ -0,0 +1,83 @@ +/* + * This file is part of wger Workout Manager . + * Copyright (C) 2020, 2021 wger Team + * + * wger Workout Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'exercise_submission.freezed.dart'; +part 'exercise_submission.g.dart'; + +// ignore_for_file: invalid_annotation_target + +/// +/// Models for the data model used when submitting an exercise to the API +/// + +/// Alias part of an exercise submission +@freezed +sealed class ExerciseAliasSubmissionApi with _$ExerciseAliasSubmissionApi { + const factory ExerciseAliasSubmissionApi({ + required String alias, + }) = _ExerciseAliasSubmissionApi; + + factory ExerciseAliasSubmissionApi.fromJson(Map json) => + _$ExerciseAliasSubmissionApiFromJson(json); +} + +/// Comment part of an exercise submission +@freezed +sealed class ExerciseCommentSubmissionApi with _$ExerciseCommentSubmissionApi { + const factory ExerciseCommentSubmissionApi({ + required String alias, + }) = _ExerciseCommentSubmissionApi; + + factory ExerciseCommentSubmissionApi.fromJson(Map json) => + _$ExerciseCommentSubmissionApiFromJson(json); +} + +/// Translation part of an exercise submission +@freezed +sealed class ExerciseTranslationSubmissionApi with _$ExerciseTranslationSubmissionApi { + const factory ExerciseTranslationSubmissionApi({ + required String name, + required String description, + required int language, + @JsonKey(name: 'license_author') required String author, + @Default([]) List aliases, + @Default([]) List comments, + }) = _ExerciseTranslationSubmissionApi; + + factory ExerciseTranslationSubmissionApi.fromJson(Map json) => + _$ExerciseTranslationSubmissionApiFromJson(json); +} + +/// "Main" part of an exercise submission +@freezed +sealed class ExerciseSubmissionApi with _$ExerciseSubmissionApi { + const factory ExerciseSubmissionApi({ + required int category, + required List muscles, + @JsonKey(name: 'muscles_secondary') required List musclesSecondary, + required List equipment, + @JsonKey(name: 'license_author') required String author, + @JsonKey(includeToJson: false) int? variation, + required List translations, + }) = _ExerciseSubmissionApi; + + factory ExerciseSubmissionApi.fromJson(Map json) => + _$ExerciseSubmissionApiFromJson(json); +} diff --git a/lib/models/exercises/exercise_submission.freezed.dart b/lib/models/exercises/exercise_submission.freezed.dart new file mode 100644 index 00000000..e156ae41 --- /dev/null +++ b/lib/models/exercises/exercise_submission.freezed.dart @@ -0,0 +1,1560 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'exercise_submission.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$ExerciseAliasSubmissionApi { + String get alias; + + /// Create a copy of ExerciseAliasSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + $ExerciseAliasSubmissionApiCopyWith get copyWith => + _$ExerciseAliasSubmissionApiCopyWithImpl( + this as ExerciseAliasSubmissionApi, _$identity); + + /// Serializes this ExerciseAliasSubmissionApi to a JSON map. + Map toJson(); + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is ExerciseAliasSubmissionApi && + (identical(other.alias, alias) || other.alias == alias)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, alias); + + @override + String toString() { + return 'ExerciseAliasSubmissionApi(alias: $alias)'; + } +} + +/// @nodoc +abstract mixin class $ExerciseAliasSubmissionApiCopyWith<$Res> { + factory $ExerciseAliasSubmissionApiCopyWith( + ExerciseAliasSubmissionApi value, $Res Function(ExerciseAliasSubmissionApi) _then) = + _$ExerciseAliasSubmissionApiCopyWithImpl; + + @useResult + $Res call({String alias}); +} + +/// @nodoc +class _$ExerciseAliasSubmissionApiCopyWithImpl<$Res> + implements $ExerciseAliasSubmissionApiCopyWith<$Res> { + _$ExerciseAliasSubmissionApiCopyWithImpl(this._self, this._then); + + final ExerciseAliasSubmissionApi _self; + final $Res Function(ExerciseAliasSubmissionApi) _then; + + /// Create a copy of ExerciseAliasSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? alias = null, + }) { + return _then(_self.copyWith( + alias: null == alias + ? _self.alias + : alias // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// Adds pattern-matching-related methods to [ExerciseAliasSubmissionApi]. +extension ExerciseAliasSubmissionApiPatterns on ExerciseAliasSubmissionApi { + /// A variant of `map` that fallback to returning `orElse`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ExerciseAliasSubmissionApi value)? $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseAliasSubmissionApi() when $default != null: + return $default(_that); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// Callbacks receives the raw object, upcasted. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case final Subclass2 value: + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult map( + TResult Function(_ExerciseAliasSubmissionApi value) $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseAliasSubmissionApi(): + return $default(_that); + } + } + + /// A variant of `map` that fallback to returning `null`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ExerciseAliasSubmissionApi value)? $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseAliasSubmissionApi() when $default != null: + return $default(_that); + case _: + return null; + } + } + + /// A variant of `when` that fallback to an `orElse` callback. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeWhen( + TResult Function(String alias)? $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseAliasSubmissionApi() when $default != null: + return $default(_that.alias); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// As opposed to `map`, this offers destructuring. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case Subclass2(:final field2): + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult when( + TResult Function(String alias) $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseAliasSubmissionApi(): + return $default(_that.alias); + } + } + + /// A variant of `when` that fallback to returning `null` + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function(String alias)? $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseAliasSubmissionApi() when $default != null: + return $default(_that.alias); + case _: + return null; + } + } +} + +/// @nodoc +@JsonSerializable() +class _ExerciseAliasSubmissionApi implements ExerciseAliasSubmissionApi { + const _ExerciseAliasSubmissionApi({required this.alias}); + + factory _ExerciseAliasSubmissionApi.fromJson(Map json) => + _$ExerciseAliasSubmissionApiFromJson(json); + + @override + final String alias; + + /// Create a copy of ExerciseAliasSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + _$ExerciseAliasSubmissionApiCopyWith<_ExerciseAliasSubmissionApi> get copyWith => + __$ExerciseAliasSubmissionApiCopyWithImpl<_ExerciseAliasSubmissionApi>(this, _$identity); + + @override + Map toJson() { + return _$ExerciseAliasSubmissionApiToJson( + this, + ); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _ExerciseAliasSubmissionApi && + (identical(other.alias, alias) || other.alias == alias)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, alias); + + @override + String toString() { + return 'ExerciseAliasSubmissionApi(alias: $alias)'; + } +} + +/// @nodoc +abstract mixin class _$ExerciseAliasSubmissionApiCopyWith<$Res> + implements $ExerciseAliasSubmissionApiCopyWith<$Res> { + factory _$ExerciseAliasSubmissionApiCopyWith( + _ExerciseAliasSubmissionApi value, $Res Function(_ExerciseAliasSubmissionApi) _then) = + __$ExerciseAliasSubmissionApiCopyWithImpl; + + @override + @useResult + $Res call({String alias}); +} + +/// @nodoc +class __$ExerciseAliasSubmissionApiCopyWithImpl<$Res> + implements _$ExerciseAliasSubmissionApiCopyWith<$Res> { + __$ExerciseAliasSubmissionApiCopyWithImpl(this._self, this._then); + + final _ExerciseAliasSubmissionApi _self; + final $Res Function(_ExerciseAliasSubmissionApi) _then; + + /// Create a copy of ExerciseAliasSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $Res call({ + Object? alias = null, + }) { + return _then(_ExerciseAliasSubmissionApi( + alias: null == alias + ? _self.alias + : alias // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +mixin _$ExerciseCommentSubmissionApi { + String get alias; + + /// Create a copy of ExerciseCommentSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + $ExerciseCommentSubmissionApiCopyWith get copyWith => + _$ExerciseCommentSubmissionApiCopyWithImpl( + this as ExerciseCommentSubmissionApi, _$identity); + + /// Serializes this ExerciseCommentSubmissionApi to a JSON map. + Map toJson(); + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is ExerciseCommentSubmissionApi && + (identical(other.alias, alias) || other.alias == alias)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, alias); + + @override + String toString() { + return 'ExerciseCommentSubmissionApi(alias: $alias)'; + } +} + +/// @nodoc +abstract mixin class $ExerciseCommentSubmissionApiCopyWith<$Res> { + factory $ExerciseCommentSubmissionApiCopyWith( + ExerciseCommentSubmissionApi value, $Res Function(ExerciseCommentSubmissionApi) _then) = + _$ExerciseCommentSubmissionApiCopyWithImpl; + + @useResult + $Res call({String alias}); +} + +/// @nodoc +class _$ExerciseCommentSubmissionApiCopyWithImpl<$Res> + implements $ExerciseCommentSubmissionApiCopyWith<$Res> { + _$ExerciseCommentSubmissionApiCopyWithImpl(this._self, this._then); + + final ExerciseCommentSubmissionApi _self; + final $Res Function(ExerciseCommentSubmissionApi) _then; + + /// Create a copy of ExerciseCommentSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? alias = null, + }) { + return _then(_self.copyWith( + alias: null == alias + ? _self.alias + : alias // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// Adds pattern-matching-related methods to [ExerciseCommentSubmissionApi]. +extension ExerciseCommentSubmissionApiPatterns on ExerciseCommentSubmissionApi { + /// A variant of `map` that fallback to returning `orElse`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ExerciseCommentSubmissionApi value)? $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseCommentSubmissionApi() when $default != null: + return $default(_that); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// Callbacks receives the raw object, upcasted. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case final Subclass2 value: + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult map( + TResult Function(_ExerciseCommentSubmissionApi value) $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseCommentSubmissionApi(): + return $default(_that); + } + } + + /// A variant of `map` that fallback to returning `null`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ExerciseCommentSubmissionApi value)? $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseCommentSubmissionApi() when $default != null: + return $default(_that); + case _: + return null; + } + } + + /// A variant of `when` that fallback to an `orElse` callback. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeWhen( + TResult Function(String alias)? $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseCommentSubmissionApi() when $default != null: + return $default(_that.alias); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// As opposed to `map`, this offers destructuring. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case Subclass2(:final field2): + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult when( + TResult Function(String alias) $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseCommentSubmissionApi(): + return $default(_that.alias); + } + } + + /// A variant of `when` that fallback to returning `null` + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function(String alias)? $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseCommentSubmissionApi() when $default != null: + return $default(_that.alias); + case _: + return null; + } + } +} + +/// @nodoc +@JsonSerializable() +class _ExerciseCommentSubmissionApi implements ExerciseCommentSubmissionApi { + const _ExerciseCommentSubmissionApi({required this.alias}); + + factory _ExerciseCommentSubmissionApi.fromJson(Map json) => + _$ExerciseCommentSubmissionApiFromJson(json); + + @override + final String alias; + + /// Create a copy of ExerciseCommentSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + _$ExerciseCommentSubmissionApiCopyWith<_ExerciseCommentSubmissionApi> get copyWith => + __$ExerciseCommentSubmissionApiCopyWithImpl<_ExerciseCommentSubmissionApi>(this, _$identity); + + @override + Map toJson() { + return _$ExerciseCommentSubmissionApiToJson( + this, + ); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _ExerciseCommentSubmissionApi && + (identical(other.alias, alias) || other.alias == alias)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, alias); + + @override + String toString() { + return 'ExerciseCommentSubmissionApi(alias: $alias)'; + } +} + +/// @nodoc +abstract mixin class _$ExerciseCommentSubmissionApiCopyWith<$Res> + implements $ExerciseCommentSubmissionApiCopyWith<$Res> { + factory _$ExerciseCommentSubmissionApiCopyWith( + _ExerciseCommentSubmissionApi value, $Res Function(_ExerciseCommentSubmissionApi) _then) = + __$ExerciseCommentSubmissionApiCopyWithImpl; + + @override + @useResult + $Res call({String alias}); +} + +/// @nodoc +class __$ExerciseCommentSubmissionApiCopyWithImpl<$Res> + implements _$ExerciseCommentSubmissionApiCopyWith<$Res> { + __$ExerciseCommentSubmissionApiCopyWithImpl(this._self, this._then); + + final _ExerciseCommentSubmissionApi _self; + final $Res Function(_ExerciseCommentSubmissionApi) _then; + + /// Create a copy of ExerciseCommentSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $Res call({ + Object? alias = null, + }) { + return _then(_ExerciseCommentSubmissionApi( + alias: null == alias + ? _self.alias + : alias // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @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 + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + $ExerciseTranslationSubmissionApiCopyWith get copyWith => + _$ExerciseTranslationSubmissionApiCopyWithImpl( + this as ExerciseTranslationSubmissionApi, _$identity); + + /// Serializes this ExerciseTranslationSubmissionApi to a JSON map. + Map toJson(); + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is ExerciseTranslationSubmissionApi && + (identical(other.name, name) || other.name == name) && + (identical(other.description, description) || other.description == description) && + (identical(other.language, language) || other.language == language) && + (identical(other.author, author) || other.author == author) && + const DeepCollectionEquality().equals(other.aliases, aliases) && + const DeepCollectionEquality().equals(other.comments, comments)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, name, description, language, author, + const DeepCollectionEquality().hash(aliases), const DeepCollectionEquality().hash(comments)); + + @override + String toString() { + return 'ExerciseTranslationSubmissionApi(name: $name, description: $description, language: $language, author: $author, aliases: $aliases, comments: $comments)'; + } +} + +/// @nodoc +abstract mixin class $ExerciseTranslationSubmissionApiCopyWith<$Res> { + factory $ExerciseTranslationSubmissionApiCopyWith(ExerciseTranslationSubmissionApi value, + $Res Function(ExerciseTranslationSubmissionApi) _then) = + _$ExerciseTranslationSubmissionApiCopyWithImpl; + + @useResult + $Res call( + {String name, + String description, + int language, + @JsonKey(name: 'license_author') String author, + List aliases, + List comments}); +} + +/// @nodoc +class _$ExerciseTranslationSubmissionApiCopyWithImpl<$Res> + implements $ExerciseTranslationSubmissionApiCopyWith<$Res> { + _$ExerciseTranslationSubmissionApiCopyWithImpl(this._self, this._then); + + final ExerciseTranslationSubmissionApi _self; + final $Res Function(ExerciseTranslationSubmissionApi) _then; + + /// Create a copy of ExerciseTranslationSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? description = null, + Object? language = null, + Object? author = null, + Object? aliases = null, + Object? comments = null, + }) { + return _then(_self.copyWith( + name: null == name + ? _self.name + : name // ignore: cast_nullable_to_non_nullable + as String, + description: null == description + ? _self.description + : description // ignore: cast_nullable_to_non_nullable + as String, + language: null == language + ? _self.language + : language // ignore: cast_nullable_to_non_nullable + as int, + author: null == author + ? _self.author + : author // ignore: cast_nullable_to_non_nullable + as String, + aliases: null == aliases + ? _self.aliases + : aliases // ignore: cast_nullable_to_non_nullable + as List, + comments: null == comments + ? _self.comments + : comments // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// Adds pattern-matching-related methods to [ExerciseTranslationSubmissionApi]. +extension ExerciseTranslationSubmissionApiPatterns on ExerciseTranslationSubmissionApi { + /// A variant of `map` that fallback to returning `orElse`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ExerciseTranslationSubmissionApi value)? $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseTranslationSubmissionApi() when $default != null: + return $default(_that); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// Callbacks receives the raw object, upcasted. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case final Subclass2 value: + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult map( + TResult Function(_ExerciseTranslationSubmissionApi value) $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseTranslationSubmissionApi(): + return $default(_that); + } + } + + /// A variant of `map` that fallback to returning `null`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ExerciseTranslationSubmissionApi value)? $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseTranslationSubmissionApi() when $default != null: + return $default(_that); + case _: + return null; + } + } + + /// A variant of `when` that fallback to an `orElse` callback. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeWhen( + TResult Function( + String name, + String description, + int language, + @JsonKey(name: 'license_author') String author, + List aliases, + List comments)? + $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseTranslationSubmissionApi() when $default != null: + return $default(_that.name, _that.description, _that.language, _that.author, _that.aliases, + _that.comments); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// As opposed to `map`, this offers destructuring. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case Subclass2(:final field2): + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult when( + TResult Function( + String name, + String description, + int language, + @JsonKey(name: 'license_author') String author, + List aliases, + List comments) + $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseTranslationSubmissionApi(): + return $default(_that.name, _that.description, _that.language, _that.author, _that.aliases, + _that.comments); + } + } + + /// A variant of `when` that fallback to returning `null` + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function( + String name, + String description, + int language, + @JsonKey(name: 'license_author') String author, + List aliases, + List comments)? + $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseTranslationSubmissionApi() when $default != null: + return $default(_that.name, _that.description, _that.language, _that.author, _that.aliases, + _that.comments); + case _: + return null; + } + } +} + +/// @nodoc +@JsonSerializable() +class _ExerciseTranslationSubmissionApi implements ExerciseTranslationSubmissionApi { + const _ExerciseTranslationSubmissionApi( + {required this.name, + required this.description, + required this.language, + @JsonKey(name: 'license_author') required this.author, + final List aliases = const [], + final List comments = const []}) + : _aliases = aliases, + _comments = comments; + + factory _ExerciseTranslationSubmissionApi.fromJson(Map json) => + _$ExerciseTranslationSubmissionApiFromJson(json); + + @override + final String name; + @override + final String description; + @override + final int language; + @override + @JsonKey(name: 'license_author') + final String author; + final List _aliases; + + @override + @JsonKey() + List get aliases { + if (_aliases is EqualUnmodifiableListView) return _aliases; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_aliases); + } + + final List _comments; + + @override + @JsonKey() + List get comments { + if (_comments is EqualUnmodifiableListView) return _comments; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_comments); + } + + /// Create a copy of ExerciseTranslationSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + _$ExerciseTranslationSubmissionApiCopyWith<_ExerciseTranslationSubmissionApi> get copyWith => + __$ExerciseTranslationSubmissionApiCopyWithImpl<_ExerciseTranslationSubmissionApi>( + this, _$identity); + + @override + Map toJson() { + return _$ExerciseTranslationSubmissionApiToJson( + this, + ); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _ExerciseTranslationSubmissionApi && + (identical(other.name, name) || other.name == name) && + (identical(other.description, description) || other.description == description) && + (identical(other.language, language) || other.language == language) && + (identical(other.author, author) || other.author == author) && + const DeepCollectionEquality().equals(other._aliases, _aliases) && + const DeepCollectionEquality().equals(other._comments, _comments)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + name, + description, + language, + author, + const DeepCollectionEquality().hash(_aliases), + const DeepCollectionEquality().hash(_comments)); + + @override + String toString() { + return 'ExerciseTranslationSubmissionApi(name: $name, description: $description, language: $language, author: $author, aliases: $aliases, comments: $comments)'; + } +} + +/// @nodoc +abstract mixin class _$ExerciseTranslationSubmissionApiCopyWith<$Res> + implements $ExerciseTranslationSubmissionApiCopyWith<$Res> { + factory _$ExerciseTranslationSubmissionApiCopyWith(_ExerciseTranslationSubmissionApi value, + $Res Function(_ExerciseTranslationSubmissionApi) _then) = + __$ExerciseTranslationSubmissionApiCopyWithImpl; + + @override + @useResult + $Res call( + {String name, + String description, + int language, + @JsonKey(name: 'license_author') String author, + List aliases, + List comments}); +} + +/// @nodoc +class __$ExerciseTranslationSubmissionApiCopyWithImpl<$Res> + implements _$ExerciseTranslationSubmissionApiCopyWith<$Res> { + __$ExerciseTranslationSubmissionApiCopyWithImpl(this._self, this._then); + + final _ExerciseTranslationSubmissionApi _self; + final $Res Function(_ExerciseTranslationSubmissionApi) _then; + + /// Create a copy of ExerciseTranslationSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $Res call({ + Object? name = null, + Object? description = null, + Object? language = null, + Object? author = null, + Object? aliases = null, + Object? comments = null, + }) { + return _then(_ExerciseTranslationSubmissionApi( + name: null == name + ? _self.name + : name // ignore: cast_nullable_to_non_nullable + as String, + description: null == description + ? _self.description + : description // ignore: cast_nullable_to_non_nullable + as String, + language: null == language + ? _self.language + : language // ignore: cast_nullable_to_non_nullable + as int, + author: null == author + ? _self.author + : author // ignore: cast_nullable_to_non_nullable + as String, + aliases: null == aliases + ? _self._aliases + : aliases // ignore: cast_nullable_to_non_nullable + as List, + comments: null == comments + ? _self._comments + : comments // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @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 + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + $ExerciseSubmissionApiCopyWith get copyWith => + _$ExerciseSubmissionApiCopyWithImpl( + this as ExerciseSubmissionApi, _$identity); + + /// Serializes this ExerciseSubmissionApi to a JSON map. + Map toJson(); + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is ExerciseSubmissionApi && + (identical(other.category, category) || other.category == category) && + const DeepCollectionEquality().equals(other.muscles, muscles) && + const DeepCollectionEquality().equals(other.musclesSecondary, musclesSecondary) && + const DeepCollectionEquality().equals(other.equipment, equipment) && + (identical(other.author, author) || other.author == author) && + (identical(other.variation, variation) || other.variation == variation) && + const DeepCollectionEquality().equals(other.translations, translations)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + category, + const DeepCollectionEquality().hash(muscles), + const DeepCollectionEquality().hash(musclesSecondary), + const DeepCollectionEquality().hash(equipment), + author, + variation, + const DeepCollectionEquality().hash(translations)); + + @override + String toString() { + return 'ExerciseSubmissionApi(category: $category, muscles: $muscles, musclesSecondary: $musclesSecondary, equipment: $equipment, author: $author, variation: $variation, translations: $translations)'; + } +} + +/// @nodoc +abstract mixin class $ExerciseSubmissionApiCopyWith<$Res> { + factory $ExerciseSubmissionApiCopyWith( + ExerciseSubmissionApi value, $Res Function(ExerciseSubmissionApi) _then) = + _$ExerciseSubmissionApiCopyWithImpl; + + @useResult + $Res call( + {int category, + List muscles, + @JsonKey(name: 'muscles_secondary') List musclesSecondary, + List equipment, + @JsonKey(name: 'license_author') String author, + @JsonKey(includeToJson: false) int? variation, + List translations}); +} + +/// @nodoc +class _$ExerciseSubmissionApiCopyWithImpl<$Res> implements $ExerciseSubmissionApiCopyWith<$Res> { + _$ExerciseSubmissionApiCopyWithImpl(this._self, this._then); + + final ExerciseSubmissionApi _self; + final $Res Function(ExerciseSubmissionApi) _then; + + /// Create a copy of ExerciseSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? category = null, + Object? muscles = null, + Object? musclesSecondary = null, + Object? equipment = null, + Object? author = null, + Object? variation = freezed, + Object? translations = null, + }) { + return _then(_self.copyWith( + category: null == category + ? _self.category + : category // ignore: cast_nullable_to_non_nullable + as int, + muscles: null == muscles + ? _self.muscles + : muscles // ignore: cast_nullable_to_non_nullable + as List, + musclesSecondary: null == musclesSecondary + ? _self.musclesSecondary + : musclesSecondary // ignore: cast_nullable_to_non_nullable + as List, + equipment: null == equipment + ? _self.equipment + : equipment // ignore: cast_nullable_to_non_nullable + as List, + author: null == author + ? _self.author + : author // ignore: cast_nullable_to_non_nullable + as String, + variation: freezed == variation + ? _self.variation + : variation // ignore: cast_nullable_to_non_nullable + as int?, + translations: null == translations + ? _self.translations + : translations // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// Adds pattern-matching-related methods to [ExerciseSubmissionApi]. +extension ExerciseSubmissionApiPatterns on ExerciseSubmissionApi { + /// A variant of `map` that fallback to returning `orElse`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeMap( + TResult Function(_ExerciseSubmissionApi value)? $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseSubmissionApi() when $default != null: + return $default(_that); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// Callbacks receives the raw object, upcasted. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case final Subclass2 value: + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult map( + TResult Function(_ExerciseSubmissionApi value) $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseSubmissionApi(): + return $default(_that); + } + } + + /// A variant of `map` that fallback to returning `null`. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case final Subclass value: + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_ExerciseSubmissionApi value)? $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseSubmissionApi() when $default != null: + return $default(_that); + case _: + return null; + } + } + + /// A variant of `when` that fallback to an `orElse` callback. + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return orElse(); + /// } + /// ``` + + @optionalTypeArgs + TResult maybeWhen( + TResult Function( + int category, + List muscles, + @JsonKey(name: 'muscles_secondary') List musclesSecondary, + List equipment, + @JsonKey(name: 'license_author') String author, + @JsonKey(includeToJson: false) int? variation, + List translations)? + $default, { + required TResult orElse(), + }) { + final _that = this; + switch (_that) { + case _ExerciseSubmissionApi() when $default != null: + return $default(_that.category, _that.muscles, _that.musclesSecondary, _that.equipment, + _that.author, _that.variation, _that.translations); + case _: + return orElse(); + } + } + + /// A `switch`-like method, using callbacks. + /// + /// As opposed to `map`, this offers destructuring. + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case Subclass2(:final field2): + /// return ...; + /// } + /// ``` + + @optionalTypeArgs + TResult when( + TResult Function( + int category, + List muscles, + @JsonKey(name: 'muscles_secondary') List musclesSecondary, + List equipment, + @JsonKey(name: 'license_author') String author, + @JsonKey(includeToJson: false) int? variation, + List translations) + $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseSubmissionApi(): + return $default(_that.category, _that.muscles, _that.musclesSecondary, _that.equipment, + _that.author, _that.variation, _that.translations); + } + } + + /// A variant of `when` that fallback to returning `null` + /// + /// It is equivalent to doing: + /// ```dart + /// switch (sealedClass) { + /// case Subclass(:final field): + /// return ...; + /// case _: + /// return null; + /// } + /// ``` + + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function( + int category, + List muscles, + @JsonKey(name: 'muscles_secondary') List musclesSecondary, + List equipment, + @JsonKey(name: 'license_author') String author, + @JsonKey(includeToJson: false) int? variation, + List translations)? + $default, + ) { + final _that = this; + switch (_that) { + case _ExerciseSubmissionApi() when $default != null: + return $default(_that.category, _that.muscles, _that.musclesSecondary, _that.equipment, + _that.author, _that.variation, _that.translations); + case _: + return null; + } + } +} + +/// @nodoc +@JsonSerializable() +class _ExerciseSubmissionApi implements ExerciseSubmissionApi { + const _ExerciseSubmissionApi( + {required this.category, + required final List muscles, + @JsonKey(name: 'muscles_secondary') required final List musclesSecondary, + required final List equipment, + @JsonKey(name: 'license_author') required this.author, + @JsonKey(includeToJson: false) this.variation, + required final List translations}) + : _muscles = muscles, + _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; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_muscles); + } + + final List _musclesSecondary; + + @override + @JsonKey(name: 'muscles_secondary') + List get musclesSecondary { + if (_musclesSecondary is EqualUnmodifiableListView) return _musclesSecondary; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_musclesSecondary); + } + + final List _equipment; + + @override + List get equipment { + if (_equipment is EqualUnmodifiableListView) return _equipment; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_equipment); + } + + @override + @JsonKey(name: 'license_author') + final String author; + @override + @JsonKey(includeToJson: false) + final int? variation; + final List _translations; + + @override + List get translations { + if (_translations is EqualUnmodifiableListView) return _translations; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_translations); + } + + /// Create a copy of ExerciseSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + @pragma('vm:prefer-inline') + _$ExerciseSubmissionApiCopyWith<_ExerciseSubmissionApi> get copyWith => + __$ExerciseSubmissionApiCopyWithImpl<_ExerciseSubmissionApi>(this, _$identity); + + @override + Map toJson() { + return _$ExerciseSubmissionApiToJson( + this, + ); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _ExerciseSubmissionApi && + (identical(other.category, category) || other.category == category) && + const DeepCollectionEquality().equals(other._muscles, _muscles) && + const DeepCollectionEquality().equals(other._musclesSecondary, _musclesSecondary) && + const DeepCollectionEquality().equals(other._equipment, _equipment) && + (identical(other.author, author) || other.author == author) && + (identical(other.variation, variation) || other.variation == variation) && + const DeepCollectionEquality().equals(other._translations, _translations)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + category, + const DeepCollectionEquality().hash(_muscles), + const DeepCollectionEquality().hash(_musclesSecondary), + const DeepCollectionEquality().hash(_equipment), + author, + variation, + const DeepCollectionEquality().hash(_translations)); + + @override + String toString() { + return 'ExerciseSubmissionApi(category: $category, muscles: $muscles, musclesSecondary: $musclesSecondary, equipment: $equipment, author: $author, variation: $variation, translations: $translations)'; + } +} + +/// @nodoc +abstract mixin class _$ExerciseSubmissionApiCopyWith<$Res> + implements $ExerciseSubmissionApiCopyWith<$Res> { + factory _$ExerciseSubmissionApiCopyWith( + _ExerciseSubmissionApi value, $Res Function(_ExerciseSubmissionApi) _then) = + __$ExerciseSubmissionApiCopyWithImpl; + + @override + @useResult + $Res call( + {int category, + List muscles, + @JsonKey(name: 'muscles_secondary') List musclesSecondary, + List equipment, + @JsonKey(name: 'license_author') String author, + @JsonKey(includeToJson: false) int? variation, + List translations}); +} + +/// @nodoc +class __$ExerciseSubmissionApiCopyWithImpl<$Res> implements _$ExerciseSubmissionApiCopyWith<$Res> { + __$ExerciseSubmissionApiCopyWithImpl(this._self, this._then); + + final _ExerciseSubmissionApi _self; + final $Res Function(_ExerciseSubmissionApi) _then; + + /// Create a copy of ExerciseSubmissionApi + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $Res call({ + Object? category = null, + Object? muscles = null, + Object? musclesSecondary = null, + Object? equipment = null, + Object? author = null, + Object? variation = freezed, + Object? translations = null, + }) { + return _then(_ExerciseSubmissionApi( + category: null == category + ? _self.category + : category // ignore: cast_nullable_to_non_nullable + as int, + muscles: null == muscles + ? _self._muscles + : muscles // ignore: cast_nullable_to_non_nullable + as List, + musclesSecondary: null == musclesSecondary + ? _self._musclesSecondary + : musclesSecondary // ignore: cast_nullable_to_non_nullable + as List, + equipment: null == equipment + ? _self._equipment + : equipment // ignore: cast_nullable_to_non_nullable + as List, + author: null == author + ? _self.author + : author // ignore: cast_nullable_to_non_nullable + as String, + variation: freezed == variation + ? _self.variation + : variation // ignore: cast_nullable_to_non_nullable + as int?, + translations: null == translations + ? _self._translations + : translations // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +// dart format on diff --git a/lib/models/exercises/exercise_submission.g.dart b/lib/models/exercises/exercise_submission.g.dart new file mode 100644 index 00000000..3dcebae5 --- /dev/null +++ b/lib/models/exercises/exercise_submission.g.dart @@ -0,0 +1,79 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'exercise_submission.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_ExerciseAliasSubmissionApi _$ExerciseAliasSubmissionApiFromJson(Map json) => + _ExerciseAliasSubmissionApi( + alias: json['alias'] as String, + ); + +Map _$ExerciseAliasSubmissionApiToJson(_ExerciseAliasSubmissionApi instance) => + { + 'alias': instance.alias, + }; + +_ExerciseCommentSubmissionApi _$ExerciseCommentSubmissionApiFromJson(Map json) => + _ExerciseCommentSubmissionApi( + alias: json['alias'] as String, + ); + +Map _$ExerciseCommentSubmissionApiToJson(_ExerciseCommentSubmissionApi instance) => + { + 'alias': instance.alias, + }; + +_ExerciseTranslationSubmissionApi _$ExerciseTranslationSubmissionApiFromJson( + Map json) => + _ExerciseTranslationSubmissionApi( + name: json['name'] as String, + description: json['description'] as String, + language: (json['language'] as num).toInt(), + author: json['license_author'] as String, + aliases: (json['aliases'] as List?) + ?.map((e) => ExerciseAliasSubmissionApi.fromJson(e as Map)) + .toList() ?? + const [], + comments: (json['comments'] as List?) + ?.map((e) => ExerciseCommentSubmissionApi.fromJson(e as Map)) + .toList() ?? + const [], + ); + +Map _$ExerciseTranslationSubmissionApiToJson( + _ExerciseTranslationSubmissionApi instance) => + { + 'name': instance.name, + 'description': instance.description, + 'language': instance.language, + 'license_author': instance.author, + 'aliases': instance.aliases, + 'comments': instance.comments, + }; + +_ExerciseSubmissionApi _$ExerciseSubmissionApiFromJson(Map json) => + _ExerciseSubmissionApi( + category: (json['category'] as num).toInt(), + muscles: (json['muscles'] as List).map((e) => (e as num).toInt()).toList(), + musclesSecondary: + (json['muscles_secondary'] as List).map((e) => (e as num).toInt()).toList(), + equipment: (json['equipment'] as List).map((e) => (e as num).toInt()).toList(), + author: json['license_author'] as String, + variation: (json['variation'] as num?)?.toInt(), + translations: (json['translations'] as List) + .map((e) => ExerciseTranslationSubmissionApi.fromJson(e as Map)) + .toList(), + ); + +Map _$ExerciseSubmissionApiToJson(_ExerciseSubmissionApi instance) => + { + 'category': instance.category, + 'muscles': instance.muscles, + 'muscles_secondary': instance.musclesSecondary, + 'equipment': instance.equipment, + 'license_author': instance.author, + 'translations': instance.translations, + }; diff --git a/lib/providers/add_exercise.dart b/lib/providers/add_exercise.dart index 2dee7912..a1e763b2 100644 --- a/lib/providers/add_exercise.dart +++ b/lib/providers/add_exercise.dart @@ -2,15 +2,12 @@ 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/alias.dart'; import 'package:wger/models/exercises/category.dart'; import 'package:wger/models/exercises/equipment.dart'; import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/exercises/exercise_submission.dart'; import 'package:wger/models/exercises/language.dart'; import 'package:wger/models/exercises/muscle.dart'; -import 'package:wger/models/exercises/translation.dart'; import 'package:wger/models/exercises/variation.dart'; import 'base_provider.dart'; @@ -28,7 +25,8 @@ class AddExerciseProvider with ChangeNotifier { String? _descriptionTranslation; int? _variationId; int? _newVariationForExercise; - Language? language; + Language? languageEn; + Language? languageTranslation; List _alternativeNamesEn = []; List _alternativeNamesTranslation = []; ExerciseCategory? category; @@ -37,15 +35,11 @@ class AddExerciseProvider with ChangeNotifier { List _primaryMuscles = []; List _secondaryMuscles = []; - static const _exerciseUrlPath = 'exercise'; - static const _imagesUrlPath = 'exerciseimage'; - static const _exerciseTranslationUrlPath = 'exercise-translation'; - static const _exerciseAliasPath = 'exercisealias'; - static const _exerciseVariationPath = 'variation'; + static const _exerciseSubmissionUrlPath = 'exercise-submission'; void clear() { _exerciseImages = []; - language = null; + languageTranslation = null; category = null; _nameEn = null; _nameTranslation = null; @@ -93,32 +87,6 @@ class AddExerciseProvider with ChangeNotifier { notifyListeners(); } - Exercise get exercise { - return Exercise( - category: category, - equipment: _equipment, - muscles: _primaryMuscles, - musclesSecondary: _secondaryMuscles, - variationId: _variationId, - ); - } - - Translation get translationEn { - return Translation( - name: _nameEn!, - description: _descriptionEn!, - language: const Language(id: 2, fullName: 'English', shortName: 'en'), - ); - } - - Translation get translation { - return Translation( - name: _nameTranslation!, - description: _descriptionTranslation!, - language: language, - ); - } - Variation get variation { return Variation(id: _variationId!); } @@ -137,6 +105,43 @@ class AddExerciseProvider with ChangeNotifier { notifyListeners(); } + ExerciseSubmissionApi get exerciseApiObject { + return ExerciseSubmissionApi( + author: '', + //variation: variationId, + category: category!.id, + muscles: _primaryMuscles.map((e) => e.id).toList(), + musclesSecondary: _secondaryMuscles.map((e) => e.id).toList(), + equipment: _equipment.map((e) => e.id).toList(), + translations: [ + // Base language (English) + ExerciseTranslationSubmissionApi( + author: '', + language: languageEn!.id, + name: _nameEn!, + description: _descriptionEn!, + aliases: _alternativeNamesEn + .where((element) => element.isNotEmpty) + .map((e) => ExerciseAliasSubmissionApi(alias: e)) + .toList(), + ), + + // Optional translation + if (languageTranslation != null) + ExerciseTranslationSubmissionApi( + author: '', + language: languageTranslation!.id, + name: _nameTranslation!, + description: _descriptionTranslation!, + aliases: _alternativeNamesTranslation + .where((element) => element.isNotEmpty) + .map((e) => ExerciseAliasSubmissionApi(alias: e)) + .toList(), + ), + ], + ); + } + void addExerciseImages(List exercises) { _exerciseImages.addAll(exercises); notifyListeners(); @@ -162,7 +167,7 @@ class AddExerciseProvider with ChangeNotifier { log(''); log('Language specific...'); - log('Language: ${language?.shortName}'); + log('Language: ${languageTranslation?.shortName}'); log('Name: en/$_nameEn translation/$_nameTranslation'); log('Description: en/$_descriptionEn translation/$_descriptionTranslation'); log('Alternate names: en/$_alternativeNamesEn translation/$_alternativeNamesTranslation'); @@ -172,58 +177,38 @@ class AddExerciseProvider with ChangeNotifier { printValues(); // Create the variations if needed - if (newVariation) { - await addVariation(); - } + // if (newVariation) { + // await addVariation(); + // } // Create the exercise - final exercise = await addExerciseBase(); - - // Create the base description in English - Translation exerciseTranslationEn = translationEn; - exerciseTranslationEn.exercise = exercise; - exerciseTranslationEn = await addExerciseTranslation(exerciseTranslationEn); - for (final alias in _alternativeNamesEn) { - if (alias.isNotEmpty) { - exerciseTranslationEn.aliases.add(await addExerciseAlias(alias, exerciseTranslationEn.id!)); - } - } - - // Create the translations - if (language != null) { - Translation exerciseTranslationLang = translation; - exerciseTranslationLang.exercise = exercise; - exerciseTranslationLang = await addExerciseTranslation(exerciseTranslationLang); - for (final alias in _alternativeNamesTranslation) { - if (alias.isNotEmpty) { - exerciseTranslationLang.aliases.add( - await addExerciseAlias(alias, exerciseTranslationLang.id!), - ); - } - } - await addExerciseTranslation(exerciseTranslationLang); - } - - // Create the images - await addImages(exercise); + final exerciseId = await addExerciseSubmission(); // Clear everything clear(); // Return exercise ID - return exercise.id!; + return exerciseId; } - Future addExerciseBase() async { - final Uri postUri = baseProvider.makeUrl(_exerciseUrlPath); - - final Map newBaseMap = await baseProvider.post(exercise.toJson(), postUri); - final Exercise newExercise = Exercise.fromJson(newBaseMap); + Future addExerciseSubmission() async { + final Map result = await baseProvider.post( + exerciseApiObject.toJson(), + baseProvider.makeUrl(_exerciseSubmissionUrlPath), + ); notifyListeners(); - return newExercise; + return result['id']; } +/* + Note: all this logic is not needed now since we are using the /exercise-submission + endpoint,however, if we ever want to implement editing of exercises, we will + need basically all of it again, so this is kept here for reference. + + + + Future addVariation() async { final Uri postUri = baseProvider.makeUrl(_exerciseVariationPath); @@ -269,4 +254,6 @@ class AddExerciseProvider with ChangeNotifier { return newAlias; } + + */ } diff --git a/lib/screens/add_exercise_screen.dart b/lib/screens/add_exercise_screen.dart index c6659092..b223db80 100644 --- a/lib/screens/add_exercise_screen.dart +++ b/lib/screens/add_exercise_screen.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/helpers/consts.dart'; +import 'package:wger/helpers/errors.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; +import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/user.dart'; @@ -42,6 +45,7 @@ class _AddExerciseStepperState extends State { int _currentStep = 0; int lastStepIndex = AddExerciseStepper.STEPS_IN_FORM - 1; bool _isLoading = false; + Widget errorWidget = const SizedBox.shrink(); final List> _keys = [ GlobalKey(), @@ -55,6 +59,7 @@ class _AddExerciseStepperState extends State { return Column( children: [ const SizedBox(height: 10), + errorWidget, Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ @@ -62,6 +67,8 @@ class _AddExerciseStepperState extends State { onPressed: details.onStepCancel, child: Text(AppLocalizations.of(context).previous), ), + + // Submit button on last step if (_currentStep == lastStepIndex) ElevatedButton( onPressed: _isLoading @@ -69,21 +76,54 @@ class _AddExerciseStepperState extends State { : () async { setState(() { _isLoading = true; + errorWidget = const SizedBox.shrink(); }); final addExerciseProvider = context.read(); final exerciseProvider = context.read(); - final exerciseId = await addExerciseProvider.addExercise(); - final exercise = await exerciseProvider.fetchAndSetExercise(exerciseId); - final name = exercise! + Exercise? exercise; + try { + final exerciseId = await addExerciseProvider.addExercise(); + exercise = await exerciseProvider.fetchAndSetExercise(exerciseId); + } on WgerHttpException catch (error) { + if (context.mounted) { + setState(() { + errorWidget = FormHttpErrorsWidget(error); + }); + } + } + + if (exercise == null) { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + if (!context.mounted) { + return; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Could not fetch the created exercise.'), + ), + ); + return; + } + + final name = exercise .getTranslation(Localizations.localeOf(context).languageCode) .name; - setState(() { - _isLoading = false; - }); + if (mounted) { + setState(() { + _isLoading = false; + }); + } + + if (!context.mounted) { + return; + } - if (!context.mounted) return; return showDialog( context: context, builder: (BuildContext context) { diff --git a/lib/widgets/add_exercise/steps/step1basics.dart b/lib/widgets/add_exercise/steps/step1basics.dart index d4402830..bb0eb52a 100644 --- a/lib/widgets/add_exercise/steps/step1basics.dart +++ b/lib/widgets/add_exercise/steps/step1basics.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/exercises/forms.dart'; import 'package:wger/helpers/i18n.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; @@ -26,6 +27,11 @@ class Step1Basics extends StatelessWidget { final muscles = exerciseProvider.muscles; final equipment = exerciseProvider.equipment; + // There mus be a better way to ensure this... + addExerciseProvider.languageEn = exerciseProvider.languages.firstWhere( + (l) => l.shortName == LANGUAGE_SHORT_ENGLISH, + ); + return Form( key: formkey, child: Column( diff --git a/lib/widgets/add_exercise/steps/step4translations.dart b/lib/widgets/add_exercise/steps/step4translations.dart index 7990b8ea..91c86408 100644 --- a/lib/widgets/add_exercise/steps/step4translations.dart +++ b/lib/widgets/add_exercise/steps/step4translations.dart @@ -49,7 +49,7 @@ class _Step4TranslationState extends State { title: '${AppLocalizations.of(context).language}*', displayName: (Language l) => l.fullName, callback: (Language newValue) { - addExerciseProvider.language = newValue; + addExerciseProvider.languageTranslation = newValue; }, validator: (Language? language) { if (language == null) { diff --git a/lib/widgets/add_exercise/steps/step6Overview.dart b/lib/widgets/add_exercise/steps/step6Overview.dart new file mode 100644 index 00000000..623d0595 --- /dev/null +++ b/lib/widgets/add_exercise/steps/step6Overview.dart @@ -0,0 +1,51 @@ +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/mixins/image_picker_mixin.dart'; +import 'package:wger/widgets/add_exercise/preview_images.dart'; + +class Step6Overview extends StatefulWidget { + final GlobalKey formkey; + + const Step6Overview({required this.formkey}); + + @override + State createState() => _Step6OverviewState(); +} + +class _Step6OverviewState extends State with ExerciseImagePickerMixin { + @override + Widget build(BuildContext context) { + return Form( + key: widget.formkey, + child: Column( + children: [ + Text( + AppLocalizations.of(context).add_exercise_image_license, + style: Theme.of(context).textTheme.bodySmall, + ), + Consumer( + builder: (ctx, provider, __) => provider.exerciseImages.isNotEmpty + ? PreviewExerciseImages( + selectedImages: provider.exerciseImages, + ) + : Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + onPressed: () => pickImages(context, pickFromCamera: true), + icon: const Icon(Icons.camera_alt), + ), + IconButton( + onPressed: () => pickImages(context), + icon: const Icon(Icons.collections), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 96cada81..34f38bbb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,7 +24,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.8.4+90 environment: - sdk: '>=3.0.0 <4.0.0' + sdk: '>=3.8.0 <4.0.0' dependencies: flutter: diff --git a/test/exercises/contribute_exercise_test.mocks.dart b/test/exercises/contribute_exercise_test.mocks.dart index 80317560..04da213b 100644 --- a/test/exercises/contribute_exercise_test.mocks.dart +++ b/test/exercises/contribute_exercise_test.mocks.dart @@ -4,23 +4,23 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i15; -import 'dart:io' as _i14; +import 'dart:io' as _i12; import 'dart:ui' as _i16; import 'package:flutter/material.dart' as _i18; import 'package:mockito/mockito.dart' as _i1; -import 'package:shared_preferences/shared_preferences.dart' as _i7; -import 'package:wger/database/exercises/exercise_database.dart' as _i8; -import 'package:wger/models/exercises/alias.dart' as _i6; -import 'package:wger/models/exercises/category.dart' as _i9; -import 'package:wger/models/exercises/equipment.dart' as _i10; -import 'package:wger/models/exercises/exercise.dart' as _i3; -import 'package:wger/models/exercises/language.dart' as _i12; -import 'package:wger/models/exercises/muscle.dart' as _i11; -import 'package:wger/models/exercises/translation.dart' as _i4; -import 'package:wger/models/exercises/variation.dart' as _i5; +import 'package:mockito/src/dummies.dart' as _i14; +import 'package:shared_preferences/shared_preferences.dart' as _i4; +import 'package:wger/database/exercises/exercise_database.dart' as _i5; +import 'package:wger/models/exercises/category.dart' as _i7; +import 'package:wger/models/exercises/equipment.dart' as _i8; +import 'package:wger/models/exercises/exercise.dart' as _i6; +import 'package:wger/models/exercises/exercise_submission.dart' as _i13; +import 'package:wger/models/exercises/language.dart' as _i10; +import 'package:wger/models/exercises/muscle.dart' as _i9; +import 'package:wger/models/exercises/variation.dart' as _i3; import 'package:wger/models/user/profile.dart' as _i19; -import 'package:wger/providers/add_exercise.dart' as _i13; +import 'package:wger/providers/add_exercise.dart' as _i11; import 'package:wger/providers/base_provider.dart' as _i2; import 'package:wger/providers/exercises.dart' as _i20; import 'package:wger/providers/user.dart' as _i17; @@ -50,8 +50,8 @@ class _FakeWgerBaseProvider_0 extends _i1.SmartFake implements _i2.WgerBaseProvi ); } -class _FakeExercise_1 extends _i1.SmartFake implements _i3.Exercise { - _FakeExercise_1( +class _FakeVariation_1 extends _i1.SmartFake implements _i3.Variation { + _FakeVariation_1( Object parent, Invocation parentInvocation, ) : super( @@ -60,8 +60,8 @@ class _FakeExercise_1 extends _i1.SmartFake implements _i3.Exercise { ); } -class _FakeTranslation_2 extends _i1.SmartFake implements _i4.Translation { - _FakeTranslation_2( +class _FakeSharedPreferencesAsync_2 extends _i1.SmartFake implements _i4.SharedPreferencesAsync { + _FakeSharedPreferencesAsync_2( Object parent, Invocation parentInvocation, ) : super( @@ -70,8 +70,8 @@ class _FakeTranslation_2 extends _i1.SmartFake implements _i4.Translation { ); } -class _FakeVariation_3 extends _i1.SmartFake implements _i5.Variation { - _FakeVariation_3( +class _FakeExerciseDatabase_3 extends _i1.SmartFake implements _i5.ExerciseDatabase { + _FakeExerciseDatabase_3( Object parent, Invocation parentInvocation, ) : super( @@ -80,8 +80,8 @@ class _FakeVariation_3 extends _i1.SmartFake implements _i5.Variation { ); } -class _FakeAlias_4 extends _i1.SmartFake implements _i6.Alias { - _FakeAlias_4( +class _FakeExercise_4 extends _i1.SmartFake implements _i6.Exercise { + _FakeExercise_4( Object parent, Invocation parentInvocation, ) : super( @@ -90,8 +90,8 @@ class _FakeAlias_4 extends _i1.SmartFake implements _i6.Alias { ); } -class _FakeSharedPreferencesAsync_5 extends _i1.SmartFake implements _i7.SharedPreferencesAsync { - _FakeSharedPreferencesAsync_5( +class _FakeExerciseCategory_5 extends _i1.SmartFake implements _i7.ExerciseCategory { + _FakeExerciseCategory_5( Object parent, Invocation parentInvocation, ) : super( @@ -100,8 +100,8 @@ class _FakeSharedPreferencesAsync_5 extends _i1.SmartFake implements _i7.SharedP ); } -class _FakeExerciseDatabase_6 extends _i1.SmartFake implements _i8.ExerciseDatabase { - _FakeExerciseDatabase_6( +class _FakeEquipment_6 extends _i1.SmartFake implements _i8.Equipment { + _FakeEquipment_6( Object parent, Invocation parentInvocation, ) : super( @@ -110,8 +110,8 @@ class _FakeExerciseDatabase_6 extends _i1.SmartFake implements _i8.ExerciseDatab ); } -class _FakeExerciseCategory_7 extends _i1.SmartFake implements _i9.ExerciseCategory { - _FakeExerciseCategory_7( +class _FakeMuscle_7 extends _i1.SmartFake implements _i9.Muscle { + _FakeMuscle_7( Object parent, Invocation parentInvocation, ) : super( @@ -120,28 +120,8 @@ class _FakeExerciseCategory_7 extends _i1.SmartFake implements _i9.ExerciseCateg ); } -class _FakeEquipment_8 extends _i1.SmartFake implements _i10.Equipment { - _FakeEquipment_8( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeMuscle_9 extends _i1.SmartFake implements _i11.Muscle { - _FakeMuscle_9( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - -class _FakeLanguage_10 extends _i1.SmartFake implements _i12.Language { - _FakeLanguage_10( +class _FakeLanguage_8 extends _i1.SmartFake implements _i10.Language { + _FakeLanguage_8( Object parent, Invocation parentInvocation, ) : super( @@ -153,7 +133,7 @@ class _FakeLanguage_10 extends _i1.SmartFake implements _i12.Language { /// A class which mocks [AddExerciseProvider]. /// /// See the documentation for Mockito's code generation for more information. -class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvider { +class MockAddExerciseProvider extends _i1.Mock implements _i11.AddExerciseProvider { MockAddExerciseProvider() { _i1.throwOnMissingStub(this); } @@ -168,16 +148,16 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ) as _i2.WgerBaseProvider); @override - List<_i14.File> get exerciseImages => (super.noSuchMethod( + List<_i12.File> get exerciseImages => (super.noSuchMethod( Invocation.getter(#exerciseImages), - returnValue: <_i14.File>[], - ) as List<_i14.File>); + returnValue: <_i12.File>[], + ) as List<_i12.File>); @override - List<_i10.Equipment> get equipment => (super.noSuchMethod( + List<_i8.Equipment> get equipment => (super.noSuchMethod( Invocation.getter(#equipment), - returnValue: <_i10.Equipment>[], - ) as List<_i10.Equipment>); + returnValue: <_i8.Equipment>[], + ) as List<_i8.Equipment>); @override bool get newVariation => (super.noSuchMethod( @@ -186,64 +166,55 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ) as bool); @override - _i3.Exercise get exercise => (super.noSuchMethod( - Invocation.getter(#exercise), - returnValue: _FakeExercise_1( - this, - Invocation.getter(#exercise), - ), - ) as _i3.Exercise); - - @override - _i4.Translation get translationEn => (super.noSuchMethod( - Invocation.getter(#translationEn), - returnValue: _FakeTranslation_2( - this, - Invocation.getter(#translationEn), - ), - ) as _i4.Translation); - - @override - _i4.Translation get translation => (super.noSuchMethod( - Invocation.getter(#translation), - returnValue: _FakeTranslation_2( - this, - Invocation.getter(#translation), - ), - ) as _i4.Translation); - - @override - _i5.Variation get variation => (super.noSuchMethod( + _i3.Variation get variation => (super.noSuchMethod( Invocation.getter(#variation), - returnValue: _FakeVariation_3( + returnValue: _FakeVariation_1( this, Invocation.getter(#variation), ), - ) as _i5.Variation); + ) as _i3.Variation); @override - List<_i11.Muscle> get primaryMuscles => (super.noSuchMethod( + List<_i9.Muscle> get primaryMuscles => (super.noSuchMethod( Invocation.getter(#primaryMuscles), - returnValue: <_i11.Muscle>[], - ) as List<_i11.Muscle>); + returnValue: <_i9.Muscle>[], + ) as List<_i9.Muscle>); @override - List<_i11.Muscle> get secondaryMuscles => (super.noSuchMethod( + List<_i9.Muscle> get secondaryMuscles => (super.noSuchMethod( Invocation.getter(#secondaryMuscles), - returnValue: <_i11.Muscle>[], - ) as List<_i11.Muscle>); + returnValue: <_i9.Muscle>[], + ) as List<_i9.Muscle>); @override - set language(_i12.Language? value) => super.noSuchMethod( + _i13.ExerciseSubmissionApi get exerciseApiObject => (super.noSuchMethod( + Invocation.getter(#exerciseApiObject), + returnValue: _i14.dummyValue<_i13.ExerciseSubmissionApi>( + this, + Invocation.getter(#exerciseApiObject), + ), + ) as _i13.ExerciseSubmissionApi); + + @override + set languageEn(_i10.Language? value) => super.noSuchMethod( Invocation.setter( - #language, + #languageEn, value, ), returnValueForMissingStub: null, ); @override - set category(_i9.ExerciseCategory? value) => super.noSuchMethod( + set languageTranslation(_i10.Language? value) => super.noSuchMethod( + Invocation.setter( + #languageTranslation, + value, + ), + returnValueForMissingStub: null, + ); + + @override + set category(_i7.ExerciseCategory? value) => super.noSuchMethod( Invocation.setter( #category, value, @@ -306,7 +277,7 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ); @override - set equipment(List<_i10.Equipment>? equipment) => super.noSuchMethod( + set equipment(List<_i8.Equipment>? equipment) => super.noSuchMethod( Invocation.setter( #equipment, equipment, @@ -333,7 +304,7 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ); @override - set primaryMuscles(List<_i11.Muscle>? muscles) => super.noSuchMethod( + set primaryMuscles(List<_i9.Muscle>? muscles) => super.noSuchMethod( Invocation.setter( #primaryMuscles, muscles, @@ -342,7 +313,7 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ); @override - set secondaryMuscles(List<_i11.Muscle>? muscles) => super.noSuchMethod( + set secondaryMuscles(List<_i9.Muscle>? muscles) => super.noSuchMethod( Invocation.setter( #secondaryMuscles, muscles, @@ -366,7 +337,7 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ); @override - void addExerciseImages(List<_i14.File>? exercises) => super.noSuchMethod( + void addExerciseImages(List<_i12.File>? exercises) => super.noSuchMethod( Invocation.method( #addExerciseImages, [exercises], @@ -402,85 +373,13 @@ class MockAddExerciseProvider extends _i1.Mock implements _i13.AddExerciseProvid ) as _i15.Future); @override - _i15.Future<_i3.Exercise> addExerciseBase() => (super.noSuchMethod( + _i15.Future addExerciseSubmission() => (super.noSuchMethod( Invocation.method( - #addExerciseBase, + #addExerciseSubmission, [], ), - returnValue: _i15.Future<_i3.Exercise>.value(_FakeExercise_1( - this, - Invocation.method( - #addExerciseBase, - [], - ), - )), - ) as _i15.Future<_i3.Exercise>); - - @override - _i15.Future<_i5.Variation> addVariation() => (super.noSuchMethod( - Invocation.method( - #addVariation, - [], - ), - returnValue: _i15.Future<_i5.Variation>.value(_FakeVariation_3( - this, - Invocation.method( - #addVariation, - [], - ), - )), - ) as _i15.Future<_i5.Variation>); - - @override - _i15.Future addImages(_i3.Exercise? exercise) => (super.noSuchMethod( - Invocation.method( - #addImages, - [exercise], - ), - returnValue: _i15.Future.value(), - returnValueForMissingStub: _i15.Future.value(), - ) as _i15.Future); - - @override - _i15.Future<_i4.Translation> addExerciseTranslation(_i4.Translation? exercise) => - (super.noSuchMethod( - Invocation.method( - #addExerciseTranslation, - [exercise], - ), - returnValue: _i15.Future<_i4.Translation>.value(_FakeTranslation_2( - this, - Invocation.method( - #addExerciseTranslation, - [exercise], - ), - )), - ) as _i15.Future<_i4.Translation>); - - @override - _i15.Future<_i6.Alias> addExerciseAlias( - String? name, - int? exerciseId, - ) => - (super.noSuchMethod( - Invocation.method( - #addExerciseAlias, - [ - name, - exerciseId, - ], - ), - returnValue: _i15.Future<_i6.Alias>.value(_FakeAlias_4( - this, - Invocation.method( - #addExerciseAlias, - [ - name, - exerciseId, - ], - ), - )), - ) as _i15.Future<_i6.Alias>); + returnValue: _i15.Future.value(0), + ) as _i15.Future); @override void addListener(_i16.VoidCallback? listener) => super.noSuchMethod( @@ -543,13 +442,13 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider { ) as _i2.WgerBaseProvider); @override - _i7.SharedPreferencesAsync get prefs => (super.noSuchMethod( + _i4.SharedPreferencesAsync get prefs => (super.noSuchMethod( Invocation.getter(#prefs), - returnValue: _FakeSharedPreferencesAsync_5( + returnValue: _FakeSharedPreferencesAsync_2( this, Invocation.getter(#prefs), ), - ) as _i7.SharedPreferencesAsync); + ) as _i4.SharedPreferencesAsync); @override set themeMode(_i18.ThemeMode? value) => super.noSuchMethod( @@ -561,7 +460,7 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider { ); @override - set prefs(_i7.SharedPreferencesAsync? value) => super.noSuchMethod( + set prefs(_i4.SharedPreferencesAsync? value) => super.noSuchMethod( Invocation.setter( #prefs, value, @@ -687,58 +586,58 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i2.WgerBaseProvider); @override - _i8.ExerciseDatabase get database => (super.noSuchMethod( + _i5.ExerciseDatabase get database => (super.noSuchMethod( Invocation.getter(#database), - returnValue: _FakeExerciseDatabase_6( + returnValue: _FakeExerciseDatabase_3( this, Invocation.getter(#database), ), - ) as _i8.ExerciseDatabase); + ) as _i5.ExerciseDatabase); @override - List<_i3.Exercise> get exercises => (super.noSuchMethod( + List<_i6.Exercise> get exercises => (super.noSuchMethod( Invocation.getter(#exercises), - returnValue: <_i3.Exercise>[], - ) as List<_i3.Exercise>); + returnValue: <_i6.Exercise>[], + ) as List<_i6.Exercise>); @override - List<_i3.Exercise> get filteredExercises => (super.noSuchMethod( + List<_i6.Exercise> get filteredExercises => (super.noSuchMethod( Invocation.getter(#filteredExercises), - returnValue: <_i3.Exercise>[], - ) as List<_i3.Exercise>); + returnValue: <_i6.Exercise>[], + ) as List<_i6.Exercise>); @override - Map> get exerciseByVariation => (super.noSuchMethod( + Map> get exerciseByVariation => (super.noSuchMethod( Invocation.getter(#exerciseByVariation), - returnValue: >{}, - ) as Map>); + returnValue: >{}, + ) as Map>); @override - List<_i9.ExerciseCategory> get categories => (super.noSuchMethod( + List<_i7.ExerciseCategory> get categories => (super.noSuchMethod( Invocation.getter(#categories), - returnValue: <_i9.ExerciseCategory>[], - ) as List<_i9.ExerciseCategory>); + returnValue: <_i7.ExerciseCategory>[], + ) as List<_i7.ExerciseCategory>); @override - List<_i11.Muscle> get muscles => (super.noSuchMethod( + List<_i9.Muscle> get muscles => (super.noSuchMethod( Invocation.getter(#muscles), - returnValue: <_i11.Muscle>[], - ) as List<_i11.Muscle>); + returnValue: <_i9.Muscle>[], + ) as List<_i9.Muscle>); @override - List<_i10.Equipment> get equipment => (super.noSuchMethod( + List<_i8.Equipment> get equipment => (super.noSuchMethod( Invocation.getter(#equipment), - returnValue: <_i10.Equipment>[], - ) as List<_i10.Equipment>); + returnValue: <_i8.Equipment>[], + ) as List<_i8.Equipment>); @override - List<_i12.Language> get languages => (super.noSuchMethod( + List<_i10.Language> get languages => (super.noSuchMethod( Invocation.getter(#languages), - returnValue: <_i12.Language>[], - ) as List<_i12.Language>); + returnValue: <_i10.Language>[], + ) as List<_i10.Language>); @override - set database(_i8.ExerciseDatabase? value) => super.noSuchMethod( + set database(_i5.ExerciseDatabase? value) => super.noSuchMethod( Invocation.setter( #database, value, @@ -747,7 +646,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ); @override - set exercises(List<_i3.Exercise>? value) => super.noSuchMethod( + set exercises(List<_i6.Exercise>? value) => super.noSuchMethod( Invocation.setter( #exercises, value, @@ -756,7 +655,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ); @override - set filteredExercises(List<_i3.Exercise>? newFilteredExercises) => super.noSuchMethod( + set filteredExercises(List<_i6.Exercise>? newFilteredExercises) => super.noSuchMethod( Invocation.setter( #filteredExercises, newFilteredExercises, @@ -765,7 +664,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ); @override - set languages(List<_i12.Language>? languages) => super.noSuchMethod( + set languages(List<_i10.Language>? languages) => super.noSuchMethod( Invocation.setter( #languages, languages, @@ -818,22 +717,22 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ); @override - _i3.Exercise findExerciseById(int? id) => (super.noSuchMethod( + _i6.Exercise findExerciseById(int? id) => (super.noSuchMethod( Invocation.method( #findExerciseById, [id], ), - returnValue: _FakeExercise_1( + returnValue: _FakeExercise_4( this, Invocation.method( #findExerciseById, [id], ), ), - ) as _i3.Exercise); + ) as _i6.Exercise); @override - List<_i3.Exercise> findExercisesByVariationId( + List<_i6.Exercise> findExercisesByVariationId( int? variationId, { int? exerciseIdToExclude, }) => @@ -843,68 +742,68 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { [variationId], {#exerciseIdToExclude: exerciseIdToExclude}, ), - returnValue: <_i3.Exercise>[], - ) as List<_i3.Exercise>); + returnValue: <_i6.Exercise>[], + ) as List<_i6.Exercise>); @override - _i9.ExerciseCategory findCategoryById(int? id) => (super.noSuchMethod( + _i7.ExerciseCategory findCategoryById(int? id) => (super.noSuchMethod( Invocation.method( #findCategoryById, [id], ), - returnValue: _FakeExerciseCategory_7( + returnValue: _FakeExerciseCategory_5( this, Invocation.method( #findCategoryById, [id], ), ), - ) as _i9.ExerciseCategory); + ) as _i7.ExerciseCategory); @override - _i10.Equipment findEquipmentById(int? id) => (super.noSuchMethod( + _i8.Equipment findEquipmentById(int? id) => (super.noSuchMethod( Invocation.method( #findEquipmentById, [id], ), - returnValue: _FakeEquipment_8( + returnValue: _FakeEquipment_6( this, Invocation.method( #findEquipmentById, [id], ), ), - ) as _i10.Equipment); + ) as _i8.Equipment); @override - _i11.Muscle findMuscleById(int? id) => (super.noSuchMethod( + _i9.Muscle findMuscleById(int? id) => (super.noSuchMethod( Invocation.method( #findMuscleById, [id], ), - returnValue: _FakeMuscle_9( + returnValue: _FakeMuscle_7( this, Invocation.method( #findMuscleById, [id], ), ), - ) as _i11.Muscle); + ) as _i9.Muscle); @override - _i12.Language findLanguageById(int? id) => (super.noSuchMethod( + _i10.Language findLanguageById(int? id) => (super.noSuchMethod( Invocation.method( #findLanguageById, [id], ), - returnValue: _FakeLanguage_10( + returnValue: _FakeLanguage_8( this, Invocation.method( #findLanguageById, [id], ), ), - ) as _i12.Language); + ) as _i10.Language); @override _i15.Future fetchAndSetCategoriesFromApi() => (super.noSuchMethod( @@ -957,17 +856,17 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future<_i3.Exercise?> fetchAndSetExercise(int? exerciseId) => (super.noSuchMethod( + _i15.Future<_i6.Exercise?> fetchAndSetExercise(int? exerciseId) => (super.noSuchMethod( Invocation.method( #fetchAndSetExercise, [exerciseId], ), - returnValue: _i15.Future<_i3.Exercise?>.value(), - ) as _i15.Future<_i3.Exercise?>); + returnValue: _i15.Future<_i6.Exercise?>.value(), + ) as _i15.Future<_i6.Exercise?>); @override - _i15.Future<_i3.Exercise> handleUpdateExerciseFromApi( - _i8.ExerciseDatabase? database, + _i15.Future<_i6.Exercise> handleUpdateExerciseFromApi( + _i5.ExerciseDatabase? database, int? exerciseId, ) => (super.noSuchMethod( @@ -978,7 +877,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { exerciseId, ], ), - returnValue: _i15.Future<_i3.Exercise>.value(_FakeExercise_1( + returnValue: _i15.Future<_i6.Exercise>.value(_FakeExercise_4( this, Invocation.method( #handleUpdateExerciseFromApi, @@ -988,7 +887,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ], ), )), - ) as _i15.Future<_i3.Exercise>); + ) as _i15.Future<_i6.Exercise>); @override _i15.Future initCacheTimesLocalPrefs({dynamic forceInit = false}) => (super.noSuchMethod( @@ -1023,7 +922,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { @override _i15.Future setExercisesFromDatabase( - _i8.ExerciseDatabase? database, { + _i5.ExerciseDatabase? database, { bool? forceDeleteCache = false, }) => (super.noSuchMethod( @@ -1037,7 +936,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future updateExerciseCache(_i8.ExerciseDatabase? database) => (super.noSuchMethod( + _i15.Future updateExerciseCache(_i5.ExerciseDatabase? database) => (super.noSuchMethod( Invocation.method( #updateExerciseCache, [database], @@ -1047,7 +946,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future fetchAndSetMuscles(_i8.ExerciseDatabase? database) => (super.noSuchMethod( + _i15.Future fetchAndSetMuscles(_i5.ExerciseDatabase? database) => (super.noSuchMethod( Invocation.method( #fetchAndSetMuscles, [database], @@ -1057,7 +956,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future fetchAndSetCategories(_i8.ExerciseDatabase? database) => (super.noSuchMethod( + _i15.Future fetchAndSetCategories(_i5.ExerciseDatabase? database) => (super.noSuchMethod( Invocation.method( #fetchAndSetCategories, [database], @@ -1067,7 +966,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future fetchAndSetLanguages(_i8.ExerciseDatabase? database) => (super.noSuchMethod( + _i15.Future fetchAndSetLanguages(_i5.ExerciseDatabase? database) => (super.noSuchMethod( Invocation.method( #fetchAndSetLanguages, [database], @@ -1077,7 +976,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future fetchAndSetEquipments(_i8.ExerciseDatabase? database) => (super.noSuchMethod( + _i15.Future fetchAndSetEquipments(_i5.ExerciseDatabase? database) => (super.noSuchMethod( Invocation.method( #fetchAndSetEquipments, [database], @@ -1087,7 +986,7 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { ) as _i15.Future); @override - _i15.Future> searchExercise( + _i15.Future> searchExercise( String? name, { String? languageCode = 'en', bool? searchEnglish = false, @@ -1101,8 +1000,8 @@ class MockExercisesProvider extends _i1.Mock implements _i20.ExercisesProvider { #searchEnglish: searchEnglish, }, ), - returnValue: _i15.Future>.value(<_i3.Exercise>[]), - ) as _i15.Future>); + returnValue: _i15.Future>.value(<_i6.Exercise>[]), + ) as _i15.Future>); @override void addListener(_i16.VoidCallback? listener) => super.noSuchMethod( diff --git a/test/utils/errors_test.dart b/test/utils/errors_test.dart index 975e6f61..a389b24f 100644 --- a/test/utils/errors_test.dart +++ b/test/utils/errors_test.dart @@ -38,6 +38,23 @@ void main() { expect(result[0].errorMessages[1], 'Error 2'); }); + testWidgets('Processes nested list values correctly', (WidgetTester tester) async { + // Arrange + final errors = { + 'validation_error': { + 'subkey': ['Error 1', 'Error 2'] + }, + }; + + // Act + final result = extractErrors(errors); + + // Assert + expect(result[0].key, 'Validation error | Subkey'); + expect(result[0].errorMessages[0], 'Error 1'); + expect(result[0].errorMessages[1], 'Error 2'); + }); + testWidgets('Processes multiple error types correctly', (WidgetTester tester) async { // Arrange final errors = {