diff --git a/client/lib/features/home/home_provider.dart b/client/lib/features/home/home_provider.dart index c33f199..e0cc80e 100644 --- a/client/lib/features/home/home_provider.dart +++ b/client/lib/features/home/home_provider.dart @@ -2,6 +2,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../features/scan/recognition_service.dart'; import '../../shared/models/home_summary.dart'; +import '../../shared/models/menu.dart'; +import '../menu/menu_provider.dart'; import 'home_service.dart'; // ── Selected date (persists while app is open) ──────────────── @@ -76,3 +78,21 @@ final allJobsProvider = StateNotifierProvider>>( (ref) => AllJobsNotifier(ref.read(recognitionServiceProvider)), ); + +// ── Planned meals from menu ──────────────────────────────────── + +/// Returns planned [MealSlot]s from the menu plan for [dateString]. +/// Derives from the already-cached weekly menu — no extra network call. +/// Returns an empty list when no plan exists for that week. +final plannedMealsProvider = + Provider.family, String>((ref, dateString) { + final date = DateTime.parse(dateString); + final weekString = isoWeekString(date); + final menuState = ref.watch(menuProvider(weekString)); + final plan = menuState.valueOrNull; + if (plan == null) return []; + for (final day in plan.days) { + if (day.date == dateString) return day.meals; + } + return []; +}); diff --git a/client/lib/features/home/home_screen.dart b/client/lib/features/home/home_screen.dart index a309d1f..d917233 100644 --- a/client/lib/features/home/home_screen.dart +++ b/client/lib/features/home/home_screen.dart @@ -13,6 +13,7 @@ import '../../core/theme/app_colors.dart'; import '../../shared/models/diary_entry.dart'; import '../../shared/models/home_summary.dart'; import '../../shared/models/meal_type.dart'; +import '../../shared/models/menu.dart'; import '../diary/food_search_sheet.dart'; import '../menu/menu_provider.dart'; import '../profile/profile_provider.dart'; @@ -20,6 +21,22 @@ import '../scan/dish_result_screen.dart'; import '../scan/recognition_service.dart'; import 'home_provider.dart'; +// ── Date context ─────────────────────────────────────────────── + +enum _DateContext { past, today, future } + +_DateContext _contextFor(DateTime selected) { + final now = DateTime.now(); + final todayNormalized = DateTime(now.year, now.month, now.day); + final selectedNormalized = + DateTime(selected.year, selected.month, selected.day); + if (selectedNormalized.isBefore(todayNormalized)) return _DateContext.past; + if (selectedNormalized.isAtSameMomentAs(todayNormalized)) { + return _DateContext.today; + } + return _DateContext.future; +} + // ── Root screen ─────────────────────────────────────────────── class HomeScreen extends ConsumerWidget { @@ -37,6 +54,9 @@ class HomeScreen extends ConsumerWidget { final selectedDate = ref.watch(selectedDateProvider); final dateString = formatDateForDiary(selectedDate); + final dateContext = _contextFor(selectedDate); + final isFutureDate = dateContext == _DateContext.future; + final diaryState = ref.watch(diaryProvider(dateString)); final entries = diaryState.valueOrNull ?? []; @@ -75,18 +95,22 @@ class HomeScreen extends ConsumerWidget { ref.read(selectedDateProvider.notifier).state = date, ), const SizedBox(height: 16), - _CaloriesCard( - loggedCalories: loggedCalories, - dailyGoal: dailyGoal, - goalType: goalType, - ), - const SizedBox(height: 12), - _MacrosRow( - proteinG: loggedProtein, - fatG: loggedFat, - carbsG: loggedCarbs, - ), - if (todayJobs.isNotEmpty) ...[ + if (isFutureDate) + _PlanningBanner(dateString: dateString) + else ...[ + _CaloriesCard( + loggedCalories: loggedCalories, + dailyGoal: dailyGoal, + goalType: goalType, + ), + const SizedBox(height: 12), + _MacrosRow( + proteinG: loggedProtein, + fatG: loggedFat, + carbsG: loggedCarbs, + ), + ], + if (!isFutureDate && todayJobs.isNotEmpty) ...[ const SizedBox(height: 16), _TodayJobsWidget(jobs: todayJobs), ], @@ -96,13 +120,13 @@ class HomeScreen extends ConsumerWidget { entries: entries, dateString: dateString, ), - if (expiringSoon.isNotEmpty) ...[ + if (!isFutureDate && expiringSoon.isNotEmpty) ...[ const SizedBox(height: 16), _ExpiringBanner(items: expiringSoon), ], const SizedBox(height: 16), _QuickActionsRow(), - if (recommendations.isNotEmpty) ...[ + if (!isFutureDate && recommendations.isNotEmpty) ...[ const SizedBox(height: 20), _SectionTitle(l10n.recommendCook), const SizedBox(height: 12), @@ -163,8 +187,12 @@ class _DateSelector extends StatefulWidget { } class _DateSelectorState extends State<_DateSelector> { - // Total days available in the past (index 0 = today, index N-1 = oldest) - static const _totalDays = 365; + // Strip covers 7 future days + today + 364 past days = 372 items total. + // With reverse: true, index 0 is rendered at the RIGHT edge (newest). + // index 0 = today + 7, index 7 = today, index 371 = today - 364. + static const _futureDays = 7; + static const _pastDays = 364; + static const _totalDays = _futureDays + 1 + _pastDays; // 372 static const _pillWidth = 48.0; static const _pillSpacing = 6.0; @@ -176,12 +204,16 @@ class _DateSelectorState extends State<_DateSelector> { return DateFormat('EEE, d MMMM', localeCode).format(date) + yearSuffix; } - // Index in the reversed list: 0 = today, 1 = yesterday, … + // Maps a date to its index in the reversed ListView. + // today → _futureDays, tomorrow → _futureDays - 1, … , +7 → 0. + // yesterday → _futureDays + 1, … , -364 → _futureDays + 364. int _indexForDate(DateTime date) { final today = DateTime.now(); final todayNormalized = DateTime(today.year, today.month, today.day); final dateNormalized = DateTime(date.year, date.month, date.day); - return todayNormalized.difference(dateNormalized).inDays.clamp(0, _totalDays - 1); + final daysFromToday = + dateNormalized.difference(todayNormalized).inDays; + return (_futureDays - daysFromToday).clamp(0, _totalDays - 1); } double _offsetForIndex(int index) => index * (_pillWidth + _pillSpacing); @@ -192,7 +224,7 @@ class _DateSelectorState extends State<_DateSelector> { DateTime(previousDay.year, previousDay.month, previousDay.day); final today = DateTime.now(); final oldestAllowed = DateTime(today.year, today.month, today.day) - .subtract(const Duration(days: _totalDays - 1)); + .subtract(const Duration(days: _pastDays)); if (!previousDayNormalized.isBefore(oldestAllowed)) { widget.onDateSelected(previousDayNormalized); } @@ -200,11 +232,12 @@ class _DateSelectorState extends State<_DateSelector> { void _selectNextDay() { final today = DateTime.now(); - final todayNormalized = DateTime(today.year, today.month, today.day); + final futureLimitDate = DateTime(today.year, today.month, today.day) + .add(const Duration(days: _futureDays)); final nextDay = widget.selectedDate.add(const Duration(days: 1)); final nextDayNormalized = DateTime(nextDay.year, nextDay.month, nextDay.day); - if (!nextDayNormalized.isAfter(todayNormalized)) { + if (!nextDayNormalized.isAfter(futureLimitDate)) { widget.onDateSelected(nextDayNormalized); } } @@ -214,7 +247,7 @@ class _DateSelectorState extends State<_DateSelector> { widget.onDateSelected(DateTime(today.year, today.month, today.day)); if (_scrollController.hasClients) { _scrollController.animateTo( - 0, + _offsetForIndex(_futureDays), duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); @@ -257,6 +290,8 @@ class _DateSelectorState extends State<_DateSelector> { final selectedNormalized = DateTime( widget.selectedDate.year, widget.selectedDate.month, widget.selectedDate.day); final isToday = selectedNormalized == todayNormalized; + final futureLimitDate = + todayNormalized.add(const Duration(days: _futureDays)); return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -298,16 +333,19 @@ class _DateSelectorState extends State<_DateSelector> { icon: const Icon(Icons.chevron_right), iconSize: 20, visualDensity: VisualDensity.compact, - onPressed: null, + onPressed: selectedNormalized.isBefore(futureLimitDate) + ? _selectNextDay + : null, ), ], ), ), const SizedBox(height: 8), // ── Day strip ──────────────────────────────────────────── + // reverse: true → index 0 (7 days from now) at the right edge; + // index _futureDays = today; past dates have higher indices. SizedBox( height: 56, - // reverse: true → index 0 (today) sits at the right edge child: ListView.separated( controller: _scrollController, scrollDirection: Axis.horizontal, @@ -315,9 +353,11 @@ class _DateSelectorState extends State<_DateSelector> { itemCount: _totalDays, separatorBuilder: (_, __) => const SizedBox(width: _pillSpacing), itemBuilder: (listContext, index) { - final date = todayNormalized.subtract(Duration(days: index)); + final date = todayNormalized + .add(Duration(days: _futureDays - index)); final isSelected = date == selectedNormalized; final isDayToday = date == todayNormalized; + final isDayFuture = date.isAfter(todayNormalized); return GestureDetector( onTap: () => widget.onDateSelected(date), @@ -327,8 +367,17 @@ class _DateSelectorState extends State<_DateSelector> { decoration: BoxDecoration( color: isSelected ? theme.colorScheme.primary - : theme.colorScheme.surfaceContainerHighest, + : isDayFuture + ? theme.colorScheme.surfaceContainerLow + : theme.colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(12), + border: isDayFuture && !isSelected + ? Border.all( + color: theme.colorScheme.outline + .withValues(alpha: 0.3), + width: 1, + ) + : null, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -338,7 +387,10 @@ class _DateSelectorState extends State<_DateSelector> { style: theme.textTheme.labelSmall?.copyWith( color: isSelected ? theme.colorScheme.onPrimary - : theme.colorScheme.onSurfaceVariant, + : isDayFuture + ? theme.colorScheme.onSurfaceVariant + .withValues(alpha: 0.7) + : theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 2), @@ -352,7 +404,10 @@ class _DateSelectorState extends State<_DateSelector> { ? theme.colorScheme.onPrimary : isDayToday ? theme.colorScheme.primary - : null, + : isDayFuture + ? theme.colorScheme.onSurface + .withValues(alpha: 0.5) + : null, ), ), ], @@ -714,6 +769,8 @@ class _DailyMealsSection extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context)!; final theme = Theme.of(context); + final plannedSlots = ref.watch(plannedMealsProvider(dateString)); + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -725,12 +782,16 @@ class _DailyMealsSection extends ConsumerWidget { final mealEntries = entries .where((entry) => entry.mealType == mealTypeId) .toList(); + final mealPlannedSlots = plannedSlots + .where((slot) => slot.mealType == mealTypeId) + .toList(); return Padding( padding: const EdgeInsets.only(bottom: 8), child: _MealCard( mealTypeOption: mealTypeOption, entries: mealEntries, dateString: dateString, + plannedSlots: mealPlannedSlots, ), ); }), @@ -928,11 +989,13 @@ class _MealCard extends ConsumerWidget { final MealTypeOption mealTypeOption; final List entries; final String dateString; + final List plannedSlots; const _MealCard({ required this.mealTypeOption, required this.entries, required this.dateString, + this.plannedSlots = const [], }); @override @@ -942,6 +1005,16 @@ class _MealCard extends ConsumerWidget { final totalCalories = entries.fold( 0.0, (sum, entry) => sum + (entry.calories ?? 0)); + // Recipe IDs that are already confirmed in the diary — don't show ghost. + final confirmedRecipeIds = + entries.map((entry) => entry.recipeId).whereType().toSet(); + + final unconfirmedSlots = plannedSlots + .where((slot) => + slot.recipe != null && + !confirmedRecipeIds.contains(slot.recipe!.id)) + .toList(); + return Card( child: Column( children: [ @@ -986,7 +1059,23 @@ class _MealCard extends ConsumerWidget { ], ), ), - // Diary entries + // Planned (ghost) slots from the menu + if (unconfirmedSlots.isNotEmpty) ...[ + const Divider(height: 1, indent: 16), + ...unconfirmedSlots.map((slot) => _PlannedSlotTile( + slot: slot, + onConfirm: () => + ref.read(diaryProvider(dateString).notifier).add({ + 'date': dateString, + 'meal_type': mealTypeOption.id, + 'recipe_id': slot.recipe!.id, + 'name': slot.recipe!.title, + 'portions': 1, + 'source': 'menu_plan', + }), + )), + ], + // Confirmed diary entries if (entries.isNotEmpty) ...[ const Divider(height: 1, indent: 16), ...entries.map((entry) => _DiaryEntryTile( @@ -1054,6 +1143,104 @@ class _DiaryEntryTile extends StatelessWidget { } } +// ── Planning banner (future dates) ──────────────────────────── + +class _PlanningBanner extends StatelessWidget { + final String dateString; + + const _PlanningBanner({required this.dateString}); + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context)!; + final theme = Theme.of(context); + final localeCode = Localizations.localeOf(context).toString(); + + String formattedDate; + try { + final date = DateTime.parse(dateString); + formattedDate = DateFormat('EEE, d MMMM', localeCode).format(date); + } catch (_) { + formattedDate = dateString; + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer.withValues(alpha: 0.5), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Icon(Icons.calendar_today_outlined, + color: theme.colorScheme.onPrimaryContainer, size: 20), + const SizedBox(width: 10), + Text( + l10n.planningForDate(formattedDate), + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ); + } +} + +// ── Planned slot tile (ghost entry from menu) ────────────────── + +class _PlannedSlotTile extends StatelessWidget { + final MealSlot slot; + final VoidCallback onConfirm; + + const _PlannedSlotTile({required this.slot, required this.onConfirm}); + + @override + Widget build(BuildContext context) { + final l10n = AppLocalizations.of(context)!; + final theme = Theme.of(context); + final recipe = slot.recipe; + if (recipe == null) return const SizedBox.shrink(); + + final calories = recipe.nutrition?.calories.toInt(); + + return Opacity( + opacity: 0.75, + child: ListTile( + dense: true, + title: Text(recipe.title, style: theme.textTheme.bodyMedium), + subtitle: Text( + l10n.plannedMealLabel, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.primary.withValues(alpha: 0.8), + ), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (calories != null) + Text( + '$calories ${l10n.caloriesUnit}', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(width: 4), + IconButton( + icon: Icon(Icons.check_circle_outline, + size: 20, color: theme.colorScheme.primary), + visualDensity: VisualDensity.compact, + tooltip: l10n.markAsEaten, + onPressed: onConfirm, + ), + ], + ), + ), + ); + } +} + // ── Expiring banner ─────────────────────────────────────────── class _ExpiringBanner extends StatelessWidget { diff --git a/client/lib/features/menu/menu_provider.dart b/client/lib/features/menu/menu_provider.dart index 01fbe56..4058212 100644 --- a/client/lib/features/menu/menu_provider.dart +++ b/client/lib/features/menu/menu_provider.dart @@ -29,6 +29,12 @@ final currentWeekProvider = StateProvider((ref) { return (thu.year, week); } +/// Returns the ISO 8601 week string for [date], e.g. "2026-W12". +String isoWeekString(DateTime date) { + final (year, week) = _isoWeek(date.toUtc()); + return '$year-W${week.toString().padLeft(2, '0')}'; +} + // ── Menu notifier ───────────────────────────────────────────── class MenuNotifier extends StateNotifier> { diff --git a/client/lib/l10n/app_ar.arb b/client/lib/l10n/app_ar.arb index 6908d27..99e0031 100644 --- a/client/lib/l10n/app_ar.arb +++ b/client/lib/l10n/app_ar.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "حصص", "addToDiary": "إضافة إلى اليومية", - "scanDishPhoto": "مسح الصورة" + "scanDishPhoto": "مسح الصورة", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_de.arb b/client/lib/l10n/app_de.arb index dd5812d..8677da7 100644 --- a/client/lib/l10n/app_de.arb +++ b/client/lib/l10n/app_de.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "Portionen", "addToDiary": "Zum Tagebuch hinzufügen", - "scanDishPhoto": "Foto scannen" + "scanDishPhoto": "Foto scannen", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_en.arb b/client/lib/l10n/app_en.arb index 9191bb1..8c55c9b 100644 --- a/client/lib/l10n/app_en.arb +++ b/client/lib/l10n/app_en.arb @@ -121,5 +121,13 @@ }, "servingsLabel": "Servings", "addToDiary": "Add to diary", - "scanDishPhoto": "Scan photo" + "scanDishPhoto": "Scan photo", + "planningForDate": "Planning for {date}", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "Mark as eaten", + "plannedMealLabel": "Planned" } diff --git a/client/lib/l10n/app_es.arb b/client/lib/l10n/app_es.arb index 02f062f..7a4b253 100644 --- a/client/lib/l10n/app_es.arb +++ b/client/lib/l10n/app_es.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "Porciones", "addToDiary": "Añadir al diario", - "scanDishPhoto": "Escanear foto" + "scanDishPhoto": "Escanear foto", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_fr.arb b/client/lib/l10n/app_fr.arb index 646466e..ccc12d8 100644 --- a/client/lib/l10n/app_fr.arb +++ b/client/lib/l10n/app_fr.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "Portions", "addToDiary": "Ajouter au journal", - "scanDishPhoto": "Scanner une photo" + "scanDishPhoto": "Scanner une photo", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_hi.arb b/client/lib/l10n/app_hi.arb index de6f1e7..d81e8bd 100644 --- a/client/lib/l10n/app_hi.arb +++ b/client/lib/l10n/app_hi.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "सर्विंग", "addToDiary": "डायरी में जोड़ें", - "scanDishPhoto": "फ़ोटो स्कैन करें" + "scanDishPhoto": "फ़ोटो स्कैन करें", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_it.arb b/client/lib/l10n/app_it.arb index b2f1177..5a590a9 100644 --- a/client/lib/l10n/app_it.arb +++ b/client/lib/l10n/app_it.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "Porzioni", "addToDiary": "Aggiungi al diario", - "scanDishPhoto": "Scansiona foto" + "scanDishPhoto": "Scansiona foto", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_ja.arb b/client/lib/l10n/app_ja.arb index b0ca73d..6000f1d 100644 --- a/client/lib/l10n/app_ja.arb +++ b/client/lib/l10n/app_ja.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "人前", "addToDiary": "日記に追加", - "scanDishPhoto": "写真をスキャン" + "scanDishPhoto": "写真をスキャン", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_ko.arb b/client/lib/l10n/app_ko.arb index dbd00f5..151f535 100644 --- a/client/lib/l10n/app_ko.arb +++ b/client/lib/l10n/app_ko.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "인분", "addToDiary": "일기에 추가", - "scanDishPhoto": "사진 스캔" + "scanDishPhoto": "사진 스캔", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_localizations.dart b/client/lib/l10n/app_localizations.dart index a65ad8f..79cfa9d 100644 --- a/client/lib/l10n/app_localizations.dart +++ b/client/lib/l10n/app_localizations.dart @@ -789,6 +789,24 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Scan photo'** String get scanDishPhoto; + + /// No description provided for @planningForDate. + /// + /// In en, this message translates to: + /// **'Planning for {date}'** + String planningForDate(String date); + + /// No description provided for @markAsEaten. + /// + /// In en, this message translates to: + /// **'Mark as eaten'** + String get markAsEaten; + + /// No description provided for @plannedMealLabel. + /// + /// In en, this message translates to: + /// **'Planned'** + String get plannedMealLabel; } class _AppLocalizationsDelegate diff --git a/client/lib/l10n/app_localizations_ar.dart b/client/lib/l10n/app_localizations_ar.dart index 4755b87..d440706 100644 --- a/client/lib/l10n/app_localizations_ar.dart +++ b/client/lib/l10n/app_localizations_ar.dart @@ -348,4 +348,15 @@ class AppLocalizationsAr extends AppLocalizations { @override String get scanDishPhoto => 'مسح الصورة'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_de.dart b/client/lib/l10n/app_localizations_de.dart index a6c587f..4c126cd 100644 --- a/client/lib/l10n/app_localizations_de.dart +++ b/client/lib/l10n/app_localizations_de.dart @@ -350,4 +350,15 @@ class AppLocalizationsDe extends AppLocalizations { @override String get scanDishPhoto => 'Foto scannen'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_en.dart b/client/lib/l10n/app_localizations_en.dart index f9c50f4..dea56e4 100644 --- a/client/lib/l10n/app_localizations_en.dart +++ b/client/lib/l10n/app_localizations_en.dart @@ -348,4 +348,15 @@ class AppLocalizationsEn extends AppLocalizations { @override String get scanDishPhoto => 'Scan photo'; + + @override + String planningForDate(String date) { + return 'Planning for $date'; + } + + @override + String get markAsEaten => 'Mark as eaten'; + + @override + String get plannedMealLabel => 'Planned'; } diff --git a/client/lib/l10n/app_localizations_es.dart b/client/lib/l10n/app_localizations_es.dart index ed04397..f1bfcdd 100644 --- a/client/lib/l10n/app_localizations_es.dart +++ b/client/lib/l10n/app_localizations_es.dart @@ -350,4 +350,15 @@ class AppLocalizationsEs extends AppLocalizations { @override String get scanDishPhoto => 'Escanear foto'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_fr.dart b/client/lib/l10n/app_localizations_fr.dart index 3406a8b..918964d 100644 --- a/client/lib/l10n/app_localizations_fr.dart +++ b/client/lib/l10n/app_localizations_fr.dart @@ -351,4 +351,15 @@ class AppLocalizationsFr extends AppLocalizations { @override String get scanDishPhoto => 'Scanner une photo'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_hi.dart b/client/lib/l10n/app_localizations_hi.dart index 7a0edef..2f3ef33 100644 --- a/client/lib/l10n/app_localizations_hi.dart +++ b/client/lib/l10n/app_localizations_hi.dart @@ -349,4 +349,15 @@ class AppLocalizationsHi extends AppLocalizations { @override String get scanDishPhoto => 'फ़ोटो स्कैन करें'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_it.dart b/client/lib/l10n/app_localizations_it.dart index b0d3275..7a7f200 100644 --- a/client/lib/l10n/app_localizations_it.dart +++ b/client/lib/l10n/app_localizations_it.dart @@ -350,4 +350,15 @@ class AppLocalizationsIt extends AppLocalizations { @override String get scanDishPhoto => 'Scansiona foto'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_ja.dart b/client/lib/l10n/app_localizations_ja.dart index 3ab2d3d..166c3c3 100644 --- a/client/lib/l10n/app_localizations_ja.dart +++ b/client/lib/l10n/app_localizations_ja.dart @@ -347,4 +347,15 @@ class AppLocalizationsJa extends AppLocalizations { @override String get scanDishPhoto => '写真をスキャン'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_ko.dart b/client/lib/l10n/app_localizations_ko.dart index 99db8e6..f7351d5 100644 --- a/client/lib/l10n/app_localizations_ko.dart +++ b/client/lib/l10n/app_localizations_ko.dart @@ -347,4 +347,15 @@ class AppLocalizationsKo extends AppLocalizations { @override String get scanDishPhoto => '사진 스캔'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_pt.dart b/client/lib/l10n/app_localizations_pt.dart index a165acd..e289d3f 100644 --- a/client/lib/l10n/app_localizations_pt.dart +++ b/client/lib/l10n/app_localizations_pt.dart @@ -350,4 +350,15 @@ class AppLocalizationsPt extends AppLocalizations { @override String get scanDishPhoto => 'Escanear foto'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_localizations_ru.dart b/client/lib/l10n/app_localizations_ru.dart index 4d80c4e..e92b4a2 100644 --- a/client/lib/l10n/app_localizations_ru.dart +++ b/client/lib/l10n/app_localizations_ru.dart @@ -348,4 +348,15 @@ class AppLocalizationsRu extends AppLocalizations { @override String get scanDishPhoto => 'Сканировать фото'; + + @override + String planningForDate(String date) { + return 'Планирование на $date'; + } + + @override + String get markAsEaten => 'Отметить как съеденное'; + + @override + String get plannedMealLabel => 'Запланировано'; } diff --git a/client/lib/l10n/app_localizations_zh.dart b/client/lib/l10n/app_localizations_zh.dart index 72953f7..c3f174f 100644 --- a/client/lib/l10n/app_localizations_zh.dart +++ b/client/lib/l10n/app_localizations_zh.dart @@ -347,4 +347,15 @@ class AppLocalizationsZh extends AppLocalizations { @override String get scanDishPhoto => '扫描照片'; + + @override + String planningForDate(String date) { + return ''; + } + + @override + String get markAsEaten => ''; + + @override + String get plannedMealLabel => ''; } diff --git a/client/lib/l10n/app_pt.arb b/client/lib/l10n/app_pt.arb index 0b33cb2..be183ce 100644 --- a/client/lib/l10n/app_pt.arb +++ b/client/lib/l10n/app_pt.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "Porções", "addToDiary": "Adicionar ao diário", - "scanDishPhoto": "Escanear foto" + "scanDishPhoto": "Escanear foto", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" } diff --git a/client/lib/l10n/app_ru.arb b/client/lib/l10n/app_ru.arb index 8987fbf..46f78c3 100644 --- a/client/lib/l10n/app_ru.arb +++ b/client/lib/l10n/app_ru.arb @@ -121,5 +121,13 @@ }, "servingsLabel": "Порций", "addToDiary": "Добавить в дневник", - "scanDishPhoto": "Сканировать фото" + "scanDishPhoto": "Сканировать фото", + "planningForDate": "Планирование на {date}", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "Отметить как съеденное", + "plannedMealLabel": "Запланировано" } diff --git a/client/lib/l10n/app_zh.arb b/client/lib/l10n/app_zh.arb index 03d385e..1543452 100644 --- a/client/lib/l10n/app_zh.arb +++ b/client/lib/l10n/app_zh.arb @@ -123,5 +123,13 @@ }, "servingsLabel": "份数", "addToDiary": "添加到日记", - "scanDishPhoto": "扫描照片" + "scanDishPhoto": "扫描照片", + "planningForDate": "", + "@planningForDate": { + "placeholders": { + "date": { "type": "String" } + } + }, + "markAsEaten": "", + "plannedMealLabel": "" }