123 lines
4.0 KiB
Dart
123 lines
4.0 KiB
Dart
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)),
|
||
|
|
],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|