Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Copy meals to today from Diary #130

55 changes: 55 additions & 0 deletions lib/core/presentation/widgets/copy_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:opennutritracker/features/add_meal/presentation/add_meal_type.dart';
import 'package:opennutritracker/generated/l10n.dart';

class CopyDialog extends StatefulWidget {
const CopyDialog({super.key});
@override
State<StatefulWidget> createState() {
return CopyDialogState();
}
}

class CopyDialogState extends State<CopyDialog> {
AddMealType _selectedValue = AddMealType.breakfastType;
AddMealType get selectedMealType => _selectedValue;

@override
void initState() {
super.initState();
}

@override
Widget build(
BuildContext context,
) {
return AlertDialog(
title: Text(S.of(context).copyDialogTitle),
content: DropdownButton<AddMealType>(
value: _selectedValue,
onChanged: (AddMealType? addMealType) {
if (addMealType != null) {
setState(() {
_selectedValue = addMealType;
});
}
},
items: AddMealType.values.map((AddMealType addMealType) {
return DropdownMenuItem(
value: addMealType,
child: Text(addMealType.getTypeName(context)));
}).toList()),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(_selectedValue);
},
child: Text(S.of(context).dialogOKLabel)),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(S.of(context).dialogCancelLabel))
]);
}
}
26 changes: 26 additions & 0 deletions lib/core/presentation/widgets/copy_or_delete_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:opennutritracker/generated/l10n.dart';

class CopyOrDeleteDialog extends StatelessWidget {
const CopyOrDeleteDialog({super.key});

@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(S.of(context).copyOrDeleteTimeDialogTitle),
content: Text(S.of(context).copyOrDeleteTimeDialogContent),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(S.of(context).dialogCopyLabel)),
TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text(S.of(context).dialogDeleteLabel))
],
);
}
}
31 changes: 31 additions & 0 deletions lib/features/diary/diary_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import 'package:opennutritracker/core/domain/entity/intake_entity.dart';
import 'package:opennutritracker/core/domain/entity/tracked_day_entity.dart';
import 'package:opennutritracker/core/domain/entity/user_activity_entity.dart';
import 'package:opennutritracker/core/utils/locator.dart';
import 'package:opennutritracker/features/add_meal/presentation/add_meal_type.dart';
import 'package:opennutritracker/features/diary/presentation/bloc/calendar_day_bloc.dart';
import 'package:opennutritracker/features/diary/presentation/bloc/diary_bloc.dart';
import 'package:opennutritracker/features/diary/presentation/widgets/diary_table_calendar.dart';
import 'package:opennutritracker/features/diary/presentation/widgets/day_info_widget.dart';
import 'package:opennutritracker/features/meal_detail/presentation/bloc/meal_detail_bloc.dart';
import 'package:opennutritracker/generated/l10n.dart';

import '../../core/domain/entity/intake_type_entity.dart';

class DiaryPage extends StatefulWidget {
const DiaryPage({super.key});

Expand All @@ -23,6 +27,7 @@ class _DiaryPageState extends State<DiaryPage> with WidgetsBindingObserver {

late DiaryBloc _diaryBloc;
late CalendarDayBloc _calendarDayBloc;
late MealDetailBloc _mealDetailBloc;

static const _calendarDurationDays = Duration(days: 356);
final _currentDate = DateTime.now();
Expand All @@ -34,6 +39,7 @@ class _DiaryPageState extends State<DiaryPage> with WidgetsBindingObserver {
WidgetsBinding.instance.addObserver(this);
_diaryBloc = locator<DiaryBloc>();
_calendarDayBloc = locator<CalendarDayBloc>();
_mealDetailBloc = locator<MealDetailBloc>();
super.initState();
}

Expand Down Expand Up @@ -103,6 +109,8 @@ class _DiaryPageState extends State<DiaryPage> with WidgetsBindingObserver {
snackIntake: state.snackIntakeList,
onDeleteIntake: _onDeleteIntakeItem,
onDeleteActivity: _onDeleteActivityItem,
onCopyIntake: _onCopyIntakeItem,
onCopyActivity: _onCopyActivityItem,
);
}
return const SizedBox();
Expand Down Expand Up @@ -138,6 +146,29 @@ class _DiaryPageState extends State<DiaryPage> with WidgetsBindingObserver {
}
}

void _onCopyIntakeItem(IntakeEntity intakeEntity,
TrackedDayEntity? trackedDayEntity, AddMealType? type) async {
IntakeTypeEntity finalType;
if (type == null) {
finalType = intakeEntity.type;
} else {
finalType = type.getIntakeType();
}
_mealDetailBloc.addIntake(
context,
intakeEntity.unit,
intakeEntity.amount.toString(),
finalType,
intakeEntity.meal,
DateTime.now());
_diaryBloc.updateHomePage();
}

void _onCopyActivityItem(UserActivityEntity userActivityEntity,
TrackedDayEntity? trackedDayEntity) async {
log.info("Should copy activity");
}

void _onDateSelected(
DateTime newDate, Map<String, TrackedDayEntity> trackedDaysMap) {
setState(() {
Expand Down
66 changes: 53 additions & 13 deletions lib/features/diary/presentation/widgets/day_info_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import 'package:opennutritracker/core/domain/entity/intake_entity.dart';
import 'package:opennutritracker/core/domain/entity/tracked_day_entity.dart';
import 'package:opennutritracker/core/domain/entity/user_activity_entity.dart';
import 'package:opennutritracker/core/presentation/widgets/activity_vertial_list.dart';
import 'package:opennutritracker/core/presentation/widgets/copy_dialog.dart';
import 'package:opennutritracker/core/presentation/widgets/delete_dialog.dart';
import 'package:opennutritracker/core/utils/custom_icons.dart';
import 'package:opennutritracker/features/add_meal/presentation/add_meal_type.dart';
import 'package:opennutritracker/features/home/presentation/widgets/intake_vertical_list.dart';
import 'package:opennutritracker/generated/l10n.dart';

import '../../../../core/presentation/widgets/copy_or_delete_dialog.dart';

class DayInfoWidget extends StatelessWidget {
final DateTime selectedDay;
final TrackedDayEntity? trackedDayEntity;
Expand All @@ -22,18 +25,25 @@ class DayInfoWidget extends StatelessWidget {
onDeleteIntake;
final Function(UserActivityEntity userActivityEntity,
TrackedDayEntity? trackedDayEntity) onDeleteActivity;
final Function(IntakeEntity intake, TrackedDayEntity? trackedDayEntity,
AddMealType? type) onCopyIntake;
final Function(UserActivityEntity userActivityEntity,
TrackedDayEntity? trackedDayEntity) onCopyActivity;

const DayInfoWidget(
{super.key,
required this.selectedDay,
required this.trackedDayEntity,
required this.userActivities,
required this.breakfastIntake,
required this.lunchIntake,
required this.dinnerIntake,
required this.snackIntake,
required this.onDeleteIntake,
required this.onDeleteActivity});
const DayInfoWidget({
super.key,
required this.selectedDay,
required this.trackedDayEntity,
required this.userActivities,
required this.breakfastIntake,
required this.lunchIntake,
required this.dinnerIntake,
required this.snackIntake,
required this.onDeleteIntake,
required this.onDeleteActivity,
required this.onCopyIntake,
required this.onCopyActivity,
});

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -171,16 +181,46 @@ class DayInfoWidget extends StatelessWidget {
return 'Carbs: $carbsTracked/${carbsGoal}g, Fat: $fatTracked/${fatGoal}g, Protein: $proteinTracked/${proteinGoal}g';
}

void onIntakeItemLongPressed(
void showCopyOrDeleteIntakeDialog(
BuildContext context, IntakeEntity intakeEntity) async {
final copyOrDelete = await showDialog<bool>(
context: context, builder: (context) => const CopyOrDeleteDialog());
if (context.mounted) {
if (copyOrDelete != null && !copyOrDelete) {
showDeleteIntakeDialog(context, intakeEntity);
} else if (copyOrDelete != null && copyOrDelete) {
showCopyDialog(context, intakeEntity);
}
}
}

void showCopyDialog(BuildContext context, IntakeEntity intakeEntity) async {
const copyDialog = CopyDialog();
final selectedMealType = await showDialog<AddMealType>(
context: context, builder: (context) => copyDialog);
if (selectedMealType != null) {
onCopyIntake(intakeEntity, null, selectedMealType);
}
}

void showDeleteIntakeDialog(
BuildContext context, IntakeEntity intakeEntity) async {
final shouldDeleteIntake = await showDialog<bool>(
context: context, builder: (context) => const DeleteDialog());

if (shouldDeleteIntake != null) {
onDeleteIntake(intakeEntity, trackedDayEntity);
}
}

void onIntakeItemLongPressed(
BuildContext context, IntakeEntity intakeEntity) async {
if (DateUtils.isSameDay(selectedDay, DateTime.now())) {
showDeleteIntakeDialog(context, intakeEntity);
} else {
showCopyOrDeleteIntakeDialog(context, intakeEntity);
}
}

void onActivityItemLongPressed(
BuildContext context, UserActivityEntity activityEntity) async {
final shouldDeleteActivity = await showDialog<bool>(
Expand Down
9 changes: 9 additions & 0 deletions lib/generated/intl/messages_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ class MessageLookup extends MessageLookupByLibrary {
"chooseWeightGoalLabel":
MessageLookupByLibrary.simpleMessage("Gewichtsziel wählen"),
"cmLabel": MessageLookupByLibrary.simpleMessage("cm"),
"copyDialogTitle": MessageLookupByLibrary.simpleMessage(
"Zu welcher Mahlzeit hinzufügen?"),
"copyOrDeleteTimeDialogContent": MessageLookupByLibrary.simpleMessage(
"Auf \"Nach heute kopieren\" klicken, um die Mahlzeit nach heute zu kopieren. Mit \"Löschen\" kann die Mahlzeit entfernt werden"),
"copyOrDeleteTimeDialogTitle":
MessageLookupByLibrary.simpleMessage("Was soll getan werden?"),
"createCustomDialogContent": MessageLookupByLibrary.simpleMessage(
"Möchten Sie einen benutzerdefinierte Mahlzeit erstellen?"),
"createCustomDialogTitle": MessageLookupByLibrary.simpleMessage(
Expand All @@ -95,6 +101,9 @@ class MessageLookup extends MessageLookupByLibrary {
"deleteTimeDialogTitle":
MessageLookupByLibrary.simpleMessage("Eintrag löschen?"),
"dialogCancelLabel": MessageLookupByLibrary.simpleMessage("ABBRECHEN"),
"dialogCopyLabel":
MessageLookupByLibrary.simpleMessage("NACH HEUTE KOPIEREN"),
"dialogDeleteLabel": MessageLookupByLibrary.simpleMessage("LÖSCHEN"),
"dialogOKLabel": MessageLookupByLibrary.simpleMessage("OK"),
"diaryLabel": MessageLookupByLibrary.simpleMessage("Tagebuch"),
"dinnerExample": MessageLookupByLibrary.simpleMessage(
Expand Down
9 changes: 9 additions & 0 deletions lib/generated/intl/messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ class MessageLookup extends MessageLookupByLibrary {
"chooseWeightGoalLabel":
MessageLookupByLibrary.simpleMessage("Choose Weight Goal"),
"cmLabel": MessageLookupByLibrary.simpleMessage("cm"),
"copyDialogTitle": MessageLookupByLibrary.simpleMessage(
"Which meal type do you want to copy to?"),
"copyOrDeleteTimeDialogContent": MessageLookupByLibrary.simpleMessage(
"With \"Copy to today\" you can copy the meal to today. With \"Delete\" you can delete the meal."),
"copyOrDeleteTimeDialogTitle":
MessageLookupByLibrary.simpleMessage("What do you want to do?"),
"createCustomDialogContent": MessageLookupByLibrary.simpleMessage(
"Do you want create a custom meal item?"),
"createCustomDialogTitle":
Expand All @@ -95,6 +101,9 @@ class MessageLookup extends MessageLookupByLibrary {
"deleteTimeDialogTitle":
MessageLookupByLibrary.simpleMessage("Delete Item?"),
"dialogCancelLabel": MessageLookupByLibrary.simpleMessage("CANCEL"),
"dialogCopyLabel":
MessageLookupByLibrary.simpleMessage("COPY TO TODAY"),
"dialogDeleteLabel": MessageLookupByLibrary.simpleMessage("DELETE"),
"dialogOKLabel": MessageLookupByLibrary.simpleMessage("OK"),
"diaryLabel": MessageLookupByLibrary.simpleMessage("Diary"),
"dinnerExample": MessageLookupByLibrary.simpleMessage(
Expand Down
9 changes: 9 additions & 0 deletions lib/generated/intl/messages_tr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ class MessageLookup extends MessageLookupByLibrary {
"chooseWeightGoalLabel":
MessageLookupByLibrary.simpleMessage("Kilo Hedefi Seçin"),
"cmLabel": MessageLookupByLibrary.simpleMessage("cm"),
"copyDialogTitle": MessageLookupByLibrary.simpleMessage(
"Hangi öğüne eklemek istiyorsunuz?"),
"copyOrDeleteTimeDialogContent": MessageLookupByLibrary.simpleMessage(
"\"Bugüne kopyala\" seçeneğine tıklayarak öğünü bugüne kopyalayabilirsiniz. \"Sil\" seçeneği ile öğün kaldırılabilir."),
"copyOrDeleteTimeDialogTitle":
MessageLookupByLibrary.simpleMessage("Ne yapılmalı?"),
"createCustomDialogContent": MessageLookupByLibrary.simpleMessage(
"Özel bir yemek öğesi oluşturmak istiyor musunuz?"),
"createCustomDialogTitle": MessageLookupByLibrary.simpleMessage(
Expand All @@ -93,6 +99,9 @@ class MessageLookup extends MessageLookupByLibrary {
"deleteTimeDialogTitle":
MessageLookupByLibrary.simpleMessage("Öğe Silinsin mi?"),
"dialogCancelLabel": MessageLookupByLibrary.simpleMessage("İPTAL"),
"dialogCopyLabel":
MessageLookupByLibrary.simpleMessage("BUGÜNE KOPYALA"),
"dialogDeleteLabel": MessageLookupByLibrary.simpleMessage("SİL"),
"dialogOKLabel": MessageLookupByLibrary.simpleMessage("TAMAM"),
"diaryLabel": MessageLookupByLibrary.simpleMessage("Günlük"),
"dinnerExample": MessageLookupByLibrary.simpleMessage(
Expand Down
50 changes: 50 additions & 0 deletions lib/generated/l10n.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions lib/l10n/intl_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@
"deleteTimeDialogContent": "Möchten Sie den ausgewählten Eintrag löschen?",
"itemDeletedSnackbar": "Eintrag gelöscht",

"copyDialogTitle": "Zu welcher Mahlzeit hinzufügen?",

"copyOrDeleteTimeDialogTitle": "Was soll getan werden?",
"copyOrDeleteTimeDialogContent": "Auf \"Nach heute kopieren\" klicken, um die Mahlzeit nach heute zu kopieren. Mit \"Löschen\" kann die Mahlzeit entfernt werden",
"dialogCopyLabel": "NACH HEUTE KOPIEREN",
"dialogDeleteLabel": "LÖSCHEN",

"suppliedLabel": "zugeführt",
"burnedLabel": "verbrannt",
"kcalLeftLabel": "kcal übrig",
Expand Down
Loading
Loading