forked from eatvio/eatvio_app
436 lines
16 KiB
Dart
436 lines
16 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'package:eatvio_app/features/diary/models/consultant_comment_model.dart';
|
|
import 'package:eatvio_app/features/diary/models/consultant_review_model.dart';
|
|
import 'package:eatvio_app/features/diary/models/create_day_model.dart';
|
|
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
|
import 'package:eatvio_app/features/diary/models/finish_diary_day_model.dart';
|
|
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
|
|
import 'package:eatvio_app/features/diary/models/product_moderation_model.dart';
|
|
import 'package:eatvio_app/features/diary/services/diary_service.dart';
|
|
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
|
|
|
class DiaryRepository {
|
|
final DiaryService diaryService;
|
|
final StreamController<String> _diaryForceFetchController = StreamController<String>.broadcast();
|
|
|
|
Stream<String> get forceFetchStream => _diaryForceFetchController.stream;
|
|
|
|
DiaryRepository({required this.diaryService});
|
|
|
|
Future<DiaryDayModel> getDiaryByDate(String date) async {
|
|
try {
|
|
Set<int> ids = {};
|
|
final diaryDays = await getDiaryIndexByDate(date);
|
|
if (diaryDays.isEmpty) {
|
|
throw Exception('No diary entry found for $date');
|
|
}
|
|
final DiaryDayModel diaryDay = diaryDays.last;
|
|
for (var meal in diaryDay.meals) {
|
|
for (var portion in meal.portions) {
|
|
if (portion.productNutritionalValueId != null) {
|
|
ids.add(portion.productNutritionalValueId!);
|
|
}
|
|
}
|
|
}
|
|
if (ids.isNotEmpty) {
|
|
final glossary = await getGlossariesIndex(ids: ids.toList());
|
|
final List<MealModel> updatedMeals = List.from(diaryDay.meals);
|
|
for (var mealIndex = 0; mealIndex < updatedMeals.length; mealIndex++) {
|
|
final meal = updatedMeals[mealIndex];
|
|
final updatedPortions = meal.portions.map((portion) {
|
|
if (portion.productNutritionalValueId != null) {
|
|
try {
|
|
final glossaryItem = glossary.glossariesList.firstWhere((g) => g.id == portion.productNutritionalValueId);
|
|
return portion.copyWith(
|
|
productCaloriesInfo: ProductCaloriesInfoModel(
|
|
id: glossaryItem.id,
|
|
productName: glossaryItem.name,
|
|
calories: glossaryItem.energyOn100Gr,
|
|
proteins: glossaryItem.proteinsOn100Gr,
|
|
fats: glossaryItem.fatsOn100Gr,
|
|
carbohydrates: glossaryItem.carbohydratesOn100Gr,
|
|
energyOnPortion: glossaryItem.energyOnPortion,
|
|
proteinsOnPortion: glossaryItem.proteinsOnPortion,
|
|
fatsOnPortion: glossaryItem.fatsOnPortion,
|
|
carbohydratesOnPortion: glossaryItem.carbohydratesOnPortion,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
return portion;
|
|
}
|
|
}
|
|
return portion;
|
|
}).toList();
|
|
|
|
updatedMeals[mealIndex] = meal.copyWith(portions: updatedPortions);
|
|
}
|
|
final updatedDiaryDay = diaryDay.copyWith(meals: updatedMeals);
|
|
return updatedDiaryDay;
|
|
}
|
|
return diaryDay;
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<List<DiaryDayModel>> getDiaryIndexByDate(String date) async {
|
|
try {
|
|
return (await diaryService.getDiaryIndexByDate(date: date));
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<DiaryDayModel> getDiaryDay(int diaryId) async {
|
|
try {
|
|
// Align with getDiaryByDate: enrich portions with glossary nutritional info
|
|
final diaryWrapper = await diaryService.getDiaryDay(diary: diaryId);
|
|
final DiaryDayModel diaryDay = diaryWrapper.diary;
|
|
Set<int> ids = {};
|
|
for (var meal in diaryDay.meals) {
|
|
for (var portion in meal.portions) {
|
|
if (portion.productNutritionalValueId != null) {
|
|
ids.add(portion.productNutritionalValueId!);
|
|
}
|
|
}
|
|
}
|
|
if (ids.isNotEmpty) {
|
|
final glossary = await getGlossariesIndex(ids: ids.toList());
|
|
final List<MealModel> updatedMeals = List.from(diaryDay.meals);
|
|
for (var mealIndex = 0; mealIndex < updatedMeals.length; mealIndex++) {
|
|
final meal = updatedMeals[mealIndex];
|
|
final updatedPortions = meal.portions.map((portion) {
|
|
if (portion.productNutritionalValueId != null) {
|
|
try {
|
|
final glossaryItem = glossary.glossariesList.firstWhere((g) => g.id == portion.productNutritionalValueId);
|
|
return portion.copyWith(
|
|
productCaloriesInfo: ProductCaloriesInfoModel(
|
|
id: glossaryItem.id,
|
|
productName: glossaryItem.name,
|
|
calories: glossaryItem.energyOn100Gr,
|
|
proteins: glossaryItem.proteinsOn100Gr,
|
|
fats: glossaryItem.fatsOn100Gr,
|
|
carbohydrates: glossaryItem.carbohydratesOn100Gr,
|
|
energyOnPortion: glossaryItem.energyOnPortion,
|
|
proteinsOnPortion: glossaryItem.proteinsOnPortion,
|
|
fatsOnPortion: glossaryItem.fatsOnPortion,
|
|
carbohydratesOnPortion: glossaryItem.carbohydratesOnPortion,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
return portion;
|
|
}
|
|
}
|
|
return portion;
|
|
}).toList();
|
|
|
|
updatedMeals[mealIndex] = meal.copyWith(portions: updatedPortions);
|
|
}
|
|
final updatedDiaryDay = diaryDay.copyWith(meals: updatedMeals);
|
|
return updatedDiaryDay;
|
|
}
|
|
return diaryDay;
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<NutritionDataModel> getNutritionData(int index) async {
|
|
try {
|
|
return await diaryService.getNutrition(diary: index);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> addPortionToMeal({
|
|
required int diaryId,
|
|
required int mealId,
|
|
required String productName,
|
|
required String portion,
|
|
required int quantity,
|
|
int? productNutritionalValueId,
|
|
}) async {
|
|
try {
|
|
return await diaryService.addProductToMeal(
|
|
diary: diaryId,
|
|
typeNo: mealId,
|
|
productName: productName,
|
|
portion: portion,
|
|
quantity: quantity,
|
|
productNutritionalValueId: productNutritionalValueId,
|
|
);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
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 {
|
|
try {
|
|
Map<String, Object?> data = ProductInMeal(productName: productName, portion: portion, quantity: quantity).toJson();
|
|
if (productNutritionalValueId != null) data['product_nutritional_value_id'] = productNutritionalValueId;
|
|
data['state'] = portionState.name;
|
|
return await diaryService.updateProductInMeal(diary: diaryId, typeNo: mealId, portionModel: portionId, productInMeal: data);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> markEaten({required int diaryId, required int mealId, required int portionId}) async {
|
|
try {
|
|
return await diaryService.markEaten(diary: diaryId, typeNo: mealId, portionModel: portionId);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> unmarkEaten({required int diaryId, required int mealId, required int portionId}) async {
|
|
try {
|
|
return await diaryService.unmarkEaten(diary: diaryId, typeNo: mealId, portionModel: portionId);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> restore({required int diaryId, required int mealId, required int portionId}) async {
|
|
try {
|
|
return await diaryService.restore(diary: diaryId, typeNo: mealId, portionModel: portionId);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> deleteProductFromMeal({required int diaryId, required int mealId, required int portionId}) async {
|
|
try {
|
|
return await diaryService.deleteProductFromMeal(diary: diaryId, typeNo: mealId, portionModel: portionId);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> uploadPhotos({required int diaryId, required int mealId, required List<File> files}) async {
|
|
try {
|
|
for (int i = 0; i < files.length; i++) {
|
|
await diaryService.uploadPhotoOfMeal(diary: diaryId, typeNo: mealId, photo: files[i]);
|
|
}
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> deletePhoto({required int diaryId, required int mealId, required DiaryPhotoModel photo}) async {
|
|
try {
|
|
await diaryService.deletePhotoOfMeal(diaryId: diaryId, typeNo: mealId, userAttachment: photo.id);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> finishDiaryDay({required int diaryId, required String wakeUp, required String retire, String? comment}) async {
|
|
try {
|
|
return await diaryService.finishDiaryDay(
|
|
diary: diaryId,
|
|
finishDiaryDayModel: FinishDiaryDayModel(wakeUp: wakeUp, retire: retire, comment: comment),
|
|
);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<GlossaryModerationModel> sendProductToModeration({
|
|
required String name,
|
|
required double energy,
|
|
required double proteins,
|
|
required double fats,
|
|
required double carbohydrates,
|
|
}) async {
|
|
try {
|
|
return await diaryService.sendProductToModeration(
|
|
data: ProductModerationModel(name: name, energy: energy, proteins: proteins, fats: fats, carbohydrates: carbohydrates).toJson(),
|
|
);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> fillSatiety({required int diaryId, required int mealId, required int satiety}) async {
|
|
try {
|
|
return await diaryService.fillSatiety(diary: diaryId, typeNo: mealId, satiety: satiety);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> fillMood({required int diaryId, required int mealId, required int mood}) async {
|
|
try {
|
|
return await diaryService.fillMood(diary: diaryId, typeNo: mealId, mood: mood);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> fillTime({required int diaryId, required int mealId, required String time}) async {
|
|
try {
|
|
return await diaryService.fillTime(diary: diaryId, typeNo: mealId, time: time);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> fillWakeup({required int diaryId, required String time}) async {
|
|
try {
|
|
return await diaryService.fillWakeup(diary: diaryId, wakeUp: time);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> fillRetire({required int diaryId, required String time}) async {
|
|
try {
|
|
return await diaryService.fillRetire(diary: diaryId, retire: time);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> commentUserDay({required int diaryId, required ConsultantCommentModel commentModel}) async {
|
|
try {
|
|
await diaryService.commentUserDay(id: diaryId, body: commentModel);
|
|
_diaryForceFetchController.add('force');
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<ConsultantReviewModel> getDiaryComments({required int planId, required int diaryId}) async {
|
|
try {
|
|
return await diaryService.getDiaryComments(planId: planId, diaryId: diaryId);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> viewCommentOfDiaryDayByConsultant({required int diaryId}) async {
|
|
try {
|
|
await diaryService.viewCommentOfDiaryDayByConsultant(diaryId: diaryId);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<GlossaryPaginationModel> getGlossariesIndex({required List<int> ids}) async {
|
|
Map<String, dynamic> filters = {};
|
|
if (ids.isNotEmpty) {
|
|
for (int i = 0; i < ids.length; i++) {
|
|
filters['filters[id][\$in][$i]'] = ids[i];
|
|
}
|
|
}
|
|
try {
|
|
return await diaryService.getGlossariesIndex(filters: filters);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<DiaryDayModel> getDiaryDayV2({required String day}) async {
|
|
try {
|
|
final diaryDay = await diaryService.getDiaryDayV2(day: day);
|
|
return setCPFCToDiary(diaryDay);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<void> createDiaryDay({required String day}) async {
|
|
try {
|
|
await diaryService.createDay(body: CreateDayModel(day: day));
|
|
await getDiaryByDate(day);
|
|
} catch (e, s) {
|
|
await Sentry.captureException(e, stackTrace: s);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<DiaryDayModel> setCPFCToDiary(DiaryDayModel diaryDay) async {
|
|
Set<int> ids = {};
|
|
for (var meal in diaryDay.meals) {
|
|
for (var portion in meal.portions) {
|
|
if (portion.productNutritionalValueId != null) {
|
|
ids.add(portion.productNutritionalValueId!);
|
|
}
|
|
}
|
|
}
|
|
if (ids.isNotEmpty) {
|
|
final glossary = await getGlossariesIndex(ids: ids.toList());
|
|
final List<MealModel> updatedMeals = List.from(diaryDay.meals);
|
|
for (var mealIndex = 0; mealIndex < updatedMeals.length; mealIndex++) {
|
|
final meal = updatedMeals[mealIndex];
|
|
final updatedPortions = meal.portions.map((portion) {
|
|
if (portion.productNutritionalValueId != null) {
|
|
try {
|
|
final glossaryItem = glossary.glossariesList.firstWhere((g) => g.id == portion.productNutritionalValueId);
|
|
return portion.copyWith(
|
|
productCaloriesInfo: ProductCaloriesInfoModel(
|
|
id: glossaryItem.id,
|
|
productName: glossaryItem.name,
|
|
calories: glossaryItem.energyOn100Gr,
|
|
proteins: glossaryItem.proteinsOn100Gr,
|
|
fats: glossaryItem.fatsOn100Gr,
|
|
carbohydrates: glossaryItem.carbohydratesOn100Gr,
|
|
energyOnPortion: glossaryItem.energyOnPortion,
|
|
proteinsOnPortion: glossaryItem.proteinsOnPortion,
|
|
fatsOnPortion: glossaryItem.fatsOnPortion,
|
|
carbohydratesOnPortion: glossaryItem.carbohydratesOnPortion,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
return portion;
|
|
}
|
|
}
|
|
return portion;
|
|
}).toList();
|
|
|
|
updatedMeals[mealIndex] = meal.copyWith(portions: updatedPortions);
|
|
}
|
|
final updatedDiaryDay = diaryDay.copyWith(meals: updatedMeals);
|
|
return updatedDiaryDay;
|
|
}
|
|
return diaryDay;
|
|
}
|
|
}
|