Add user-facing appearance setting (System/Light/Dark) wired via
preferredColorScheme at the app root. Replace hardcoded .black tints
and foreground styles with .primary so toolbar buttons and text remain
visible in dark mode. Remove profile picture from settings and
SwiftSoup from acknowledgements.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Introduces weekly meal planning with a calendar-based tab view, per-recipe
date assignments synced via Nextcloud Cookbook custom metadata, and 30-day
automatic pruning of old entries on load, save, and sync merge.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace the single "+" button with a 2-option menu (Create New Recipe / Import
from URL) across RecipeTabView, RecipeListView, and AllRecipesListView. Add
ImportURLSheet for server-side recipe import with loading and error states.
Completely redesign edit mode to use a native Form layout with inline editing
for all sections (metadata, duration, ingredients, instructions, tools,
nutrition) instead of the previous sheet-based EditableListView approach. Move
delete action from edit toolbar to view mode context menu. Add recipe image
display to the edit form.
Refactor RecipeListView and AllRecipesListView to use closure-based callbacks
instead of Binding<Bool> for the create/import actions. Add preloadedRecipeDetail
support to RecipeView.ViewModel for imported recipes.
Add DE/ES/FR translations for all new UI strings.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Introduce a GroceryListManager facade that delegates to either the existing
in-app GroceryList or a new RemindersGroceryStore backed by EventKit. Users
choose the mode in Settings; when Reminders mode is active the Grocery List
tab is hidden. Recipe-to-reminder grouping uses a local mapping file
(reminder_mappings.data) instead of polluting the reminder's notes field,
with automatic pruning when reminders are deleted externally.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Overhaul SearchTabView with search history, empty/no-results states, and dynamic
navigation title. Extract CategoryCardView and RecentRecipesSection into standalone
views. Update RecipeTabView, RecipeListView, RecipeCardView, and MainView for the
modernized UI. Add all 12 missing German translations in Localizable.xcstrings.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Network layer:
- Replace static CookbookApi protocol with instance-based CookbookApiProtocol
using async/throws instead of tuple returns
- Refactor ApiRequest to use URLComponents for proper URL encoding, replace
print statements with OSLog, and return typed NetworkError cases
- Add structured NetworkError variants (httpError, connectionError, etc.)
- Remove global cookbookApi constant in favor of injected dependency on AppState
- Delete unused RecipeEditViewModel, RecipeScraper, and Scraper playground
Data & model fixes:
- Add custom Decodable for RecipeDetail with safe fallbacks for malformed JSON
- Make Category Hashable/Equatable use only `name` so NavigationSplitView
selection survives category refreshes with updated recipe_count
- Return server-assigned ID from uploadRecipe so new recipes get their ID
before the post-upload refresh block executes
View updates:
- Refresh both old and new category recipe lists after upload when category
changes, mapping empty recipeCategory to "*" for uncategorized recipes
- Raise deployment target to iOS 18, adopt new SwiftUI API conventions
- Clean up alerts, onboarding views, and settings
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>