Initial commit: CookIT recipe collection and week planner
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
7d7a0bc60b
173 files changed
+22803
No files matched your search
@@ -0,0 +1,123 @@
|
||||
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<void> rerollEntry(BuildContext context, PlanEntry entry, Recipe current) async {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
final week = context.read<WeekPlanProvider>();
|
||||
final recipes = context.read<RecipeListProvider>().allRecipes;
|
||||
final plan = context.read<PlanRepository>();
|
||||
final weekStart = weekStartOf(entry.day, context.read<SettingsController>().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<void> moveEntryWithPicker(BuildContext context, PlanEntry entry) async {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final plan = context.read<PlanRepository>();
|
||||
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<void> removeEntryWithUndo(BuildContext context, PlanEntry entry, String name) async {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
final plan = context.read<PlanRepository>();
|
||||
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<void> editNote(BuildContext context, PlanEntry entry) async {
|
||||
final plan = context.read<PlanRepository>();
|
||||
final text = await showDialog<String>(
|
||||
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)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user