import 'dart:async'; import 'dart:developer'; import 'package:dio/dio.dart'; import 'package:easy_debounce/easy_debounce.dart'; import 'package:eatvio_app/core/utils/date_time_utils.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/cubit/about_diet_state.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class AboutDietCubit extends Cubit { AboutDietCubit({required this.dietsRepository, required this.profileRepository}) : super(AboutDietState.initial()); final DietRepository dietsRepository; final ProfileRepository profileRepository; bool isCurrentDietStarted = false; bool hasStartedDiet = false; String? userStartedDietName; Future getDiet(int id, {int? index}) async { try { final diet = await dietsRepository.getDiet(id); if (index != null) { dietsRepository.emitCommentsStateToFeed(CommentsState(index: index, totalComments: diet.totalComments)); } emit(AboutDietState.loaded(diet: diet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } catch (e) { log(e.toString()); emit(AboutDietState.error(message: e.toString())); } } Future initDietPage(int id) async { try { emit(AboutDietState.loading()); final diet = await dietsRepository.getDiet(id); final chosenDiets = await profileRepository.getChosenDiets(); final lastChosenDiet = chosenDiets.firstOrNull; if (lastChosenDiet != null && ['inited', 'started'].contains(lastChosenDiet.state)) { hasStartedDiet = true; if (diet.id == lastChosenDiet.dietId) { isCurrentDietStarted = true; } else { if (lastChosenDiet.dietId != null) { final chosenDiet = await dietsRepository.getDiet(lastChosenDiet.dietId!); userStartedDietName = chosenDiet.name; } } } emit(AboutDietState.loaded(diet: diet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } catch (e) { log(e.toString()); emit(AboutDietState.error(message: e.toString())); } } Future likeDiet(int id, int? dietIndexInFeed) async { if (state is! DietStateLoaded) return; final currentDiet = (state as DietStateLoaded).diet; if (currentDiet.wasLikedByMe) { final updatedDiet = currentDiet.copyWith( totalLikes: currentDiet.totalLikes - 1, wasLikedByMe: false, ); if (dietIndexInFeed != null) { dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed)); } emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } else { final updatedDiet = currentDiet.copyWith( totalLikes: currentDiet.totalLikes + 1, wasLikedByMe: true, ); if (dietIndexInFeed != null) { dietsRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed)); } emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } EasyDebounce.debounce( 'like_diet', Duration(seconds: 1), () async { try { await dietsRepository.likeDiet(id); } catch (e) { log(e.toString()); if (dietIndexInFeed != null) { dietsRepository .emitLikesStateToFeed(LikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed)); } emit(AboutDietState.loaded(diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } }, ); } Future addToFavorite(int id, int? dietIndex) async { if (state is! DietStateLoaded) return; final currentDiet = (state as DietStateLoaded).diet; final updatedDiet = currentDiet.copyWith( isFavorite: true, ); if (dietIndex != null) { dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex)); } emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); EasyDebounce.debounce( 'add_or_remove_diet_to_favorites', Duration(seconds: 1), () async { try { await dietsRepository.addToFavorite(id); } catch (e) { log(e.toString()); showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); if (dietIndex != null) { dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex)); } emit(AboutDietState.loaded(diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } }, ); } Future removeFromFavorite(int id, int? dietIndex) async { if (state is! DietStateLoaded) return; final currentDiet = (state as DietStateLoaded).diet; final updatedDiet = currentDiet.copyWith( isFavorite: false, ); if (dietIndex != null) { dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndex)); } emit(AboutDietState.loaded(diet: updatedDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); EasyDebounce.debounce( 'add_or_remove_diet_to_favorites', Duration(seconds: 1), () async { try { await dietsRepository.removeFromFavorite(id); } catch (e) { log(e.toString()); showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); if (dietIndex != null) { dietsRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndex)); } emit(AboutDietState.loaded(diet: currentDiet, isStarted: isCurrentDietStarted, hasStartedDiet: hasStartedDiet)); } }, ); } Future startDiet(DateTime date) async { try { if (state is! DietStateLoaded) return false; final id = (state as DietStateLoaded).diet.id; final stringDate = date.format('yyyy-MM-dd'); await dietsRepository.startDiet(id, stringDate); return true; } catch (e, st) { log(e.toString(), stackTrace: st); return false; } } Future cancelDiet() async { try { if (state is! DietStateLoaded) return false; final id = (state as DietStateLoaded).diet.id; await dietsRepository.cancelDiet(id); return true; } on DioException catch (e) { log(e.toString()); return false; } catch (e) { log(e.toString()); return false; } } void clearStartedDietsState() { if (state is! DietStateLoaded) return; final diet = (state as DietStateLoaded).diet; emit(AboutDietState.loaded(diet: diet)); } void emitCurrentStartedDietsState() { if (state is! DietStateLoaded) return; final diet = (state as DietStateLoaded).diet; emit(AboutDietState.loaded(diet: diet, isStarted: true)); } }