forked from eatvio/eatvio_app
423 lines
16 KiB
Dart
423 lines
16 KiB
Dart
import 'dart:developer';
|
|
import 'dart:io';
|
|
|
|
import 'package:dio/dio.dart';
|
|
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/entities/diary_day_entity.dart';
|
|
import 'package:eatvio_app/features/diary/entities/diary_future_diet_day_entity.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<DiaryState> {
|
|
late final DateTime today;
|
|
late DateTime selectedDay;
|
|
int selectedMeal = 1;
|
|
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((_) {
|
|
fetchDiaryV2(needLoading: true, diaryId: diaryId);
|
|
});
|
|
}
|
|
|
|
String comment = '';
|
|
|
|
Future<bool> setSelectedDay(DateTime day) async {
|
|
final prevDay = selectedDay;
|
|
final prevMeal = selectedMeal;
|
|
selectedDay = day;
|
|
selectedMeal = 1;
|
|
final canSelect = await fetchDiaryV2(needLoading: true);
|
|
|
|
if (!canSelect) {
|
|
selectedDay = prevDay;
|
|
selectedMeal = prevMeal;
|
|
}
|
|
|
|
return canSelect;
|
|
}
|
|
|
|
Future<bool> fetchDiaryV2({bool needLoading = false, int? diaryId}) async {
|
|
final currentState = state;
|
|
try {
|
|
if (needLoading) {
|
|
emit(const DiaryState.loading());
|
|
}
|
|
if (diaryId != null) {
|
|
final diaryDayById = await diaryRepository.getDiaryDay(diaryId);
|
|
final diaryEntity = diaryDayById.toEntity();
|
|
if (diaryEntity != null) {
|
|
setDiary(diaryDay: diaryEntity, diaryId: diaryId);
|
|
return true;
|
|
}
|
|
}
|
|
final diaryDay = await getDiary();
|
|
if (diaryDay == null) {
|
|
emit(const DiaryState.error(errorMessage: 'Diary not found'));
|
|
return true;
|
|
}
|
|
|
|
final diaryEntity = diaryDay.toEntity();
|
|
if (diaryEntity != null) {
|
|
setDiary(diaryDay: diaryEntity, diaryId: diaryId);
|
|
return true;
|
|
}
|
|
if (diaryDay.typeOfDiary.hasChosenDiet == true && diaryDay.typeOfDiary.diaryState == null) {
|
|
setDiaryForDietOnly(diaryDay.toDiaryFutureDayEntity());
|
|
return true;
|
|
}
|
|
emit(currentState);
|
|
return false;
|
|
} catch (e, st) {
|
|
log(e.toString(), stackTrace: st);
|
|
emit(DiaryState.error(errorMessage: e.toString()));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<void> updateCurrentDiary() async {
|
|
try {
|
|
final diaryDay = await diaryRepository.getDiaryDayV2(day: selectedDay.toISO8601WithTimeZoneOffset());
|
|
final diaryEntity = diaryDay.toEntity();
|
|
if (diaryEntity != null) {
|
|
setDiary(diaryDay: diaryEntity, diaryId: diaryId);
|
|
}
|
|
} catch (e) {
|
|
log(e.toString());
|
|
}
|
|
}
|
|
|
|
Future<DiaryDayModel?> getDiary() async {
|
|
try {
|
|
await diaryRepository.createDiaryDay(day: selectedDay.toISO8601WithTimeZoneOffset());
|
|
final diaryDay = await diaryRepository.getDiaryDayV2(day: selectedDay.toISO8601WithTimeZoneOffset());
|
|
return diaryDay;
|
|
} catch (e, st) {
|
|
log(e.toString(), stackTrace: st);
|
|
if (e is DioException) {
|
|
if (e.response?.statusCode == 422) {
|
|
final diaryDay = await diaryRepository.getDiaryDayV2(day: selectedDay.toISO8601WithTimeZoneOffset());
|
|
return diaryDay;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
void 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<bool> setDiaryForDietOnly(DiaryFutureDietDayEntity diaryDay) async {
|
|
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;
|
|
}
|
|
|
|
Future<void> setDiary({int? diaryId, required DiaryDayEntity diaryDay}) async {
|
|
this.diaryId ??= diaryId;
|
|
final isConsultantView = this.diaryId != null;
|
|
try {
|
|
bool isMoodEnabled = false;
|
|
bool isWakeUpAndRetireTimeEnabled = false;
|
|
if (diaryId != null) {
|
|
} else {
|
|
final profileSettings = await settingsRepository.getProfileSettings();
|
|
isMoodEnabled = profileSettings.isMoodFillable;
|
|
isWakeUpAndRetireTimeEnabled = profileSettings.isBedtimeFillable;
|
|
}
|
|
ConsultantReviewModel? consultantReview;
|
|
int? planDuration;
|
|
int? currentPlanDay;
|
|
String? planName;
|
|
if (diaryDay.chosenPlanId != null) {
|
|
final chosenPlanModel = await chatRepository.getChosenPlan(id: diaryDay.chosenPlanId!);
|
|
if (!isConsultantView &&
|
|
(diaryDay.typeOfDiary.diaryState == DiaryStateEnum.lastDayCommented || diaryDay.typeOfDiary.diaryState == DiaryStateEnum.commented)) {
|
|
await diaryRepository.viewCommentOfDiaryDayByConsultant(diaryId: diaryDay.id);
|
|
}
|
|
consultantReview = await diaryRepository.getDiaryComments(planId: diaryDay.chosenPlanId!, diaryId: diaryDay.id);
|
|
planDuration = chosenPlanModel.plan.duration;
|
|
planName = chosenPlanModel.plan.name;
|
|
currentPlanDay = consultantReview.currentPlanDay;
|
|
}
|
|
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: isConsultantView,
|
|
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()));
|
|
}
|
|
}
|
|
|
|
Future<void> 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 updateCurrentDiary();
|
|
}
|
|
|
|
Future<NutritionDataModel> getNutrition(int index) async {
|
|
return (await diaryRepository.getNutritionData(index));
|
|
}
|
|
|
|
Future<void> addProductToMeal({
|
|
required int diaryId,
|
|
required int mealId,
|
|
required String productName,
|
|
required String portion,
|
|
required int quantity,
|
|
int? productNutritionalValueId,
|
|
}) async {
|
|
emit((state as DiaryStateLoaded).copyWith(isLoadingAddingProductInMeal: true));
|
|
await diaryRepository.addPortionToMeal(
|
|
diaryId: diaryId,
|
|
mealId: mealId,
|
|
productName: productName,
|
|
portion: portion,
|
|
quantity: quantity,
|
|
productNutritionalValueId: productNutritionalValueId,
|
|
);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> 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 updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> markEaten({required int diaryId, required int mealId, required int portionId}) async {
|
|
await diaryRepository.markEaten(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> unmarkEaten({required int diaryId, required int mealId, required int portionId}) async {
|
|
await diaryRepository.unmarkEaten(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> restore({required int diaryId, required int mealId, required int portionId}) async {
|
|
await diaryRepository.restore(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> deleteProductFromMeal({required int diaryId, required int mealId, required int portionId}) async {
|
|
await diaryRepository.deleteProductFromMeal(diaryId: diaryId, mealId: mealId, portionId: portionId);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<List<GlossaryModel>> getGlossaryListByQuery(String query) async {
|
|
return await glossaryRepository.getGlossaryListByQuery(query);
|
|
}
|
|
|
|
Future<void> uploadPhotos({required List<File> files, required int diaryId}) async {
|
|
await diaryRepository.uploadPhotos(files: await ImageCompressUtility.compressFilesList(files), diaryId: diaryId, mealId: selectedMeal);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> deletePhoto({required DiaryPhotoModel photo, required int diaryId}) async {
|
|
await diaryRepository.deletePhoto(photo: photo, diaryId: diaryId, mealId: selectedMeal);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<GlossaryModerationModel?> 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;
|
|
}
|
|
|
|
Future<void> fillTime({required int diaryId, required String time}) async {
|
|
await diaryRepository.fillTime(diaryId: diaryId, mealId: selectedMeal, time: time);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> fillWakeup({required int diaryId, required String time}) async {
|
|
await diaryRepository.fillWakeup(diaryId: diaryId, time: time);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> fillRetire({required int diaryId, required String time}) async {
|
|
await diaryRepository.fillRetire(diaryId: diaryId, time: time);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> fillSatiety({required int diaryId, required int satiety}) async {
|
|
await diaryRepository.fillSatiety(diaryId: diaryId, mealId: selectedMeal, satiety: satiety);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
Future<void> fillMood({required int diaryId, required int mood}) async {
|
|
await diaryRepository.fillMood(diaryId: diaryId, mealId: selectedMeal, mood: mood);
|
|
await updateCurrentDiary();
|
|
}
|
|
|
|
void fillComment(String comment) {
|
|
this.comment = comment;
|
|
}
|
|
}
|
|
|
|
enum DiaryFetchingErrors { canNotCreateFutureDays, dayAlreadyExists }
|