import 'dart:developer'; import 'package:dio/dio.dart'; 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/plans/enums/plan_option_type_enum.dart'; import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart'; import 'package:eatvio_app/features/plans/presentation/cubit/about_plan_state.dart'; import 'package:eatvio_app/features/plans/repositories/plan_repository.dart'; import 'package:eatvio_app/features/profile/models/chosen_diets_pagination_model.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:eatvio_app/core/error_reporting/report_from.dart'; class AboutPlanCubit extends Cubit { final PlanRepository planRepository; final ProfileRepository profileRepository; final DietRepository dietRepository; AboutPlanCubit({ required this.planRepository, required this.profileRepository, required this.dietRepository, }) : super(AboutPlanState.initial()); Future getPlan({required String slug, int? index}) async { try { final plan = await planRepository.getPlan(slug); if (index != null) { planRepository.emitCommentsStateToFeed(CommentsState(index: index, totalComments: plan.totalComments)); } emit(state.copyWith(planModel: plan, error: null)); } catch (e, stackTrace) { await reportFrom(e, stackTrace, this); log(e.toString(), stackTrace: stackTrace); emit(state.copyWith(error: e.toString(), isLoading: false)); } } Future getPlanWithLoading(String slug) async { try { emit(state.copyWith(isLoading: true)); final plan = await planRepository.getPlan(slug); emit(state.copyWith(planModel: plan, error: null, isLoading: false)); } catch (e, stackTrace) { await reportFrom(e, stackTrace, this); log(e.toString(), stackTrace: stackTrace); emit(state.copyWith(error: e.toString(), isLoading: false)); } } void choseOption(int index) { emit(state.copyWith(chosenOptionIndex: index)); } Future likePlan({required int? index, required String slug}) async { final currentPlan = state.planModel; if (currentPlan == null) return; if (currentPlan.wasLikedByMe) { emit(state.copyWith(planModel: currentPlan.copyWith(wasLikedByMe: false, totalLikes: currentPlan.totalLikes - 1), error: null)); if (index != null) { planRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: false, totalLikes: currentPlan.totalLikes - 1, index: index)); } } else { emit(state.copyWith(planModel: currentPlan.copyWith(wasLikedByMe: true, totalLikes: currentPlan.totalLikes + 1), error: null)); if (index != null) { planRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: true, totalLikes: currentPlan.totalLikes + 1, index: index)); } } EasyDebounce.debounce('like_plan_$slug', const Duration(seconds: 1), () async { try { await planRepository.likePlan(slug); } catch (e, st) { await reportFrom(e, st, this); log(e.toString()); if (index != null) { planRepository.emitLikesStateToFeed(LikesState(wasLikedByMe: currentPlan.wasLikedByMe, totalLikes: currentPlan.totalLikes, index: index)); } emit(state.copyWith(planModel: currentPlan, error: null)); } }); } Future addToFavorite({required String slug, required int? index}) async { final currentPlan = state.planModel; if (currentPlan == null) return; emit(state.copyWith(planModel: currentPlan.copyWith(isFavorite: true))); if (index != null) { planRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: true, index: index)); } EasyDebounce.debounce('add_or_remove_plan_to_favorites', const Duration(seconds: 1), () async { try { await planRepository.addToFavorite(slug); } catch (e, st) { await reportFrom(e, st, this); log(e.toString()); showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); if (index != null) { planRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentPlan.isFavorite, index: index)); } emit(state.copyWith(planModel: currentPlan, error: null)); } }); } Future removeFromFavorite({required String slug, required int? index}) async { final currentPlan = state.planModel; if (currentPlan == null) return; emit(state.copyWith(planModel: currentPlan.copyWith(isFavorite: false))); if (index != null) { planRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: false, index: index)); } EasyDebounce.debounce('add_or_remove_plan_to_favorites', const Duration(seconds: 1), () async { try { await planRepository.removeFromFavorite(slug); } catch (e, st) { await reportFrom(e, st, this); log(e.toString()); showErrorToast('Произошла ошибка. Попробуйте ещё раз через некоторое время'); if (index != null) { planRepository.emitFavoriteStateToFeed(FavoriteState(isFavorite: currentPlan.isFavorite, index: index)); } emit(state.copyWith(planModel: currentPlan, error: null)); } }); } Future<(ChosenPlanModel?, String?)> chosePlan() async { try { final slug = state.planModel?.slug; final optionIndex = state.chosenOptionIndex; if (slug != null) { final optionName = PlanOptionType.fromIndex(optionIndex).apiValue; final body = {'options_type': optionName}; return (await planRepository.chosePlan(slug, body), null); } } on DioException catch (e, st) { await reportFrom(e, st, this); if (e.response?.statusCode == 400) { return (null, 'hasPlan'); } log(e.toString(), stackTrace: st); } catch (e, st) { await reportFrom(e, st, this); log(e.toString(), stackTrace: st); } return (null, ''); } /// Активная публичная диета (без привязки к плану) в статусах inited/started. Future getActivePublicDiet() async { try { final chosenDiets = await profileRepository.getChosenDiets(); final lastChosenDiet = chosenDiets.firstOrNull; if (lastChosenDiet == null) { return null; } final isActive = ['inited', 'started'].contains(lastChosenDiet.state); final isPublic = lastChosenDiet.chosenPlanId == 0; if (isActive && isPublic && lastChosenDiet.dietId != null) { return lastChosenDiet; } return null; } catch (e, st) { await reportFrom(e, st, this); log(e.toString(), stackTrace: st); return null; } } Future cancelPublicDiet(int dietId) async { try { await dietRepository.cancelDiet(dietId); return true; } catch (e, st) { await reportFrom(e, st, this); log(e.toString(), stackTrace: st); return false; } } }