added diets to diary

This commit is contained in:
Username1548
2025-05-27 23:30:36 +07:00
parent b4dd9b3a3a
commit c36aabd9a4
12 changed files with 216 additions and 23 deletions

View File

@@ -114,7 +114,7 @@ Future<void> init() async {
sl.registerFactory<PlansCubit>(() => PlansCubit(feedRepository: sl(), planRepository: sl()));
sl.registerFactory<SettingsCubit>(() => SettingsCubit(profileRepository: sl(), settingsRepository: sl()));
sl.registerFactory<RegisterConsultantCubit>(() => RegisterConsultantCubit(consultantRepository: sl()));
sl.registerFactory<DiaryCubit>(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl()));
sl.registerFactory<DiaryCubit>(() => DiaryCubit(diaryRepository: sl(), glossaryRepository: sl(), profileRepository: sl(), dietRepository: sl()));
sl.registerFactory<AboutDietCubit>(() => AboutDietCubit(dietsRepository: sl(), profileRepository: sl()));
sl.registerFactory<BlogPostCreateCubit>(() => BlogPostCreateCubit(blogPostRepository: sl()));
sl.registerFactory<SubCubit>(() => SubCubit(profileRepository: sl()));

View File

@@ -196,6 +196,12 @@ abstract class TextStyles {
height: 1.255,
);
static const textLMedium = TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
height: 1.255,
);
static const textMSemibold = TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,

View File

@@ -44,7 +44,8 @@ class DiaryDayModel with _$DiaryDayModel {
@JsonKey(name: "state") required TypeOfDiaryModel typeOfDiary,
@JsonKey(name: "meals") required List<MealModel> meals,
@JsonKey(name: "chosen_plan_id") required int? chosenPlanId,
@JsonKey(name: "day_of_chosen_diet") required int? dayOfChosenDiet,
@JsonKey(name: "day_of_chosen_diet") required int? dayOfChosenDiet,
@JsonKey(name: "chosen_diet", fromJson: _parseDiet) required DiaryDietModel? diet,
}) = _DiaryDayModel;
factory DiaryDayModel.fromJson(Map<String, dynamic> json) => _$DiaryDayModelFromJson(json);
@@ -56,11 +57,29 @@ class DiaryFutureDietDayModel with _$DiaryFutureDietDayModel {
@JsonKey(name: "date") required String date,
@JsonKey(name: "state", fromJson: _parseDayTypeForFutureDay) required TypeOfDiaryModel typeOfDiary,
@JsonKey(name: "meals") required List<MealModel> meals,
@JsonKey(name: "chosen_diet", fromJson: _parseDiet) required DiaryDietModel? diet,
@JsonKey(name: "day_of_chosen_diet") required int? dayOfChosenDiet,
}) = _DiaryFutureDietDayModel;
factory DiaryFutureDietDayModel.fromJson(Map<String, dynamic> json) => _$DiaryFutureDietDayModelFromJson(json);
}
DiaryDietModel? _parseDiet(json) {
if (json == null) return null;
return DiaryDietModel.fromJson(json['diet']);
}
@freezed
class DiaryDietModel with _$DiaryDietModel {
const factory DiaryDietModel({
required int id,
required int duration,
required String name,
}) = _DiaryDietModel;
factory DiaryDietModel.fromJson(Map<String, dynamic> json) => _$DiaryDietModelFromJson(json);
}
TypeOfDiaryModel _parseDayTypeForFutureDay(json) {
return TypeOfDiaryModel(
hasChosenDiet: json['has_chosen_diet'] as bool,

View File

@@ -9,6 +9,7 @@ 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';
@@ -21,12 +22,10 @@ class DiaryCubit extends Cubit<DiaryState> {
final DiaryRepository diaryRepository;
final GlossaryRepository glossaryRepository;
final ProfileRepository profileRepository;
final DietRepository dietRepository;
int? diaryId;
DiaryCubit({
required this.diaryRepository,
required this.glossaryRepository,
required this.profileRepository,
}) : super(const DiaryState.loading()) {
DiaryCubit({required this.diaryRepository, required this.glossaryRepository, required this.profileRepository, required this.dietRepository})
: super(const DiaryState.loading()) {
today = DateTime.now();
selectedDay = today;
diaryRepository.forceFetchStream.listen((_) {
@@ -36,13 +35,14 @@ class DiaryCubit extends Cubit<DiaryState> {
String comment = '';
setSelectedDay(DateTime day, {bool? forDietOnly}) async {
Future<bool?> setSelectedDay(DateTime day, {bool? forDietOnly}) async {
selectedDay = day;
if (forDietOnly ?? false) {
await fetchDiaryForDietOnly();
return;
final result = await fetchDiaryForDietOnly();
return result;
}
await fetchDiary(true);
return null;
}
setSelectedMeal(int meal) {
@@ -55,10 +55,93 @@ class DiaryCubit extends Cubit<DiaryState> {
}
}
Future<void> fetchDiaryForDietOnly() async {
Future<bool> fetchDiaryForDietOnly() async {
final stringDate = selectedDay.format('yyyy-MM-dd');
final diaryDay = await diaryRepository.getDiaryByDateForDietOnly(stringDate);
emit(DiaryState.loadedTomorrowWithDiet(diary: diaryDay, selectedDay: selectedDay, selectedMeal: selectedMeal));
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]) async {

View File

@@ -49,12 +49,13 @@ class _CalendarWidgetState extends State<CalendarWidget> {
leftChevronVisible: false,
rightChevronVisible: false,
),
onDaySelected: (selectedDay, focusedDay) {
onDaySelected: (selectedDay, focusedDay) async {
if (!isSameDay(_selectedDay, selectedDay)) {
final today = DateTime.now();
if (selectedDay.isAfter(today)) {
if ((state is DiaryStateLoaded)) {
if (!state.diary.typeOfDiary.hasChosenDiet) {
final result = await context.read<DiaryCubit>().setSelectedDay(_selectedDay, forDietOnly: true);
if (result == false && context.mounted) {
showErrorDialog(context, title: s.want_to_see_tomorrow, description: s.can_not_see_next_day);
return;
}
@@ -62,11 +63,11 @@ class _CalendarWidgetState extends State<CalendarWidget> {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
context.read<DiaryCubit>().setSelectedDay(_selectedDay, forDietOnly: true);
return;
}
if (state is DiaryStateLoadedTomorrowWithDiet) {
if (!state.diary.typeOfDiary.hasChosenDiet) {
final result = await context.read<DiaryCubit>().setSelectedDay(_selectedDay, forDietOnly: true);
if (result == false && context.mounted) {
showErrorDialog(context, title: s.want_to_see_tomorrow, description: s.can_not_see_next_day);
return;
}
@@ -74,7 +75,6 @@ class _CalendarWidgetState extends State<CalendarWidget> {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
context.read<DiaryCubit>().setSelectedDay(_selectedDay, forDietOnly: true);
return;
}
}

View File

@@ -0,0 +1,82 @@
import 'package:eatvio_app/core/theme/custom_text_style.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/widgets/custom_divider.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ChosenDietWidget extends StatelessWidget {
const ChosenDietWidget({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<DiaryCubit, DiaryState>(builder: (context, state) {
if (state is DiaryStateLoaded) {
if (state.diary.typeOfDiary.hasChosenDiet) {
return ChosenDietWidgetContent(
currentDietDay: state.diary.dayOfChosenDiet ?? 0,
dietName: state.diary.diet?.name ?? '',
dietDuration: state.diary.diet?.duration ?? 0,
);
}
}
if (state is DiaryStateLoadedTomorrowWithDiet) {
if (state.diary.typeOfDiary.hasChosenDiet) {
return Column(
children: [
const CustomDivider(),
const SizedBox(height: 16),
ChosenDietWidgetContent(
currentDietDay: state.diary.dayOfChosenDiet ?? 0,
dietName: state.diary.diet?.name ?? '',
dietDuration: state.diary.diet?.duration ?? 0,
),
],
);
}
}
return const SizedBox.shrink();
});
}
}
class ChosenDietWidgetContent extends StatelessWidget {
const ChosenDietWidgetContent({
super.key,
required this.currentDietDay,
required this.dietName,
required this.dietDuration,
});
final int currentDietDay;
final String dietName;
final int dietDuration;
@override
Widget build(BuildContext context) {
final size = MediaQuery.sizeOf(context);
final s = S.of(context);
return Column(
children: [
Row(
children: [
SizedBox(
width: size.width * 0.4,
child: Text(dietName, style: TextStyles.textLMedium.copyWith(color: appTheme.black)),
),
const Spacer(),
Container(
decoration: BoxDecoration(color: appTheme.dividerColor, borderRadius: BorderRadius.circular(12)),
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
child: Text('${s.day} $currentDietDay из $dietDuration', style: TextStyles.textMSemibold.copyWith(color: appTheme.gray)),
)
],
),
const SizedBox(
height: 16,
)
],
);
}
}

View File

@@ -4,6 +4,7 @@ import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/add_product_button_widget.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/chosen_diet_widget.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/comment_container.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/meal_button_widget.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/meal_comment_widget.dart';
@@ -57,7 +58,8 @@ class _MealWidgetState extends State<MealWidget> {
),
const SizedBox(height: 12),
const TimeOfMealPickerWidget(),
const SizedBox(height: 12),
const ChosenDietWidget(),
const ProductsListWidget(),
if (widget.showAddButton) ...[
const SizedBox(height: 12),

View File

@@ -67,7 +67,7 @@ class _ProductWidgetState extends State<ProductWidget> {
if (state is DiaryStateLoadedTomorrowWithDiet) {
return ListTile(
horizontalTitleGap: 0,
contentPadding: widget.portion.fromDiet ? const EdgeInsets.only(right: 24, left: 4) : null,
contentPadding: widget.portion.fromDiet ? const EdgeInsets.only(right: 24, left: 12) : null,
title: Text(widget.portion.productName),
subtitle: Text('${widget.portion.quantity} ${widget.portion.portion == 'gr' ? 'гр' : 'шт'}'),
shape: RoundedRectangleBorder(

View File

@@ -124,6 +124,7 @@ class _TimeOfMealPickerWidgetState extends State<TimeOfMealPickerWidget> {
),
),
const CustomDivider(),
const SizedBox(height: 12),
],
);
}

View File

@@ -693,7 +693,7 @@ class MessageLookup extends MessageLookupByLibrary {
"Ожидайте начала плана питания",
),
"want_to_see_tomorrow": MessageLookupByLibrary.simpleMessage(
"Хотите заглянуть в завтра?",
"Хотите заглянуть в будущее?",
),
"weapon": MessageLookupByLibrary.simpleMessage("Оружие"),
"weight": MessageLookupByLibrary.simpleMessage("Вес"),

View File

@@ -2865,10 +2865,10 @@ class S {
);
}
/// `Хотите заглянуть в завтра?`
/// `Хотите заглянуть в будущее?`
String get want_to_see_tomorrow {
return Intl.message(
'Хотите заглянуть в завтра?',
'Хотите заглянуть в будущее?',
name: 'want_to_see_tomorrow',
desc: '',
args: [],

View File

@@ -349,7 +349,7 @@
"try_again_2": "Попробуйте ещё раз",
"sorry_we_did_not_find_the_plan": "Извините, план где-то потерялся, мы уже ищем его",
"can_not_see_next_day": "Просмотр последующего дня возможен только при прохождении диеты",
"want_to_see_tomorrow": "Хотите заглянуть в завтра?",
"want_to_see_tomorrow": "Хотите заглянуть в будущее?",
"you_can_not_start_plan_until_end_of_prev_one": "Вы не можете начать план, пока не закончите прохождение предыдущего",
"end_previous_plan": "Закончите прохождение предыдущего плана",
"you_can_not_open_this_day": "Вы не можете перейти в этот день",