import 'dart:developer'; import 'dart:io'; import 'package:eatvio_app/core/image_compressing/image_compress_utility.dart'; import 'package:eatvio_app/core/utils/date_time_utils.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/consultations/models/consultation_model.dart'; import 'package:eatvio_app/features/diary/models/consultant_review_model.dart'; import 'package:eatvio_app/features/diary/models/diary_day_model.dart'; import 'package:eatvio_app/features/diary/models/nutrition_model.dart'; import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart'; import 'package:eatvio_app/features/diary/repositories/diary_repository.dart'; import 'package:eatvio_app/features/diets/repositories/diet_repository.dart'; import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:eatvio_app/features/settings/repositories/service_repository.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class DiaryCubit extends Cubit { late final DateTime today; late DateTime selectedDay; late int selectedMeal; final DiaryRepository diaryRepository; final GlossaryRepository glossaryRepository; final ProfileRepository profileRepository; final DietRepository dietRepository; final ChatRepository chatRepository; final SettingsRepository settingsRepository; int? diaryId; DiaryCubit({ required this.chatRepository, required this.diaryRepository, required this.glossaryRepository, required this.profileRepository, required this.dietRepository, required this.settingsRepository, }) : super(const DiaryState.loading()) { today = DateTime.now(); selectedDay = today; diaryRepository.forceFetchStream.listen((_) { fetchDiary(true, diaryId); }); } String comment = ''; Future setSelectedDay(DateTime day, {bool? forDietOnly}) async { selectedDay = day; if (forDietOnly ?? false) { final result = await fetchDiaryForDietOnly(); return result; } await fetchDiary(true); return null; } setSelectedMeal(int meal) { selectedMeal = meal; final currentState = state; if (currentState is DiaryStateLoaded) { emit(currentState.copyWith(selectedMeal: selectedMeal)); } else if (currentState is DiaryStateLoadedTomorrowWithDiet) { emit(currentState.copyWith(selectedMeal: selectedMeal)); } } Future fetchDiaryForDietOnly() async { final stringDate = selectedDay.format('yyyy-MM-dd'); final diaryDay = await diaryRepository.getDiaryByDateForDietOnly(stringDate); if (!diaryDay.typeOfDiary.hasChosenDiet) { return false; } emit(const DiaryState.loading()); if (diaryDay.diet?.id != null && diaryDay.dayOfChosenDiet != null) { final diet = await dietRepository.getDiet((diaryDay.diet?.id)!); final meals = diet.dailySchedule[diaryDay.dayOfChosenDiet]; final firstMealPortions = meals?[1]?.values.map((elem) { return PortionModel( id: 0, productName: elem.name, quantity: elem.quantity, portion: elem.portion.getValue(), fromDiet: true, portionState: PortionState.filledDiet, ); }).toList(); final secondMealPortions = meals?[2]?.values.map((elem) { return PortionModel( id: 0, productName: elem.name, quantity: elem.quantity, portion: elem.portion.getValue(), fromDiet: true, portionState: PortionState.filledDiet, ); }).toList(); final thirdMealPortions = meals?[3]?.values.map((elem) { return PortionModel( id: 0, productName: elem.name, quantity: elem.quantity, portion: elem.portion.getValue(), fromDiet: true, portionState: PortionState.filledDiet, ); }).toList(); final fourthMealPortions = meals?[4]?.values.map((elem) { return PortionModel( id: 0, productName: elem.name, quantity: elem.quantity, portion: elem.portion.getValue(), fromDiet: true, portionState: PortionState.filledDiet, ); }).toList(); final fifthMealPortions = meals?[5]?.values.map((elem) { return PortionModel( id: 0, productName: elem.name, quantity: elem.quantity, portion: elem.portion.getValue(), fromDiet: true, portionState: PortionState.filledDiet, ); }).toList(); final firstMeal = MealModel(id: 0, time: '0', typeNumber: 1, satiety: 0, mood: 0, portions: firstMealPortions ?? [], photos: []); final secondMeal = MealModel(id: 0, time: '0', typeNumber: 2, satiety: 0, mood: 0, portions: secondMealPortions ?? [], photos: []); final thirdMeal = MealModel(id: 0, time: '0', typeNumber: 3, satiety: 0, mood: 0, portions: thirdMealPortions ?? [], photos: []); final fourthMeal = MealModel(id: 0, time: '0', typeNumber: 4, satiety: 0, mood: 0, portions: fourthMealPortions ?? [], photos: []); final fifthMeal = MealModel(id: 0, time: '0', typeNumber: 5, satiety: 0, mood: 0, portions: fifthMealPortions ?? [], photos: []); emit( DiaryState.loadedTomorrowWithDiet( diary: diaryDay.copyWith( meals: [ firstMeal, secondMeal, thirdMeal, fourthMeal, fifthMeal, ], ), selectedDay: selectedDay, selectedMeal: selectedMeal, ), ); return true; } return false; } fetchDiary([bool needLoading = false, int? diaryId, int? currentDay]) async { this.diaryId ??= diaryId; if (needLoading) { emit(const DiaryState.loading()); selectedMeal = 1; } try { final DiaryDayModel diaryDay; bool isMoodEnabled = false; bool isWakeUpAndRetireTimeEnabled = false; if (diaryId != null) { diaryDay = await diaryRepository.getDiaryDay(diaryId); } else { final stringDate = selectedDay.format('yyyy-MM-dd'); diaryDay = await diaryRepository.getDiaryByDate(stringDate); final profileSettings = await settingsRepository.getProfileSettings(); isMoodEnabled = profileSettings.isMoodFillable; isWakeUpAndRetireTimeEnabled = profileSettings.isBedtimeFillable; } ConsultantReviewModel? consultantReview; int? planDuration; int? currentPlanDay; String? planName; if (diaryDay.chosenPlanId != null) { consultantReview = await diaryRepository.getDiaryComments(planId: diaryDay.chosenPlanId!, diaryId: diaryDay.id); final chosenPlanModel = await chatRepository.getChosenPlan(id: diaryDay.chosenPlanId!); planDuration = chosenPlanModel.plan.duration; planName = chosenPlanModel.plan.name; currentPlanDay = currentDay ?? DateTime.now().difference(chosenPlanModel.startDate).inDays + 1; } final nutrition = await getNutrition(diaryDay.id); final isDiaryFinished = diaryDay.typeOfDiary.diaryState == DiaryStateEnum.finished || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayFinished; final isDiaryCommented = diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayCommented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.reviewedByUser; emit( DiaryState.loaded( diary: diaryDay, nutrition: nutrition, selectedDay: selectedDay, selectedMeal: selectedMeal, isConsultantView: this.diaryId != null, consultantReview: consultantReview, isDiaryFinished: isDiaryFinished, isDiaryCommented: isDiaryCommented, chosenPlanCurrentDay: currentPlanDay, chosenPlanDuration: planDuration, chosenPlanName: planName, isMoodEnabled: isMoodEnabled, isWakeUpAndRetireEnabled: isWakeUpAndRetireTimeEnabled ), ); } catch (e, st) { log(e.toString(), stackTrace: st); emit(DiaryState.error(errorMessage: e.toString())); } } finishDiaryDay({ required int diaryId, required String wakeUp, required String retire, }) async { await diaryRepository.finishDiaryDay( diaryId: diaryId, wakeUp: wakeUp, retire: retire, comment: comment.isEmpty ? null : comment, ); await fetchDiary(); } Future getNutrition(int index) async { return (await diaryRepository.getNutritionData(index)); } addProductToMeal({ required int diaryId, required int mealId, required String productName, required String portion, required int quantity, int? productNutritionalValueId, }) async { await diaryRepository.addPortionToMeal( diaryId: diaryId, mealId: mealId, productName: productName, portion: portion, quantity: quantity, productNutritionalValueId: productNutritionalValueId, ); await fetchDiary(); } updateProductInMeal({ required int diaryId, required int mealId, required int portionId, required String productName, required String portion, required int quantity, int? productNutritionalValueId, required PortionState portionState, }) async { if (portionState == PortionState.filledDiet || portionState == PortionState.eatenFromDiet) { await diaryRepository.addPortionToMeal( diaryId: diaryId, mealId: mealId, productName: productName, portion: portion, quantity: quantity, productNutritionalValueId: productNutritionalValueId, ); } else { await diaryRepository.updateProductInMeal( diaryId: diaryId, mealId: mealId, portionId: portionId, productName: productName, portion: portion, quantity: quantity, productNutritionalValueId: productNutritionalValueId, portionState: portionState, ); } await fetchDiary(); } markEaten({required int diaryId, required int mealId, required int portionId}) async { await diaryRepository.markEaten(diaryId: diaryId, mealId: mealId, portionId: portionId); await fetchDiary(); } unmarkEaten({required int diaryId, required int mealId, required int portionId}) async { await diaryRepository.unmarkEaten(diaryId: diaryId, mealId: mealId, portionId: portionId); await fetchDiary(); } restore({required int diaryId, required int mealId, required int portionId}) async { await diaryRepository.restore(diaryId: diaryId, mealId: mealId, portionId: portionId); await fetchDiary(); } deleteProductFromMeal({required int diaryId, required int mealId, required int portionId}) async { await diaryRepository.deleteProductFromMeal(diaryId: diaryId, mealId: mealId, portionId: portionId); await fetchDiary(); } Future> getGlossaryListByQuery(String query) async { return await glossaryRepository.getGlossaryListByQuery(query); } uploadPhotos({required List files, required int diaryId}) async { await diaryRepository.uploadPhotos(files: await ImageCompressUtility.compressFilesList(files), diaryId: diaryId, mealId: selectedMeal); await fetchDiary(); } deletePhoto({required DiaryPhotoModel photo, required int diaryId}) async { await diaryRepository.deletePhoto(photo: photo, diaryId: diaryId, mealId: selectedMeal); await fetchDiary(); } Future sendProductToModeration({ required String name, required double energy, required double proteins, required double fats, required double carbohydrates, }) async { try { return await diaryRepository.sendProductToModeration(name: name, energy: energy, proteins: proteins, fats: fats, carbohydrates: carbohydrates); } catch (e, stackTrace) { log(e.toString(), stackTrace: stackTrace); } return null; } fillTime({required int diaryId, required String time}) async { await diaryRepository.fillTime(diaryId: diaryId, mealId: selectedMeal, time: time); await fetchDiary(); } fillWakeup({required int diaryId, required String time}) async { await diaryRepository.fillWakeup(diaryId: diaryId, time: time); await fetchDiary(); } fillRetire({required int diaryId, required String time}) async { await diaryRepository.fillRetire(diaryId: diaryId, time: time); await fetchDiary(); } fillSatiety({required int diaryId, required int satiety}) async { await diaryRepository.fillSatiety(diaryId: diaryId, mealId: selectedMeal, satiety: satiety); await fetchDiary(); } fillMood({required int diaryId, required int mood}) async { await diaryRepository.fillMood(diaryId: diaryId, mealId: selectedMeal, mood: mood); await fetchDiary(); } fillComment(String comment) { this.comment = comment; } }