import 'dart:math'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../../localization/app_localizations.dart'; import '../../../recipes/models/recipe.dart'; import '../../../recipes/recipe_list_provider.dart'; import '../../../settings/settings_controller.dart'; import '../../day.dart'; import '../../models/plan_entry.dart'; import '../../plan_repository.dart'; import '../../week_fill.dart'; import '../../week_plan_provider.dart'; import 'plan_slot_sheet.dart'; /// "Neu würfeln": another Recipe of the same Course, by the rules of "Woche füllen". Future rerollEntry(BuildContext context, PlanEntry entry, Recipe current) async { final l10n = AppLocalizations.of(context); final messenger = ScaffoldMessenger.of(context); final week = context.read(); final recipes = context.read().allRecipes; final plan = context.read(); final weekStart = weekStartOf(entry.day, context.read().weekStart); final replacement = pickReplacement( candidates: [ for (final r in recipes) if (current.courseId == null || r.courseId == current.courseId) r, ], inWeek: week.recipeIdsBetween(weekStart, addDays(weekStart, 6)), recent: week.recipeIdsBetween(addDays(weekStart, -7 * recentWeeks), addDays(weekStart, -1)), random: Random(), ); if (replacement == null) { messenger.showSnackBar(SnackBar(content: Text(l10n.noOtherRecipe))); return; } await plan.replaceRecipe(entry.id, replacement.id); } /// "Verschieben …": asks for a day and Meal. Future moveEntryWithPicker(BuildContext context, PlanEntry entry) async { final l10n = AppLocalizations.of(context); final plan = context.read(); final slot = await showPlanSlotSheet( context, action: l10n.moveEntryTitle, initialDay: entry.day, initialMealId: entry.mealId, ); if (slot == null) return; final (day, mealId) = slot; await plan.moveEntry(entry.id, day, mealId); } /// Removes the entry, with "Rückgängig" in the SnackBar. Future removeEntryWithUndo(BuildContext context, PlanEntry entry, String name) async { final l10n = AppLocalizations.of(context); final messenger = ScaffoldMessenger.of(context); final plan = context.read(); await plan.removeEntry(entry.id); messenger ..hideCurrentSnackBar() ..showSnackBar( SnackBar( content: Text(l10n.entryRemoved(name)), duration: const Duration(milliseconds: 1500), action: SnackBarAction( label: l10n.undo, onPressed: () => plan.addEntry(entry.day, entry.mealId, recipeId: entry.recipeId, note: entry.note), ), ), ); } /// "Bearbeiten" on a note: a small dialog with its text. Future editNote(BuildContext context, PlanEntry entry) async { final plan = context.read(); final text = await showDialog( context: context, builder: (_) => _NoteDialog(note: entry.note ?? ''), ); if (text != null && text.isNotEmpty) await plan.updateNote(entry.id, text); } class _NoteDialog extends StatefulWidget { const _NoteDialog({required this.note}); final String note; @override State<_NoteDialog> createState() => _NoteDialogState(); } class _NoteDialogState extends State<_NoteDialog> { late final _text = TextEditingController(text: widget.note); @override void dispose() { _text.dispose(); super.dispose(); } void _save() => Navigator.pop(context, _text.text.trim()); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); return AlertDialog( title: Text(l10n.editNoteTitle), content: TextField( controller: _text, autofocus: true, textCapitalization: TextCapitalization.sentences, onSubmitted: (_) => _save(), ), actions: [ TextButton(onPressed: () => Navigator.pop(context), child: Text(l10n.cancel)), FilledButton(onPressed: _save, child: Text(l10n.save)), ], ); } }