From 6f03d279e9dd7f784d15c649960e79843522590d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 6 Dec 2024 13:46:15 +0300 Subject: [PATCH] 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