From 6f03d279e9dd7f784d15c649960e79843522590d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 6 Dec 2024 13:46:15 +0300 Subject: [PATCH 01/10] feat(profile): consultant --- lib/core/locator_service.dart | 6 + .../feed/models/diets_pagination_model.dart | 2 +- .../diets_pagination_model.freezed.dart | 26 +- .../feed/models/diets_pagination_model.g.dart | 2 +- .../feed/models/plan_pagination_model.dart | 8 +- .../models/plan_pagination_model.freezed.dart | 105 ++- .../feed/models/plan_pagination_model.g.dart | 8 +- .../widgets/blog_post_widget.dart | 2 +- .../plans/repositories/plans_repository.dart | 16 + .../plans/services/plans_service.dart | 15 + .../plans/services/plans_service.g.dart | 86 +++ .../profile/models/profile_model.dart | 36 +- .../profile/models/profile_model.freezed.dart | 625 ++++++++++++++--- .../profile/models/profile_model.g.dart | 54 +- .../bloc/plans_cubit/plans_cubit.dart | 21 + .../bloc/plans_cubit/plans_state.dart | 19 + .../bloc/plans_cubit/plans_state.freezed.dart | 641 ++++++++++++++++++ .../bloc/profile_cubit/profile_cubit.dart | 18 +- .../presentation/pages/profile_screen.dart | 305 ++++++--- .../widgets/profile_blog_post_widget.dart | 245 +++++++ pubspec.yaml | 2 +- 21 files changed, 1957 insertions(+), 285 deletions(-) create mode 100644 lib/features/plans/repositories/plans_repository.dart create mode 100644 lib/features/plans/services/plans_service.dart create mode 100644 lib/features/plans/services/plans_service.g.dart create mode 100644 lib/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart create mode 100644 lib/features/profile/presentation/bloc/plans_cubit/plans_state.dart create mode 100644 lib/features/profile/presentation/bloc/plans_cubit/plans_state.freezed.dart create mode 100644 lib/features/profile/presentation/widgets/profile_blog_post_widget.dart diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart index 63bf1fed..a9a7623e 100644 --- a/lib/core/locator_service.dart +++ b/lib/core/locator_service.dart @@ -36,6 +36,8 @@ import 'package:eatvio_app/features/feed/services/feed_service.dart'; import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart'; import 'package:eatvio_app/features/glossary/services/glossary_service.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; +import 'package:eatvio_app/features/plans/repositories/plans_repository.dart'; +import 'package:eatvio_app/features/plans/services/plans_service.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/sub_cubit/sub_cubit.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; @@ -50,6 +52,7 @@ import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/se import 'package:eatvio_app/features/settings/repositories/service_repository.dart'; import 'package:eatvio_app/features/settings/services/settings_service.dart'; import 'package:get_it/get_it.dart'; +import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profilePlans; final sl = GetIt.instance; @@ -67,6 +70,7 @@ Future init() async { sl.registerFactory(() => RecipesCubit(feedRepository: sl(), recipeRepository: sl())); sl.registerFactory(() => CalendarCubit(calendarRepository: sl())); sl.registerFactory(() => ProfileCubit(profileRepository: sl(), chatRepository: sl())); + sl.registerFactory(() => profilePlans.PlansCubit(plansRepository: sl())); sl.registerFactory(() => RecipeCreateCubit(recipeRepository: sl())); sl.registerFactory(() => DietsCubit(feedRepository: sl(), dietsRepository: sl())); sl.registerFactory(() => CommentsCubit(feedRepository: sl())); @@ -96,6 +100,7 @@ Future init() async { sl.registerLazySingleton(() => DietRepository(dietsService: sl())); sl.registerLazySingleton(() => BlogPostRepository(blogPostService: sl())); sl.registerLazySingleton(() => CreateDietRepository(createDietService: sl())); + sl.registerLazySingleton(() => PlansRepository(plansService: sl())); // Services sl.registerLazySingleton(() => ChatService(sl())); @@ -111,6 +116,7 @@ Future init() async { sl.registerLazySingleton(() => DietService(sl())); sl.registerLazySingleton(() => BlogPostService(sl())); sl.registerLazySingleton(() => CreateDietService(sl())); + sl.registerLazySingleton(() => PlansService(sl())); // External sl.registerLazySingleton( diff --git a/lib/features/feed/models/diets_pagination_model.dart b/lib/features/feed/models/diets_pagination_model.dart index 7518573d..14d03f00 100644 --- a/lib/features/feed/models/diets_pagination_model.dart +++ b/lib/features/feed/models/diets_pagination_model.dart @@ -46,7 +46,7 @@ class Author with _$Author { @JsonKey(name: "author_name") required String authorName, @JsonKey(name: "author_profile_icon") required String authorProfileIcon, @JsonKey(name: "author_is_me") required bool authorIsMe, - @JsonKey(name: "is_entity_subscribed_by_me") required bool isEntitySubscribedByMe, + @JsonKey(name: "is_entity_subscribed_by_me") bool? isEntitySubscribedByMe, }) = _Author; factory Author.fromJson(Map json) => _$AuthorFromJson(json); diff --git a/lib/features/feed/models/diets_pagination_model.freezed.dart b/lib/features/feed/models/diets_pagination_model.freezed.dart index d30a57cc..f50c4561 100644 --- a/lib/features/feed/models/diets_pagination_model.freezed.dart +++ b/lib/features/feed/models/diets_pagination_model.freezed.dart @@ -813,7 +813,7 @@ mixin _$Author { @JsonKey(name: "author_is_me") bool get authorIsMe => throw _privateConstructorUsedError; @JsonKey(name: "is_entity_subscribed_by_me") - bool get isEntitySubscribedByMe => throw _privateConstructorUsedError; + bool? get isEntitySubscribedByMe => throw _privateConstructorUsedError; /// Serializes this Author to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -835,7 +835,7 @@ abstract class $AuthorCopyWith<$Res> { @JsonKey(name: "author_profile_icon") String authorProfileIcon, @JsonKey(name: "author_is_me") bool authorIsMe, @JsonKey(name: "is_entity_subscribed_by_me") - bool isEntitySubscribedByMe}); + bool? isEntitySubscribedByMe}); } /// @nodoc @@ -857,7 +857,7 @@ class _$AuthorCopyWithImpl<$Res, $Val extends Author> Object? authorName = null, Object? authorProfileIcon = null, Object? authorIsMe = null, - Object? isEntitySubscribedByMe = null, + Object? isEntitySubscribedByMe = freezed, }) { return _then(_value.copyWith( authorSlug: null == authorSlug @@ -876,10 +876,10 @@ class _$AuthorCopyWithImpl<$Res, $Val extends Author> ? _value.authorIsMe : authorIsMe // ignore: cast_nullable_to_non_nullable as bool, - isEntitySubscribedByMe: null == isEntitySubscribedByMe + isEntitySubscribedByMe: freezed == isEntitySubscribedByMe ? _value.isEntitySubscribedByMe : isEntitySubscribedByMe // ignore: cast_nullable_to_non_nullable - as bool, + as bool?, ) as $Val); } } @@ -897,7 +897,7 @@ abstract class _$$AuthorImplCopyWith<$Res> implements $AuthorCopyWith<$Res> { @JsonKey(name: "author_profile_icon") String authorProfileIcon, @JsonKey(name: "author_is_me") bool authorIsMe, @JsonKey(name: "is_entity_subscribed_by_me") - bool isEntitySubscribedByMe}); + bool? isEntitySubscribedByMe}); } /// @nodoc @@ -917,7 +917,7 @@ class __$$AuthorImplCopyWithImpl<$Res> Object? authorName = null, Object? authorProfileIcon = null, Object? authorIsMe = null, - Object? isEntitySubscribedByMe = null, + Object? isEntitySubscribedByMe = freezed, }) { return _then(_$AuthorImpl( authorSlug: null == authorSlug @@ -936,10 +936,10 @@ class __$$AuthorImplCopyWithImpl<$Res> ? _value.authorIsMe : authorIsMe // ignore: cast_nullable_to_non_nullable as bool, - isEntitySubscribedByMe: null == isEntitySubscribedByMe + isEntitySubscribedByMe: freezed == isEntitySubscribedByMe ? _value.isEntitySubscribedByMe : isEntitySubscribedByMe // ignore: cast_nullable_to_non_nullable - as bool, + as bool?, )); } } @@ -953,7 +953,7 @@ class _$AuthorImpl implements _Author { @JsonKey(name: "author_profile_icon") required this.authorProfileIcon, @JsonKey(name: "author_is_me") required this.authorIsMe, @JsonKey(name: "is_entity_subscribed_by_me") - required this.isEntitySubscribedByMe}); + this.isEntitySubscribedByMe}); factory _$AuthorImpl.fromJson(Map json) => _$$AuthorImplFromJson(json); @@ -972,7 +972,7 @@ class _$AuthorImpl implements _Author { final bool authorIsMe; @override @JsonKey(name: "is_entity_subscribed_by_me") - final bool isEntitySubscribedByMe; + final bool? isEntitySubscribedByMe; @override String toString() { @@ -1025,7 +1025,7 @@ abstract class _Author implements Author { required final String authorProfileIcon, @JsonKey(name: "author_is_me") required final bool authorIsMe, @JsonKey(name: "is_entity_subscribed_by_me") - required final bool isEntitySubscribedByMe}) = _$AuthorImpl; + final bool? isEntitySubscribedByMe}) = _$AuthorImpl; factory _Author.fromJson(Map json) = _$AuthorImpl.fromJson; @@ -1043,7 +1043,7 @@ abstract class _Author implements Author { bool get authorIsMe; @override @JsonKey(name: "is_entity_subscribed_by_me") - bool get isEntitySubscribedByMe; + bool? get isEntitySubscribedByMe; /// Create a copy of Author /// with the given fields replaced by the non-null parameter values. diff --git a/lib/features/feed/models/diets_pagination_model.g.dart b/lib/features/feed/models/diets_pagination_model.g.dart index 776b52e5..4475442d 100644 --- a/lib/features/feed/models/diets_pagination_model.g.dart +++ b/lib/features/feed/models/diets_pagination_model.g.dart @@ -74,7 +74,7 @@ _$AuthorImpl _$$AuthorImplFromJson(Map json) => _$AuthorImpl( authorName: json['author_name'] as String, authorProfileIcon: json['author_profile_icon'] as String, authorIsMe: json['author_is_me'] as bool, - isEntitySubscribedByMe: json['is_entity_subscribed_by_me'] as bool, + isEntitySubscribedByMe: json['is_entity_subscribed_by_me'] as bool?, ); Map _$$AuthorImplToJson(_$AuthorImpl instance) => diff --git a/lib/features/feed/models/plan_pagination_model.dart b/lib/features/feed/models/plan_pagination_model.dart index 7abb842e..cc938620 100644 --- a/lib/features/feed/models/plan_pagination_model.dart +++ b/lib/features/feed/models/plan_pagination_model.dart @@ -57,10 +57,10 @@ class PacketOptions with _$PacketOptions { @freezed class PlanType with _$PlanType { const factory PlanType({ - @JsonKey(name: "fit") required bool fit, - @JsonKey(name: "slim") required bool slim, - @JsonKey(name: "behavior") required bool behavior, - @JsonKey(name: "wellness") required bool wellness, + @JsonKey(name: "fit") bool? fit, + @JsonKey(name: "slim") bool? slim, + @JsonKey(name: "behavior") bool? behavior, + @JsonKey(name: "wellness") bool? wellness, }) = _PlanType; factory PlanType.fromJson(Map json) => _$PlanTypeFromJson(json); diff --git a/lib/features/feed/models/plan_pagination_model.freezed.dart b/lib/features/feed/models/plan_pagination_model.freezed.dart index caa2ef10..b7e77deb 100644 --- a/lib/features/feed/models/plan_pagination_model.freezed.dart +++ b/lib/features/feed/models/plan_pagination_model.freezed.dart @@ -1030,13 +1030,13 @@ PlanType _$PlanTypeFromJson(Map json) { /// @nodoc mixin _$PlanType { @JsonKey(name: "fit") - bool get fit => throw _privateConstructorUsedError; + bool? get fit => throw _privateConstructorUsedError; @JsonKey(name: "slim") - bool get slim => throw _privateConstructorUsedError; + bool? get slim => throw _privateConstructorUsedError; @JsonKey(name: "behavior") - bool get behavior => throw _privateConstructorUsedError; + bool? get behavior => throw _privateConstructorUsedError; @JsonKey(name: "wellness") - bool get wellness => throw _privateConstructorUsedError; + bool? get wellness => throw _privateConstructorUsedError; /// Serializes this PlanType to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -1054,10 +1054,10 @@ abstract class $PlanTypeCopyWith<$Res> { _$PlanTypeCopyWithImpl<$Res, PlanType>; @useResult $Res call( - {@JsonKey(name: "fit") bool fit, - @JsonKey(name: "slim") bool slim, - @JsonKey(name: "behavior") bool behavior, - @JsonKey(name: "wellness") bool wellness}); + {@JsonKey(name: "fit") bool? fit, + @JsonKey(name: "slim") bool? slim, + @JsonKey(name: "behavior") bool? behavior, + @JsonKey(name: "wellness") bool? wellness}); } /// @nodoc @@ -1075,28 +1075,28 @@ class _$PlanTypeCopyWithImpl<$Res, $Val extends PlanType> @pragma('vm:prefer-inline') @override $Res call({ - Object? fit = null, - Object? slim = null, - Object? behavior = null, - Object? wellness = null, + Object? fit = freezed, + Object? slim = freezed, + Object? behavior = freezed, + Object? wellness = freezed, }) { return _then(_value.copyWith( - fit: null == fit + fit: freezed == fit ? _value.fit : fit // ignore: cast_nullable_to_non_nullable - as bool, - slim: null == slim + as bool?, + slim: freezed == slim ? _value.slim : slim // ignore: cast_nullable_to_non_nullable - as bool, - behavior: null == behavior + as bool?, + behavior: freezed == behavior ? _value.behavior : behavior // ignore: cast_nullable_to_non_nullable - as bool, - wellness: null == wellness + as bool?, + wellness: freezed == wellness ? _value.wellness : wellness // ignore: cast_nullable_to_non_nullable - as bool, + as bool?, ) as $Val); } } @@ -1110,10 +1110,10 @@ abstract class _$$PlanTypeImplCopyWith<$Res> @override @useResult $Res call( - {@JsonKey(name: "fit") bool fit, - @JsonKey(name: "slim") bool slim, - @JsonKey(name: "behavior") bool behavior, - @JsonKey(name: "wellness") bool wellness}); + {@JsonKey(name: "fit") bool? fit, + @JsonKey(name: "slim") bool? slim, + @JsonKey(name: "behavior") bool? behavior, + @JsonKey(name: "wellness") bool? wellness}); } /// @nodoc @@ -1129,28 +1129,28 @@ class __$$PlanTypeImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? fit = null, - Object? slim = null, - Object? behavior = null, - Object? wellness = null, + Object? fit = freezed, + Object? slim = freezed, + Object? behavior = freezed, + Object? wellness = freezed, }) { return _then(_$PlanTypeImpl( - fit: null == fit + fit: freezed == fit ? _value.fit : fit // ignore: cast_nullable_to_non_nullable - as bool, - slim: null == slim + as bool?, + slim: freezed == slim ? _value.slim : slim // ignore: cast_nullable_to_non_nullable - as bool, - behavior: null == behavior + as bool?, + behavior: freezed == behavior ? _value.behavior : behavior // ignore: cast_nullable_to_non_nullable - as bool, - wellness: null == wellness + as bool?, + wellness: freezed == wellness ? _value.wellness : wellness // ignore: cast_nullable_to_non_nullable - as bool, + as bool?, )); } } @@ -1159,26 +1159,26 @@ class __$$PlanTypeImplCopyWithImpl<$Res> @JsonSerializable() class _$PlanTypeImpl implements _PlanType { const _$PlanTypeImpl( - {@JsonKey(name: "fit") required this.fit, - @JsonKey(name: "slim") required this.slim, - @JsonKey(name: "behavior") required this.behavior, - @JsonKey(name: "wellness") required this.wellness}); + {@JsonKey(name: "fit") this.fit, + @JsonKey(name: "slim") this.slim, + @JsonKey(name: "behavior") this.behavior, + @JsonKey(name: "wellness") this.wellness}); factory _$PlanTypeImpl.fromJson(Map json) => _$$PlanTypeImplFromJson(json); @override @JsonKey(name: "fit") - final bool fit; + final bool? fit; @override @JsonKey(name: "slim") - final bool slim; + final bool? slim; @override @JsonKey(name: "behavior") - final bool behavior; + final bool? behavior; @override @JsonKey(name: "wellness") - final bool wellness; + final bool? wellness; @override String toString() { @@ -1220,27 +1220,26 @@ class _$PlanTypeImpl implements _PlanType { abstract class _PlanType implements PlanType { const factory _PlanType( - {@JsonKey(name: "fit") required final bool fit, - @JsonKey(name: "slim") required final bool slim, - @JsonKey(name: "behavior") required final bool behavior, - @JsonKey(name: "wellness") required final bool wellness}) = - _$PlanTypeImpl; + {@JsonKey(name: "fit") final bool? fit, + @JsonKey(name: "slim") final bool? slim, + @JsonKey(name: "behavior") final bool? behavior, + @JsonKey(name: "wellness") final bool? wellness}) = _$PlanTypeImpl; factory _PlanType.fromJson(Map json) = _$PlanTypeImpl.fromJson; @override @JsonKey(name: "fit") - bool get fit; + bool? get fit; @override @JsonKey(name: "slim") - bool get slim; + bool? get slim; @override @JsonKey(name: "behavior") - bool get behavior; + bool? get behavior; @override @JsonKey(name: "wellness") - bool get wellness; + bool? get wellness; /// Create a copy of PlanType /// with the given fields replaced by the non-null parameter values. diff --git a/lib/features/feed/models/plan_pagination_model.g.dart b/lib/features/feed/models/plan_pagination_model.g.dart index 8f203fa8..92405f55 100644 --- a/lib/features/feed/models/plan_pagination_model.g.dart +++ b/lib/features/feed/models/plan_pagination_model.g.dart @@ -80,10 +80,10 @@ Map _$$PacketOptionsImplToJson(_$PacketOptionsImpl instance) => _$PlanTypeImpl _$$PlanTypeImplFromJson(Map json) => _$PlanTypeImpl( - fit: json['fit'] as bool, - slim: json['slim'] as bool, - behavior: json['behavior'] as bool, - wellness: json['wellness'] as bool, + fit: json['fit'] as bool?, + slim: json['slim'] as bool?, + behavior: json['behavior'] as bool?, + wellness: json['wellness'] as bool?, ); Map _$$PlanTypeImplToJson(_$PlanTypeImpl instance) => diff --git a/lib/features/feed/presentation/widgets/blog_post_widget.dart b/lib/features/feed/presentation/widgets/blog_post_widget.dart index 9d796fa6..3c775084 100644 --- a/lib/features/feed/presentation/widgets/blog_post_widget.dart +++ b/lib/features/feed/presentation/widgets/blog_post_widget.dart @@ -88,7 +88,7 @@ class _BlogPostWidgetState extends State { ], ), const Spacer(), - if (!state.feedBlogPostList[widget.index].author.isEntitySubscribedByMe && !state.feedBlogPostList[widget.index].author.authorIsMe) + if (!state.feedBlogPostList[widget.index].author.isEntitySubscribedByMe! && !state.feedBlogPostList[widget.index].author.authorIsMe) SubscribeButtonWidget( slug: state.feedBlogPostList[widget.index].author.authorSlug, ), diff --git a/lib/features/plans/repositories/plans_repository.dart b/lib/features/plans/repositories/plans_repository.dart new file mode 100644 index 00000000..6533dd90 --- /dev/null +++ b/lib/features/plans/repositories/plans_repository.dart @@ -0,0 +1,16 @@ +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/plans/services/plans_service.dart'; + +class PlansRepository { + final PlansService plansService; + + PlansRepository({required this.plansService}); + + Future> getPlansBySlug(String slug) async { + try { + return (await plansService.getPlansBySlug(author: slug)).data; + } catch (e) { + rethrow; + } + } +} diff --git a/lib/features/plans/services/plans_service.dart b/lib/features/plans/services/plans_service.dart new file mode 100644 index 00000000..5f8769ce --- /dev/null +++ b/lib/features/plans/services/plans_service.dart @@ -0,0 +1,15 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'plans_service.g.dart'; + +@RestApi() +abstract class PlansService { + factory PlansService(Dio dio, {String baseUrl}) = _PlansService; + + @GET('/api/plans/get_by_author/{author}') + Future getPlansBySlug({ + @Path() required String author, + }); +} diff --git a/lib/features/plans/services/plans_service.g.dart b/lib/features/plans/services/plans_service.g.dart new file mode 100644 index 00000000..7fe37d3d --- /dev/null +++ b/lib/features/plans/services/plans_service.g.dart @@ -0,0 +1,86 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'plans_service.dart'; + +// ************************************************************************** +// RetrofitGenerator +// ************************************************************************** + +// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations + +class _PlansService implements PlansService { + _PlansService( + this._dio, { + this.baseUrl, + this.errorLogger, + }); + + final Dio _dio; + + String? baseUrl; + + final ParseErrorLogger? errorLogger; + + @override + Future getPlansBySlug({required String author}) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/get_by_author/${author}', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + ))); + final _result = await _dio.fetch>(_options); + late PlanPaginationModel _value; + try { + _value = PlanPaginationModel.fromJson(_result.data!); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + return _value; + } + + RequestOptions _setStreamType(RequestOptions requestOptions) { + if (T != dynamic && + !(requestOptions.responseType == ResponseType.bytes || + requestOptions.responseType == ResponseType.stream)) { + if (T == String) { + requestOptions.responseType = ResponseType.plain; + } else { + requestOptions.responseType = ResponseType.json; + } + } + return requestOptions; + } + + String _combineBaseUrls( + String dioBaseUrl, + String? baseUrl, + ) { + if (baseUrl == null || baseUrl.trim().isEmpty) { + return dioBaseUrl; + } + + final url = Uri.parse(baseUrl); + + if (url.isAbsolute) { + return url.toString(); + } + + return Uri.parse(dioBaseUrl).resolveUri(url).toString(); + } +} diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart index 374111cc..3e4c1764 100644 --- a/lib/features/profile/models/profile_model.dart +++ b/lib/features/profile/models/profile_model.dart @@ -2,7 +2,6 @@ import 'package:eatvio_app/features/profile/models/badge_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'profile_model.freezed.dart'; - part 'profile_model.g.dart'; @freezed @@ -11,6 +10,7 @@ class ProfileModel with _$ProfileModel { @JsonKey(name: "id") required int id, @JsonKey(name: "name") required String name, @JsonKey(name: "email") required String email, + @JsonKey(name: "rating_place") int? ratingPlace, @JsonKey(name: "email_verified_at") DateTime? emailVerifiedAt, @JsonKey(name: "created_at") DateTime? createdAt, @JsonKey(name: "updated_at") DateTime? updatedAt, @@ -22,25 +22,47 @@ class ProfileModel with _$ProfileModel { @JsonKey(name: "badges") required List badges, @JsonKey(name: "subscriptions") required List subscriptions, @JsonKey(name: "subscribers") required List subscribers, - @JsonKey(name: "education_resource") EducationResource? educationResource, + @JsonKey(name: "education_resource") EducationModel? educationResource, + @JsonKey(name: "cert_photos") List? diplomasAndCertificates, }) = _ProfileModel; factory ProfileModel.fromJson(Map json) => _$ProfileModelFromJson(json); } @freezed -class EducationResource with _$EducationResource { - const factory EducationResource({ - @JsonKey(name: "has_medical_education") int? hasMedical_Education, +class DiplomasAndCertificatesModel with _$DiplomasAndCertificatesModel { + const factory DiplomasAndCertificatesModel({ + required int id, + required String path, + }) = _DiplomasAndCertificatesModel; + + factory DiplomasAndCertificatesModel.fromJson(Map json) => _$DiplomasAndCertificatesModelFromJson(json); +} + +@freezed +class EducationModel with _$EducationModel { + const factory EducationModel({ + @JsonKey(name: "has_medical_education") int? hasMedicalEducation, + @JsonKey(name: "completed_cources") Map? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @JsonKey(name: "tg_link") String? tgLink, @JsonKey(name: "personal_site_link") String? personalSiteLink, @JsonKey(name: "request_state") String? requestState, - }) = _EducationResource; + }) = _EducationModel; - factory EducationResource.fromJson(Map json) => _$EducationResourceFromJson(json); + factory EducationModel.fromJson(Map json) => _$EducationModelFromJson(json); +} + +@freezed +class CompletedCoursesModel with _$CompletedCoursesModel { + const factory CompletedCoursesModel({ + required String date, + required String title, + }) = _CompletedCoursesModel; + + factory CompletedCoursesModel.fromJson(Map json) => _$CompletedCoursesModelFromJson(json); } @freezed diff --git a/lib/features/profile/models/profile_model.freezed.dart b/lib/features/profile/models/profile_model.freezed.dart index 95be8ea8..dc863ee9 100644 --- a/lib/features/profile/models/profile_model.freezed.dart +++ b/lib/features/profile/models/profile_model.freezed.dart @@ -26,6 +26,8 @@ mixin _$ProfileModel { String get name => throw _privateConstructorUsedError; @JsonKey(name: "email") String get email => throw _privateConstructorUsedError; + @JsonKey(name: "rating_place") + int? get ratingPlace => throw _privateConstructorUsedError; @JsonKey(name: "email_verified_at") DateTime? get emailVerifiedAt => throw _privateConstructorUsedError; @JsonKey(name: "created_at") @@ -51,7 +53,9 @@ mixin _$ProfileModel { List get subscribers => throw _privateConstructorUsedError; @JsonKey(name: "education_resource") - EducationResource? get educationResource => + EducationModel? get educationResource => throw _privateConstructorUsedError; + @JsonKey(name: "cert_photos") + List? get diplomasAndCertificates => throw _privateConstructorUsedError; /// Serializes this ProfileModel to a JSON map. @@ -74,6 +78,7 @@ abstract class $ProfileModelCopyWith<$Res> { {@JsonKey(name: "id") int id, @JsonKey(name: "name") String name, @JsonKey(name: "email") String email, + @JsonKey(name: "rating_place") int? ratingPlace, @JsonKey(name: "email_verified_at") DateTime? emailVerifiedAt, @JsonKey(name: "created_at") DateTime? createdAt, @JsonKey(name: "updated_at") DateTime? updatedAt, @@ -85,10 +90,11 @@ abstract class $ProfileModelCopyWith<$Res> { @JsonKey(name: "badges") List badges, @JsonKey(name: "subscriptions") List subscriptions, @JsonKey(name: "subscribers") List subscribers, - @JsonKey(name: "education_resource") - EducationResource? educationResource}); + @JsonKey(name: "education_resource") EducationModel? educationResource, + @JsonKey(name: "cert_photos") + List? diplomasAndCertificates}); - $EducationResourceCopyWith<$Res>? get educationResource; + $EducationModelCopyWith<$Res>? get educationResource; } /// @nodoc @@ -109,6 +115,7 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> Object? id = null, Object? name = null, Object? email = null, + Object? ratingPlace = freezed, Object? emailVerifiedAt = freezed, Object? createdAt = freezed, Object? updatedAt = freezed, @@ -121,6 +128,7 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> Object? subscriptions = null, Object? subscribers = null, Object? educationResource = freezed, + Object? diplomasAndCertificates = freezed, }) { return _then(_value.copyWith( id: null == id @@ -135,6 +143,10 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> ? _value.email : email // ignore: cast_nullable_to_non_nullable as String, + ratingPlace: freezed == ratingPlace + ? _value.ratingPlace + : ratingPlace // ignore: cast_nullable_to_non_nullable + as int?, emailVerifiedAt: freezed == emailVerifiedAt ? _value.emailVerifiedAt : emailVerifiedAt // ignore: cast_nullable_to_non_nullable @@ -182,7 +194,11 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> educationResource: freezed == educationResource ? _value.educationResource : educationResource // ignore: cast_nullable_to_non_nullable - as EducationResource?, + as EducationModel?, + diplomasAndCertificates: freezed == diplomasAndCertificates + ? _value.diplomasAndCertificates + : diplomasAndCertificates // ignore: cast_nullable_to_non_nullable + as List?, ) as $Val); } @@ -190,12 +206,12 @@ class _$ProfileModelCopyWithImpl<$Res, $Val extends ProfileModel> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $EducationResourceCopyWith<$Res>? get educationResource { + $EducationModelCopyWith<$Res>? get educationResource { if (_value.educationResource == null) { return null; } - return $EducationResourceCopyWith<$Res>(_value.educationResource!, (value) { + return $EducationModelCopyWith<$Res>(_value.educationResource!, (value) { return _then(_value.copyWith(educationResource: value) as $Val); }); } @@ -213,6 +229,7 @@ abstract class _$$ProfileModelImplCopyWith<$Res> {@JsonKey(name: "id") int id, @JsonKey(name: "name") String name, @JsonKey(name: "email") String email, + @JsonKey(name: "rating_place") int? ratingPlace, @JsonKey(name: "email_verified_at") DateTime? emailVerifiedAt, @JsonKey(name: "created_at") DateTime? createdAt, @JsonKey(name: "updated_at") DateTime? updatedAt, @@ -224,11 +241,12 @@ abstract class _$$ProfileModelImplCopyWith<$Res> @JsonKey(name: "badges") List badges, @JsonKey(name: "subscriptions") List subscriptions, @JsonKey(name: "subscribers") List subscribers, - @JsonKey(name: "education_resource") - EducationResource? educationResource}); + @JsonKey(name: "education_resource") EducationModel? educationResource, + @JsonKey(name: "cert_photos") + List? diplomasAndCertificates}); @override - $EducationResourceCopyWith<$Res>? get educationResource; + $EducationModelCopyWith<$Res>? get educationResource; } /// @nodoc @@ -247,6 +265,7 @@ class __$$ProfileModelImplCopyWithImpl<$Res> Object? id = null, Object? name = null, Object? email = null, + Object? ratingPlace = freezed, Object? emailVerifiedAt = freezed, Object? createdAt = freezed, Object? updatedAt = freezed, @@ -259,6 +278,7 @@ class __$$ProfileModelImplCopyWithImpl<$Res> Object? subscriptions = null, Object? subscribers = null, Object? educationResource = freezed, + Object? diplomasAndCertificates = freezed, }) { return _then(_$ProfileModelImpl( id: null == id @@ -273,6 +293,10 @@ class __$$ProfileModelImplCopyWithImpl<$Res> ? _value.email : email // ignore: cast_nullable_to_non_nullable as String, + ratingPlace: freezed == ratingPlace + ? _value.ratingPlace + : ratingPlace // ignore: cast_nullable_to_non_nullable + as int?, emailVerifiedAt: freezed == emailVerifiedAt ? _value.emailVerifiedAt : emailVerifiedAt // ignore: cast_nullable_to_non_nullable @@ -320,7 +344,11 @@ class __$$ProfileModelImplCopyWithImpl<$Res> educationResource: freezed == educationResource ? _value.educationResource : educationResource // ignore: cast_nullable_to_non_nullable - as EducationResource?, + as EducationModel?, + diplomasAndCertificates: freezed == diplomasAndCertificates + ? _value._diplomasAndCertificates + : diplomasAndCertificates // ignore: cast_nullable_to_non_nullable + as List?, )); } } @@ -332,6 +360,7 @@ class _$ProfileModelImpl implements _ProfileModel { {@JsonKey(name: "id") required this.id, @JsonKey(name: "name") required this.name, @JsonKey(name: "email") required this.email, + @JsonKey(name: "rating_place") this.ratingPlace, @JsonKey(name: "email_verified_at") this.emailVerifiedAt, @JsonKey(name: "created_at") this.createdAt, @JsonKey(name: "updated_at") this.updatedAt, @@ -346,10 +375,13 @@ class _$ProfileModelImpl implements _ProfileModel { required final List subscriptions, @JsonKey(name: "subscribers") required final List subscribers, - @JsonKey(name: "education_resource") this.educationResource}) + @JsonKey(name: "education_resource") this.educationResource, + @JsonKey(name: "cert_photos") + final List? diplomasAndCertificates}) : _badges = badges, _subscriptions = subscriptions, - _subscribers = subscribers; + _subscribers = subscribers, + _diplomasAndCertificates = diplomasAndCertificates; factory _$ProfileModelImpl.fromJson(Map json) => _$$ProfileModelImplFromJson(json); @@ -364,6 +396,9 @@ class _$ProfileModelImpl implements _ProfileModel { @JsonKey(name: "email") final String email; @override + @JsonKey(name: "rating_place") + final int? ratingPlace; + @override @JsonKey(name: "email_verified_at") final DateTime? emailVerifiedAt; @override @@ -416,11 +451,22 @@ class _$ProfileModelImpl implements _ProfileModel { @override @JsonKey(name: "education_resource") - final EducationResource? educationResource; + final EducationModel? educationResource; + final List? _diplomasAndCertificates; + @override + @JsonKey(name: "cert_photos") + List? get diplomasAndCertificates { + final value = _diplomasAndCertificates; + if (value == null) return null; + if (_diplomasAndCertificates is EqualUnmodifiableListView) + return _diplomasAndCertificates; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } @override String toString() { - return 'ProfileModel(id: $id, name: $name, email: $email, emailVerifiedAt: $emailVerifiedAt, createdAt: $createdAt, updatedAt: $updatedAt, isPublicProfile: $isPublicProfile, isEntitySubscribedByMe: $isEntitySubscribedByMe, slug: $slug, profilePhotoUrl: $profilePhotoUrl, role: $role, badges: $badges, subscriptions: $subscriptions, subscribers: $subscribers, educationResource: $educationResource)'; + return 'ProfileModel(id: $id, name: $name, email: $email, ratingPlace: $ratingPlace, emailVerifiedAt: $emailVerifiedAt, createdAt: $createdAt, updatedAt: $updatedAt, isPublicProfile: $isPublicProfile, isEntitySubscribedByMe: $isEntitySubscribedByMe, slug: $slug, profilePhotoUrl: $profilePhotoUrl, role: $role, badges: $badges, subscriptions: $subscriptions, subscribers: $subscribers, educationResource: $educationResource, diplomasAndCertificates: $diplomasAndCertificates)'; } @override @@ -431,6 +477,8 @@ class _$ProfileModelImpl implements _ProfileModel { (identical(other.id, id) || other.id == id) && (identical(other.name, name) || other.name == name) && (identical(other.email, email) || other.email == email) && + (identical(other.ratingPlace, ratingPlace) || + other.ratingPlace == ratingPlace) && (identical(other.emailVerifiedAt, emailVerifiedAt) || other.emailVerifiedAt == emailVerifiedAt) && (identical(other.createdAt, createdAt) || @@ -451,7 +499,9 @@ class _$ProfileModelImpl implements _ProfileModel { const DeepCollectionEquality() .equals(other._subscribers, _subscribers) && (identical(other.educationResource, educationResource) || - other.educationResource == educationResource)); + other.educationResource == educationResource) && + const DeepCollectionEquality().equals( + other._diplomasAndCertificates, _diplomasAndCertificates)); } @JsonKey(includeFromJson: false, includeToJson: false) @@ -461,6 +511,7 @@ class _$ProfileModelImpl implements _ProfileModel { id, name, email, + ratingPlace, emailVerifiedAt, createdAt, updatedAt, @@ -472,7 +523,8 @@ class _$ProfileModelImpl implements _ProfileModel { const DeepCollectionEquality().hash(_badges), const DeepCollectionEquality().hash(_subscriptions), const DeepCollectionEquality().hash(_subscribers), - educationResource); + educationResource, + const DeepCollectionEquality().hash(_diplomasAndCertificates)); /// Create a copy of ProfileModel /// with the given fields replaced by the non-null parameter values. @@ -495,6 +547,7 @@ abstract class _ProfileModel implements ProfileModel { {@JsonKey(name: "id") required final int id, @JsonKey(name: "name") required final String name, @JsonKey(name: "email") required final String email, + @JsonKey(name: "rating_place") final int? ratingPlace, @JsonKey(name: "email_verified_at") final DateTime? emailVerifiedAt, @JsonKey(name: "created_at") final DateTime? createdAt, @JsonKey(name: "updated_at") final DateTime? updatedAt, @@ -510,7 +563,10 @@ abstract class _ProfileModel implements ProfileModel { @JsonKey(name: "subscribers") required final List subscribers, @JsonKey(name: "education_resource") - final EducationResource? educationResource}) = _$ProfileModelImpl; + final EducationModel? educationResource, + @JsonKey(name: "cert_photos") + final List? + diplomasAndCertificates}) = _$ProfileModelImpl; factory _ProfileModel.fromJson(Map json) = _$ProfileModelImpl.fromJson; @@ -525,6 +581,9 @@ abstract class _ProfileModel implements ProfileModel { @JsonKey(name: "email") String get email; @override + @JsonKey(name: "rating_place") + int? get ratingPlace; + @override @JsonKey(name: "email_verified_at") DateTime? get emailVerifiedAt; @override @@ -559,7 +618,10 @@ abstract class _ProfileModel implements ProfileModel { List get subscribers; @override @JsonKey(name: "education_resource") - EducationResource? get educationResource; + EducationModel? get educationResource; + @override + @JsonKey(name: "cert_photos") + List? get diplomasAndCertificates; /// Create a copy of ProfileModel /// with the given fields replaced by the non-null parameter values. @@ -569,14 +631,198 @@ abstract class _ProfileModel implements ProfileModel { throw _privateConstructorUsedError; } -EducationResource _$EducationResourceFromJson(Map json) { - return _EducationResource.fromJson(json); +DiplomasAndCertificatesModel _$DiplomasAndCertificatesModelFromJson( + Map json) { + return _DiplomasAndCertificatesModel.fromJson(json); } /// @nodoc -mixin _$EducationResource { +mixin _$DiplomasAndCertificatesModel { + int get id => throw _privateConstructorUsedError; + String get path => throw _privateConstructorUsedError; + + /// Serializes this DiplomasAndCertificatesModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of DiplomasAndCertificatesModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $DiplomasAndCertificatesModelCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DiplomasAndCertificatesModelCopyWith<$Res> { + factory $DiplomasAndCertificatesModelCopyWith( + DiplomasAndCertificatesModel value, + $Res Function(DiplomasAndCertificatesModel) then) = + _$DiplomasAndCertificatesModelCopyWithImpl<$Res, + DiplomasAndCertificatesModel>; + @useResult + $Res call({int id, String path}); +} + +/// @nodoc +class _$DiplomasAndCertificatesModelCopyWithImpl<$Res, + $Val extends DiplomasAndCertificatesModel> + implements $DiplomasAndCertificatesModelCopyWith<$Res> { + _$DiplomasAndCertificatesModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of DiplomasAndCertificatesModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? path = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$DiplomasAndCertificatesModelImplCopyWith<$Res> + implements $DiplomasAndCertificatesModelCopyWith<$Res> { + factory _$$DiplomasAndCertificatesModelImplCopyWith( + _$DiplomasAndCertificatesModelImpl value, + $Res Function(_$DiplomasAndCertificatesModelImpl) then) = + __$$DiplomasAndCertificatesModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int id, String path}); +} + +/// @nodoc +class __$$DiplomasAndCertificatesModelImplCopyWithImpl<$Res> + extends _$DiplomasAndCertificatesModelCopyWithImpl<$Res, + _$DiplomasAndCertificatesModelImpl> + implements _$$DiplomasAndCertificatesModelImplCopyWith<$Res> { + __$$DiplomasAndCertificatesModelImplCopyWithImpl( + _$DiplomasAndCertificatesModelImpl _value, + $Res Function(_$DiplomasAndCertificatesModelImpl) _then) + : super(_value, _then); + + /// Create a copy of DiplomasAndCertificatesModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? path = null, + }) { + return _then(_$DiplomasAndCertificatesModelImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DiplomasAndCertificatesModelImpl + implements _DiplomasAndCertificatesModel { + const _$DiplomasAndCertificatesModelImpl( + {required this.id, required this.path}); + + factory _$DiplomasAndCertificatesModelImpl.fromJson( + Map json) => + _$$DiplomasAndCertificatesModelImplFromJson(json); + + @override + final int id; + @override + final String path; + + @override + String toString() { + return 'DiplomasAndCertificatesModel(id: $id, path: $path)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DiplomasAndCertificatesModelImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.path, path) || other.path == path)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, id, path); + + /// Create a copy of DiplomasAndCertificatesModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$DiplomasAndCertificatesModelImplCopyWith< + _$DiplomasAndCertificatesModelImpl> + get copyWith => __$$DiplomasAndCertificatesModelImplCopyWithImpl< + _$DiplomasAndCertificatesModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$DiplomasAndCertificatesModelImplToJson( + this, + ); + } +} + +abstract class _DiplomasAndCertificatesModel + implements DiplomasAndCertificatesModel { + const factory _DiplomasAndCertificatesModel( + {required final int id, + required final String path}) = _$DiplomasAndCertificatesModelImpl; + + factory _DiplomasAndCertificatesModel.fromJson(Map json) = + _$DiplomasAndCertificatesModelImpl.fromJson; + + @override + int get id; + @override + String get path; + + /// Create a copy of DiplomasAndCertificatesModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$DiplomasAndCertificatesModelImplCopyWith< + _$DiplomasAndCertificatesModelImpl> + get copyWith => throw _privateConstructorUsedError; +} + +EducationModel _$EducationModelFromJson(Map json) { + return _EducationModel.fromJson(json); +} + +/// @nodoc +mixin _$EducationModel { @JsonKey(name: "has_medical_education") - int? get hasMedical_Education => throw _privateConstructorUsedError; + int? get hasMedicalEducation => throw _privateConstructorUsedError; + @JsonKey(name: "completed_cources") + Map? get completedCourses => + throw _privateConstructorUsedError; @JsonKey(name: "vk_link") String? get vkLink => throw _privateConstructorUsedError; @JsonKey(name: "insta_link") @@ -590,24 +836,26 @@ mixin _$EducationResource { @JsonKey(name: "request_state") String? get requestState => throw _privateConstructorUsedError; - /// Serializes this EducationResource to a JSON map. + /// Serializes this EducationModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; - /// Create a copy of EducationResource + /// Create a copy of EducationModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - $EducationResourceCopyWith get copyWith => + $EducationModelCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class $EducationResourceCopyWith<$Res> { - factory $EducationResourceCopyWith( - EducationResource value, $Res Function(EducationResource) then) = - _$EducationResourceCopyWithImpl<$Res, EducationResource>; +abstract class $EducationModelCopyWith<$Res> { + factory $EducationModelCopyWith( + EducationModel value, $Res Function(EducationModel) then) = + _$EducationModelCopyWithImpl<$Res, EducationModel>; @useResult $Res call( - {@JsonKey(name: "has_medical_education") int? hasMedical_Education, + {@JsonKey(name: "has_medical_education") int? hasMedicalEducation, + @JsonKey(name: "completed_cources") + Map? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @@ -617,21 +865,22 @@ abstract class $EducationResourceCopyWith<$Res> { } /// @nodoc -class _$EducationResourceCopyWithImpl<$Res, $Val extends EducationResource> - implements $EducationResourceCopyWith<$Res> { - _$EducationResourceCopyWithImpl(this._value, this._then); +class _$EducationModelCopyWithImpl<$Res, $Val extends EducationModel> + implements $EducationModelCopyWith<$Res> { + _$EducationModelCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of EducationResource + /// Create a copy of EducationModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ - Object? hasMedical_Education = freezed, + Object? hasMedicalEducation = freezed, + Object? completedCourses = freezed, Object? vkLink = freezed, Object? instaLink = freezed, Object? fbLink = freezed, @@ -640,10 +889,14 @@ class _$EducationResourceCopyWithImpl<$Res, $Val extends EducationResource> Object? requestState = freezed, }) { return _then(_value.copyWith( - hasMedical_Education: freezed == hasMedical_Education - ? _value.hasMedical_Education - : hasMedical_Education // ignore: cast_nullable_to_non_nullable + hasMedicalEducation: freezed == hasMedicalEducation + ? _value.hasMedicalEducation + : hasMedicalEducation // ignore: cast_nullable_to_non_nullable as int?, + completedCourses: freezed == completedCourses + ? _value.completedCourses + : completedCourses // ignore: cast_nullable_to_non_nullable + as Map?, vkLink: freezed == vkLink ? _value.vkLink : vkLink // ignore: cast_nullable_to_non_nullable @@ -673,15 +926,17 @@ class _$EducationResourceCopyWithImpl<$Res, $Val extends EducationResource> } /// @nodoc -abstract class _$$EducationResourceImplCopyWith<$Res> - implements $EducationResourceCopyWith<$Res> { - factory _$$EducationResourceImplCopyWith(_$EducationResourceImpl value, - $Res Function(_$EducationResourceImpl) then) = - __$$EducationResourceImplCopyWithImpl<$Res>; +abstract class _$$EducationModelImplCopyWith<$Res> + implements $EducationModelCopyWith<$Res> { + factory _$$EducationModelImplCopyWith(_$EducationModelImpl value, + $Res Function(_$EducationModelImpl) then) = + __$$EducationModelImplCopyWithImpl<$Res>; @override @useResult $Res call( - {@JsonKey(name: "has_medical_education") int? hasMedical_Education, + {@JsonKey(name: "has_medical_education") int? hasMedicalEducation, + @JsonKey(name: "completed_cources") + Map? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @@ -691,19 +946,20 @@ abstract class _$$EducationResourceImplCopyWith<$Res> } /// @nodoc -class __$$EducationResourceImplCopyWithImpl<$Res> - extends _$EducationResourceCopyWithImpl<$Res, _$EducationResourceImpl> - implements _$$EducationResourceImplCopyWith<$Res> { - __$$EducationResourceImplCopyWithImpl(_$EducationResourceImpl _value, - $Res Function(_$EducationResourceImpl) _then) +class __$$EducationModelImplCopyWithImpl<$Res> + extends _$EducationModelCopyWithImpl<$Res, _$EducationModelImpl> + implements _$$EducationModelImplCopyWith<$Res> { + __$$EducationModelImplCopyWithImpl( + _$EducationModelImpl _value, $Res Function(_$EducationModelImpl) _then) : super(_value, _then); - /// Create a copy of EducationResource + /// Create a copy of EducationModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ - Object? hasMedical_Education = freezed, + Object? hasMedicalEducation = freezed, + Object? completedCourses = freezed, Object? vkLink = freezed, Object? instaLink = freezed, Object? fbLink = freezed, @@ -711,11 +967,15 @@ class __$$EducationResourceImplCopyWithImpl<$Res> Object? personalSiteLink = freezed, Object? requestState = freezed, }) { - return _then(_$EducationResourceImpl( - hasMedical_Education: freezed == hasMedical_Education - ? _value.hasMedical_Education - : hasMedical_Education // ignore: cast_nullable_to_non_nullable + return _then(_$EducationModelImpl( + hasMedicalEducation: freezed == hasMedicalEducation + ? _value.hasMedicalEducation + : hasMedicalEducation // ignore: cast_nullable_to_non_nullable as int?, + completedCourses: freezed == completedCourses + ? _value._completedCourses + : completedCourses // ignore: cast_nullable_to_non_nullable + as Map?, vkLink: freezed == vkLink ? _value.vkLink : vkLink // ignore: cast_nullable_to_non_nullable @@ -746,22 +1006,36 @@ class __$$EducationResourceImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() -class _$EducationResourceImpl implements _EducationResource { - const _$EducationResourceImpl( - {@JsonKey(name: "has_medical_education") this.hasMedical_Education, +class _$EducationModelImpl implements _EducationModel { + const _$EducationModelImpl( + {@JsonKey(name: "has_medical_education") this.hasMedicalEducation, + @JsonKey(name: "completed_cources") + final Map? completedCourses, @JsonKey(name: "vk_link") this.vkLink, @JsonKey(name: "insta_link") this.instaLink, @JsonKey(name: "fb_link") this.fbLink, @JsonKey(name: "tg_link") this.tgLink, @JsonKey(name: "personal_site_link") this.personalSiteLink, - @JsonKey(name: "request_state") this.requestState}); + @JsonKey(name: "request_state") this.requestState}) + : _completedCourses = completedCourses; - factory _$EducationResourceImpl.fromJson(Map json) => - _$$EducationResourceImplFromJson(json); + factory _$EducationModelImpl.fromJson(Map json) => + _$$EducationModelImplFromJson(json); @override @JsonKey(name: "has_medical_education") - final int? hasMedical_Education; + final int? hasMedicalEducation; + final Map? _completedCourses; + @override + @JsonKey(name: "completed_cources") + Map? get completedCourses { + final value = _completedCourses; + if (value == null) return null; + if (_completedCourses is EqualUnmodifiableMapView) return _completedCourses; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); + } + @override @JsonKey(name: "vk_link") final String? vkLink; @@ -783,16 +1057,18 @@ class _$EducationResourceImpl implements _EducationResource { @override String toString() { - return 'EducationResource(hasMedical_Education: $hasMedical_Education, vkLink: $vkLink, instaLink: $instaLink, fbLink: $fbLink, tgLink: $tgLink, personalSiteLink: $personalSiteLink, requestState: $requestState)'; + return 'EducationModel(hasMedicalEducation: $hasMedicalEducation, completedCourses: $completedCourses, vkLink: $vkLink, instaLink: $instaLink, fbLink: $fbLink, tgLink: $tgLink, personalSiteLink: $personalSiteLink, requestState: $requestState)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$EducationResourceImpl && - (identical(other.hasMedical_Education, hasMedical_Education) || - other.hasMedical_Education == hasMedical_Education) && + other is _$EducationModelImpl && + (identical(other.hasMedicalEducation, hasMedicalEducation) || + other.hasMedicalEducation == hasMedicalEducation) && + const DeepCollectionEquality() + .equals(other._completedCourses, _completedCourses) && (identical(other.vkLink, vkLink) || other.vkLink == vkLink) && (identical(other.instaLink, instaLink) || other.instaLink == instaLink) && @@ -806,43 +1082,56 @@ class _$EducationResourceImpl implements _EducationResource { @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, hasMedical_Education, vkLink, - instaLink, fbLink, tgLink, personalSiteLink, requestState); + int get hashCode => Object.hash( + runtimeType, + hasMedicalEducation, + const DeepCollectionEquality().hash(_completedCourses), + vkLink, + instaLink, + fbLink, + tgLink, + personalSiteLink, + requestState); - /// Create a copy of EducationResource + /// Create a copy of EducationModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$EducationResourceImplCopyWith<_$EducationResourceImpl> get copyWith => - __$$EducationResourceImplCopyWithImpl<_$EducationResourceImpl>( + _$$EducationModelImplCopyWith<_$EducationModelImpl> get copyWith => + __$$EducationModelImplCopyWithImpl<_$EducationModelImpl>( this, _$identity); @override Map toJson() { - return _$$EducationResourceImplToJson( + return _$$EducationModelImplToJson( this, ); } } -abstract class _EducationResource implements EducationResource { - const factory _EducationResource( - {@JsonKey(name: "has_medical_education") final int? hasMedical_Education, +abstract class _EducationModel implements EducationModel { + const factory _EducationModel( + {@JsonKey(name: "has_medical_education") final int? hasMedicalEducation, + @JsonKey(name: "completed_cources") + final Map? completedCourses, @JsonKey(name: "vk_link") final String? vkLink, @JsonKey(name: "insta_link") final String? instaLink, @JsonKey(name: "fb_link") final String? fbLink, @JsonKey(name: "tg_link") final String? tgLink, @JsonKey(name: "personal_site_link") final String? personalSiteLink, @JsonKey(name: "request_state") - final String? requestState}) = _$EducationResourceImpl; + final String? requestState}) = _$EducationModelImpl; - factory _EducationResource.fromJson(Map json) = - _$EducationResourceImpl.fromJson; + factory _EducationModel.fromJson(Map json) = + _$EducationModelImpl.fromJson; @override @JsonKey(name: "has_medical_education") - int? get hasMedical_Education; + int? get hasMedicalEducation; + @override + @JsonKey(name: "completed_cources") + Map? get completedCourses; @override @JsonKey(name: "vk_link") String? get vkLink; @@ -862,14 +1151,186 @@ abstract class _EducationResource implements EducationResource { @JsonKey(name: "request_state") String? get requestState; - /// Create a copy of EducationResource + /// Create a copy of EducationModel /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$EducationResourceImplCopyWith<_$EducationResourceImpl> get copyWith => + _$$EducationModelImplCopyWith<_$EducationModelImpl> get copyWith => throw _privateConstructorUsedError; } +CompletedCoursesModel _$CompletedCoursesModelFromJson( + Map json) { + return _CompletedCoursesModel.fromJson(json); +} + +/// @nodoc +mixin _$CompletedCoursesModel { + String get date => throw _privateConstructorUsedError; + String get title => throw _privateConstructorUsedError; + + /// Serializes this CompletedCoursesModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of CompletedCoursesModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $CompletedCoursesModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CompletedCoursesModelCopyWith<$Res> { + factory $CompletedCoursesModelCopyWith(CompletedCoursesModel value, + $Res Function(CompletedCoursesModel) then) = + _$CompletedCoursesModelCopyWithImpl<$Res, CompletedCoursesModel>; + @useResult + $Res call({String date, String title}); +} + +/// @nodoc +class _$CompletedCoursesModelCopyWithImpl<$Res, + $Val extends CompletedCoursesModel> + implements $CompletedCoursesModelCopyWith<$Res> { + _$CompletedCoursesModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CompletedCoursesModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? title = null, + }) { + return _then(_value.copyWith( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as String, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$CompletedCoursesModelImplCopyWith<$Res> + implements $CompletedCoursesModelCopyWith<$Res> { + factory _$$CompletedCoursesModelImplCopyWith( + _$CompletedCoursesModelImpl value, + $Res Function(_$CompletedCoursesModelImpl) then) = + __$$CompletedCoursesModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String date, String title}); +} + +/// @nodoc +class __$$CompletedCoursesModelImplCopyWithImpl<$Res> + extends _$CompletedCoursesModelCopyWithImpl<$Res, + _$CompletedCoursesModelImpl> + implements _$$CompletedCoursesModelImplCopyWith<$Res> { + __$$CompletedCoursesModelImplCopyWithImpl(_$CompletedCoursesModelImpl _value, + $Res Function(_$CompletedCoursesModelImpl) _then) + : super(_value, _then); + + /// Create a copy of CompletedCoursesModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? date = null, + Object? title = null, + }) { + return _then(_$CompletedCoursesModelImpl( + date: null == date + ? _value.date + : date // ignore: cast_nullable_to_non_nullable + as String, + title: null == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$CompletedCoursesModelImpl implements _CompletedCoursesModel { + const _$CompletedCoursesModelImpl({required this.date, required this.title}); + + factory _$CompletedCoursesModelImpl.fromJson(Map json) => + _$$CompletedCoursesModelImplFromJson(json); + + @override + final String date; + @override + final String title; + + @override + String toString() { + return 'CompletedCoursesModel(date: $date, title: $title)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CompletedCoursesModelImpl && + (identical(other.date, date) || other.date == date) && + (identical(other.title, title) || other.title == title)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, date, title); + + /// Create a copy of CompletedCoursesModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CompletedCoursesModelImplCopyWith<_$CompletedCoursesModelImpl> + get copyWith => __$$CompletedCoursesModelImplCopyWithImpl< + _$CompletedCoursesModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$CompletedCoursesModelImplToJson( + this, + ); + } +} + +abstract class _CompletedCoursesModel implements CompletedCoursesModel { + const factory _CompletedCoursesModel( + {required final String date, + required final String title}) = _$CompletedCoursesModelImpl; + + factory _CompletedCoursesModel.fromJson(Map json) = + _$CompletedCoursesModelImpl.fromJson; + + @override + String get date; + @override + String get title; + + /// Create a copy of CompletedCoursesModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CompletedCoursesModelImplCopyWith<_$CompletedCoursesModelImpl> + get copyWith => throw _privateConstructorUsedError; +} + ProfileDetailsModel _$ProfileDetailsModelFromJson(Map json) { return _ProfileDetailsModel.fromJson(json); } diff --git a/lib/features/profile/models/profile_model.g.dart b/lib/features/profile/models/profile_model.g.dart index f22b5656..e8925091 100644 --- a/lib/features/profile/models/profile_model.g.dart +++ b/lib/features/profile/models/profile_model.g.dart @@ -11,6 +11,7 @@ _$ProfileModelImpl _$$ProfileModelImplFromJson(Map json) => id: (json['id'] as num).toInt(), name: json['name'] as String, email: json['email'] as String, + ratingPlace: (json['rating_place'] as num?)?.toInt(), emailVerifiedAt: json['email_verified_at'] == null ? null : DateTime.parse(json['email_verified_at'] as String), @@ -36,8 +37,12 @@ _$ProfileModelImpl _$$ProfileModelImplFromJson(Map json) => .toList(), educationResource: json['education_resource'] == null ? null - : EducationResource.fromJson( + : EducationModel.fromJson( json['education_resource'] as Map), + diplomasAndCertificates: (json['cert_photos'] as List?) + ?.map((e) => + DiplomasAndCertificatesModel.fromJson(e as Map)) + .toList(), ); Map _$$ProfileModelImplToJson(_$ProfileModelImpl instance) => @@ -45,6 +50,7 @@ Map _$$ProfileModelImplToJson(_$ProfileModelImpl instance) => 'id': instance.id, 'name': instance.name, 'email': instance.email, + 'rating_place': instance.ratingPlace, 'email_verified_at': instance.emailVerifiedAt?.toIso8601String(), 'created_at': instance.createdAt?.toIso8601String(), 'updated_at': instance.updatedAt?.toIso8601String(), @@ -57,12 +63,31 @@ Map _$$ProfileModelImplToJson(_$ProfileModelImpl instance) => 'subscriptions': instance.subscriptions, 'subscribers': instance.subscribers, 'education_resource': instance.educationResource, + 'cert_photos': instance.diplomasAndCertificates, }; -_$EducationResourceImpl _$$EducationResourceImplFromJson( +_$DiplomasAndCertificatesModelImpl _$$DiplomasAndCertificatesModelImplFromJson( Map json) => - _$EducationResourceImpl( - hasMedical_Education: (json['has_medical_education'] as num?)?.toInt(), + _$DiplomasAndCertificatesModelImpl( + id: (json['id'] as num).toInt(), + path: json['path'] as String, + ); + +Map _$$DiplomasAndCertificatesModelImplToJson( + _$DiplomasAndCertificatesModelImpl instance) => + { + 'id': instance.id, + 'path': instance.path, + }; + +_$EducationModelImpl _$$EducationModelImplFromJson(Map json) => + _$EducationModelImpl( + hasMedicalEducation: (json['has_medical_education'] as num?)?.toInt(), + completedCourses: + (json['completed_cources'] as Map?)?.map( + (k, e) => MapEntry( + k, CompletedCoursesModel.fromJson(e as Map)), + ), vkLink: json['vk_link'] as String?, instaLink: json['insta_link'] as String?, fbLink: json['fb_link'] as String?, @@ -71,10 +96,11 @@ _$EducationResourceImpl _$$EducationResourceImplFromJson( requestState: json['request_state'] as String?, ); -Map _$$EducationResourceImplToJson( - _$EducationResourceImpl instance) => +Map _$$EducationModelImplToJson( + _$EducationModelImpl instance) => { - 'has_medical_education': instance.hasMedical_Education, + 'has_medical_education': instance.hasMedicalEducation, + 'completed_cources': instance.completedCourses, 'vk_link': instance.vkLink, 'insta_link': instance.instaLink, 'fb_link': instance.fbLink, @@ -83,6 +109,20 @@ Map _$$EducationResourceImplToJson( 'request_state': instance.requestState, }; +_$CompletedCoursesModelImpl _$$CompletedCoursesModelImplFromJson( + Map json) => + _$CompletedCoursesModelImpl( + date: json['date'] as String, + title: json['title'] as String, + ); + +Map _$$CompletedCoursesModelImplToJson( + _$CompletedCoursesModelImpl instance) => + { + 'date': instance.date, + 'title': instance.title, + }; + _$ProfileDetailsModelImpl _$$ProfileDetailsModelImplFromJson( Map json) => _$ProfileDetailsModelImpl( diff --git a/lib/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart b/lib/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart new file mode 100644 index 00000000..79eb02a8 --- /dev/null +++ b/lib/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart @@ -0,0 +1,21 @@ +import 'package:eatvio_app/features/plans/repositories/plans_repository.dart'; +import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_state.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class PlansCubit extends Cubit { + final PlansRepository plansRepository; + + PlansCubit({ + required this.plansRepository, + }) : super(const PlansState()); + + getPlans(String slug) async { + emit(const PlansState.loading()); + try { + emit(PlansState.loaded(plansList: await plansRepository.getPlansBySlug(slug))); + } catch (e) { + print(e); + emit(PlansState.error(errorMessage: e.toString())); + } + } +} diff --git a/lib/features/profile/presentation/bloc/plans_cubit/plans_state.dart b/lib/features/profile/presentation/bloc/plans_cubit/plans_state.dart new file mode 100644 index 00000000..86666644 --- /dev/null +++ b/lib/features/profile/presentation/bloc/plans_cubit/plans_state.dart @@ -0,0 +1,19 @@ +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'plans_state.freezed.dart'; + +@freezed +abstract class PlansState with _$PlansState { + const factory PlansState() = _PlansState; + + const factory PlansState.loading() = PlansStateLoading; + + const factory PlansState.loaded({ + required List plansList, + }) = PlansStateLoaded; + + const factory PlansState.error({ + required String errorMessage, + }) = PlansStateError; +} diff --git a/lib/features/profile/presentation/bloc/plans_cubit/plans_state.freezed.dart b/lib/features/profile/presentation/bloc/plans_cubit/plans_state.freezed.dart new file mode 100644 index 00000000..9230dbdf --- /dev/null +++ b/lib/features/profile/presentation/bloc/plans_cubit/plans_state.freezed.dart @@ -0,0 +1,641 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// 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 'plans_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$PlansState { + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List plansList) loaded, + required TResult Function(String errorMessage) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List plansList)? loaded, + TResult? Function(String errorMessage)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List plansList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map( + TResult Function(_PlansState value) $default, { + required TResult Function(PlansStateLoading value) loading, + required TResult Function(PlansStateLoaded value) loaded, + required TResult Function(PlansStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_PlansState value)? $default, { + TResult? Function(PlansStateLoading value)? loading, + TResult? Function(PlansStateLoaded value)? loaded, + TResult? Function(PlansStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap( + TResult Function(_PlansState value)? $default, { + TResult Function(PlansStateLoading value)? loading, + TResult Function(PlansStateLoaded value)? loaded, + TResult Function(PlansStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlansStateCopyWith<$Res> { + factory $PlansStateCopyWith( + PlansState value, $Res Function(PlansState) then) = + _$PlansStateCopyWithImpl<$Res, PlansState>; +} + +/// @nodoc +class _$PlansStateCopyWithImpl<$Res, $Val extends PlansState> + implements $PlansStateCopyWith<$Res> { + _$PlansStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$PlansStateImplCopyWith<$Res> { + factory _$$PlansStateImplCopyWith( + _$PlansStateImpl value, $Res Function(_$PlansStateImpl) then) = + __$$PlansStateImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$PlansStateImplCopyWithImpl<$Res> + extends _$PlansStateCopyWithImpl<$Res, _$PlansStateImpl> + implements _$$PlansStateImplCopyWith<$Res> { + __$$PlansStateImplCopyWithImpl( + _$PlansStateImpl _value, $Res Function(_$PlansStateImpl) _then) + : super(_value, _then); + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$PlansStateImpl implements _PlansState { + const _$PlansStateImpl(); + + @override + String toString() { + return 'PlansState()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$PlansStateImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List plansList) loaded, + required TResult Function(String errorMessage) error, + }) { + return $default(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List plansList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return $default?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List plansList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_PlansState value) $default, { + required TResult Function(PlansStateLoading value) loading, + required TResult Function(PlansStateLoaded value) loaded, + required TResult Function(PlansStateError value) error, + }) { + return $default(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_PlansState value)? $default, { + TResult? Function(PlansStateLoading value)? loading, + TResult? Function(PlansStateLoaded value)? loaded, + TResult? Function(PlansStateError value)? error, + }) { + return $default?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_PlansState value)? $default, { + TResult Function(PlansStateLoading value)? loading, + TResult Function(PlansStateLoaded value)? loaded, + TResult Function(PlansStateError value)? error, + required TResult orElse(), + }) { + if ($default != null) { + return $default(this); + } + return orElse(); + } +} + +abstract class _PlansState implements PlansState { + const factory _PlansState() = _$PlansStateImpl; +} + +/// @nodoc +abstract class _$$PlansStateLoadingImplCopyWith<$Res> { + factory _$$PlansStateLoadingImplCopyWith(_$PlansStateLoadingImpl value, + $Res Function(_$PlansStateLoadingImpl) then) = + __$$PlansStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$PlansStateLoadingImplCopyWithImpl<$Res> + extends _$PlansStateCopyWithImpl<$Res, _$PlansStateLoadingImpl> + implements _$$PlansStateLoadingImplCopyWith<$Res> { + __$$PlansStateLoadingImplCopyWithImpl(_$PlansStateLoadingImpl _value, + $Res Function(_$PlansStateLoadingImpl) _then) + : super(_value, _then); + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc + +class _$PlansStateLoadingImpl implements PlansStateLoading { + const _$PlansStateLoadingImpl(); + + @override + String toString() { + return 'PlansState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$PlansStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List plansList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List plansList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List plansList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_PlansState value) $default, { + required TResult Function(PlansStateLoading value) loading, + required TResult Function(PlansStateLoaded value) loaded, + required TResult Function(PlansStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_PlansState value)? $default, { + TResult? Function(PlansStateLoading value)? loading, + TResult? Function(PlansStateLoaded value)? loaded, + TResult? Function(PlansStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_PlansState value)? $default, { + TResult Function(PlansStateLoading value)? loading, + TResult Function(PlansStateLoaded value)? loaded, + TResult Function(PlansStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class PlansStateLoading implements PlansState { + const factory PlansStateLoading() = _$PlansStateLoadingImpl; +} + +/// @nodoc +abstract class _$$PlansStateLoadedImplCopyWith<$Res> { + factory _$$PlansStateLoadedImplCopyWith(_$PlansStateLoadedImpl value, + $Res Function(_$PlansStateLoadedImpl) then) = + __$$PlansStateLoadedImplCopyWithImpl<$Res>; + @useResult + $Res call({List plansList}); +} + +/// @nodoc +class __$$PlansStateLoadedImplCopyWithImpl<$Res> + extends _$PlansStateCopyWithImpl<$Res, _$PlansStateLoadedImpl> + implements _$$PlansStateLoadedImplCopyWith<$Res> { + __$$PlansStateLoadedImplCopyWithImpl(_$PlansStateLoadedImpl _value, + $Res Function(_$PlansStateLoadedImpl) _then) + : super(_value, _then); + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? plansList = null, + }) { + return _then(_$PlansStateLoadedImpl( + plansList: null == plansList + ? _value._plansList + : plansList // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$PlansStateLoadedImpl implements PlansStateLoaded { + const _$PlansStateLoadedImpl({required final List plansList}) + : _plansList = plansList; + + final List _plansList; + @override + List get plansList { + if (_plansList is EqualUnmodifiableListView) return _plansList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_plansList); + } + + @override + String toString() { + return 'PlansState.loaded(plansList: $plansList)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlansStateLoadedImpl && + const DeepCollectionEquality() + .equals(other._plansList, _plansList)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_plansList)); + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$PlansStateLoadedImplCopyWith<_$PlansStateLoadedImpl> get copyWith => + __$$PlansStateLoadedImplCopyWithImpl<_$PlansStateLoadedImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List plansList) loaded, + required TResult Function(String errorMessage) error, + }) { + return loaded(plansList); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List plansList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return loaded?.call(plansList); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List plansList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(plansList); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_PlansState value) $default, { + required TResult Function(PlansStateLoading value) loading, + required TResult Function(PlansStateLoaded value) loaded, + required TResult Function(PlansStateError value) error, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_PlansState value)? $default, { + TResult? Function(PlansStateLoading value)? loading, + TResult? Function(PlansStateLoaded value)? loaded, + TResult? Function(PlansStateError value)? error, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_PlansState value)? $default, { + TResult Function(PlansStateLoading value)? loading, + TResult Function(PlansStateLoaded value)? loaded, + TResult Function(PlansStateError value)? error, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class PlansStateLoaded implements PlansState { + const factory PlansStateLoaded({required final List plansList}) = + _$PlansStateLoadedImpl; + + List get plansList; + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PlansStateLoadedImplCopyWith<_$PlansStateLoadedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$PlansStateErrorImplCopyWith<$Res> { + factory _$$PlansStateErrorImplCopyWith(_$PlansStateErrorImpl value, + $Res Function(_$PlansStateErrorImpl) then) = + __$$PlansStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({String errorMessage}); +} + +/// @nodoc +class __$$PlansStateErrorImplCopyWithImpl<$Res> + extends _$PlansStateCopyWithImpl<$Res, _$PlansStateErrorImpl> + implements _$$PlansStateErrorImplCopyWith<$Res> { + __$$PlansStateErrorImplCopyWithImpl( + _$PlansStateErrorImpl _value, $Res Function(_$PlansStateErrorImpl) _then) + : super(_value, _then); + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? errorMessage = null, + }) { + return _then(_$PlansStateErrorImpl( + errorMessage: null == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$PlansStateErrorImpl implements PlansStateError { + const _$PlansStateErrorImpl({required this.errorMessage}); + + @override + final String errorMessage; + + @override + String toString() { + return 'PlansState.error(errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlansStateErrorImpl && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, errorMessage); + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$PlansStateErrorImplCopyWith<_$PlansStateErrorImpl> get copyWith => + __$$PlansStateErrorImplCopyWithImpl<_$PlansStateErrorImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when( + TResult Function() $default, { + required TResult Function() loading, + required TResult Function(List plansList) loaded, + required TResult Function(String errorMessage) error, + }) { + return error(errorMessage); + } + + @override + @optionalTypeArgs + TResult? whenOrNull( + TResult? Function()? $default, { + TResult? Function()? loading, + TResult? Function(List plansList)? loaded, + TResult? Function(String errorMessage)? error, + }) { + return error?.call(errorMessage); + } + + @override + @optionalTypeArgs + TResult maybeWhen( + TResult Function()? $default, { + TResult Function()? loading, + TResult Function(List plansList)? loaded, + TResult Function(String errorMessage)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(errorMessage); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map( + TResult Function(_PlansState value) $default, { + required TResult Function(PlansStateLoading value) loading, + required TResult Function(PlansStateLoaded value) loaded, + required TResult Function(PlansStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull( + TResult? Function(_PlansState value)? $default, { + TResult? Function(PlansStateLoading value)? loading, + TResult? Function(PlansStateLoaded value)? loaded, + TResult? Function(PlansStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap( + TResult Function(_PlansState value)? $default, { + TResult Function(PlansStateLoading value)? loading, + TResult Function(PlansStateLoaded value)? loaded, + TResult Function(PlansStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class PlansStateError implements PlansState { + const factory PlansStateError({required final String errorMessage}) = + _$PlansStateErrorImpl; + + String get errorMessage; + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PlansStateErrorImplCopyWith<_$PlansStateErrorImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart index ad975da2..7f2cf65a 100644 --- a/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart +++ b/lib/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart @@ -1,7 +1,7 @@ import 'dart:io'; - import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_state.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -50,6 +50,22 @@ class ProfileCubit extends Cubit { } } + updateFeedBlogPostList(FeedBlogPostModel feedBlogPostModel, bool wasLikedByMe) { + List feedBlogPostList = [...(state as ProfileStateLoaded).blogPosts]; + final int index = feedBlogPostList.indexOf(feedBlogPostModel); + feedBlogPostList[index] = feedBlogPostModel.copyWith( + wasLikedByMe: wasLikedByMe, + totalLikes: wasLikedByMe == false ? feedBlogPostList[index].totalLikes - 1 : feedBlogPostList[index].totalLikes + 1, + ); + emit( + ProfileState.loaded( + profile: (state as ProfileStateLoaded).profile, + profileDetails: (state as ProfileStateLoaded).profileDetails, + blogPosts: feedBlogPostList, + ), + ); + } + addCircumference({ required int chestCircumference, required int waistCircumference, diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 2647b989..246498e9 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -8,15 +8,18 @@ import 'package:eatvio_app/core/widgets/loader.dart'; import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart'; import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; -import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart'; import 'package:eatvio_app/features/profile/models/circumference_model.dart'; import 'package:eatvio_app/features/profile/models/weight_model.dart'; +import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart'; +import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_state.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_state.dart'; import 'package:eatvio_app/features/profile/presentation/bloc/sub_cubit/sub_cubit.dart'; import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart'; import 'package:eatvio_app/features/profile/presentation/widgets/circumference_chart_widget.dart'; import 'package:eatvio_app/features/profile/presentation/widgets/imt_chart_widget.dart'; +import 'package:eatvio_app/features/profile/presentation/widgets/profile_blog_post_widget.dart'; import 'package:eatvio_app/features/profile/presentation/widgets/weight_chart_widget.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; @@ -42,7 +45,8 @@ class ProfileScreen extends StatefulWidget { } class _ProfileScreenState extends State { - final ProfileCubit profileCubit = sl(); + late final ProfileCubit profileCubit = sl(); + final PlansCubit plansCubit = sl(); final List chipsLabelList = ['Вес', 'Замеры', 'ИМТ']; final List chipsIntervalLabelList = ['1М', '3М', '6М', '1Г', 'ВСЁ ВРЕМЯ']; final List chipsIntervalList = ['1', '3', '6', '12', 'all']; @@ -53,6 +57,7 @@ class _ProfileScreenState extends State { int _selectedIntervalChipIndex = 0; late bool canSub; bool isFirstFetch = true; + int _currentBullet = 0; @override void initState() { @@ -62,36 +67,42 @@ class _ProfileScreenState extends State { @override Widget build(BuildContext context) { - return BlocBuilder( - bloc: profileCubit, - builder: (BuildContext context, ProfileState state) { - if (state is ProfileStateLoaded) { - if (state.circumferencePoints != null) { - circumferencePoints = state.circumferencePoints!; - weightPoints = state.weightPoints!; - } - if (isFirstFetch) { - canSub = !state.profile.isEntitySubscribedByMe; - isFirstFetch = false; - } - return widget.author == null ? _myProfileScreen(state) : _profileScreen(state); - } else if (state is ProfileStateError) { - return Scaffold( - appBar: AppBar(), - body: Center( - child: Padding( - padding: const EdgeInsets.all(16), - child: Text(state.errorMessage), + return BlocProvider( + create: (BuildContext context) => plansCubit, + child: BlocBuilder( + bloc: profileCubit, + builder: (BuildContext context, ProfileState state) { + if (state is ProfileStateLoaded) { + if (state.circumferencePoints != null) { + circumferencePoints = state.circumferencePoints!; + weightPoints = state.weightPoints!; + } + if (isFirstFetch) { + canSub = !state.profile.isEntitySubscribedByMe; + if (state.profile.role == 'consultant') { + plansCubit..getPlans(state.profile.slug); + } + isFirstFetch = false; + } + return widget.author == null ? _myProfileScreen(state) : _profileScreen(state); + } else if (state is ProfileStateError) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: Padding( + padding: const EdgeInsets.all(16), + child: Text(state.errorMessage), + ), ), - ), - ); - } else { - return Scaffold( - appBar: AppBar(), - body: const Loader(), - ); - } - }, + ); + } else { + return Scaffold( + appBar: AppBar(), + body: const Loader(), + ); + } + }, + ), ); } @@ -114,6 +125,62 @@ class _ProfileScreenState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ _header(state), + if (state.profile.role == 'consultant') + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const SizedBox(width: 16), + Text( + 'Консультант', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color( + 0xFF323F4B, + ), + ), + ), + const SizedBox(width: 12), + if (state.profile.ratingPlace != null) + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Color(0xFFF6FAFF), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + '${state.profile.ratingPlace!}-й в рейтинге', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: appTheme.blueA400, + ), + ), + ), + ], + ), + if (state.profile.educationResource?.hasMedicalEducation == 1) + Row( + children: [ + const SizedBox(width: 16), + Icon( + Icons.done_rounded, + color: Colors.green, + ), + Text( + 'Медицинское образование', + style: TextStyle( + color: Color(0xFF323F4B), + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ], + ), if (state.profileDetails.additionalInfo.isNotEmpty) _additionalInfo(state), const SizedBox(height: 8), _messageAndSubscribe(state), @@ -176,36 +243,51 @@ class _ProfileScreenState extends State { if (state.profile.role != 'consultant') { return const SizedBox.shrink(); } - return Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return BlocBuilder( + bloc: plansCubit, + builder: (BuildContext context, PlansState state) { + if (state is PlansStateLoaded) { + return Column( children: [ - Text( - 'Активные планы', - style: TextStyle( - color: Color(0xFF323F4B), - fontSize: 24, - height: 1, - fontWeight: FontWeight.w600, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Активные планы', + style: TextStyle( + color: Color(0xFF323F4B), + fontSize: 24, + height: 1, + fontWeight: FontWeight.w600, + ), + ), + ], ), ), - Text( - widget.author == null ? 'Редактировать' : 'Показать все', - style: TextStyle( - color: Color(0xFF2F80ED), - fontSize: 16, - fontWeight: FontWeight.w500, + const SizedBox(height: 8), + SizedBox( + height: 378, + child: PageView.builder( + itemBuilder: (BuildContext context, int index) { + return PlanWidget(planModel: state.plansList[index]); + }, + onPageChanged: (bullet) { + setState(() { + _currentBullet = bullet; + }); + }, + itemCount: state.plansList.length, ), ), + const SizedBox(height: 8), + _bullets(_currentBullet, state.plansList.length), ], - ), - ), - const SizedBox(height: 8), - _bullets(0, 4), - ], + ); + } + return Loader(); + }, ); } @@ -302,7 +384,7 @@ class _ProfileScreenState extends State { ), ), Text( - widget.author == null ? 'Редактировать' : 'Показать все', + widget.author == null ? 'Редактировать' : '', style: TextStyle( color: Color(0xFF2F80ED), fontSize: 16, @@ -325,21 +407,8 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ - _diplomaImage( - state.profile.profilePhotoUrl, - ), - const SizedBox(width: 8), - _diplomaImage( - state.profile.profilePhotoUrl, - ), - const SizedBox(width: 8), - _diplomaImage( - state.profile.profilePhotoUrl, - ), - const SizedBox(width: 8), - _diplomaImage( - state.profile.profilePhotoUrl, - ), + if (state.profile.diplomasAndCertificates != null) + ...state.profile.diplomasAndCertificates!.map((d) => _diplomaImage(baseUrl + '/storage/' + d.path)).toList(), ], ), ), @@ -350,13 +419,27 @@ class _ProfileScreenState extends State { } _diplomaImage(String url) { - return ClipRRect( - borderRadius: BorderRadius.circular(8), - child: CachedNetworkImage( - imageUrl: url, - fit: BoxFit.fitHeight, - width: MediaQuery.of(context).size.width / 3 - (60 / 3), - height: 160, + return GestureDetector( + onTap: () { + context.pushTransparentRoute( + rootNavigator: true, + PhotoViewScreen( + imageUrls: [url], + index: 0, + ), + ); + }, + child: Hero( + tag: url, + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: CachedNetworkImage( + imageUrl: url, + fit: BoxFit.fitHeight, + width: MediaQuery.of(context).size.width / 3 - (60 / 3), + height: 160, + ), + ), ), ); } @@ -381,7 +464,7 @@ class _ProfileScreenState extends State { ), ), Text( - widget.author == null ? 'Редактировать' : 'Показать все', + widget.author == null ? 'Редактировать' : '', style: TextStyle( color: Color(0xFF2F80ED), fontSize: 16, @@ -401,10 +484,8 @@ class _ProfileScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Column( children: [ - _educationBlock( - 'Наименование диплома или сертификата в 2 строки', - '30.01.2020', - ), + if (state.profile.educationResource?.completedCourses != null) + ...state.profile.educationResource!.completedCourses!.values.map((c) => _educationBlock(c.title, c.date)).toList(), ], ), ), @@ -415,34 +496,37 @@ class _ProfileScreenState extends State { } _educationBlock(String title, String date) { - return Material( - color: Color(0xFFF6FAFF), - borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: TextStyle( - height: 1, - color: Color(0xFF323F4B), - fontWeight: FontWeight.w500, - fontSize: 16, + return SizedBox( + width: double.infinity, + child: Material( + color: Color(0xFFF6FAFF), + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + height: 1, + color: Color(0xFF323F4B), + fontWeight: FontWeight.w500, + fontSize: 16, + ), ), - ), - const SizedBox(height: 4), - Text( - date, - style: TextStyle( - height: 1, - color: Color(0xFF6D6F71), - fontWeight: FontWeight.w500, - fontSize: 14, + const SizedBox(height: 4), + Text( + date, + style: TextStyle( + height: 1, + color: Color(0xFF6D6F71), + fontWeight: FontWeight.w500, + fontSize: 14, + ), ), - ), - ], + ], + ), ), ), ); @@ -705,8 +789,9 @@ class _ProfileScreenState extends State { padding: EdgeInsets.symmetric(vertical: 16), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => BlogPostWidget( + itemBuilder: (context, index) => ProfileBlogPostWidget( index: index, + profileCubit: profileCubit, ), separatorBuilder: (context, index) => SizedBox(height: 8), itemCount: state.blogPosts.length, diff --git a/lib/features/profile/presentation/widgets/profile_blog_post_widget.dart b/lib/features/profile/presentation/widgets/profile_blog_post_widget.dart new file mode 100644 index 00000000..6fcb4f40 --- /dev/null +++ b/lib/features/profile/presentation/widgets/profile_blog_post_widget.dart @@ -0,0 +1,245 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dismissible_page/dismissible_page.dart'; +import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/utils/date_time_utils.dart'; +import 'package:eatvio_app/core/widgets/feed_icon_button.dart'; +import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/feed/presentation/widgets/subscribe_button_widget.dart'; +import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart'; +import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_state.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:go_router/go_router.dart'; +import 'package:share_plus/share_plus.dart'; + +class ProfileBlogPostWidget extends StatefulWidget { + final int index; + final ProfileCubit profileCubit; + + const ProfileBlogPostWidget({ + super.key, + required this.index, + required this.profileCubit, + }); + + @override + State createState() => _ProfileBlogPostWidgetState(); +} + +class _ProfileBlogPostWidgetState extends State { + late bool isLiked; + late int totalLikes; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + bloc: widget.profileCubit, + builder: (BuildContext context, ProfileState state) { + if (state is ProfileStateLoaded) { + isLiked = state.blogPosts[widget.index].wasLikedByMe; + totalLikes = state.blogPosts[widget.index].totalLikes; + return InkWell( + borderRadius: BorderRadius.circular(12), + onTap: () => GoRouter.of(context).pushNamed( + 'blogPostScreen', + extra: state.blogPosts[widget.index], + ), + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.white, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + CircleAvatar( + radius: 20, + backgroundColor: Colors.black12, + foregroundImage: NetworkImage( + state.blogPosts[widget.index].author.authorProfileIcon, + ), + ), + SizedBox(width: 8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + state.blogPosts[widget.index].author.authorName, + style: TextStyle( + height: 1, + color: Colors.black87, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 4), + Text( + '${calculateDifference(state.blogPosts[widget.index].createdAt)} в ${state.blogPosts[widget.index].createdAt.hour.toString().padLeft(2, '0')}:${state.blogPosts[widget.index].createdAt.minute.toString().padLeft(2, '0')}', + style: TextStyle( + height: 1, + color: Colors.black45, + ), + ), + ], + ), + const Spacer(), + if (!state.blogPosts[widget.index].author.isEntitySubscribedByMe! && !state.blogPosts[widget.index].author.authorIsMe) + SubscribeButtonWidget( + slug: state.blogPosts[widget.index].author.authorSlug, + ), + ], + ), + ), + if (state.blogPosts[widget.index].title.isNotEmpty || state.blogPosts[widget.index].description.isNotEmpty) SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + state.blogPosts[widget.index].title, + style: TextStyle( + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + ), + if (state.blogPosts[widget.index].title.isNotEmpty && state.blogPosts[widget.index].description.isNotEmpty) SizedBox(height: 8), + if (state.blogPosts[widget.index].description.isNotEmpty) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Html( + data: state.blogPosts[widget.index].description.length > 200 + ? state.blogPosts[widget.index].description.substring(0, 200) + : state.blogPosts[widget.index].description, + style: { + "*": Style( + color: Colors.black87, + ), + }, + ), + ), + if (state.blogPosts[widget.index].description.length > 200) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Читать полностью...', + style: TextStyle( + height: 1, + color: appTheme.blueA400, + decoration: TextDecoration.underline, + ), + ), + ), + if (state.blogPosts[widget.index].title.isNotEmpty || state.blogPosts[widget.index].description.isNotEmpty) SizedBox(height: 8), + GestureDetector( + onTap: () { + context.pushTransparentRoute( + rootNavigator: true, + PhotoViewScreen( + imageUrls: [baseUrl + '/storage/' + state.blogPosts[widget.index].image], + index: 0, + ), + ); + }, + child: Hero( + tag: baseUrl + '/storage/' + state.blogPosts[widget.index].image, + child: CachedNetworkImage( + fit: BoxFit.fitWidth, + width: MediaQuery.of(context).size.width, + imageUrl: baseUrl + '/storage/' + state.blogPosts[widget.index].image, + errorWidget: (context, str, object) => SizedBox.shrink(), + ), + ), + ), + SizedBox(height: 12), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + FeedIconButton( + icon: isLiked ? Icons.favorite_rounded : Icons.favorite_border_rounded, + text: totalLikes.toString(), + iconColor: isLiked ? Colors.red.withOpacity(0.8) : null, + backgroundColor: isLiked ? Colors.red.withOpacity(0.1) : null, + textColor: isLiked ? Colors.red.withOpacity(0.8) : null, + onTap: () async { + setState(() { + isLiked = !isLiked; + isLiked ? totalLikes++ : totalLikes--; + }); + isLiked + ? await context.read().likePost(state.blogPosts[widget.index].id) + : await context.read().unlikedPost(state.blogPosts[widget.index].id); + await widget.profileCubit.updateFeedBlogPostList( + state.blogPosts[widget.index], + isLiked ? false : true, + ); + }, + ), + SizedBox(width: 8), + FeedIconButton( + svgIcon: SvgPicture.asset( + 'assets/icons/comment.svg', + height: 20, + width: 20, + colorFilter: ColorFilter.mode( + appTheme.gray600, + BlendMode.srcIn, + ), + ), + text: state.blogPosts[widget.index].totalComments.toString(), + onTap: () => GoRouter.of(context).pushNamed( + 'blogPostScreen', + extra: state.blogPosts[widget.index], + ), + ), + SizedBox(width: 8), + FeedIconButton( + svgIcon: SvgPicture.asset( + height: 20, + width: 20, + 'assets/icons/share.svg', + colorFilter: ColorFilter.mode(appTheme.gray600, BlendMode.srcIn), + ), + onTap: () => Share.shareUri( + Uri.parse( + baseUrl + '/ru/blog_post/' + state.blogPosts[widget.index].id.toString(), + ), + ), + ), + Spacer(), + Icon( + Icons.visibility_rounded, + size: 16, + color: appTheme.gray500, + ), + SizedBox(width: 4), + Text( + state.blogPosts[widget.index].totalViews.toString(), + style: TextStyle( + fontSize: 12, + color: appTheme.gray500, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + SizedBox(height: 8), + ], + ), + ), + ); + } + return const SizedBox.shrink(); + }, + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 44dc695b..551f8b50 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: json_annotation: ^4.9.0 validators: ^3.0.0 path_provider: ^2.1.5 - carousel_slider_plus: ^7.0.2 + carousel_slider_plus: ^7.1.0 flutter_form_builder: ^9.5.0 image_picker: ^1.1.2 flutter_typeahead: ^5.2.0 From 178060e85e76460f9fc1f151e42a78ecdf9c9b01 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 6 Dec 2024 14:04:37 +0300 Subject: [PATCH 02/10] fix: black screen after splash --- lib/features/auth/auth_screen/auth_screen.dart | 2 ++ lib/features/profile/presentation/pages/profile_screen.dart | 2 ++ lib/main.dart | 1 - pubspec.yaml | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/features/auth/auth_screen/auth_screen.dart b/lib/features/auth/auth_screen/auth_screen.dart index 220d61a5..94914e51 100644 --- a/lib/features/auth/auth_screen/auth_screen.dart +++ b/lib/features/auth/auth_screen/auth_screen.dart @@ -18,6 +18,7 @@ import 'package:validators/validators.dart'; import 'bloc/auth_bloc.dart'; import 'models/auth_model.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; class AuthScreen extends StatefulWidget { static Widget builder(BuildContext context) { @@ -43,6 +44,7 @@ class _AuthScreenState extends State { @override Widget build(BuildContext context) { + FlutterNativeSplash.remove(); final s = S.of(context); return Scaffold( appBar: AppBar( diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 246498e9..98ad0e81 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -31,6 +31,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:image_picker/image_picker.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; class ProfileScreen extends StatefulWidget { final Author? author; @@ -67,6 +68,7 @@ class _ProfileScreenState extends State { @override Widget build(BuildContext context) { + FlutterNativeSplash.remove(); return BlocProvider( create: (BuildContext context) => plansCubit, child: BlocBuilder( diff --git a/lib/main.dart b/lib/main.dart index 97522447..edc0a152 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,7 +19,6 @@ void main() async { WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); await di.init(); - await Future.delayed(Duration(seconds: 1), () => FlutterNativeSplash.remove()); runApp(MyApp()); } diff --git a/pubspec.yaml b/pubspec.yaml index 551f8b50..3274a97a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,7 +48,7 @@ dependencies: file_picker: ^8.1.4 audioplayers: ^6.1.0 intl: ^0.19.0 - rive: ^0.13.19 + rive: ^0.13.20 mask_text_input_formatter: ^2.9.0 lottie: ^3.1.3 flutter_portal: ^1.1.4 From afdcea1e1fd91d81796f680f2c93f50075b956ad Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Dec 2024 11:16:20 +0300 Subject: [PATCH 03/10] fix: glossary modeartion --- .../initialization_cubit.dart | 16 ++++++++++------ .../diary/presentation/bloc/diary_cubit.dart | 2 +- ...glossary_moderation_request_modal_widget.dart | 10 ++++------ .../diary/repositories/diary_repository.dart | 2 +- lib/features/diary/services/diary_service.dart | 2 +- lib/features/diary/services/diary_service.g.dart | 14 +++----------- 6 files changed, 20 insertions(+), 26 deletions(-) diff --git a/lib/core/initialization_cubit/initialization_cubit.dart b/lib/core/initialization_cubit/initialization_cubit.dart index aedcc3cd..2bdc881f 100644 --- a/lib/core/initialization_cubit/initialization_cubit.dart +++ b/lib/core/initialization_cubit/initialization_cubit.dart @@ -87,13 +87,17 @@ class InitializationCubit extends Cubit { await subscribeNotifications(wsUrl.userId, client); await subscribeChatMessages(wsUrl.userId, client); - emit(InitializationState.success( - client: client, - ),); + emit( + InitializationState.success( + client: client, + ), + ); } catch (e) { - emit(InitializationState.error( - errorMessage: e.toString(), - ),); + emit( + InitializationState.error( + errorMessage: e.toString(), + ), + ); rethrow; } } diff --git a/lib/features/diary/presentation/bloc/diary_cubit.dart b/lib/features/diary/presentation/bloc/diary_cubit.dart index 9e667a03..ddc35422 100644 --- a/lib/features/diary/presentation/bloc/diary_cubit.dart +++ b/lib/features/diary/presentation/bloc/diary_cubit.dart @@ -155,7 +155,7 @@ class DiaryCubit extends Cubit { await fetchDiary(); } - Future sendProductToModeration({ + Future sendProductToModeration({ required String name, required double energy, required double proteins, diff --git a/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart b/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart index e069b3d9..a3a6d9ad 100644 --- a/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart +++ b/lib/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart @@ -1,7 +1,6 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; -import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; @@ -28,7 +27,7 @@ class _GlossaryModerationRequestModalWidgetState extends State sendProductToModeration({ + Future sendProductToModeration({ required String name, required double energy, required double proteins, diff --git a/lib/features/diary/services/diary_service.dart b/lib/features/diary/services/diary_service.dart index bb14e8cf..58a4005c 100644 --- a/lib/features/diary/services/diary_service.dart +++ b/lib/features/diary/services/diary_service.dart @@ -88,7 +88,7 @@ abstract class DiaryService { }); @POST('/api/diary/product_nutritional_values/sendToModeration') - Future sendProductToModeration({ + Future sendProductToModeration({ @Body() required Map data, }); } diff --git a/lib/features/diary/services/diary_service.g.dart b/lib/features/diary/services/diary_service.g.dart index 13951947..19253e5c 100644 --- a/lib/features/diary/services/diary_service.g.dart +++ b/lib/features/diary/services/diary_service.g.dart @@ -387,14 +387,14 @@ class _DiaryService implements DiaryService { } @override - Future sendProductToModeration( + Future sendProductToModeration( {required Map data}) async { final _extra = {}; final queryParameters = {}; final _headers = {}; final _data = {}; _data.addAll(data); - final _options = _setStreamType(Options( + final _options = _setStreamType(Options( method: 'POST', headers: _headers, extra: _extra, @@ -410,15 +410,7 @@ class _DiaryService implements DiaryService { _dio.options.baseUrl, baseUrl, ))); - final _result = await _dio.fetch>(_options); - late GlossaryModerationModel _value; - try { - _value = GlossaryModerationModel.fromJson(_result.data!); - } on Object catch (e, s) { - errorLogger?.logError(e, s, _options); - rethrow; - } - return _value; + await _dio.fetch(_options); } RequestOptions _setStreamType(RequestOptions requestOptions) { From 9ba0e68e79dfc8eb043f5febf2f6a96c44907477 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Dec 2024 11:17:07 +0300 Subject: [PATCH 04/10] fix: analyzer --- lib/features/diary/repositories/diary_repository.dart | 1 - lib/features/diary/services/diary_service.dart | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/features/diary/repositories/diary_repository.dart b/lib/features/diary/repositories/diary_repository.dart index 0f4f0884..6839722a 100644 --- a/lib/features/diary/repositories/diary_repository.dart +++ b/lib/features/diary/repositories/diary_repository.dart @@ -4,7 +4,6 @@ import 'package:eatvio_app/features/diary/models/finish_diary_day_model.dart'; import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:eatvio_app/features/diary/models/product_moderation_model.dart'; import 'package:eatvio_app/features/diary/services/diary_service.dart'; -import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; class DiaryRepository { final DiaryService diaryService; diff --git a/lib/features/diary/services/diary_service.dart b/lib/features/diary/services/diary_service.dart index 58a4005c..e484ee08 100644 --- a/lib/features/diary/services/diary_service.dart +++ b/lib/features/diary/services/diary_service.dart @@ -3,7 +3,6 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; import 'package:eatvio_app/features/diary/models/finish_diary_day_model.dart'; import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; -import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; import 'package:retrofit/retrofit.dart'; part 'diary_service.g.dart'; From f073a7b92126164b80d0f24f71db0193c8590bda Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Dec 2024 16:26:48 +0300 Subject: [PATCH 05/10] feat: fontSize in blog post --- .../widgets/blog_post_widget.dart | 4 ++ pubspec.yaml | 11 +++--- test/auth_test.dart | 37 ------------------- 3 files changed, 10 insertions(+), 42 deletions(-) delete mode 100644 test/auth_test.dart diff --git a/lib/features/feed/presentation/widgets/blog_post_widget.dart b/lib/features/feed/presentation/widgets/blog_post_widget.dart index 3c775084..5c1f021e 100644 --- a/lib/features/feed/presentation/widgets/blog_post_widget.dart +++ b/lib/features/feed/presentation/widgets/blog_post_widget.dart @@ -75,6 +75,7 @@ class _BlogPostWidgetState extends State { height: 1, color: Colors.black87, fontWeight: FontWeight.w500, + fontSize: 16, ), ), const SizedBox(height: 4), @@ -83,6 +84,7 @@ class _BlogPostWidgetState extends State { style: TextStyle( height: 1, color: Colors.black45, + fontSize: 14, ), ), ], @@ -102,6 +104,7 @@ class _BlogPostWidgetState extends State { child: Text( state.feedBlogPostList[widget.index].title, style: TextStyle( + fontSize: 18, fontWeight: FontWeight.w600, color: Colors.black87, ), @@ -117,6 +120,7 @@ class _BlogPostWidgetState extends State { : state.feedBlogPostList[widget.index].description, style: { "*": Style( + fontSize: FontSize(16), color: Colors.black87, ), }, diff --git a/pubspec.yaml b/pubspec.yaml index 3274a97a..b9f4611f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: flutter_secure_storage: ^9.2.2 flutter_bloc: ^8.1.6 cached_network_image: ^3.4.1 - flutter_svg: ^2.0.14 - equatable: ^2.0.5 + flutter_svg: ^2.0.16 + equatable: ^2.0.7 freezed_annotation: ^2.4.4 json_annotation: ^4.9.0 validators: ^3.0.0 @@ -26,7 +26,7 @@ dependencies: flutter_form_builder: ^9.5.0 image_picker: ^1.1.2 flutter_typeahead: ^5.2.0 - go_router: ^14.6.0 + go_router: ^14.6.2 keyboard_dismisser: ^3.0.0 retrofit: ^4.4.1 get_it: ^8.0.2 @@ -39,8 +39,8 @@ dependencies: badges: ^3.1.2 google_fonts: ^6.2.1 location: ^7.0.1 - syncfusion_flutter_charts: ^27.2.2 - syncfusion_flutter_gauges: ^27.2.2 + syncfusion_flutter_charts: ^27.2.5 + syncfusion_flutter_gauges: ^27.2.5 table_calendar: ^3.1.2 flutter_keyboard_visibility: ^6.0.0 share_plus: ^10.1.2 @@ -65,6 +65,7 @@ dev_dependencies: freezed: ^2.5.7 json_serializable: ^6.9.0 retrofit_generator: ^9.1.5 + mockito: ^5.4.4 flutter_test: sdk: flutter diff --git a/test/auth_test.dart b/test/auth_test.dart deleted file mode 100644 index 626a1ce1..00000000 --- a/test/auth_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:eatvio_app/features/auth/auth_screen/auth_screen.dart'; -import 'package:eatvio_app/features/auth/auth_screen/bloc/auth_bloc.dart'; -import 'package:eatvio_app/features/auth/auth_screen/models/auth_model.dart'; -import 'package:eatvio_app/generated/l10n.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:flutter_test/flutter_test.dart'; - - -void main() { - group('AuthScreen', () { - testWidgets('renders AuthScreen with initial state', (WidgetTester tester) async { - final authBloc = AuthBloc(AuthState(authModelObj: AuthModel())); - - await tester.pumpWidget( - MaterialApp( - localizationsDelegates: const [ - S.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: S.delegate.supportedLocales, - home: BlocProvider( - create: (context) => authBloc, - child: Builder( - builder: (context) { - return AuthScreen(); - }, - ), - ), - ), - ); - }); - }); -} From 25ea4eccadbc2060094d00e3c45da9f3bf99e941 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Dec 2024 17:24:10 +0300 Subject: [PATCH 06/10] feat: test profile model --- test/profile_service_test.dart | 33 +++ test/profile_service_test.mocks.dart | 414 +++++++++++++++++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 test/profile_service_test.dart create mode 100644 test/profile_service_test.mocks.dart diff --git a/test/profile_service_test.dart b/test/profile_service_test.dart new file mode 100644 index 00000000..5df6d580 --- /dev/null +++ b/test/profile_service_test.dart @@ -0,0 +1,33 @@ +import 'package:eatvio_app/features/profile/models/profile_model.dart'; +import 'package:eatvio_app/features/profile/services/profile_service.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'profile_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('fetchProfile', () { + final mockProfileService = MockProfileService(); + + test('getMyProfile', () async { + when(mockProfileService.getMyProfile()).thenAnswer( + (_) async => ProfileModel( + id: 0, + name: 'Alexander Avanesyan', + email: 'mso7nueh@mail.ru', + isPublicProfile: true, + isEntitySubscribedByMe: false, + slug: 'slug', + profilePhotoUrl: '', + role: 'user', + badges: [], + subscriptions: [], + subscribers: [], + ), + ); + expect(await mockProfileService.getMyProfile(), isA()); + }); + }); +} diff --git a/test/profile_service_test.mocks.dart b/test/profile_service_test.mocks.dart new file mode 100644 index 00000000..2361099d --- /dev/null +++ b/test/profile_service_test.mocks.dart @@ -0,0 +1,414 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in eatvio_app/test/profile_service_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i5; +import 'dart:io' as _i9; + +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart' + as _i6; +import 'package:eatvio_app/features/profile/models/circumference_model.dart' + as _i8; +import 'package:eatvio_app/features/profile/models/profile_model.dart' as _i2; +import 'package:eatvio_app/features/profile/models/sub_model.dart' as _i3; +import 'package:eatvio_app/features/profile/models/weight_model.dart' as _i7; +import 'package:eatvio_app/features/profile/services/profile_service.dart' + as _i4; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeProfileModel_0 extends _i1.SmartFake implements _i2.ProfileModel { + _FakeProfileModel_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeProfileDetailsModel_1 extends _i1.SmartFake + implements _i2.ProfileDetailsModel { + _FakeProfileDetailsModel_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSubPaginationModel_2 extends _i1.SmartFake + implements _i3.SubPaginationModel { + _FakeSubPaginationModel_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [ProfileService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockProfileService extends _i1.Mock implements _i4.ProfileService { + @override + _i5.Future<_i2.ProfileModel> getProfileBySlug({required String? slug}) => + (super.noSuchMethod( + Invocation.method( + #getProfileBySlug, + [], + {#slug: slug}, + ), + returnValue: _i5.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getProfileBySlug, + [], + {#slug: slug}, + ), + )), + returnValueForMissingStub: + _i5.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getProfileBySlug, + [], + {#slug: slug}, + ), + )), + ) as _i5.Future<_i2.ProfileModel>); + + @override + _i5.Future<_i2.ProfileModel> getMyProfile() => (super.noSuchMethod( + Invocation.method( + #getMyProfile, + [], + ), + returnValue: _i5.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getMyProfile, + [], + ), + )), + returnValueForMissingStub: + _i5.Future<_i2.ProfileModel>.value(_FakeProfileModel_0( + this, + Invocation.method( + #getMyProfile, + [], + ), + )), + ) as _i5.Future<_i2.ProfileModel>); + + @override + _i5.Future<_i2.ProfileDetailsModel> getMyProfileDetails() => + (super.noSuchMethod( + Invocation.method( + #getMyProfileDetails, + [], + ), + returnValue: _i5.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getMyProfileDetails, + [], + ), + )), + returnValueForMissingStub: _i5.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getMyProfileDetails, + [], + ), + )), + ) as _i5.Future<_i2.ProfileDetailsModel>); + + @override + _i5.Future<_i2.ProfileDetailsModel> getProfileDetailsBySlug( + {required String? slug}) => + (super.noSuchMethod( + Invocation.method( + #getProfileDetailsBySlug, + [], + {#slug: slug}, + ), + returnValue: _i5.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getProfileDetailsBySlug, + [], + {#slug: slug}, + ), + )), + returnValueForMissingStub: _i5.Future<_i2.ProfileDetailsModel>.value( + _FakeProfileDetailsModel_1( + this, + Invocation.method( + #getProfileDetailsBySlug, + [], + {#slug: slug}, + ), + )), + ) as _i5.Future<_i2.ProfileDetailsModel>); + + @override + _i5.Future addCircumference({ + required int? chestCircumference, + required int? waistCircumference, + required int? hipCircumference, + }) => + (super.noSuchMethod( + Invocation.method( + #addCircumference, + [], + { + #chestCircumference: chestCircumference, + #waistCircumference: waistCircumference, + #hipCircumference: hipCircumference, + }, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + + @override + _i5.Future addWeight({required double? weight}) => (super.noSuchMethod( + Invocation.method( + #addWeight, + [], + {#weight: weight}, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + + @override + _i5.Future> getBlogPostByAuthorSlug( + {required String? slug}) => + (super.noSuchMethod( + Invocation.method( + #getBlogPostByAuthorSlug, + [], + {#slug: slug}, + ), + returnValue: _i5.Future>.value( + <_i6.FeedBlogPostModel>[]), + returnValueForMissingStub: + _i5.Future>.value( + <_i6.FeedBlogPostModel>[]), + ) as _i5.Future>); + + @override + _i5.Future> getWeight({required String? period}) => + (super.noSuchMethod( + Invocation.method( + #getWeight, + [], + {#period: period}, + ), + returnValue: + _i5.Future>.value(<_i7.WeightModel>[]), + returnValueForMissingStub: + _i5.Future>.value(<_i7.WeightModel>[]), + ) as _i5.Future>); + + @override + _i5.Future> getWeightBySlug({ + required String? period, + required String? slug, + }) => + (super.noSuchMethod( + Invocation.method( + #getWeightBySlug, + [], + { + #period: period, + #slug: slug, + }, + ), + returnValue: + _i5.Future>.value(<_i7.WeightModel>[]), + returnValueForMissingStub: + _i5.Future>.value(<_i7.WeightModel>[]), + ) as _i5.Future>); + + @override + _i5.Future> getCircumferences( + {required String? period}) => + (super.noSuchMethod( + Invocation.method( + #getCircumferences, + [], + {#period: period}, + ), + returnValue: _i5.Future>.value( + <_i8.CircumferenceModel>[]), + returnValueForMissingStub: + _i5.Future>.value( + <_i8.CircumferenceModel>[]), + ) as _i5.Future>); + + @override + _i5.Future> getCircumferencesBySlug({ + required String? period, + required String? slug, + }) => + (super.noSuchMethod( + Invocation.method( + #getCircumferencesBySlug, + [], + { + #period: period, + #slug: slug, + }, + ), + returnValue: _i5.Future>.value( + <_i8.CircumferenceModel>[]), + returnValueForMissingStub: + _i5.Future>.value( + <_i8.CircumferenceModel>[]), + ) as _i5.Future>); + + @override + _i5.Future<_i3.SubPaginationModel> getSubscribers({ + required String? slug, + String? query, + }) => + (super.noSuchMethod( + Invocation.method( + #getSubscribers, + [], + { + #slug: slug, + #query: query, + }, + ), + returnValue: + _i5.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscribers, + [], + { + #slug: slug, + #query: query, + }, + ), + )), + returnValueForMissingStub: + _i5.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscribers, + [], + { + #slug: slug, + #query: query, + }, + ), + )), + ) as _i5.Future<_i3.SubPaginationModel>); + + @override + _i5.Future<_i3.SubPaginationModel> getSubscriptions({ + required String? slug, + String? query, + }) => + (super.noSuchMethod( + Invocation.method( + #getSubscriptions, + [], + { + #slug: slug, + #query: query, + }, + ), + returnValue: + _i5.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscriptions, + [], + { + #slug: slug, + #query: query, + }, + ), + )), + returnValueForMissingStub: + _i5.Future<_i3.SubPaginationModel>.value(_FakeSubPaginationModel_2( + this, + Invocation.method( + #getSubscriptions, + [], + { + #slug: slug, + #query: query, + }, + ), + )), + ) as _i5.Future<_i3.SubPaginationModel>); + + @override + _i5.Future subscribe({required String? slug}) => (super.noSuchMethod( + Invocation.method( + #subscribe, + [], + {#slug: slug}, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + + @override + _i5.Future unsubscribe({required String? slug}) => (super.noSuchMethod( + Invocation.method( + #unsubscribe, + [], + {#slug: slug}, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + + @override + _i5.Future uploadPhoto({required _i9.File? photo}) => + (super.noSuchMethod( + Invocation.method( + #uploadPhoto, + [], + {#photo: photo}, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + + @override + _i5.Future deletePhoto() => (super.noSuchMethod( + Invocation.method( + #deletePhoto, + [], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); +} From 4ce97c76404838e522db9d3d807bce07b1c0ce20 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Dec 2024 18:33:06 +0300 Subject: [PATCH 07/10] feat: test profile service --- .../services/profile_service_test.dart | 92 +++++++++++++++++++ .../services}/profile_service_test.mocks.dart | 0 test/profile_service_test.dart | 33 ------- 3 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 test/features/profile/services/profile_service_test.dart rename test/{ => features/profile/services}/profile_service_test.mocks.dart (100%) delete mode 100644 test/profile_service_test.dart diff --git a/test/features/profile/services/profile_service_test.dart b/test/features/profile/services/profile_service_test.dart new file mode 100644 index 00000000..4db6526b --- /dev/null +++ b/test/features/profile/services/profile_service_test.dart @@ -0,0 +1,92 @@ +import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart'; +import 'package:eatvio_app/features/profile/models/circumference_model.dart'; +import 'package:eatvio_app/features/profile/models/profile_model.dart'; +import 'package:eatvio_app/features/profile/models/weight_model.dart'; +import 'package:eatvio_app/features/profile/services/profile_service.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'profile_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('profileService', () { + final mockProfileService = MockProfileService(); + test('getMyProfile', () async { + when(mockProfileService.getMyProfile()).thenAnswer( + (_) async => await Future.value( + ProfileModel( + id: 0, + name: 'Alexander Avanesyan', + email: 'mso7nueh@mail.ru', + isPublicProfile: true, + isEntitySubscribedByMe: false, + slug: 'slug', + profilePhotoUrl: '', + role: 'user', + badges: [], + subscriptions: [], + subscribers: [], + ), + ), + ); + expect(await mockProfileService.getMyProfile(), isA()); + }); + + test('getProfileDetailsBySlug', () async { + when(mockProfileService.getProfileDetailsBySlug(slug: 'slug')).thenAnswer( + (_) async => await Future.value( + ProfileDetailsModel( + firstName: 'Alexnader', + lastName: 'Avanesyan', + birthdate: '2024-05-28', + gender: 'male', + country: 'Russia', + city: 'Moscow', + lang: 'Russian', + weight: 84, + height: 178, + chestCircumference: 100, + waistCircumference: 80, + hipCircumference: 90, + bloodPressureUp: 120, + bloodPressureDown: 80, + hasHypo: false, + hasHyper: false, + aboutAlergy: '', + aboutTakingPils: '', + aboutSportHobbies: 'Judo', + favoriteFoods: '', + unfavoriteFoods: '', + additionalInfo: '10 lvl faceit', + isMoodFillable: true, + isBedtimeFillable: true, + activityCoefficient: 2, + ), + ), + ); + expect(await mockProfileService.getProfileDetailsBySlug(slug: 'slug'), isA()); + }); + + test('getBlogPostByAuthorSlug', () async { + when(mockProfileService.getBlogPostByAuthorSlug(slug: '')).thenAnswer( + (_) async => [], + ); + expect(await mockProfileService.getBlogPostByAuthorSlug(slug: 'slug'), isA>()); + }); + + test('getWeight', () async { + when(mockProfileService.getWeight(period: '')).thenAnswer( + (_) async => [], + ); + expect(await mockProfileService.getWeight(period: ''), isA>()); + }); + + test('getCircumferences', () async { + when(mockProfileService.getCircumferences(period: '')).thenAnswer( + (_) async => [], + ); + expect(await mockProfileService.getCircumferences(period: ''), isA>()); + }); + }); +} diff --git a/test/profile_service_test.mocks.dart b/test/features/profile/services/profile_service_test.mocks.dart similarity index 100% rename from test/profile_service_test.mocks.dart rename to test/features/profile/services/profile_service_test.mocks.dart diff --git a/test/profile_service_test.dart b/test/profile_service_test.dart deleted file mode 100644 index 5df6d580..00000000 --- a/test/profile_service_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:eatvio_app/features/profile/models/profile_model.dart'; -import 'package:eatvio_app/features/profile/services/profile_service.dart'; -import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'profile_service_test.mocks.dart'; - -@GenerateNiceMocks([MockSpec()]) -void main() { - group('fetchProfile', () { - final mockProfileService = MockProfileService(); - - test('getMyProfile', () async { - when(mockProfileService.getMyProfile()).thenAnswer( - (_) async => ProfileModel( - id: 0, - name: 'Alexander Avanesyan', - email: 'mso7nueh@mail.ru', - isPublicProfile: true, - isEntitySubscribedByMe: false, - slug: 'slug', - profilePhotoUrl: '', - role: 'user', - badges: [], - subscriptions: [], - subscribers: [], - ), - ); - expect(await mockProfileService.getMyProfile(), isA()); - }); - }); -} From 95b7f82770e8c60003c3d20f6a73088b9e7e2ed4 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 11 Dec 2024 11:49:16 +0300 Subject: [PATCH 08/10] fix: profile --- android/settings.gradle | 2 +- .../profile/models/profile_model.dart | 2 +- .../profile/models/profile_model.freezed.dart | 25 ++++++++++--------- .../profile/models/profile_model.g.dart | 9 +++---- .../presentation/pages/profile_screen.dart | 2 +- .../services/profile_service_test.mocks.dart | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/android/settings.gradle b/android/settings.gradle index 42a51c65..a9f0eb13 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.2" apply false + id "com.android.application" version "8.7.3" apply false id "org.jetbrains.kotlin.android" version "2.0.21" apply false } diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart index 3e4c1764..9e793a1b 100644 --- a/lib/features/profile/models/profile_model.dart +++ b/lib/features/profile/models/profile_model.dart @@ -43,7 +43,7 @@ class DiplomasAndCertificatesModel with _$DiplomasAndCertificatesModel { class EducationModel with _$EducationModel { const factory EducationModel({ @JsonKey(name: "has_medical_education") int? hasMedicalEducation, - @JsonKey(name: "completed_cources") Map? completedCourses, + @JsonKey(name: "completed_cources") List? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, diff --git a/lib/features/profile/models/profile_model.freezed.dart b/lib/features/profile/models/profile_model.freezed.dart index dc863ee9..a349c3f2 100644 --- a/lib/features/profile/models/profile_model.freezed.dart +++ b/lib/features/profile/models/profile_model.freezed.dart @@ -821,7 +821,7 @@ mixin _$EducationModel { @JsonKey(name: "has_medical_education") int? get hasMedicalEducation => throw _privateConstructorUsedError; @JsonKey(name: "completed_cources") - Map? get completedCourses => + List? get completedCourses => throw _privateConstructorUsedError; @JsonKey(name: "vk_link") String? get vkLink => throw _privateConstructorUsedError; @@ -855,7 +855,7 @@ abstract class $EducationModelCopyWith<$Res> { $Res call( {@JsonKey(name: "has_medical_education") int? hasMedicalEducation, @JsonKey(name: "completed_cources") - Map? completedCourses, + List? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @@ -896,7 +896,7 @@ class _$EducationModelCopyWithImpl<$Res, $Val extends EducationModel> completedCourses: freezed == completedCourses ? _value.completedCourses : completedCourses // ignore: cast_nullable_to_non_nullable - as Map?, + as List?, vkLink: freezed == vkLink ? _value.vkLink : vkLink // ignore: cast_nullable_to_non_nullable @@ -936,7 +936,7 @@ abstract class _$$EducationModelImplCopyWith<$Res> $Res call( {@JsonKey(name: "has_medical_education") int? hasMedicalEducation, @JsonKey(name: "completed_cources") - Map? completedCourses, + List? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @@ -975,7 +975,7 @@ class __$$EducationModelImplCopyWithImpl<$Res> completedCourses: freezed == completedCourses ? _value._completedCourses : completedCourses // ignore: cast_nullable_to_non_nullable - as Map?, + as List?, vkLink: freezed == vkLink ? _value.vkLink : vkLink // ignore: cast_nullable_to_non_nullable @@ -1010,7 +1010,7 @@ class _$EducationModelImpl implements _EducationModel { const _$EducationModelImpl( {@JsonKey(name: "has_medical_education") this.hasMedicalEducation, @JsonKey(name: "completed_cources") - final Map? completedCourses, + final List? completedCourses, @JsonKey(name: "vk_link") this.vkLink, @JsonKey(name: "insta_link") this.instaLink, @JsonKey(name: "fb_link") this.fbLink, @@ -1025,15 +1025,16 @@ class _$EducationModelImpl implements _EducationModel { @override @JsonKey(name: "has_medical_education") final int? hasMedicalEducation; - final Map? _completedCourses; + final List? _completedCourses; @override @JsonKey(name: "completed_cources") - Map? get completedCourses { + List? get completedCourses { final value = _completedCourses; if (value == null) return null; - if (_completedCourses is EqualUnmodifiableMapView) return _completedCourses; + if (_completedCourses is EqualUnmodifiableListView) + return _completedCourses; // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(value); + return EqualUnmodifiableListView(value); } @override @@ -1114,7 +1115,7 @@ abstract class _EducationModel implements EducationModel { const factory _EducationModel( {@JsonKey(name: "has_medical_education") final int? hasMedicalEducation, @JsonKey(name: "completed_cources") - final Map? completedCourses, + final List? completedCourses, @JsonKey(name: "vk_link") final String? vkLink, @JsonKey(name: "insta_link") final String? instaLink, @JsonKey(name: "fb_link") final String? fbLink, @@ -1131,7 +1132,7 @@ abstract class _EducationModel implements EducationModel { int? get hasMedicalEducation; @override @JsonKey(name: "completed_cources") - Map? get completedCourses; + List? get completedCourses; @override @JsonKey(name: "vk_link") String? get vkLink; diff --git a/lib/features/profile/models/profile_model.g.dart b/lib/features/profile/models/profile_model.g.dart index e8925091..75ff5889 100644 --- a/lib/features/profile/models/profile_model.g.dart +++ b/lib/features/profile/models/profile_model.g.dart @@ -83,11 +83,10 @@ Map _$$DiplomasAndCertificatesModelImplToJson( _$EducationModelImpl _$$EducationModelImplFromJson(Map json) => _$EducationModelImpl( hasMedicalEducation: (json['has_medical_education'] as num?)?.toInt(), - completedCourses: - (json['completed_cources'] as Map?)?.map( - (k, e) => MapEntry( - k, CompletedCoursesModel.fromJson(e as Map)), - ), + completedCourses: (json['completed_cources'] as List?) + ?.map( + (e) => CompletedCoursesModel.fromJson(e as Map)) + .toList(), vkLink: json['vk_link'] as String?, instaLink: json['insta_link'] as String?, fbLink: json['fb_link'] as String?, diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 98ad0e81..25a16f98 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -487,7 +487,7 @@ class _ProfileScreenState extends State { child: Column( children: [ if (state.profile.educationResource?.completedCourses != null) - ...state.profile.educationResource!.completedCourses!.values.map((c) => _educationBlock(c.title, c.date)).toList(), + ...state.profile.educationResource!.completedCourses!.map((c) => _educationBlock(c.title, c.date)).toList(), ], ), ), diff --git a/test/features/profile/services/profile_service_test.mocks.dart b/test/features/profile/services/profile_service_test.mocks.dart index 2361099d..bb0c633a 100644 --- a/test/features/profile/services/profile_service_test.mocks.dart +++ b/test/features/profile/services/profile_service_test.mocks.dart @@ -1,5 +1,5 @@ // Mocks generated by Mockito 5.4.4 from annotations -// in eatvio_app/test/profile_service_test.dart. +// in eatvio_app/test/features/profile/services/profile_service_test.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes From 4b2e642b9d61e761fbf1898c30287e171dac42ba Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 11 Dec 2024 13:41:14 +0300 Subject: [PATCH 09/10] fix: comments --- .../presentation/pages/calendar_screen.dart | 114 +++++++++--------- .../presentation/widgets/comments_widget.dart | 2 +- 2 files changed, 61 insertions(+), 55 deletions(-) diff --git a/lib/features/calendar/presentation/pages/calendar_screen.dart b/lib/features/calendar/presentation/pages/calendar_screen.dart index 0457c9bc..393337f1 100644 --- a/lib/features/calendar/presentation/pages/calendar_screen.dart +++ b/lib/features/calendar/presentation/pages/calendar_screen.dart @@ -49,39 +49,43 @@ class CalendarScreen extends StatelessWidget { } Widget _buildCalendar(BuildContext context, CalendarStateLoaded state) { - return Stack(alignment: Alignment.bottomCenter, children: [ - FormBuilder( - child: Scaffold( - appBar: AppBar( - toolbarHeight: 0, - automaticallyImplyLeading: false, - ), - backgroundColor: Colors.white, - resizeToAvoidBottomInset: true, - body: SizedBox( - width: double.maxFinite, - child: Column( - children: [ - Expanded( - child: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.only(bottom: 8), - child: Column( - children: [ - SizedBox(height: 24), - _buildCalendarBody(context, state), - SizedBox(height: 24), - ], + return Stack( + alignment: Alignment.bottomCenter, + children: [ + FormBuilder( + child: Scaffold( + appBar: AppBar( + title: Text( + 'Календарь', + ), + ), + backgroundColor: Colors.white, + resizeToAvoidBottomInset: true, + body: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only(bottom: 8), + child: Column( + children: [ + SizedBox(height: 24), + _buildCalendarBody(context, state), + SizedBox(height: 24), + ], + ), ), ), ), - ), - ], + ], + ), ), ), ), - ), - ],); + ], + ); } _buildCalendarBody(BuildContext context, CalendarStateLoaded state) { @@ -180,44 +184,46 @@ class CalendarScreen extends StatelessWidget { style: theme.textTheme.titleMedium, ), SizedBox(height: 4), - Row(children: [ - Container( - padding: EdgeInsets.all(4.0), // Отступы внутри контейнера - decoration: BoxDecoration( - color: diary['state'] == 'finished' ? Color.fromRGBO(1, 154, 62, 1) : Color.fromRGBO(154, 74, 1, 1), - borderRadius: BorderRadius.circular(24.0), // Закругленные углы - ), - child: Text( - _getStateText(diary['state'] ?? ''), - style: CustomTextStyles.titleSmallBold, // Предполагается, что текст белый - ), - ), - SizedBox(width: 4), - if (diary['state'] == 'started') + Row( + children: [ Container( padding: EdgeInsets.all(4.0), // Отступы внутри контейнера decoration: BoxDecoration( - color: Color.fromRGBO(13, 110, 253, 1), + color: diary['state'] == 'finished' ? Color.fromRGBO(1, 154, 62, 1) : Color.fromRGBO(154, 74, 1, 1), borderRadius: BorderRadius.circular(24.0), // Закругленные углы ), child: Text( - 'Заполнить отчет', + _getStateText(diary['state'] ?? ''), style: CustomTextStyles.titleSmallBold, // Предполагается, что текст белый ), ), - if (diary['state'] == 'finished') - Container( - padding: EdgeInsets.all(4.0), // Отступы внутри контейнера - decoration: BoxDecoration( - color: Color.fromRGBO(13, 110, 253, 1), - borderRadius: BorderRadius.circular(24.0), // Закругленные углы + SizedBox(width: 4), + if (diary['state'] == 'started') + Container( + padding: EdgeInsets.all(4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: Color.fromRGBO(13, 110, 253, 1), + borderRadius: BorderRadius.circular(24.0), // Закругленные углы + ), + child: Text( + 'Заполнить отчет', + style: CustomTextStyles.titleSmallBold, // Предполагается, что текст белый + ), ), - child: Text( - 'Изменить отчет', - style: CustomTextStyles.titleSmallBold, // Предполагается, что текст белый + if (diary['state'] == 'finished') + Container( + padding: EdgeInsets.all(4.0), // Отступы внутри контейнера + decoration: BoxDecoration( + color: Color.fromRGBO(13, 110, 253, 1), + borderRadius: BorderRadius.circular(24.0), // Закругленные углы + ), + child: Text( + 'Изменить отчет', + style: CustomTextStyles.titleSmallBold, // Предполагается, что текст белый + ), ), - ), - ],), + ], + ), ], ), ), diff --git a/lib/features/feed/presentation/widgets/comments_widget.dart b/lib/features/feed/presentation/widgets/comments_widget.dart index fd931541..24205961 100644 --- a/lib/features/feed/presentation/widgets/comments_widget.dart +++ b/lib/features/feed/presentation/widgets/comments_widget.dart @@ -78,7 +78,7 @@ class _CommentsWidgetState extends State { ), SizedBox(height: 4), SizedBox( - width: MediaQuery.of(context).size.width * 0.8, + width: isChild ? MediaQuery.of(context).size.width * 0.72 : MediaQuery.of(context).size.width * 0.8, child: Text( comment.body, style: TextStyle( From 728c362e246a7be67197f4af6fec66da2d77758f Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 11 Dec 2024 14:22:00 +0300 Subject: [PATCH 10/10] fix: profile 2 --- .../profile/models/profile_model.dart | 2 +- .../profile/models/profile_model.freezed.dart | 20 +++++++++---------- .../profile/models/profile_model.g.dart | 6 ++++-- .../presentation/pages/profile_screen.dart | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/features/profile/models/profile_model.dart b/lib/features/profile/models/profile_model.dart index 9e793a1b..b6debe84 100644 --- a/lib/features/profile/models/profile_model.dart +++ b/lib/features/profile/models/profile_model.dart @@ -43,7 +43,7 @@ class DiplomasAndCertificatesModel with _$DiplomasAndCertificatesModel { class EducationModel with _$EducationModel { const factory EducationModel({ @JsonKey(name: "has_medical_education") int? hasMedicalEducation, - @JsonKey(name: "completed_cources") List? completedCourses, + @JsonKey(name: "completed_cources") List>? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, diff --git a/lib/features/profile/models/profile_model.freezed.dart b/lib/features/profile/models/profile_model.freezed.dart index a349c3f2..c46e1027 100644 --- a/lib/features/profile/models/profile_model.freezed.dart +++ b/lib/features/profile/models/profile_model.freezed.dart @@ -821,7 +821,7 @@ mixin _$EducationModel { @JsonKey(name: "has_medical_education") int? get hasMedicalEducation => throw _privateConstructorUsedError; @JsonKey(name: "completed_cources") - List? get completedCourses => + List>? get completedCourses => throw _privateConstructorUsedError; @JsonKey(name: "vk_link") String? get vkLink => throw _privateConstructorUsedError; @@ -855,7 +855,7 @@ abstract class $EducationModelCopyWith<$Res> { $Res call( {@JsonKey(name: "has_medical_education") int? hasMedicalEducation, @JsonKey(name: "completed_cources") - List? completedCourses, + List>? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @@ -896,7 +896,7 @@ class _$EducationModelCopyWithImpl<$Res, $Val extends EducationModel> completedCourses: freezed == completedCourses ? _value.completedCourses : completedCourses // ignore: cast_nullable_to_non_nullable - as List?, + as List>?, vkLink: freezed == vkLink ? _value.vkLink : vkLink // ignore: cast_nullable_to_non_nullable @@ -936,7 +936,7 @@ abstract class _$$EducationModelImplCopyWith<$Res> $Res call( {@JsonKey(name: "has_medical_education") int? hasMedicalEducation, @JsonKey(name: "completed_cources") - List? completedCourses, + List>? completedCourses, @JsonKey(name: "vk_link") String? vkLink, @JsonKey(name: "insta_link") String? instaLink, @JsonKey(name: "fb_link") String? fbLink, @@ -975,7 +975,7 @@ class __$$EducationModelImplCopyWithImpl<$Res> completedCourses: freezed == completedCourses ? _value._completedCourses : completedCourses // ignore: cast_nullable_to_non_nullable - as List?, + as List>?, vkLink: freezed == vkLink ? _value.vkLink : vkLink // ignore: cast_nullable_to_non_nullable @@ -1010,7 +1010,7 @@ class _$EducationModelImpl implements _EducationModel { const _$EducationModelImpl( {@JsonKey(name: "has_medical_education") this.hasMedicalEducation, @JsonKey(name: "completed_cources") - final List? completedCourses, + final List>? completedCourses, @JsonKey(name: "vk_link") this.vkLink, @JsonKey(name: "insta_link") this.instaLink, @JsonKey(name: "fb_link") this.fbLink, @@ -1025,10 +1025,10 @@ class _$EducationModelImpl implements _EducationModel { @override @JsonKey(name: "has_medical_education") final int? hasMedicalEducation; - final List? _completedCourses; + final List>? _completedCourses; @override @JsonKey(name: "completed_cources") - List? get completedCourses { + List>? get completedCourses { final value = _completedCourses; if (value == null) return null; if (_completedCourses is EqualUnmodifiableListView) @@ -1115,7 +1115,7 @@ abstract class _EducationModel implements EducationModel { const factory _EducationModel( {@JsonKey(name: "has_medical_education") final int? hasMedicalEducation, @JsonKey(name: "completed_cources") - final List? completedCourses, + final List>? completedCourses, @JsonKey(name: "vk_link") final String? vkLink, @JsonKey(name: "insta_link") final String? instaLink, @JsonKey(name: "fb_link") final String? fbLink, @@ -1132,7 +1132,7 @@ abstract class _EducationModel implements EducationModel { int? get hasMedicalEducation; @override @JsonKey(name: "completed_cources") - List? get completedCourses; + List>? get completedCourses; @override @JsonKey(name: "vk_link") String? get vkLink; diff --git a/lib/features/profile/models/profile_model.g.dart b/lib/features/profile/models/profile_model.g.dart index 75ff5889..c7d0d444 100644 --- a/lib/features/profile/models/profile_model.g.dart +++ b/lib/features/profile/models/profile_model.g.dart @@ -84,8 +84,10 @@ _$EducationModelImpl _$$EducationModelImplFromJson(Map json) => _$EducationModelImpl( hasMedicalEducation: (json['has_medical_education'] as num?)?.toInt(), completedCourses: (json['completed_cources'] as List?) - ?.map( - (e) => CompletedCoursesModel.fromJson(e as Map)) + ?.map((e) => (e as Map).map( + (k, e) => MapEntry(k, + CompletedCoursesModel.fromJson(e as Map)), + )) .toList(), vkLink: json['vk_link'] as String?, instaLink: json['insta_link'] as String?, diff --git a/lib/features/profile/presentation/pages/profile_screen.dart b/lib/features/profile/presentation/pages/profile_screen.dart index 25a16f98..9c0f18ad 100644 --- a/lib/features/profile/presentation/pages/profile_screen.dart +++ b/lib/features/profile/presentation/pages/profile_screen.dart @@ -487,7 +487,7 @@ class _ProfileScreenState extends State { child: Column( children: [ if (state.profile.educationResource?.completedCourses != null) - ...state.profile.educationResource!.completedCourses!.map((c) => _educationBlock(c.title, c.date)).toList(), + ...state.profile.educationResource!.completedCourses!.map((c) => _educationBlock(c.values.first.title, c.values.first.date)).toList(), ], ), ),