import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../../design/cookit_colors.dart'; import '../../../localization/app_localizations.dart'; import '../../../recipes/recipe_list_provider.dart'; import '../../../recipes/views/widgets/recipe_photo.dart'; import '../../day.dart'; import '../../day_format.dart'; import '../../models/meal.dart'; import '../../plan_repository.dart'; /// "+" on a Meal: search the collection for a Recipe, or keep what was typed as a note. Future showAddEntrySheet(BuildContext context, DateTime day, Meal meal) => showModalBottomSheet( context: context, isScrollControlled: true, showDragHandle: true, builder: (_) => _AddEntrySheet(day: day, meal: meal), ); class _AddEntrySheet extends StatefulWidget { const _AddEntrySheet({required this.day, required this.meal}); final DateTime day; final Meal meal; @override State<_AddEntrySheet> createState() => _AddEntrySheetState(); } class _AddEntrySheetState extends State<_AddEntrySheet> { final _query = TextEditingController(); /// Only Recipes of this Course; null shows all. String? _courseId; @override void dispose() { _query.dispose(); super.dispose(); } Future _add({String? recipeId, String? note}) async { final plan = context.read(); Navigator.pop(context); await plan.addEntry(widget.day, widget.meal.id, recipeId: recipeId, note: note); } @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final c = CookItColors.of(context); final provider = context.watch(); final text = _query.text.trim(); final recipes = provider.allRecipes .where((r) => _courseId == null || r.courseId == _courseId) .where((r) => r.name.toLowerCase().contains(text.toLowerCase())) .toList(); return Padding( padding: EdgeInsets.only(bottom: MediaQuery.viewInsetsOf(context).bottom), child: SizedBox( height: MediaQuery.sizeOf(context).height * 0.75, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 0, 20, 12), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( l10n.addEntryTitle(widget.meal.name, dayLabel(l10n, widget.day, dayOf(DateTime.now()))), style: TextStyle(fontFamily: 'Nunito', fontWeight: FontWeight.w900, fontSize: 22, color: c.ink), ), const SizedBox(height: 12), TextField( controller: _query, autofocus: true, textCapitalization: TextCapitalization.sentences, textInputAction: TextInputAction.done, onChanged: (_) => setState(() {}), onSubmitted: (value) { if (value.trim().isNotEmpty) _add(note: value.trim()); }, decoration: InputDecoration( hintText: l10n.addEntryHint, prefixIcon: Icon(Icons.search_rounded, color: c.green), fillColor: c.background, ), ), ], ), ), SizedBox( height: 40, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 20), children: [ for (final course in [null, ...provider.courses]) Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(course == null ? l10n.filterAll : course.label), selected: _courseId == course?.id, showCheckmark: false, onSelected: (_) => setState(() => _courseId = course?.id), ), ), ], ), ), const SizedBox(height: 8), Expanded( child: ListView( children: [ if (text.isNotEmpty) ListTile( leading: CircleAvatar( backgroundColor: c.tiles[0], child: Icon(Icons.sticky_note_2_outlined, color: c.green), ), title: Text(l10n.addAsNote(text), style: const TextStyle(fontWeight: FontWeight.w800)), onTap: () => _add(note: text), ), for (final recipe in recipes) ListTile( leading: ClipRRect( borderRadius: BorderRadius.circular(10), child: SizedBox( width: 44, height: 44, child: RecipePhoto( photo: recipe.mainPhoto, seed: recipe.id, placeholderEmoji: provider.courseOf(recipe)?.emoji, cacheWidth: 132, ), ), ), title: Text(recipe.name), subtitle: provider.courseOf(recipe) == null ? null : Text(provider.courseOf(recipe)!.name), onTap: () => _add(recipeId: recipe.id), ), ], ), ), ], ), ), ); } }