diff --git a/lib/core/locator_service.dart b/lib/core/locator_service.dart index a72c1b33..567fe833 100644 --- a/lib/core/locator_service.dart +++ b/lib/core/locator_service.dart @@ -79,7 +79,7 @@ Future init() async { sl.registerFactory(() => AboutDietCubit(dietsRepository: sl())); sl.registerFactory(() => BlogPostCreateCubit(blogPostRepository: sl())); sl.registerFactory(() => SubCubit(profileRepository: sl())); - sl.registerFactory(() => CreateDietCubit(createDietRepository: sl())); + sl.registerFactory(() => CreateDietCubit(createDietRepository: sl(), glossaryRepository: sl())); // Repository diff --git a/lib/core/utils/toasts.dart b/lib/core/utils/toasts.dart index 2f86daa9..2730d6ce 100644 --- a/lib/core/utils/toasts.dart +++ b/lib/core/utils/toasts.dart @@ -5,11 +5,24 @@ const int _toastDuration = 2; void showInfoToast(String message) { Fluttertoast.showToast( - msg: message, - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.TOP, - timeInSecForIosWeb: _toastDuration, - backgroundColor: appTheme.blueA400, - textColor: appTheme.whiteA700, - fontSize: 16.0,); + msg: message, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.TOP, + timeInSecForIosWeb: _toastDuration, + backgroundColor: appTheme.blueA400, + textColor: appTheme.whiteA700, + fontSize: 16.0, + ); +} + +void showErrorToast(String message) { + Fluttertoast.showToast( + msg: message, + toastLength: Toast.LENGTH_LONG, + gravity: ToastGravity.TOP, + timeInSecForIosWeb: _toastDuration, + backgroundColor: appTheme.whiteA700, + textColor: appTheme.gray, + fontSize: 16.0, + ); } 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 2e27e729..43ccedf4 100644 --- a/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart +++ b/lib/features/create_diet/presentation/cubit/create_diet_cubit.dart @@ -2,13 +2,16 @@ import 'package:eatvio_app/core/const.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'; +import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; +import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; class CreateDietCubit extends Cubit { final CreateDietRepository createDietRepository; + final GlossaryRepository glossaryRepository; static const _dietStateValues = ['active', 'draft', 'personal']; - CreateDietCubit({required this.createDietRepository}) : super(CreateDietState.initial()); + CreateDietCubit({required this.createDietRepository, required this.glossaryRepository}) : super(CreateDietState.initial()); void setDetails(String text) { emit(state.copyWith(dietData: state.dietData.copyWith(details: text))); @@ -29,6 +32,10 @@ class CreateDietCubit extends Cubit { ); } + Future> getGlossaryListByQuery(String query) async { + return await glossaryRepository.getGlossaryListByQuery(query); + } + void setImage(XFile? image) { emit(state.copyWith(dietData: state.dietData.copyWith(image: image))); } @@ -44,4 +51,16 @@ class CreateDietCubit extends Cubit { void setDietType(List type) { emit(state.copyWith(dietData: state.dietData.copyWith(type: type))); } + + void addPortion({required int dayIndex,required int mealIndex, required DailySchedule portion}) { + final currentSchedule = state.dietData.dailySchedule; + if (currentSchedule != null) { + + } + } + + void removePortion({required int day,required int meal,required int portionIndex, }) {} + + void updatePortion({required int day,required int meal,required int portionIndex, required DailySchedule portion}) {} + } diff --git a/lib/features/create_diet/presentation/widgets/add_meal_widget.dart b/lib/features/create_diet/presentation/widgets/add_meal_widget.dart new file mode 100644 index 00000000..67e41566 --- /dev/null +++ b/lib/features/create_diet/presentation/widgets/add_meal_widget.dart @@ -0,0 +1,235 @@ +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/utils/toasts.dart'; +import 'package:eatvio_app/core/widgets/custom_text_form_field.dart'; +import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart'; +import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart'; +import 'package:eatvio_app/features/diary/presentation/widgets/glossary_moderation_request_modal_widget.dart'; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; +import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; + +class AddMealWidget extends StatefulWidget { + const AddMealWidget({ + super.key, + required this.createDietCubit, + this.portionIndex, + this.productNameControllerText, + this.quantityControllerText, + required this.dayIndex, + required this.mealIndex, + }); + final CreateDietCubit createDietCubit; + final String? productNameControllerText; + final String? quantityControllerText; + final int? portionIndex; + final int dayIndex; + final int mealIndex; + @override + State createState() => _AddMealWidgetState(); +} + +class _AddMealWidgetState extends State { + GlossaryModel? selectedGlossary; + final productNameController = TextEditingController(); + final quantityController = TextEditingController(); + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16) + + EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Добавление блюда', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: Color(0xFF323F4B), + ), + ), + const SizedBox(height: 16), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.8 - 32, + child: TypeAheadField( + controller: productNameController, + itemBuilder: (context, glossary) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + glossary.name, + style: TextStyle( + height: 1, + fontSize: 16, + ), + ), + ); + }, + itemSeparatorBuilder: (context, index) => _divider(context), + onSelected: (newSelectedGlossary) async { + setState(() { + selectedGlossary = newSelectedGlossary; + productNameController.text = selectedGlossary!.name; + }); + }, + suggestionsCallback: (query) async { + if (query.length < 1) return []; + final suggestionsList = await widget.createDietCubit.getGlossaryListByQuery(query); + return suggestionsList; + }, + builder: (context, controller, focusNode) { + return CustomTextFormField( + controller: controller, + autofocus: true, + focusNode: focusNode, + hintText: 'Введите название продукта/блюда', + ); + }, + emptyBuilder: (context) { + return const SizedBox.shrink(); + }, + errorBuilder: (context, object) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Нет подходящих вариантов'), + ), + ), + ), + const SizedBox(width: 4), + SizedBox( + width: MediaQuery.of(context).size.width * 0.2 - 4, + child: CustomTextFormField( + controller: quantityController, + keyboardType: TextInputType.number, + hintText: selectedGlossary == null + ? '100' + : selectedGlossary!.grInPortion == 0 + ? '100' + : '1', + suffixText: selectedGlossary == null + ? 'гр' + : selectedGlossary?.grInPortion == 0 + ? 'гр' + : 'шт', + ), + ), + ], + ), + const SizedBox(height: 16), + Row( + children: [ + if (widget.portionIndex != null) + InkWell( + onTap: () { + Navigator.of(context).pop(); + }, + borderRadius: BorderRadius.circular(20), + child: Ink( + width: 52, + height: 52, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Color(0xFFF6F6F6), + ), + child: Icon( + Icons.delete_outline_rounded, + color: Colors.red, + ), + ), + ), + if (widget.portionIndex != null) const SizedBox(width: 8), + InkWell( + onTap: () { + if (widget.portionIndex == null) { + // final glossary = selectedGlossary; + // if (glossary != null) { + // final measurementUnits = glossary.grInPortion != 0 ? Portion.PCS : Portion.GRAMS ; + // final portion = DailySchedule( + // quantity: int.parse(quantityController.text), + // name: glossary.name, + // uniq: glossary.id.toString(), + // portion: measurementUnits, + // ); + // widget.createDietCubit.addPortion( + // dayIndex: widget.dayIndex, + // mealIndex: widget.mealIndex, + // portion: portion, + // ); + // } + } else { + // final portion = DailySchedule( + // quantity: int.parse(quantityController.text), + // name: glossary.name, + // uniq: glossary.id.toString(), + // portion: measurementUnits, + // ); + // widget.createDietCubit.updatePortion( + // day: widget.dayIndex, + // meal: widget.mealIndex, + // portionIndex: widget.portionIndex!, + // portion: portion, + // ); + } + Navigator.of(context).pop(); + if (selectedGlossary == null) { + showModalBottomSheet( + isScrollControlled: true, + useRootNavigator: true, + context: context, + builder: (context) => Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: GlossaryModerationRequestModalWidget( + productName: productNameController.text, + diaryCubit: sl(), + ), + ), + ); + } + }, + borderRadius: BorderRadius.circular(20), + child: Ink( + width: MediaQuery.of(context).size.width - (widget.portionIndex == null ? 32 : 92), + height: 52, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: appTheme.blueA400, + ), + child: Center( + child: Text( + widget.portionIndex == null ? 'Добавить' : 'Сохранить', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + ), + ), + ), + ), + ], + ), + ], + ), + ); + } + + _divider(BuildContext context) { + return Container( + height: 0.4, + width: MediaQuery.of(context).size.width - 32, + decoration: BoxDecoration( + color: Colors.black26, + borderRadius: BorderRadius.circular(16), + ), + ); + } +} diff --git a/lib/features/create_diet/presentation/widgets/day_widget.dart b/lib/features/create_diet/presentation/widgets/day_widget.dart index b249f81f..4d9c470c 100644 --- a/lib/features/create_diet/presentation/widgets/day_widget.dart +++ b/lib/features/create_diet/presentation/widgets/day_widget.dart @@ -1,15 +1,19 @@ import 'package:eatvio_app/core/theme/custom_text_style.dart'; import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/utils/localization_utils.dart'; import 'package:eatvio_app/core/widgets/custom_divider.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_diet/presentation/cubit/create_diet_cubit.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart'; +import 'package:eatvio_app/features/create_diet/presentation/widgets/add_meal_widget.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; class DayWidget extends StatefulWidget { const DayWidget({ @@ -22,7 +26,7 @@ class DayWidget extends StatefulWidget { } class _DayWidgetState extends State { - int _selectedDayIndex = 0; + int _selectedMealIndex = 0; final chipsLabelList = ['1', '2', '3', '4', '5']; @override Widget build(BuildContext context) { @@ -74,10 +78,10 @@ class _DayWidgetState extends State { fontSize: TextStyles.textMMedium.fontSize, fontWeight: TextStyles.textMMedium.fontWeight, index: 0, - selectedChipIndex: _selectedDayIndex, + selectedChipIndex: _selectedMealIndex, onSelected: (selectedValue) { setState(() { - _selectedDayIndex = 0; + _selectedMealIndex = 0; }); }, ), @@ -88,10 +92,10 @@ class _DayWidgetState extends State { fontSize: TextStyles.textMMedium.fontSize, fontWeight: TextStyles.textMMedium.fontWeight, index: 1, - selectedChipIndex: _selectedDayIndex, + selectedChipIndex: _selectedMealIndex, onSelected: (selectedValue) { setState(() { - _selectedDayIndex = 1; + _selectedMealIndex = 1; }); }, ), @@ -102,10 +106,10 @@ class _DayWidgetState extends State { fontSize: TextStyles.textMMedium.fontSize, fontWeight: TextStyles.textMMedium.fontWeight, index: 2, - selectedChipIndex: _selectedDayIndex, + selectedChipIndex: _selectedMealIndex, onSelected: (selectedValue) { setState(() { - _selectedDayIndex = 2; + _selectedMealIndex = 2; }); }, ), @@ -116,10 +120,10 @@ class _DayWidgetState extends State { fontSize: TextStyles.textMMedium.fontSize, fontWeight: TextStyles.textMMedium.fontWeight, index: 3, - selectedChipIndex: _selectedDayIndex, + selectedChipIndex: _selectedMealIndex, onSelected: (selectedValue) { setState(() { - _selectedDayIndex = 3; + _selectedMealIndex = 3; }); }, ), @@ -130,15 +134,37 @@ class _DayWidgetState extends State { fontSize: TextStyles.textMMedium.fontSize, fontWeight: TextStyles.textMMedium.fontWeight, index: 4, - selectedChipIndex: _selectedDayIndex, + selectedChipIndex: _selectedMealIndex, onSelected: (selectedValue) { setState(() { - _selectedDayIndex = 4; + _selectedMealIndex = 4; }); }, ), ], ), + ListView.builder( + itemBuilder: (context, index) { + final product = state.dietData.dailySchedule?[widget.index][_selectedMealIndex][index]; + if (product != null) { + return _product( + index, + product.name, + product.quantity, + getLocalizedMeasurementUnits( + s, + product.portion, + ), + widget.index, + _selectedMealIndex, + ); + } + return null; + }, + itemCount: state.dietData.dailySchedule?[widget.index][_selectedMealIndex].length ?? 0, + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + ), SizedBox(height: 16), Row( children: [ @@ -154,6 +180,13 @@ class _DayWidgetState extends State { SizedBox(width: 8), Expanded( child: CustomOutlinedButton( + onPressed: () { + _modalBottomSheet( + dayIndex: widget.index, + mealIndex: _selectedMealIndex, + createDietCubit: context.read(), + ); + }, text: s.add, height: 52, buttonTextStyle: TextStyles.textMSemibold.copyWith( @@ -175,4 +208,54 @@ class _DayWidgetState extends State { }, ); } + + _product(int index, String product, int quantity, String portion, int dayIndex, int mealIndex) { + return ListTile( + onTap: () { + _modalBottomSheet( + mealIndex: mealIndex, + dayIndex: dayIndex, + createDietCubit: context.read(), + portionIndex: index, + productNameControllerText: product, + quantityControllerText: quantity.toString(), + ); + }, + trailing: Icon(Icons.more_vert_rounded), + title: Text(product), + subtitle: Text('$quantity $portion'), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + tileColor: Color(0xFFF6FAFF), + ); + } + + _modalBottomSheet({ + required CreateDietCubit createDietCubit, + required int dayIndex, + required int mealIndex, + int? portionIndex, + String? productNameControllerText, + String? quantityControllerText, + }) { + return showModalBottomSheet( + useRootNavigator: true, + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(12)), + ), + isScrollControlled: true, + builder: (context) { + return AddMealWidget( + dayIndex: dayIndex, + createDietCubit: createDietCubit, + portionIndex: portionIndex, + productNameControllerText: productNameControllerText, + quantityControllerText: quantityControllerText, + mealIndex: mealIndex, + ); + }, + ); + } } diff --git a/lib/features/diary/presentation/pages/diary_screen.dart b/lib/features/diary/presentation/pages/diary_screen.dart index 9c405a7e..ce7a8f97 100644 --- a/lib/features/diary/presentation/pages/diary_screen.dart +++ b/lib/features/diary/presentation/pages/diary_screen.dart @@ -877,7 +877,7 @@ class _DiaryScreenState extends State { children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.8 - 32, - child: TypeAheadField( + child: TypeAheadField( controller: productNameController, itemBuilder: (context, glossary) { return Padding( diff --git a/lib/features/diets/presentation/bloc/about_diet_cubit.dart b/lib/features/diets/presentation/bloc/about_diet_cubit.dart index 470da0de..8beaf5cc 100644 --- a/lib/features/diets/presentation/bloc/about_diet_cubit.dart +++ b/lib/features/diets/presentation/bloc/about_diet_cubit.dart @@ -2,6 +2,7 @@ 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:flutter_bloc/flutter_bloc.dart'; @@ -59,13 +60,7 @@ class AboutDietCubit extends Cubit { Duration(seconds: 1), () async { try { - final dietLikeStateData = await dietsRepository.likeDiet(id); - final actualDiet = currentDiet.copyWith( - wasLikedByMe: dietLikeStateData.isLiked, - totalLikes: dietLikeStateData.totalLikes, - ); - emit(AboutDietState.loaded(actualDiet)); - dietsRepository.emitLikesStateToFeed(DietLikesState(wasLikedByMe: actualDiet.wasLikedByMe, totalLikes: actualDiet.totalLikes, index: dietIndexInFeed)); + await dietsRepository.likeDiet(id); } catch (e) { log(e.toString()); dietsRepository @@ -92,11 +87,10 @@ class AboutDietCubit extends Cubit { Duration(seconds: 1), () async { try { - final diet = await dietsRepository.addToFavorite(id); - emit(AboutDietState.loaded(diet)); - dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: diet.isFavorite, index: dietIndexInFeed)); + await dietsRepository.addToFavorite(id); } catch (e) { log(e.toString()); + showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndexInFeed)); emit(AboutDietState.loaded(currentDiet)); } @@ -120,11 +114,10 @@ class AboutDietCubit extends Cubit { Duration(seconds: 1), () async { try { - final diet = await dietsRepository.removeFromFavorite(id); - emit(AboutDietState.loaded(diet)); - dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: diet.isFavorite, index: dietIndexInFeed)); + await dietsRepository.removeFromFavorite(id); } catch (e) { log(e.toString()); + showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndexInFeed)); emit(AboutDietState.loaded(currentDiet)); } diff --git a/lib/features/diets/presentation/pages/about_diet_screen.dart b/lib/features/diets/presentation/pages/about_diet_screen.dart index d5a7f163..0e1c2299 100644 --- a/lib/features/diets/presentation/pages/about_diet_screen.dart +++ b/lib/features/diets/presentation/pages/about_diet_screen.dart @@ -132,7 +132,7 @@ class _AboutDietScreenState extends State { ), backgroundColor: appTheme.greenA700, onPressed: () { - showModalBottomSheet(context: context, builder: (context) => StartDietBottomSheet()); + showModalBottomSheet(context: context, builder: (context) => StartDietBottomSheet(aboutDietCubit: context.read(),)); }, label: Text( s.startDiet, diff --git a/lib/features/diets/presentation/widgets/calendar_widget.dart b/lib/features/diets/presentation/widgets/calendar_widget.dart index c3ff1ee1..bd3fdca2 100644 --- a/lib/features/diets/presentation/widgets/calendar_widget.dart +++ b/lib/features/diets/presentation/widgets/calendar_widget.dart @@ -23,7 +23,7 @@ class _CalendarWidgetState extends State { Padding( padding: const EdgeInsets.only(top: 5), child: TableCalendar( - firstDay: DateTime.utc(2010, 10, 16), + firstDay: DateTime.now(), lastDay: DateTime.utc(2030, 3, 14), locale: 'ru_RU', startingDayOfWeek: StartingDayOfWeek.monday, 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 db2ecc95..ae9bc696 100644 --- a/lib/features/diets/presentation/widgets/start_diet_bottom_sheet.dart +++ b/lib/features/diets/presentation/widgets/start_diet_bottom_sheet.dart @@ -1,5 +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/widgets/calendar_widget.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/core/theme/custom_text_style.dart'; @@ -8,8 +9,8 @@ import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:flutter/material.dart'; class StartDietBottomSheet extends StatelessWidget { - const StartDietBottomSheet({super.key}); - + const StartDietBottomSheet({super.key, required this.aboutDietCubit}); + final AboutDietCubit aboutDietCubit; @override Widget build(BuildContext context) { final s = S.of(context); @@ -45,6 +46,7 @@ class StartDietBottomSheet extends StatelessWidget { Padding( padding: EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28), child: CustomOutlinedButton( + onPressed: () {}, height: 60, text: s.startDiet, buttonTextStyle: TextStyles.textLSemibold.copyWith( diff --git a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart index ef4ecb2d..c299cdc0 100644 --- a/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart +++ b/lib/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:easy_debounce/easy_debounce.dart'; import 'package:eatvio_app/core/const.dart'; +import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:eatvio_app/features/diets/repositories/diet_repository.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart'; import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; @@ -164,21 +165,7 @@ class DietsCubit extends Cubit { Duration(milliseconds: 200), () async { try { - final dietLikeStateData = await dietsRepository.likeDiet(id); - final actualDiet = currentDiet.copyWith( - wasLikedByMe: dietLikeStateData.isLiked, - totalLikes: dietLikeStateData.totalLikes, - ); - dietsForModification[index] = actualDiet; - emit( - state.copyWith( - dietsList: [ - ...dietsForModification, - ], - isLoading: isLoading, - errorMessage: null, - ), - ); + await dietsRepository.likeDiet(id); } catch (e) { log(e.toString()); emit( @@ -274,19 +261,10 @@ class DietsCubit extends Cubit { Duration(milliseconds: 200), () async { try { - final diet = await dietsRepository.addToFavorite(id); - dietsForModification[index] = diet; - emit( - state.copyWith( - dietsList: [ - ...dietsForModification, - ], - isLoading: isLoading, - errorMessage: null, - ), - ); + await dietsRepository.addToFavorite(id); } catch (e) { log(e.toString()); + showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); emit( state.copyWith( dietsList: [ @@ -323,19 +301,10 @@ class DietsCubit extends Cubit { Duration(milliseconds: 200), () async { try { - final diet = await dietsRepository.removeFromFavorite(id); - dietsForModification[index] = diet; - emit( - state.copyWith( - dietsList: [ - ...dietsForModification, - ], - isLoading: isLoading, - errorMessage: null, - ), - ); + await dietsRepository.removeFromFavorite(id); } catch (e) { log(e.toString()); + showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); emit( state.copyWith( dietsList: [ diff --git a/lib/features/feed/presentation/widgets/sorting_drop_down_filter.dart b/lib/features/feed/presentation/widgets/sorting_drop_down_filter.dart index 65f7cdc8..ec85409d 100644 --- a/lib/features/feed/presentation/widgets/sorting_drop_down_filter.dart +++ b/lib/features/feed/presentation/widgets/sorting_drop_down_filter.dart @@ -26,7 +26,8 @@ class _SortingDropDownFilterState extends State { sortingTypes.add(s.popular); sortingTypes.add(s.most_new); sortingTypes.add(s.most_old); - sortingTypes.add(s.most_liked); + sortingTypes.add(s.from_a_to_z); + sortingTypes.add(s.from_z_to_a); } } diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 879c1f0f..41adcc0c 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -124,6 +124,8 @@ class MessageLookup extends MessageLookupByLibrary { "Имя обязательно для заполнения"), "first_name_short": MessageLookupByLibrary.simpleMessage( "В имени должен быть минимум 1 символ"), + "from_a_to_z": MessageLookupByLibrary.simpleMessage("Название: А-Я"), + "from_z_to_a": MessageLookupByLibrary.simpleMessage("Название: Я-А"), "gallery": MessageLookupByLibrary.simpleMessage("Галерея"), "gr": MessageLookupByLibrary.simpleMessage("гр"), "grams": MessageLookupByLibrary.simpleMessage("гр"), @@ -157,10 +159,6 @@ class MessageLookup extends MessageLookupByLibrary { "meat_type_desc": MessageLookupByLibrary.simpleMessage( "Диета с мясом полезная и сбалансированная. Включает в себя нежирное мясо: курицу, индейку, кролика или говядину. В сочетании с овощами получаете все необходимые витамины и минералы. Не забывайте о порциях и старайтесь есть медленно, прислушиваясь к своему организму."), "milliliter": MessageLookupByLibrary.simpleMessage("мл"), - "most_copleted": - MessageLookupByLibrary.simpleMessage("Больше всего пройденных"), - "most_liked": - MessageLookupByLibrary.simpleMessage("Больше всего лайкнутых"), "most_new": MessageLookupByLibrary.simpleMessage("Самые новые"), "most_old": MessageLookupByLibrary.simpleMessage("Самые старые"), "msg_network_err": diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 96da0e7e..4e94c27a 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -1440,21 +1440,21 @@ class S { ); } - /// `Больше всего лайкнутых` - String get most_liked { + /// `Название: А-Я` + String get from_a_to_z { return Intl.message( - 'Больше всего лайкнутых', - name: 'most_liked', + 'Название: А-Я', + name: 'from_a_to_z', desc: '', args: [], ); } - /// `Больше всего пройденных` - String get most_copleted { + /// `Название: Я-А` + String get from_z_to_a { return Intl.message( - 'Больше всего пройденных', - name: 'most_copleted', + 'Название: Я-А', + name: 'from_z_to_a', desc: '', args: [], ); diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index bd0fd888..e522522c 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -138,8 +138,8 @@ "popular": "Популярные", "most_new": "Самые новые", "most_old": "Самые старые", - "most_liked": "Больше всего лайкнутых", - "most_copleted": "Больше всего пройденных", + "from_a_to_z": "Название: А-Я", + "from_z_to_a": "Название: Я-А", "by_default": "По умолчянию", "create_diet": "Создание диеты", "enter_diet_name": "Выведите название диеты", diff --git a/lib/main.dart b/lib/main.dart index ddbacf93..c17baa7c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_portal/flutter_portal.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; void main() async { diff --git a/test/auth_test.dart b/test/auth_test.dart index 5058e6aa..626a1ce1 100644 --- a/test/auth_test.dart +++ b/test/auth_test.dart @@ -7,6 +7,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; + void main() { group('AuthScreen', () { testWidgets('renders AuthScreen with initial state', (WidgetTester tester) async {