From bc0b3829c99eb87cb26a70e1c810ace911262e91 Mon Sep 17 00:00:00 2001 From: Username1548 Date: Wed, 4 Dec 2024 22:03:31 +0700 Subject: [PATCH] added plan pagination and updated plans creation screen --- assets/icons/question_mark.svg | 3 + assets/icons/trash_can.svg | 6 + lib/core/app_router.dart | 2 +- lib/core/locator_service.dart | 10 +- lib/core/widgets/custom_text_form_field.dart | 1 + .../create_diet/models/create_diet_model.dart | 19 +- .../models/create_diet_model.freezed.dart | 24 +- .../presentation/cubit/create_diet_cubit.dart | 41 +- .../presentation/cubit/create_diet_state.dart | 15 +- .../widgets/diet_type_choice_widget.dart | 33 +- .../repositories/create_diet_repository.dart | 16 +- .../services/create_diet_service.dart | 9 +- .../services/create_diet_service.g.dart | 54 +- .../create_plan/models/create_plan_model.dart | 4 +- .../presentation/create_plan_screen.dart | 83 ++- .../presentation/cubit/create_plan_cubit.dart | 39 ++ .../presentation/cubit/create_plan_state.dart | 6 +- .../presentation/widgets/add_item_widget.dart | 72 ++ .../presentation/widgets/option_widget.dart | 318 ++++++++- .../widgets/options_count_button.dart | 4 +- .../widgets/select_exact_option_widget.dart | 68 +- .../{bloc => cubit}/about_diet_cubit.dart | 3 +- .../{bloc => cubit}/about_diet_state.dart | 0 .../about_diet_state.freezed.dart | 0 .../presentation/pages/about_diet_screen.dart | 4 +- .../widgets/start_diet_bottom_sheet.dart | 2 +- .../models/plan_pagination_model.dart | 4 +- .../models/plan_pagination_model.freezed.dart | 0 .../models/plan_pagination_model.g.dart | 0 .../bloc/plans_cubit/plans_cubit.dart | 68 ++ .../bloc/plans_cubit/plans_state.dart | 19 + .../bloc/plans_cubit/plans_state.freezed.dart | 191 ++++++ .../feed/presentation/pages/feed_screen.dart | 55 +- .../presentation/widgets/plan_widget.dart | 2 +- .../feed/repositories/feed_repository.dart | 17 + lib/features/feed/services/feed_service.dart | 17 +- .../feed/services/feed_service.g.dart | 33 + .../bloc/plans_cubit/plans_cubit.dart | 19 - .../bloc/plans_cubit/plans_state.dart | 19 - .../bloc/plans_cubit/plans_state.freezed.dart | 646 ------------------ .../presentation/cubit/about_plan_cubit.dart | 11 + .../presentation/cubit/about_plan_state.dart | 18 + .../cubit/about_plan_state.freezed.dart | 201 ++++++ .../presentation/pages/about_plan_screen.dart | 2 +- .../plans/repositories/plans_repository.dart | 16 - .../plans/services/plans_service.dart | 13 - .../plans/services/plans_service.g.dart | 86 --- lib/generated/intl/messages_en.dart | 22 + lib/generated/l10n.dart | 150 ++++ lib/l10n/intl_en.arb | 18 +- 50 files changed, 1504 insertions(+), 959 deletions(-) create mode 100644 assets/icons/question_mark.svg create mode 100644 assets/icons/trash_can.svg create mode 100644 lib/features/create_plan/presentation/widgets/add_item_widget.dart rename lib/features/diets/presentation/{bloc => cubit}/about_diet_cubit.dart (98%) rename lib/features/diets/presentation/{bloc => cubit}/about_diet_state.dart (100%) rename lib/features/diets/presentation/{bloc => cubit}/about_diet_state.freezed.dart (100%) rename lib/features/{plans => feed}/models/plan_pagination_model.dart (98%) rename lib/features/{plans => feed}/models/plan_pagination_model.freezed.dart (100%) rename lib/features/{plans => feed}/models/plan_pagination_model.g.dart (100%) create mode 100644 lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart create mode 100644 lib/features/feed/presentation/bloc/plans_cubit/plans_state.dart create mode 100644 lib/features/feed/presentation/bloc/plans_cubit/plans_state.freezed.dart delete mode 100644 lib/features/plans/presentation/bloc/plans_cubit/plans_cubit.dart delete mode 100644 lib/features/plans/presentation/bloc/plans_cubit/plans_state.dart delete mode 100644 lib/features/plans/presentation/bloc/plans_cubit/plans_state.freezed.dart create mode 100644 lib/features/plans/presentation/cubit/about_plan_cubit.dart create mode 100644 lib/features/plans/presentation/cubit/about_plan_state.dart create mode 100644 lib/features/plans/presentation/cubit/about_plan_state.freezed.dart delete mode 100644 lib/features/plans/repositories/plans_repository.dart delete mode 100644 lib/features/plans/services/plans_service.dart delete mode 100644 lib/features/plans/services/plans_service.g.dart diff --git a/assets/icons/question_mark.svg b/assets/icons/question_mark.svg new file mode 100644 index 00000000..21fccc12 --- /dev/null +++ b/assets/icons/question_mark.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/trash_can.svg b/assets/icons/trash_can.svg new file mode 100644 index 00000000..02dc5171 --- /dev/null +++ b/assets/icons/trash_can.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/lib/core/app_router.dart b/lib/core/app_router.dart index 1cb3b901..02976f48 100644 --- a/lib/core/app_router.dart +++ b/lib/core/app_router.dart @@ -23,7 +23,7 @@ import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit import 'package:eatvio_app/features/feed/presentation/pages/feed_screen.dart'; import 'package:eatvio_app/features/menu/presentation/pages/menu_screen.dart'; import 'package:eatvio_app/features/notifications/presentation/pages/notifications_screen.dart'; -import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/plans/presentation/pages/about_plan_screen.dart'; import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart'; import 'package:eatvio_app/features/profile/presentation/pages/subs_screen.dart'; diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart index 8d6994f5..2352a5e7 100644 --- a/lib/core/locator_service.dart +++ b/lib/core/locator_service.dart @@ -26,7 +26,7 @@ import 'package:eatvio_app/features/consultant/become_consultant/services/consul import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart'; import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; import 'package:eatvio_app/features/diary/services/diary_service.dart'; -import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_cubit.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart'; @@ -35,9 +35,7 @@ import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; 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/plans/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/feed/presentation/bloc/plans_cubit/plans_cubit.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'; @@ -73,7 +71,7 @@ Future init() async { sl.registerFactory(() => DietsCubit(feedRepository: sl(), dietsRepository: sl())); sl.registerFactory(() => CommentsCubit(feedRepository: sl())); sl.registerFactory(() => ChatSelectCubit(chatRepository: sl())); - sl.registerFactory(() => PlansCubit(plansRepository: sl())); + sl.registerFactory(() => PlansCubit(feedRepository: sl())); sl.registerFactory(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl())); sl.registerFactory(() => RegisterConsultantCubit(consultantRepository: sl())); sl.registerFactory(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl())); @@ -91,7 +89,6 @@ Future init() async { sl.registerLazySingleton(() => CalendarRepository(calendarService: sl())); sl.registerLazySingleton(() => ProfileRepository(profileService: sl())); sl.registerLazySingleton(() => RecipeRepository(recipeService: sl())); - sl.registerLazySingleton(() => PlansRepository(plansService: sl())); sl.registerLazySingleton(() => SettingsRepository(settingsService: sl())); sl.registerLazySingleton(() => ConsultantRepository(consultantService: sl())); sl.registerLazySingleton(() => DiaryRepository(diaryService: sl())); @@ -107,7 +104,6 @@ Future init() async { sl.registerLazySingleton(() => CalendarService(sl())); sl.registerLazySingleton(() => ProfileService(sl())); sl.registerLazySingleton(() => RecipeService(sl())); - sl.registerLazySingleton(() => PlansService(sl())); sl.registerLazySingleton(() => SettingsService(sl())); sl.registerLazySingleton(() => ConsultantService(sl())); sl.registerLazySingleton(() => DiaryService(sl())); diff --git a/lib/core/widgets/custom_text_form_field.dart b/lib/core/widgets/custom_text_form_field.dart index 77e7086a..34e1c7d7 100644 --- a/lib/core/widgets/custom_text_form_field.dart +++ b/lib/core/widgets/custom_text_form_field.dart @@ -79,6 +79,7 @@ class CustomTextFormField extends StatelessWidget { return Align( alignment: alignment ?? Alignment.center, child: TextFormField( + textAlignVertical: textAlignVertical, expands: expands, minLines: minLines, diff --git a/lib/features/create_diet/models/create_diet_model.dart b/lib/features/create_diet/models/create_diet_model.dart index 5a53754b..f089ff92 100644 --- a/lib/features/create_diet/models/create_diet_model.dart +++ b/lib/features/create_diet/models/create_diet_model.dart @@ -1,7 +1,3 @@ -import 'dart:io'; - -import 'package:dio/dio.dart'; -import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -17,21 +13,8 @@ class CreateDietModel with _$CreateDietModel { String? details, String? state, int? duration, - required List type, + required Map type, XFile? image, List>>? dailySchedule, }) = _CreateDietModel; - - Future> toCreationJson() async => { - 'name': name, - 'duration': duration, - 'state': state, - 'type': type, - 'details': details, - 'image': image != null ? await MultipartFile.fromFile((await ImageCompressUtility.compressFile(File(image!.path))).path, filename: image!.name) : null, - }; - - Map toDailyScheduleCreationJson() => { - 'daily_schedule': dailySchedule?.map((element) => element.map((element) => element.map((element) => element.toJson()).toList()).toList()).toList(), - }; } diff --git a/lib/features/create_diet/models/create_diet_model.freezed.dart b/lib/features/create_diet/models/create_diet_model.freezed.dart index 05001e64..199f8e49 100644 --- a/lib/features/create_diet/models/create_diet_model.freezed.dart +++ b/lib/features/create_diet/models/create_diet_model.freezed.dart @@ -20,7 +20,7 @@ mixin _$CreateDietModel { String? get details => throw _privateConstructorUsedError; String? get state => throw _privateConstructorUsedError; int? get duration => throw _privateConstructorUsedError; - List get type => throw _privateConstructorUsedError; + Map get type => throw _privateConstructorUsedError; XFile? get image => throw _privateConstructorUsedError; List>>? get dailySchedule => throw _privateConstructorUsedError; @@ -43,7 +43,7 @@ abstract class $CreateDietModelCopyWith<$Res> { String? details, String? state, int? duration, - List type, + Map type, XFile? image, List>>? dailySchedule}); } @@ -91,7 +91,7 @@ class _$CreateDietModelCopyWithImpl<$Res, $Val extends CreateDietModel> type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable - as List, + as Map, image: freezed == image ? _value.image : image // ignore: cast_nullable_to_non_nullable @@ -117,7 +117,7 @@ abstract class _$$CreateDietModelImplCopyWith<$Res> String? details, String? state, int? duration, - List type, + Map type, XFile? image, List>>? dailySchedule}); } @@ -163,7 +163,7 @@ class __$$CreateDietModelImplCopyWithImpl<$Res> type: null == type ? _value._type : type // ignore: cast_nullable_to_non_nullable - as List, + as Map, image: freezed == image ? _value.image : image // ignore: cast_nullable_to_non_nullable @@ -184,7 +184,7 @@ class _$CreateDietModelImpl extends _CreateDietModel { this.details, this.state, this.duration, - required final List type, + required final Map type, this.image, final List>>? dailySchedule}) : _type = type, @@ -199,12 +199,12 @@ class _$CreateDietModelImpl extends _CreateDietModel { final String? state; @override final int? duration; - final List _type; + final Map _type; @override - List get type { - if (_type is EqualUnmodifiableListView) return _type; + Map get type { + if (_type is EqualUnmodifiableMapView) return _type; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_type); + return EqualUnmodifiableMapView(_type); } @override @@ -267,7 +267,7 @@ abstract class _CreateDietModel extends CreateDietModel { final String? details, final String? state, final int? duration, - required final List type, + required final Map type, final XFile? image, final List>>? dailySchedule}) = _$CreateDietModelImpl; @@ -282,7 +282,7 @@ abstract class _CreateDietModel extends CreateDietModel { @override int? get duration; @override - List get type; + Map get type; @override XFile? get image; @override diff --git a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart index 949241af..88113a6d 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart @@ -1,5 +1,9 @@ import 'dart:convert'; +import 'dart:io'; +import 'package:dio/dio.dart'; import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; +import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart'; import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; @@ -89,7 +93,9 @@ class CreateDietCubit extends Cubit { emit(state.copyWith(dietStateIndex: index, dietData: state.dietData.copyWith(state: _dietStateValues[index]))); } - void setDietType(List type) { + void setDietType({required String key, required bool value}) { + final type = Map.from(state.dietData.type); + type[key] = value; emit(state.copyWith(dietData: state.dietData.copyWith(type: type))); } @@ -248,19 +254,24 @@ class CreateDietCubit extends Cubit { } Future publishDiet() async { - // бек судя по всему с багом - // try { - // final model = await state.dietData.toCreationJson(); - // model.remove('image'); - // final dailySchedule = await state.dietData.toDailyScheduleCreationJson(); - // final dio = sl(); - // final qwe = await dio.post('/api/diets/create', data: model); - // // final diet = await createDietRepository.createDiet(model: model); - // // final qwe2 = createDietRepository.createDietDailySchedule(id: diet.id, model: dailySchedule); - // } catch (e, stackTrace) { - // print(e); - // print('---------------------------------'); - // print(stackTrace); - // } + try { + // final types = jsonEncode(state.dietData.type); + // if (state.dietData.image == null) { + // return; + // } + // final image = await ImageCompressUtility.compressFile(File(state.dietData.image!.path)); + // final diet = await createDietRepository.createDiet( + // name: state.dietData.name, + // duration: state.dietData.duration, + // state: state.dietData.state, + // image: image, + // type: types, + // details: state.dietData.details, + // ); + } catch (e, stackTrace) { + print(e); + print('---------------------------------'); + print(stackTrace); + } } } diff --git a/lib/features/create_diet/presentation/cubit/create_diet_state.dart b/lib/features/create_diet/presentation/cubit/create_diet_state.dart index df571110..0c554d28 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_state.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_state.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/features/create_diet/models/create_diet_model.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -6,14 +7,20 @@ part 'create_diet_state.freezed.dart'; @freezed class CreateDietState with _$CreateDietState { - const factory CreateDietState({ + const factory CreateDietState({ required bool isLoading, required String? errorMessage, - required CreateDietModel dietData, - List>? copiedDay, + required CreateDietModel dietData, + List>? copiedDay, int? durationIndex, int? dietStateIndex, }) = _CreateDietState; - factory CreateDietState.initial() => CreateDietState(isLoading: false, errorMessage: null, dietData: CreateDietModel(type: [false, false, false, false])); + factory CreateDietState.initial() => CreateDietState( + isLoading: false, + errorMessage: null, + dietData: CreateDietModel( + type: Map.fromIterable(typeValues, value: (element) => false), + ), + ); } diff --git a/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart b/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart index fd324885..fec8d5a2 100644 --- a/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart +++ b/lib/features/create_diet/presentation/widgets/diet_type_choice_widget.dart @@ -1,3 +1,4 @@ +import 'package:eatvio_app/core/const.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart'; @@ -18,15 +19,11 @@ class _DietTypeChoiceWidgetState extends State { final List<(String, String)> choiceContent = []; @override void didChangeDependencies() { + // const List typeValues = ['veg', 'light', 'carb', 'meat']; super.didChangeDependencies(); final s = S.of(context); if (choiceContent.isEmpty) { - choiceContent.add( - ( - 'assets/icons/meat2.svg', - s.meat, - ), - ); + choiceContent.add( ( 'assets/icons/broccoli.svg', @@ -35,14 +32,20 @@ class _DietTypeChoiceWidgetState extends State { ); choiceContent.add( ( - 'assets/icons/bread.svg', - s.carb_type, + 'assets/icons/cocktail.svg', + s.light_type, ), ); choiceContent.add( ( - 'assets/icons/cocktail.svg', - s.light_type, + 'assets/icons/bread.svg', + s.carb_type, + ), + ); + choiceContent.add( + ( + 'assets/icons/meat2.svg', + s.meat, ), ); } @@ -58,18 +61,18 @@ class _DietTypeChoiceWidgetState extends State { return Expanded( child: GestureDetector( onTap: () { - final dietTypes = [...state.dietData.type]; - dietTypes[index] = !dietTypes[index]; - context.read().setDietType(dietTypes); + final key = typeValues[index]; + final value = !(state.dietData.type[key] ?? true); + context.read().setDietType(key: key, value: value); }, child: Container( margin: EdgeInsets.only(right: index == 3 ? 0 : 4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), - color: state.dietData.type[index] ? appTheme.cardBackground : appTheme.whiteA700, + color: state.dietData.type[typeValues[index]] == true ? appTheme.cardBackground : appTheme.whiteA700, border: Border.all( width: 1, - color: state.dietData.type[index] ? appTheme.blueA400 : appTheme.lightGray00, + color: state.dietData.type[typeValues[index]] == true ? appTheme.blueA400 : appTheme.lightGray00, ), ), height: 80, diff --git a/lib/features/create_diet/repositories/create_diet_repository.dart b/lib/features/create_diet/repositories/create_diet_repository.dart index 4400d1c8..7d5a99db 100644 --- a/lib/features/create_diet/repositories/create_diet_repository.dart +++ b/lib/features/create_diet/repositories/create_diet_repository.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; @@ -6,10 +8,20 @@ class CreateDietRepository { CreateDietRepository({required this.createDietService}); Future createDiet({ - required Map model, + String? name, + int? duration, + String? state, + String? type, + String? details, + File? image, }) { return createDietService.createDiet( - model: model, + name: name, + duration: duration, + state: state, + type: type, + details: details, + image: image, ); } diff --git a/lib/features/create_diet/services/create_diet_service.dart b/lib/features/create_diet/services/create_diet_service.dart index 03ab2a78..ab48669a 100644 --- a/lib/features/create_diet/services/create_diet_service.dart +++ b/lib/features/create_diet/services/create_diet_service.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:retrofit/retrofit.dart'; @@ -11,7 +13,12 @@ abstract class CreateDietService { @POST('/api/diets/create') @MultiPart() Future createDiet({ - @Body() required Map model, + @Part(name: 'name') String? name, + @Part(name: 'duration') int? duration, + @Part(name: 'state') String? state, + @Part(name: 'type') String? type, + @Part(name: 'details') String? details, + @Part(name: 'image') File? image, }); @POST('/api/diets/create/{id}/daily_schedule') diff --git a/lib/features/create_diet/services/create_diet_service.g.dart b/lib/features/create_diet/services/create_diet_service.g.dart index 41ed51e7..23d1c97c 100644 --- a/lib/features/create_diet/services/create_diet_service.g.dart +++ b/lib/features/create_diet/services/create_diet_service.g.dart @@ -22,12 +22,60 @@ class _CreateDietService implements CreateDietService { final ParseErrorLogger? errorLogger; @override - Future createDiet({required Map model}) async { + Future createDiet({ + String? name, + int? duration, + String? state, + String? type, + String? details, + File? image, + }) async { final _extra = {}; final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); final _headers = {}; - final _data = {}; - _data.addAll(model); + final _data = FormData(); + if (name != null) { + _data.fields.add(MapEntry( + 'name', + name, + )); + } + if (duration != null) { + _data.fields.add(MapEntry( + 'duration', + duration.toString(), + )); + } + if (state != null) { + _data.fields.add(MapEntry( + 'state', + state, + )); + } + if (type != null) { + _data.fields.add(MapEntry( + 'type', + type, + )); + } + if (details != null) { + _data.fields.add(MapEntry( + 'details', + details, + )); + } + if (image != null) { + if (image != null) { + _data.files.add(MapEntry( + 'image', + MultipartFile.fromFileSync( + image.path, + filename: image.path.split(Platform.pathSeparator).last, + ), + )); + } + } final _options = _setStreamType(Options( method: 'POST', headers: _headers, diff --git a/lib/features/create_plan/models/create_plan_model.dart b/lib/features/create_plan/models/create_plan_model.dart index c4d3ed21..37e4b883 100644 --- a/lib/features/create_plan/models/create_plan_model.dart +++ b/lib/features/create_plan/models/create_plan_model.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; -import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -16,7 +16,7 @@ class CreatePlanModel with _$CreatePlanModel { String? name, String? details, String? state, - int? duration, + int? duration, required List type, XFile? image, required List options, diff --git a/lib/features/create_plan/presentation/create_plan_screen.dart b/lib/features/create_plan/presentation/create_plan_screen.dart index 5eda713c..a530add4 100644 --- a/lib/features/create_plan/presentation/create_plan_screen.dart +++ b/lib/features/create_plan/presentation/create_plan_screen.dart @@ -1,9 +1,12 @@ import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; import 'package:eatvio_app/core/widgets/main_background_bouble.dart'; import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart'; +import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart'; +import 'package:eatvio_app/features/create_plan/presentation/widgets/option_widget.dart'; import 'package:eatvio_app/features/create_plan/presentation/widgets/options_count_button.dart'; import 'package:eatvio_app/features/create_plan/presentation/widgets/plan_duration_drop_down_widget.dart'; import 'package:eatvio_app/features/create_plan/presentation/widgets/plan_image_picker_widget.dart'; @@ -118,7 +121,7 @@ class CreatePlanScreenContent extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 16), child: Text( - s.plan_desc, + s.services, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, softWrap: true, @@ -127,16 +130,80 @@ class CreatePlanScreenContent extends StatelessWidget { ), SizedBox(height: 8), OptionsCountButton(), - SizedBox(height: 200), + SizedBox(height: 20), + BlocBuilder( + buildWhen: (previous, current) => previous.selectedOptionIndex != current.selectedOptionIndex, + builder: (context, state) { + if (state.selectedOptionIndex == null) { + return SizedBox.shrink(); + } + return Padding( + padding: const EdgeInsets.only(left: 16), + child: Text( + '${s.option} ${(state.selectedOptionIndex ?? 0) + 1}', + style: TextStyles.textLSemibold.copyWith(color: appTheme.blueGray400), + ), + ); + }, + ), + SizedBox(height: 8), + OptionWidget(), + SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + children: [ + CustomOutlinedButton( + onPressed: () {}, + text: s.to_draft, + height: 52, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray), + buttonStyle: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder), + ), + ), + SizedBox(height: 12), + CustomOutlinedButton( + onPressed: () async {}, + text: s.preview, + height: 52, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.gray), + buttonStyle: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.dottedBorder), + ), + ), + SizedBox(height: 12), + CustomOutlinedButton( + onPressed: () {}, + text: s.publish, + height: 52, + buttonTextStyle: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700), + buttonStyle: ButtonStyle( + side: WidgetStatePropertyAll(BorderSide.none), + backgroundColor: WidgetStatePropertyAll(appTheme.blueA400), + ), + ), + ], + ), + ), ], ), ), - Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: Align( - alignment: Alignment.bottomCenter, - child: SelectExactOptionWidget(), - ), + BlocBuilder( + builder: (context, state) { + if (state.selectedOptionIndex == null) { + return SizedBox.shrink(); + } + return Padding( + padding: const EdgeInsets.only(bottom: 24.0), + child: Align( + alignment: Alignment.bottomCenter, + child: SelectExactOptionWidget(), + ), + ); + }, ), ], ), diff --git a/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart b/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart index 19f782dd..8d406a71 100644 --- a/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart +++ b/lib/features/create_plan/presentation/cubit/create_plan_cubit.dart @@ -14,6 +14,45 @@ class CreatePlanCubit extends Cubit { emit(state.copyWith(planData: state.planData.copyWith(name: name))); } + void setOptionTitle(String title) { + final options = [...state.planData.options]; + options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(short: title); + emit(state.copyWith(planData: state.planData.copyWith(options: options))); + } + + void setPrice(double price){ + final selectedOptionIndex = state.selectedOptionIndex ?? 0; + final options = [...state.planData.options]; + options[selectedOptionIndex] = options[selectedOptionIndex].copyWith(price: price); + emit(state.copyWith(planData: state.planData.copyWith(options: options))); + } + + void setOptionDescription(String description) { + final options = [...state.planData.options]; + options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(description: description); + emit(state.copyWith(planData: state.planData.copyWith(options: options))); + } + + void setOptionContent(String content, index) { + final options = [...state.planData.options]; + final items = [...options[state.selectedOptionIndex ?? 0].items]; + if (items.length <= index) { + items.add(content); + }else { + items[index] = content; + } + options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(items: items); + emit(state.copyWith(planData: state.planData.copyWith(options: options))); + } + + void removeOptionContentItem(int index) { + final options = [...state.planData.options]; + final updatedItems = [...options[state.selectedOptionIndex ?? 0].items]; + updatedItems.removeAt(index); + options[state.selectedOptionIndex ?? 0] = options[state.selectedOptionIndex ?? 0].copyWith(items: updatedItems); + emit(state.copyWith(planData: state.planData.copyWith(options: options))); + } + void setDuration(int index) { emit( state.copyWith( diff --git a/lib/features/create_plan/presentation/cubit/create_plan_state.dart b/lib/features/create_plan/presentation/cubit/create_plan_state.dart index fc8edf18..684df959 100644 --- a/lib/features/create_plan/presentation/cubit/create_plan_state.dart +++ b/lib/features/create_plan/presentation/cubit/create_plan_state.dart @@ -1,5 +1,5 @@ import 'package:eatvio_app/features/create_plan/models/create_plan_model.dart'; -import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'create_plan_state.freezed.dart'; @@ -9,7 +9,7 @@ class CreatePlanState with _$CreatePlanState { const factory CreatePlanState({ required bool isLoading, required String? errorMessage, - required CreatePlanModel planData, + required CreatePlanModel planData, int? durationIndex, int? selectedOptionIndex, }) = _CreatePlanState; @@ -20,6 +20,6 @@ class CreatePlanState with _$CreatePlanState { planData: CreatePlanModel( type: [false, false, false, false], options: [PacketOptions.empty(), PacketOptions.empty(), PacketOptions.empty()], - ), + ), ); } diff --git a/lib/features/create_plan/presentation/widgets/add_item_widget.dart b/lib/features/create_plan/presentation/widgets/add_item_widget.dart new file mode 100644 index 00000000..e57c916e --- /dev/null +++ b/lib/features/create_plan/presentation/widgets/add_item_widget.dart @@ -0,0 +1,72 @@ +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; +import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class AddItemWidget extends StatefulWidget { + AddItemWidget({ + super.key, + required this.canBeDeleted, + required this.enableHint, + required this.index, + required this.items, + }); + final int index; + final bool canBeDeleted; + final bool enableHint; + final List items; + @override + State createState() => _AddItemWidgetState(); +} + +class _AddItemWidgetState extends State { + final controller = TextEditingController(); + + @override + void didUpdateWidget(oldWidget) { + super.didUpdateWidget(oldWidget); + if (!widget.canBeDeleted && widget.items.length >= widget.index) { + controller.clear(); + } + } + + @override + Widget build(BuildContext context) { + final s = S.of(context); + if (widget.items.length > widget.index && controller.text != widget.items[widget.index]) { + controller.text = widget.items[widget.index]; + } + return Row( + children: [ + Expanded( + child: CustomTextFormField( + controller: controller, + hintText: widget.enableHint ? s.option_content_hint_text : null, + onChanged: (value) { + context.read().setOptionContent(value, widget.index); + }, + ), + ), + if (widget.canBeDeleted) ...[ + SizedBox(width: 8), + GestureDetector( + onTap: () { + context.read().removeOptionContentItem(widget.index); + }, + child: Container( + padding: EdgeInsets.all(14), + decoration: BoxDecoration( + color: appTheme.lightGray0, + borderRadius: BorderRadius.circular(20), + ), + child: SvgPicture.asset('assets/icons/trash_can.svg', width: 20, height: 24), + ), + ), + ], + ], + ); + } +} diff --git a/lib/features/create_plan/presentation/widgets/option_widget.dart b/lib/features/create_plan/presentation/widgets/option_widget.dart index 8224e871..bda55262 100644 --- a/lib/features/create_plan/presentation/widgets/option_widget.dart +++ b/lib/features/create_plan/presentation/widgets/option_widget.dart @@ -1,10 +1,320 @@ +import 'package:eatvio_app/core/theme/custom_text_style.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_divider.dart'; +import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; +import 'package:eatvio_app/core/widgets/main_background_bouble.dart'; +import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart'; +import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart'; +import 'package:eatvio_app/features/create_plan/presentation/widgets/add_item_widget.dart'; +import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_svg/flutter_svg.dart'; -class OptionWidget extends StatelessWidget { - const OptionWidget({super.key}); +class OptionWidget extends StatefulWidget { + OptionWidget({super.key}); + + @override + State createState() => _OptionWidgetState(); +} + +class _OptionWidgetState extends State { + final customerPriceController = TextEditingController()..text = '1200₽'; + final creatorPriceController = TextEditingController()..text = '1000₽'; + final optionTitleController = TextEditingController(); + final optionDescriptionController = TextEditingController(); + bool firstExplanationVisible = false; + bool isChecked = false; + bool secondExplanationVisible = false; + @override + void initState() { + super.initState(); + customerPriceController.addListener(() { + if (!customerPriceController.text.endsWith('₽')) { + final textWithoutCurrency = customerPriceController.text.replaceAll('₽', ''); + customerPriceController.value = TextEditingValue( + text: "$textWithoutCurrency₽", + selection: TextSelection.collapsed(offset: textWithoutCurrency.length), + ); + } + final price = double.tryParse(customerPriceController.text.replaceAll('₽', '')); + if (price != null && price < 1200) { + customerPriceController.value = TextEditingValue( + text: "1200₽", + selection: TextSelection.collapsed(offset: 4), + ); + } + }); + + creatorPriceController.addListener(() { + if (!creatorPriceController.text.endsWith('₽')) { + final textWithoutCurrency = creatorPriceController.text.replaceAll('₽', ''); + creatorPriceController.value = TextEditingValue( + text: "$textWithoutCurrency₽", + selection: TextSelection.collapsed(offset: textWithoutCurrency.length), + ); + } + final price = double.tryParse(creatorPriceController.text.replaceAll('₽', '')); + if (price != null && price < 1000) { + creatorPriceController.value = TextEditingValue( + text: "1000₽", + selection: TextSelection.collapsed(offset: 4), + ); + } + }); + } @override Widget build(BuildContext context) { - return Placeholder(); + final s = S.of(context); + return BlocBuilder( + builder: (context, state) { + final optionNameHintText = switch (state.selectedOptionIndex ?? 1) { + 0 => s.economy, + 2 => s.comfort, + _ => s.standard, + }; + final selectedOptionIndex = state.selectedOptionIndex ?? 0; + + optionTitleController.text = state.planData.options[selectedOptionIndex].short; + optionDescriptionController.text = state.planData.options[selectedOptionIndex].description; + return MainBackgroundBouble( + padding: EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + s.option_title, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyles.textSMedium.copyWith(color: appTheme.black), + ), + SizedBox(height: 4), + CustomTextFormField( + hintText: optionNameHintText, + controller: optionTitleController, + onChanged: (value) { + context.read().setOptionTitle(value); + }, + maxLength: 150, + ), + SizedBox(height: 12), + Text( + s.option_desc, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyles.textSMedium.copyWith(color: appTheme.black), + ), + SizedBox(height: 4), + SizedBox( + height: 120, + child: CustomTextFormField( + controller: optionDescriptionController, + textAlignVertical: TextAlignVertical.top, + maxLength: 1000, + minLines: null, + maxLines: null, + expands: true, + hintText: s.option_desc_hint_text, + onChanged: (value) { + context.read().setOptionDescription(value); + }, + ), + ), + SizedBox(height: 12), + Row( + children: [ + Text( + s.you_will_get, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyles.textSMedium.copyWith(color: appTheme.black), + ), + SizedBox(width: 4), + _PriceExplanationWidget(), + ], + ), + SizedBox(height: 4), + CustomTextFormField( + controller: creatorPriceController, + onChanged: (value) { + double? price = double.tryParse(value.replaceAll('₽', '')); + if (price != null) { + price = price * 1.2; + customerPriceController.text = price.toStringAsFixed(2); + context.read().setPrice(price); + } + }, + maxLength: 20, + ), + SizedBox(height: 12), + Row( + children: [ + Text( + s.customer_price, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyles.textSMedium.copyWith(color: appTheme.black), + ), + SizedBox(width: 4), + _PriceExplanationWidget(), + ], + ), + SizedBox(height: 4), + CustomTextFormField( + controller: customerPriceController, + textInputType: TextInputType.numberWithOptions(decimal: true), + onChanged: (value) { + final price = double.tryParse(value.replaceAll('₽', '')); + if (price != null) { + creatorPriceController.text = (price * 0.8).toStringAsFixed(2); + context.read().setPrice(price); + } + }, + maxLength: 20, + ), + SizedBox(height: 10), + Text( + s.minimal_customer_price, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyles.textSMedium.copyWith(color: appTheme.black), + ), + SizedBox(height: 16), + CustomDivider(), + SizedBox(height: 16), + Text( + s.option_content, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyles.textSMedium.copyWith(color: appTheme.black), + ), + SizedBox(height: 4), + ListView.separated( + padding: EdgeInsets.zero, + separatorBuilder: (context, index) => SizedBox(height: 8), + reverse: false, + itemBuilder: (context, index) { + final items = state.planData.options[selectedOptionIndex].items; + + if (items.isEmpty) { + return AddItemWidget( + index: index, + canBeDeleted: false, + enableHint: true, + items: items, + ); + } else { + if (index < items.length) { + return AddItemWidget( + canBeDeleted: true, + enableHint: false, + index: index, + items: items, + ); + } else { + return AddItemWidget( + canBeDeleted: false, + enableHint: false, + index: index, + items: items, + ); + } + } + }, + itemCount: state.planData.options[selectedOptionIndex].items.length + 1, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + ), + SizedBox(height: 16), + CustomDivider(), + SizedBox(height: 16), + Row( + children: [ + Checkbox( + value: isChecked, + activeColor: appTheme.gray, + checkColor: appTheme.gray, + fillColor: WidgetStatePropertyAll(Colors.transparent), + side: WidgetStateBorderSide.resolveWith( + (Set states) { + return BorderSide(width: 1, color: appTheme.gray); + }, + ), + onChanged: (bool? value) { + setState(() { + isChecked = value ?? false; + }); + }, + ), + Expanded( + child: Text( + s.option_personal_diet_desc, + style: TextStyles.textMMedium.copyWith(color: appTheme.black), + ), + ), + ], + ), + ], + ), + ); + }, + ); } -} \ No newline at end of file +} + +class _PriceExplanationWidget extends StatefulWidget { + const _PriceExplanationWidget(); + + @override + State<_PriceExplanationWidget> createState() => _PriceExplanationWidgetState(); +} + +class _PriceExplanationWidgetState extends State<_PriceExplanationWidget> { + bool visible = false; + @override + Widget build(BuildContext context) { + final s = S.of(context); + return PortalTarget( + closeDuration: Duration(milliseconds: 300), + portalFollower: AnimatedContainer( + padding: EdgeInsets.all(10), + duration: const Duration(milliseconds: 300), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: visible ? appTheme.black : Colors.transparent, + ), + child: AnimatedDefaultTextStyle( + style: TextStyles.textMMediumAuto.copyWith( + color: visible ? appTheme.whiteA700 : Colors.transparent, + ), + duration: const Duration(milliseconds: 300), + child: Text( + s.price_explanation, + ), + ), + ), + visible: visible, + anchor: Aligned( + shiftToWithinBound: AxisFlag(x: true, y: true), + follower: Alignment.bottomLeft, + target: Alignment.topRight, + ), + child: GestureDetector( + onTap: () { + setState(() { + visible = !visible; + }); + }, + child: SvgPicture.asset('assets/icons/question_mark.svg', height: 12, width: 12), + ), + ); + } +} diff --git a/lib/features/create_plan/presentation/widgets/options_count_button.dart b/lib/features/create_plan/presentation/widgets/options_count_button.dart index 35140514..32e9d4a7 100644 --- a/lib/features/create_plan/presentation/widgets/options_count_button.dart +++ b/lib/features/create_plan/presentation/widgets/options_count_button.dart @@ -61,7 +61,7 @@ class _AnimatedOptionButton extends StatelessWidget { return GestureDetector( onTap: onTap, child: AnimatedContainer( - duration: const Duration(milliseconds: 200), + duration: const Duration(milliseconds: 300), height: 40, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100), @@ -69,7 +69,7 @@ class _AnimatedOptionButton extends StatelessWidget { ), child: Center( child: AnimatedDefaultTextStyle( - duration: const Duration(milliseconds: 200), + duration: const Duration(milliseconds: 300), style: TextStyles.textMSemibold.copyWith( color: isSelected ? appTheme.whiteA700 : appTheme.black, ), diff --git a/lib/features/create_plan/presentation/widgets/select_exact_option_widget.dart b/lib/features/create_plan/presentation/widgets/select_exact_option_widget.dart index 12cf43ff..6660bc46 100644 --- a/lib/features/create_plan/presentation/widgets/select_exact_option_widget.dart +++ b/lib/features/create_plan/presentation/widgets/select_exact_option_widget.dart @@ -1,25 +1,47 @@ import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart'; +import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; -class SelectExactOptionWidget extends StatelessWidget { +class SelectExactOptionWidget extends StatefulWidget { const SelectExactOptionWidget({super.key}); + @override + State createState() => _SelectExactOptionWidgetState(); +} + +class _SelectExactOptionWidgetState extends State { @override Widget build(BuildContext context) { - return Container( - width: 140, - height: 48, - decoration: BoxDecoration( - color: appTheme.black, - borderRadius: BorderRadius.circular(100), - ), - child: Row( - children: [ - _OptionButton(isSelected: true, text: '1'), - _OptionButton(isSelected: true, text: '2'), - _OptionButton(isSelected: true, text: '3'), - ], - ), + return BlocBuilder( + builder: (context, state) { + final selectedIndex = state.selectedOptionIndex; + return Container( + padding: EdgeInsets.all(4), + width: 140, + height: 48, + decoration: BoxDecoration( + color: appTheme.black, + borderRadius: BorderRadius.circular(100), + ), + child: Row( + children: [ + ...List.generate( + 3, + (index) => Expanded( + child: GestureDetector( + onTap: () { + context.read().setSelectedOptionIndex(index); + }, + child: _OptionButton(isSelected: selectedIndex == index, text: '${index + 1}'), + ), + ), + ), + ], + ), + ); + }, ); } } @@ -30,13 +52,21 @@ class _OptionButton extends StatelessWidget { final String text; @override Widget build(BuildContext context) { - return Container( - + return AnimatedContainer( + duration: const Duration(milliseconds: 300), decoration: BoxDecoration( - color: appTheme.whiteA700, + color: isSelected ? appTheme.whiteA700 : Colors.transparent, shape: BoxShape.circle, ), - child: Text(text), + child: Center( + child: AnimatedDefaultTextStyle( + duration: const Duration(milliseconds: 300), + style: TextStyle(color: isSelected ? appTheme.black : appTheme.whiteA700), + child: Text( + text, + ), + ), + ), ); } } diff --git a/lib/features/diets/presentation/bloc/about_diet_cubit.dart b/lib/features/diets/presentation/cubit/about_diet_cubit.dart similarity index 98% rename from lib/features/diets/presentation/bloc/about_diet_cubit.dart rename to lib/features/diets/presentation/cubit/about_diet_cubit.dart index 8beaf5cc..b2780516 100644 --- a/lib/features/diets/presentation/bloc/about_diet_cubit.dart +++ b/lib/features/diets/presentation/cubit/about_diet_cubit.dart @@ -1,10 +1,9 @@ import 'dart:async'; import 'dart:developer'; - import 'package:easy_debounce/easy_debounce.dart'; import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:eatvio_app/features/diets/repositories/diet_repository.dart'; -import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_state.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_state.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class AboutDietCubit extends Cubit { diff --git a/lib/features/diets/presentation/bloc/about_diet_state.dart b/lib/features/diets/presentation/cubit/about_diet_state.dart similarity index 100% rename from lib/features/diets/presentation/bloc/about_diet_state.dart rename to lib/features/diets/presentation/cubit/about_diet_state.dart diff --git a/lib/features/diets/presentation/bloc/about_diet_state.freezed.dart b/lib/features/diets/presentation/cubit/about_diet_state.freezed.dart similarity index 100% rename from lib/features/diets/presentation/bloc/about_diet_state.freezed.dart rename to lib/features/diets/presentation/cubit/about_diet_state.freezed.dart diff --git a/lib/features/diets/presentation/pages/about_diet_screen.dart b/lib/features/diets/presentation/pages/about_diet_screen.dart index 26c723c9..c10d17e0 100644 --- a/lib/features/diets/presentation/pages/about_diet_screen.dart +++ b/lib/features/diets/presentation/pages/about_diet_screen.dart @@ -8,8 +8,8 @@ import 'package:eatvio_app/core/widgets/bookmark_button.dart'; import 'package:eatvio_app/core/widgets/custom_divider.dart'; import 'package:eatvio_app/core/widgets/diet_info_row.dart'; import 'package:eatvio_app/core/widgets/loader.dart'; -import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_cubit.dart'; -import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_state.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_state.dart'; import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart'; import 'package:eatvio_app/core/widgets/cpfc_container.dart'; import 'package:eatvio_app/features/diets/presentation/widgets/expandable_text.dart'; diff --git a/lib/features/diets/presentation/widgets/start_diet_bottom_sheet.dart b/lib/features/diets/presentation/widgets/start_diet_bottom_sheet.dart index ae9bc696..b7ac41d5 100644 --- a/lib/features/diets/presentation/widgets/start_diet_bottom_sheet.dart +++ b/lib/features/diets/presentation/widgets/start_diet_bottom_sheet.dart @@ -1,6 +1,6 @@ import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart'; import 'package:eatvio_app/core/widgets/custom_divider.dart'; -import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_cubit.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart'; import 'package:eatvio_app/features/diets/presentation/widgets/calendar_widget.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; diff --git a/lib/features/plans/models/plan_pagination_model.dart b/lib/features/feed/models/plan_pagination_model.dart similarity index 98% rename from lib/features/plans/models/plan_pagination_model.dart rename to lib/features/feed/models/plan_pagination_model.dart index dcd0e643..7abb842e 100644 --- a/lib/features/plans/models/plan_pagination_model.dart +++ b/lib/features/feed/models/plan_pagination_model.dart @@ -34,7 +34,7 @@ class PlanModel with _$PlanModel { @JsonKey(name: "author") required Author author, @JsonKey(name: "total_likes") required int totalLikes, @JsonKey(name: "total_views") required int totalViews, - @JsonKey(name: "total_comments") required int totalComments, + @JsonKey(name: "total_comments") required int totalComments, }) = _PlanModel; factory PlanModel.fromJson(Map json) => _$PlanModelFromJson(json); @@ -51,7 +51,7 @@ class PacketOptions with _$PacketOptions { factory PacketOptions.fromJson(Map json) => _$PacketOptionsFromJson(json); - factory PacketOptions.empty() => PacketOptions(items: [], price: -1, short: '', description: ''); + factory PacketOptions.empty() => PacketOptions(items: [], price: 1200, short: '', description: ''); } @freezed diff --git a/lib/features/plans/models/plan_pagination_model.freezed.dart b/lib/features/feed/models/plan_pagination_model.freezed.dart similarity index 100% rename from lib/features/plans/models/plan_pagination_model.freezed.dart rename to lib/features/feed/models/plan_pagination_model.freezed.dart diff --git a/lib/features/plans/models/plan_pagination_model.g.dart b/lib/features/feed/models/plan_pagination_model.g.dart similarity index 100% rename from lib/features/plans/models/plan_pagination_model.g.dart rename to lib/features/feed/models/plan_pagination_model.g.dart diff --git a/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart b/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart new file mode 100644 index 00000000..10afc3ea --- /dev/null +++ b/lib/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart @@ -0,0 +1,68 @@ +import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart'; +import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; + +import 'package:flutter_bloc/flutter_bloc.dart'; + +class PlansCubit extends Cubit { + final FeedRepository feedRepository; + int currentPage = 1; + late int lastPage; + bool isLoading = false; + String? _query; + + PlansCubit({ + required this.feedRepository, + }) : super(PlansState.initial()); + + loadPlans({ + String? query, + }) async { + try { + _query = query; + final plansPagination = await feedRepository.getPlans( + query: query, + ); + lastPage = plansPagination.meta.lastPage; + emit( + state.copyWith( + plans: plansPagination.data, + errorMessage: null, + isLoading: false, + ), + ); + } catch (e) { + emit(state.copyWith(errorMessage: e.toString())); + } + } + + loadNextPage() async { + if (currentPage < lastPage && !isLoading) { + isLoading = true; + + emit((state.copyWith(isLoading: isLoading, errorMessage: null))); + + try { + if (currentPage < lastPage) { + currentPage++; + final plansPagination = await feedRepository.getPlans( + page: currentPage, + query: _query, + ); + isLoading = false; + emit( + state.copyWith( + plans: [ + ...state.plans, + ...plansPagination.data, + ], + isLoading: isLoading, + errorMessage: null, + ), + ); + } + } catch (e) { + emit(state.copyWith(errorMessage: e.toString())); + } + } + } +} diff --git a/lib/features/feed/presentation/bloc/plans_cubit/plans_state.dart b/lib/features/feed/presentation/bloc/plans_cubit/plans_state.dart new file mode 100644 index 00000000..668cef22 --- /dev/null +++ b/lib/features/feed/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({ + required bool isLoading, + required List plans, + required String? errorMessage, + }) = _PlansState; + + factory PlansState.initial() => const _PlansState( + isLoading: true, + plans: [], + errorMessage: null, + ); +} diff --git a/lib/features/feed/presentation/bloc/plans_cubit/plans_state.freezed.dart b/lib/features/feed/presentation/bloc/plans_cubit/plans_state.freezed.dart new file mode 100644 index 00000000..664e3b2e --- /dev/null +++ b/lib/features/feed/presentation/bloc/plans_cubit/plans_state.freezed.dart @@ -0,0 +1,191 @@ +// 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 { + bool get isLoading => throw _privateConstructorUsedError; + List get plans => throw _privateConstructorUsedError; + String? get errorMessage => throw _privateConstructorUsedError; + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $PlansStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlansStateCopyWith<$Res> { + factory $PlansStateCopyWith( + PlansState value, $Res Function(PlansState) then) = + _$PlansStateCopyWithImpl<$Res, PlansState>; + @useResult + $Res call({bool isLoading, List plans, String? errorMessage}); +} + +/// @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. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isLoading = null, + Object? plans = null, + Object? errorMessage = freezed, + }) { + return _then(_value.copyWith( + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, + plans: null == plans + ? _value.plans + : plans // ignore: cast_nullable_to_non_nullable + as List, + errorMessage: freezed == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PlansStateImplCopyWith<$Res> + implements $PlansStateCopyWith<$Res> { + factory _$$PlansStateImplCopyWith( + _$PlansStateImpl value, $Res Function(_$PlansStateImpl) then) = + __$$PlansStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool isLoading, List plans, String? errorMessage}); +} + +/// @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. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isLoading = null, + Object? plans = null, + Object? errorMessage = freezed, + }) { + return _then(_$PlansStateImpl( + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, + plans: null == plans + ? _value._plans + : plans // ignore: cast_nullable_to_non_nullable + as List, + errorMessage: freezed == errorMessage + ? _value.errorMessage + : errorMessage // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$PlansStateImpl implements _PlansState { + const _$PlansStateImpl( + {required this.isLoading, + required final List plans, + required this.errorMessage}) + : _plans = plans; + + @override + final bool isLoading; + final List _plans; + @override + List get plans { + if (_plans is EqualUnmodifiableListView) return _plans; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_plans); + } + + @override + final String? errorMessage; + + @override + String toString() { + return 'PlansState(isLoading: $isLoading, plans: $plans, errorMessage: $errorMessage)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlansStateImpl && + (identical(other.isLoading, isLoading) || + other.isLoading == isLoading) && + const DeepCollectionEquality().equals(other._plans, _plans) && + (identical(other.errorMessage, errorMessage) || + other.errorMessage == errorMessage)); + } + + @override + int get hashCode => Object.hash(runtimeType, isLoading, + const DeepCollectionEquality().hash(_plans), 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') + _$$PlansStateImplCopyWith<_$PlansStateImpl> get copyWith => + __$$PlansStateImplCopyWithImpl<_$PlansStateImpl>(this, _$identity); +} + +abstract class _PlansState implements PlansState { + const factory _PlansState( + {required final bool isLoading, + required final List plans, + required final String? errorMessage}) = _$PlansStateImpl; + + @override + bool get isLoading; + @override + List get plans; + @override + String? get errorMessage; + + /// Create a copy of PlansState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$PlansStateImplCopyWith<_$PlansStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/feed/presentation/pages/feed_screen.dart b/lib/features/feed/presentation/pages/feed_screen.dart index f86430ef..f18b6110 100644 --- a/lib/features/feed/presentation/pages/feed_screen.dart +++ b/lib/features/feed/presentation/pages/feed_screen.dart @@ -16,8 +16,8 @@ import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart' import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.dart'; -import 'package:eatvio_app/features/plans/presentation/bloc/plans_cubit/plans_cubit.dart'; -import 'package:eatvio_app/features/plans/presentation/bloc/plans_cubit/plans_state.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; +import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:flutter/material.dart'; @@ -76,7 +76,7 @@ class _FeedScreenState extends State { _onScrollPlans() { if (plansScrollController.offset >= plansScrollController.position.maxScrollExtent && !plansScrollController.position.outOfRange) { - // plansCubit.loadNextPage(); + plansCubit.loadNextPage(); } } @@ -119,11 +119,13 @@ class _FeedScreenState extends State { ), backgroundColor: Colors.grey.shade200, body: NestedScrollView( - controller: _selectedChipIndex == 0 - ? blogPostsScrollController - : _selectedChipIndex == 1 - ? recipesScrollController - : dietsScrollController, + controller: switch (_selectedChipIndex) { + 0 => blogPostsScrollController, + 1 => recipesScrollController, + 2 => dietsScrollController, + 3 => plansScrollController, + _ => blogPostsScrollController + }, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( @@ -317,35 +319,34 @@ class _FeedScreenState extends State { onRefresh: () => plansCubit.loadPlans(), child: BlocBuilder( builder: (BuildContext context, PlansState state) { - if (state is PlansStateLoaded) { - return ListView.separated( - padding: EdgeInsets.symmetric(vertical: 8), - shrinkWrap: true, - physics: BouncingScrollPhysics(), - itemBuilder: (context, index) { - return PlanWidget(planModel: state.plansModel.data[index]); - }, - separatorBuilder: (context, index) { - return SizedBox(height: 8); - }, - itemCount: state.plansModel.data.length, + if (state.isLoading) { + return Scaffold( + backgroundColor: Colors.grey.shade200, + body: const Loader(), ); - } else if (state is PlansStateError) { + } else if (state.errorMessage != null) { return Scaffold( backgroundColor: Colors.grey.shade200, body: Padding( padding: const EdgeInsets.all(16), child: Center( - child: Text(state.errorMessage), + child: Text(state.errorMessage ?? ''), ), ), ); - } else { - return Scaffold( - backgroundColor: Colors.grey.shade200, - body: const Loader(), - ); } + return ListView.separated( + padding: EdgeInsets.symmetric(vertical: 8), + shrinkWrap: true, + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + return PlanWidget(planModel: state.plans[index]); + }, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemCount: state.plans.length, + ); }, ), ), diff --git a/lib/features/feed/presentation/widgets/plan_widget.dart b/lib/features/feed/presentation/widgets/plan_widget.dart index 0364dbb0..7036ee50 100644 --- a/lib/features/feed/presentation/widgets/plan_widget.dart +++ b/lib/features/feed/presentation/widgets/plan_widget.dart @@ -1,6 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:eatvio_app/core/const.dart'; -import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:go_router/go_router.dart'; diff --git a/lib/features/feed/repositories/feed_repository.dart b/lib/features/feed/repositories/feed_repository.dart index 5fe12d8a..d11f56f7 100644 --- a/lib/features/feed/repositories/feed_repository.dart +++ b/lib/features/feed/repositories/feed_repository.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/features/feed/models/comment_model.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_model.dart'; import 'package:eatvio_app/features/feed/services/feed_service.dart'; @@ -62,6 +63,22 @@ class FeedRepository { } } + Future getPlans({ + int page = 1, + String? query, + String? types, + int? duration, + String? sorting, + }) async { + try { + return (await feedService.getPlans( + page: page, + )); + } catch (e) { + rethrow; + } + } + Future getBlogPostComments({ required String id, }) async { diff --git a/lib/features/feed/services/feed_service.dart b/lib/features/feed/services/feed_service.dart index 771a6a1f..683cd8fd 100644 --- a/lib/features/feed/services/feed_service.dart +++ b/lib/features/feed/services/feed_service.dart @@ -2,6 +2,7 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/features/feed/models/comment_model.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/feed_blog_post_settings_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/recipes_pagination_model.dart'; import 'package:retrofit/retrofit.dart'; @@ -27,10 +28,15 @@ abstract class FeedService { @GET('/api/diets/index') Future getDiets({ @Query('page') required int page, - @Query('filters[name][\$startsWith]') String? query, - @Query('filters[type][\$contains]') String? types, - @Query('filters[duration][\$eq]') int? duration, - @Query('sort') String? sorting, + @Query('filters[name][\$startsWith]') String? query, + @Query('filters[type][\$contains]') String? types, + @Query('filters[duration][\$eq]') int? duration, + @Query('sort') String? sorting, + }); + + @GET('/api/plans/index') + Future getPlans({ + @Query('page') required int page, }); @GET('/api/blogPosts/{id}/comments/show') @@ -77,6 +83,5 @@ abstract class FeedService { @POST('/api/blogPosts/{id}/unliked') Future unlikedBlogPost({ @Path() required int id, - }); - + }); } diff --git a/lib/features/feed/services/feed_service.g.dart b/lib/features/feed/services/feed_service.g.dart index e7a83c0e..18d3ad18 100644 --- a/lib/features/feed/services/feed_service.g.dart +++ b/lib/features/feed/services/feed_service.g.dart @@ -149,6 +149,39 @@ class _FeedService implements FeedService { return _value; } + @override + Future getPlans({required int page}) async { + final _extra = {}; + final queryParameters = {r'page': page}; + final _headers = {}; + const Map? _data = null; + final _options = _setStreamType(Options( + method: 'GET', + headers: _headers, + extra: _extra, + ) + .compose( + _dio.options, + '/api/plans/index', + 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; + } + @override Future getBlogPostComments({required String id}) async { final _extra = {}; diff --git a/lib/features/plans/presentation/bloc/plans_cubit/plans_cubit.dart b/lib/features/plans/presentation/bloc/plans_cubit/plans_cubit.dart deleted file mode 100644 index 2190654a..00000000 --- a/lib/features/plans/presentation/bloc/plans_cubit/plans_cubit.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:eatvio_app/features/plans/presentation/bloc/plans_cubit/plans_state.dart'; -import 'package:eatvio_app/features/plans/repositories/plans_repository.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class PlansCubit extends Cubit { - final PlansRepository plansRepository; - - PlansCubit({ - required this.plansRepository, - }) : super(PlansState.loading()); - - loadPlans() async { - try { - emit(PlansState.loaded(plansModel: await plansRepository.getPlans())); - } catch (e) { - emit(PlansState.error(errorMessage: e.toString())); - } - } -} diff --git a/lib/features/plans/presentation/bloc/plans_cubit/plans_state.dart b/lib/features/plans/presentation/bloc/plans_cubit/plans_state.dart deleted file mode 100644 index ca3193cf..00000000 --- a/lib/features/plans/presentation/bloc/plans_cubit/plans_state.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:eatvio_app/features/plans/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 PlanPaginationModel plansModel, - }) = PlansStateLoaded; - - const factory PlansState.error({ - required String errorMessage, - }) = PlansStateError; -} diff --git a/lib/features/plans/presentation/bloc/plans_cubit/plans_state.freezed.dart b/lib/features/plans/presentation/bloc/plans_cubit/plans_state.freezed.dart deleted file mode 100644 index 1bbe3cac..00000000 --- a/lib/features/plans/presentation/bloc/plans_cubit/plans_state.freezed.dart +++ /dev/null @@ -1,646 +0,0 @@ -// 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(PlanPaginationModel plansModel) loaded, - required TResult Function(String errorMessage) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PlanPaginationModel plansModel)? loaded, - TResult? Function(String errorMessage)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PlanPaginationModel plansModel)? 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(PlanPaginationModel plansModel) loaded, - required TResult Function(String errorMessage) error, - }) { - return $default(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PlanPaginationModel plansModel)? loaded, - TResult? Function(String errorMessage)? error, - }) { - return $default?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PlanPaginationModel plansModel)? 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(PlanPaginationModel plansModel) loaded, - required TResult Function(String errorMessage) error, - }) { - return loading(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PlanPaginationModel plansModel)? loaded, - TResult? Function(String errorMessage)? error, - }) { - return loading?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PlanPaginationModel plansModel)? 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({PlanPaginationModel plansModel}); - - $PlanPaginationModelCopyWith<$Res> get plansModel; -} - -/// @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? plansModel = null, - }) { - return _then(_$PlansStateLoadedImpl( - plansModel: null == plansModel - ? _value.plansModel - : plansModel // ignore: cast_nullable_to_non_nullable - as PlanPaginationModel, - )); - } - - /// Create a copy of PlansState - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $PlanPaginationModelCopyWith<$Res> get plansModel { - return $PlanPaginationModelCopyWith<$Res>(_value.plansModel, (value) { - return _then(_value.copyWith(plansModel: value)); - }); - } -} - -/// @nodoc - -class _$PlansStateLoadedImpl implements PlansStateLoaded { - const _$PlansStateLoadedImpl({required this.plansModel}); - - @override - final PlanPaginationModel plansModel; - - @override - String toString() { - return 'PlansState.loaded(plansModel: $plansModel)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PlansStateLoadedImpl && - (identical(other.plansModel, plansModel) || - other.plansModel == plansModel)); - } - - @override - int get hashCode => Object.hash(runtimeType, plansModel); - - /// 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(PlanPaginationModel plansModel) loaded, - required TResult Function(String errorMessage) error, - }) { - return loaded(plansModel); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PlanPaginationModel plansModel)? loaded, - TResult? Function(String errorMessage)? error, - }) { - return loaded?.call(plansModel); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PlanPaginationModel plansModel)? loaded, - TResult Function(String errorMessage)? error, - required TResult orElse(), - }) { - if (loaded != null) { - return loaded(plansModel); - } - 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 PlanPaginationModel plansModel}) = _$PlansStateLoadedImpl; - - PlanPaginationModel get plansModel; - - /// 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(PlanPaginationModel plansModel) loaded, - required TResult Function(String errorMessage) error, - }) { - return error(errorMessage); - } - - @override - @optionalTypeArgs - TResult? whenOrNull( - TResult? Function()? $default, { - TResult? Function()? loading, - TResult? Function(PlanPaginationModel plansModel)? loaded, - TResult? Function(String errorMessage)? error, - }) { - return error?.call(errorMessage); - } - - @override - @optionalTypeArgs - TResult maybeWhen( - TResult Function()? $default, { - TResult Function()? loading, - TResult Function(PlanPaginationModel plansModel)? 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/plans/presentation/cubit/about_plan_cubit.dart b/lib/features/plans/presentation/cubit/about_plan_cubit.dart new file mode 100644 index 00000000..95933f66 --- /dev/null +++ b/lib/features/plans/presentation/cubit/about_plan_cubit.dart @@ -0,0 +1,11 @@ +import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_state.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class AboutPlanCubit extends Cubit { + AboutPlanCubit() : super(AboutPlanState.initial()); + + + Future getPlan() async{ + + } +} diff --git a/lib/features/plans/presentation/cubit/about_plan_state.dart b/lib/features/plans/presentation/cubit/about_plan_state.dart new file mode 100644 index 00000000..19859f4b --- /dev/null +++ b/lib/features/plans/presentation/cubit/about_plan_state.dart @@ -0,0 +1,18 @@ + + +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'about_plan_state.freezed.dart'; + +@freezed +class AboutPlanState with _$AboutPlanState { + + const factory AboutPlanState({ + required bool isLoading, + required String? error, + required PlanModel? planModel, + }) = _AboutPlanState; + + factory AboutPlanState.initial() => const AboutPlanState(isLoading: false, error: null, planModel: null); +} \ No newline at end of file diff --git a/lib/features/plans/presentation/cubit/about_plan_state.freezed.dart b/lib/features/plans/presentation/cubit/about_plan_state.freezed.dart new file mode 100644 index 00000000..98a97a2f --- /dev/null +++ b/lib/features/plans/presentation/cubit/about_plan_state.freezed.dart @@ -0,0 +1,201 @@ +// 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 'about_plan_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 _$AboutPlanState { + bool get isLoading => throw _privateConstructorUsedError; + String? get error => throw _privateConstructorUsedError; + PlanModel? get planModel => throw _privateConstructorUsedError; + + /// Create a copy of AboutPlanState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AboutPlanStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AboutPlanStateCopyWith<$Res> { + factory $AboutPlanStateCopyWith( + AboutPlanState value, $Res Function(AboutPlanState) then) = + _$AboutPlanStateCopyWithImpl<$Res, AboutPlanState>; + @useResult + $Res call({bool isLoading, String? error, PlanModel? planModel}); + + $PlanModelCopyWith<$Res>? get planModel; +} + +/// @nodoc +class _$AboutPlanStateCopyWithImpl<$Res, $Val extends AboutPlanState> + implements $AboutPlanStateCopyWith<$Res> { + _$AboutPlanStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AboutPlanState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isLoading = null, + Object? error = freezed, + Object? planModel = freezed, + }) { + return _then(_value.copyWith( + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, + error: freezed == error + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as String?, + planModel: freezed == planModel + ? _value.planModel + : planModel // ignore: cast_nullable_to_non_nullable + as PlanModel?, + ) as $Val); + } + + /// Create a copy of AboutPlanState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $PlanModelCopyWith<$Res>? get planModel { + if (_value.planModel == null) { + return null; + } + + return $PlanModelCopyWith<$Res>(_value.planModel!, (value) { + return _then(_value.copyWith(planModel: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$AboutPlanStateImplCopyWith<$Res> + implements $AboutPlanStateCopyWith<$Res> { + factory _$$AboutPlanStateImplCopyWith(_$AboutPlanStateImpl value, + $Res Function(_$AboutPlanStateImpl) then) = + __$$AboutPlanStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool isLoading, String? error, PlanModel? planModel}); + + @override + $PlanModelCopyWith<$Res>? get planModel; +} + +/// @nodoc +class __$$AboutPlanStateImplCopyWithImpl<$Res> + extends _$AboutPlanStateCopyWithImpl<$Res, _$AboutPlanStateImpl> + implements _$$AboutPlanStateImplCopyWith<$Res> { + __$$AboutPlanStateImplCopyWithImpl( + _$AboutPlanStateImpl _value, $Res Function(_$AboutPlanStateImpl) _then) + : super(_value, _then); + + /// Create a copy of AboutPlanState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isLoading = null, + Object? error = freezed, + Object? planModel = freezed, + }) { + return _then(_$AboutPlanStateImpl( + isLoading: null == isLoading + ? _value.isLoading + : isLoading // ignore: cast_nullable_to_non_nullable + as bool, + error: freezed == error + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as String?, + planModel: freezed == planModel + ? _value.planModel + : planModel // ignore: cast_nullable_to_non_nullable + as PlanModel?, + )); + } +} + +/// @nodoc + +class _$AboutPlanStateImpl implements _AboutPlanState { + const _$AboutPlanStateImpl( + {required this.isLoading, required this.error, required this.planModel}); + + @override + final bool isLoading; + @override + final String? error; + @override + final PlanModel? planModel; + + @override + String toString() { + return 'AboutPlanState(isLoading: $isLoading, error: $error, planModel: $planModel)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AboutPlanStateImpl && + (identical(other.isLoading, isLoading) || + other.isLoading == isLoading) && + (identical(other.error, error) || other.error == error) && + (identical(other.planModel, planModel) || + other.planModel == planModel)); + } + + @override + int get hashCode => Object.hash(runtimeType, isLoading, error, planModel); + + /// Create a copy of AboutPlanState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AboutPlanStateImplCopyWith<_$AboutPlanStateImpl> get copyWith => + __$$AboutPlanStateImplCopyWithImpl<_$AboutPlanStateImpl>( + this, _$identity); +} + +abstract class _AboutPlanState implements AboutPlanState { + const factory _AboutPlanState( + {required final bool isLoading, + required final String? error, + required final PlanModel? planModel}) = _$AboutPlanStateImpl; + + @override + bool get isLoading; + @override + String? get error; + @override + PlanModel? get planModel; + + /// Create a copy of AboutPlanState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AboutPlanStateImplCopyWith<_$AboutPlanStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/features/plans/presentation/pages/about_plan_screen.dart b/lib/features/plans/presentation/pages/about_plan_screen.dart index 50f81867..97070101 100644 --- a/lib/features/plans/presentation/pages/about_plan_screen.dart +++ b/lib/features/plans/presentation/pages/about_plan_screen.dart @@ -1,4 +1,4 @@ -import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:flutter/material.dart'; class AboutPlanScreen extends StatelessWidget { diff --git a/lib/features/plans/repositories/plans_repository.dart b/lib/features/plans/repositories/plans_repository.dart deleted file mode 100644 index ee8e7fb7..00000000 --- a/lib/features/plans/repositories/plans_repository.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:eatvio_app/features/plans/models/plan_pagination_model.dart'; -import 'package:eatvio_app/features/plans/services/plans_service.dart'; - -class PlansRepository { - final PlansService plansService; - - const PlansRepository({required this.plansService}); - - Future getPlans() async { - try { - return await plansService.getPlans(); - } catch (e) { - rethrow; - } - } -} diff --git a/lib/features/plans/services/plans_service.dart b/lib/features/plans/services/plans_service.dart deleted file mode 100644 index 2b842047..00000000 --- a/lib/features/plans/services/plans_service.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:eatvio_app/features/plans/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/index') - Future getPlans(); -} diff --git a/lib/features/plans/services/plans_service.g.dart b/lib/features/plans/services/plans_service.g.dart deleted file mode 100644 index b0e19fb9..00000000 --- a/lib/features/plans/services/plans_service.g.dart +++ /dev/null @@ -1,86 +0,0 @@ -// 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 getPlans() 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/index', - 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/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 215f3a55..08eef1e1 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -71,6 +71,7 @@ class MessageLookup extends MessageLookupByLibrary { "city": MessageLookupByLibrary.simpleMessage("Город"), "city_of_living": MessageLookupByLibrary.simpleMessage("Город проживания"), + "comfort": MessageLookupByLibrary.simpleMessage("Комфорт"), "comment": MessageLookupByLibrary.simpleMessage("комментарий"), "comments": MessageLookupByLibrary.simpleMessage("Комментарии"), "comments_plural": MessageLookupByLibrary.simpleMessage("комментариев"), @@ -81,6 +82,8 @@ class MessageLookup extends MessageLookupByLibrary { "copy_link": MessageLookupByLibrary.simpleMessage("Скопировать ссылку"), "country": MessageLookupByLibrary.simpleMessage("Страна"), "create_diet": MessageLookupByLibrary.simpleMessage("Создание диеты"), + "customer_price": + MessageLookupByLibrary.simpleMessage("Цена для покупателя"), "date_of_birth": MessageLookupByLibrary.simpleMessage("Дата рождения"), "day": MessageLookupByLibrary.simpleMessage("День"), "days": MessageLookupByLibrary.simpleMessage("дней"), @@ -101,6 +104,7 @@ class MessageLookup extends MessageLookupByLibrary { "draft": MessageLookupByLibrary.simpleMessage("Черновик"), "eating_behavior": MessageLookupByLibrary.simpleMessage("Пищевое поведение"), + "economy": MessageLookupByLibrary.simpleMessage("Эконом"), "email": MessageLookupByLibrary.simpleMessage("Элетронная почта"), "email_empty": MessageLookupByLibrary.simpleMessage( "Необходимо ввести адрес электронной почты"), @@ -167,6 +171,8 @@ class MessageLookup extends MessageLookupByLibrary { "meat_type_desc": MessageLookupByLibrary.simpleMessage( "Диета с мясом полезная и сбалансированная. Включает в себя нежирное мясо: курицу, индейку, кролика или говядину. В сочетании с овощами получаете все необходимые витамины и минералы. Не забывайте о порциях и старайтесь есть медленно, прислушиваясь к своему организму."), "milliliter": MessageLookupByLibrary.simpleMessage("мл"), + "minimal_customer_price": MessageLookupByLibrary.simpleMessage( + "Минимальная цена для покупателя: 1200₽"), "most_new": MessageLookupByLibrary.simpleMessage("Самые новые"), "most_old": MessageLookupByLibrary.simpleMessage("Самые старые"), "msg_network_err": @@ -183,6 +189,17 @@ class MessageLookup extends MessageLookupByLibrary { "no_account": MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"), "one_option": MessageLookupByLibrary.simpleMessage("1 опция"), + "option": MessageLookupByLibrary.simpleMessage("Опция"), + "option_content": + MessageLookupByLibrary.simpleMessage("Содержание опции"), + "option_content_hint_text": + MessageLookupByLibrary.simpleMessage("На связи 7 дней в неделю"), + "option_desc": MessageLookupByLibrary.simpleMessage("Описание опции"), + "option_desc_hint_text": MessageLookupByLibrary.simpleMessage( + "Этот план питания для похудения на 7 дней сбалансированный и разнообразный"), + "option_personal_diet_desc": MessageLookupByLibrary.simpleMessage( + "Опция подразумевает создание индивидуальной диеты"), + "option_title": MessageLookupByLibrary.simpleMessage("Заголовок опции"), "order": MessageLookupByLibrary.simpleMessage("Порядок"), "password": MessageLookupByLibrary.simpleMessage("Пароль"), "password_confirmation": @@ -215,14 +232,18 @@ class MessageLookup extends MessageLookupByLibrary { "pressure_is_not_a_number": MessageLookupByLibrary.simpleMessage( "Все показатели давления должны быть числами"), "preview": MessageLookupByLibrary.simpleMessage("Превью"), + "price_explanation": MessageLookupByLibrary.simpleMessage( + "Разница в ценах, это комиссия Итвио"), "profile": MessageLookupByLibrary.simpleMessage("Профиль"), "proteins": MessageLookupByLibrary.simpleMessage("Белки"), "publish": MessageLookupByLibrary.simpleMessage("Опубликовать"), "save": MessageLookupByLibrary.simpleMessage("Сохранить"), + "services": MessageLookupByLibrary.simpleMessage("Оказание услуг"), "settings": MessageLookupByLibrary.simpleMessage("Настройки"), "share": MessageLookupByLibrary.simpleMessage("Поделиться"), "skip": MessageLookupByLibrary.simpleMessage("Пропустить"), "slim": MessageLookupByLibrary.simpleMessage("Похудение"), + "standard": MessageLookupByLibrary.simpleMessage("Стандарт"), "startDiet": MessageLookupByLibrary.simpleMessage("Начать диету"), "tell_your_schedule": MessageLookupByLibrary.simpleMessage( "Расскажите в свободной форме о том как просыпаетесь, когда едите, когда ложитесь спать:"), @@ -254,6 +275,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Как вас зовут?"), "wrong_credentials": MessageLookupByLibrary.simpleMessage( "Неверные данные пользователя"), + "you_will_get": MessageLookupByLibrary.simpleMessage("Вы получите"), "your_blood_pressure": MessageLookupByLibrary.simpleMessage("Ваше артериальное давление?"), "your_favorite_sports": diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index a0837964..1c19a2b3 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -1779,6 +1779,156 @@ class S { args: [], ); } + + /// `Опция` + String get option { + return Intl.message( + 'Опция', + name: 'option', + desc: '', + args: [], + ); + } + + /// `Оказание услуг` + String get services { + return Intl.message( + 'Оказание услуг', + name: 'services', + desc: '', + args: [], + ); + } + + /// `Эконом` + String get economy { + return Intl.message( + 'Эконом', + name: 'economy', + desc: '', + args: [], + ); + } + + /// `Стандарт` + String get standard { + return Intl.message( + 'Стандарт', + name: 'standard', + desc: '', + args: [], + ); + } + + /// `Комфорт` + String get comfort { + return Intl.message( + 'Комфорт', + name: 'comfort', + desc: '', + args: [], + ); + } + + /// `Заголовок опции` + String get option_title { + return Intl.message( + 'Заголовок опции', + name: 'option_title', + desc: '', + args: [], + ); + } + + /// `Описание опции` + String get option_desc { + return Intl.message( + 'Описание опции', + name: 'option_desc', + desc: '', + args: [], + ); + } + + /// `Этот план питания для похудения на 7 дней сбалансированный и разнообразный` + String get option_desc_hint_text { + return Intl.message( + 'Этот план питания для похудения на 7 дней сбалансированный и разнообразный', + name: 'option_desc_hint_text', + desc: '', + args: [], + ); + } + + /// `Вы получите` + String get you_will_get { + return Intl.message( + 'Вы получите', + name: 'you_will_get', + desc: '', + args: [], + ); + } + + /// `Цена для покупателя` + String get customer_price { + return Intl.message( + 'Цена для покупателя', + name: 'customer_price', + desc: '', + args: [], + ); + } + + /// `Минимальная цена для покупателя: 1200₽` + String get minimal_customer_price { + return Intl.message( + 'Минимальная цена для покупателя: 1200₽', + name: 'minimal_customer_price', + desc: '', + args: [], + ); + } + + /// `Разница в ценах, это комиссия Итвио` + String get price_explanation { + return Intl.message( + 'Разница в ценах, это комиссия Итвио', + name: 'price_explanation', + desc: '', + args: [], + ); + } + + /// `Содержание опции` + String get option_content { + return Intl.message( + 'Содержание опции', + name: 'option_content', + desc: '', + args: [], + ); + } + + /// `На связи 7 дней в неделю` + String get option_content_hint_text { + return Intl.message( + 'На связи 7 дней в неделю', + name: 'option_content_hint_text', + desc: '', + args: [], + ); + } + + /// `Опция подразумевает создание индивидуальной диеты` + String get option_personal_diet_desc { + return Intl.message( + 'Опция подразумевает создание индивидуальной диеты', + name: 'option_personal_diet_desc', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index f47a166f..d42aec15 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -171,6 +171,20 @@ "plan_desc": "Описание плана", "plan_desc_example": "Большое подробное, привлекательное описание плана", "one_option": "1 опция", - "three_options": "3 опции" - + "three_options": "3 опции", + "option": "Опция", + "services": "Оказание услуг", + "economy": "Эконом", + "standard": "Стандарт", + "comfort": "Комфорт", + "option_title": "Заголовок опции", + "option_desc": "Описание опции", + "option_desc_hint_text": "Этот план питания для похудения на 7 дней сбалансированный и разнообразный", + "you_will_get": "Вы получите", + "customer_price": "Цена для покупателя", + "minimal_customer_price": "Минимальная цена для покупателя: 1200₽", + "price_explanation": "Разница в ценах, это комиссия Итвио", + "option_content": "Содержание опции", + "option_content_hint_text": "На связи 7 дней в неделю", + "option_personal_diet_desc": "Опция подразумевает создание индивидуальной диеты" }