Files
Nextcloud-Cookbook-iOS/Nextcloud Cookbook iOS Client/Views/Recipes/AllRecipesListView.swift
Hendrik Hogertz 02118e3d7a Add dark mode support with appearance picker and fix hardcoded colors
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>
2026-02-15 06:31:14 +01:00

105 lines
3.8 KiB
Swift

//
// AllRecipesListView.swift
// Nextcloud Cookbook iOS Client
//
import SwiftUI
struct AllRecipesListView: View {
@EnvironmentObject var appState: AppState
@EnvironmentObject var groceryList: GroceryListManager
@EnvironmentObject var mealPlan: MealPlanManager
var onCreateNew: () -> Void
var onImportFromURL: () -> Void
@State private var allRecipes: [Recipe] = []
@State private var searchText: String = ""
private let gridColumns = [GridItem(.adaptive(minimum: 160), spacing: 12)]
var body: some View {
Group {
let recipes = recipesFiltered()
if !recipes.isEmpty {
ScrollView {
VStack(alignment: .leading, spacing: 8) {
Text("\(recipes.count) recipes")
.font(.subheadline)
.foregroundStyle(.secondary)
.padding(.horizontal)
LazyVGrid(columns: gridColumns, spacing: 12) {
ForEach(recipes, id: \.recipe_id) { recipe in
NavigationLink(value: recipe) {
RecipeCardView(recipe: recipe)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal)
}
.padding(.vertical)
}
} else {
VStack(spacing: 16) {
Image(systemName: "fork.knife")
.font(.system(size: 48))
.foregroundStyle(.secondary)
Text("No recipes found")
.font(.headline)
.foregroundStyle(.secondary)
Button {
Task {
allRecipes = await appState.getRecipes()
}
} label: {
Label("Refresh", systemImage: "arrow.clockwise")
.bold()
}
.buttonStyle(.bordered)
.tint(.primary)
}.padding()
}
}
.searchable(text: $searchText, prompt: "Search recipes/keywords")
.navigationTitle(String(localized: "All Recipes"))
.navigationDestination(for: Recipe.self) { recipe in
RecipeView(viewModel: RecipeView.ViewModel(recipe: recipe))
.environmentObject(appState)
.environmentObject(groceryList)
.environmentObject(mealPlan)
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Menu {
Button {
onCreateNew()
} label: {
Label("Create New Recipe", systemImage: "square.and.pencil")
}
Button {
onImportFromURL()
} label: {
Label("Import from URL", systemImage: "link")
}
} label: {
Image(systemName: "plus.circle.fill")
}
}
}
.task {
allRecipes = await appState.getRecipes()
}
.refreshable {
allRecipes = await appState.getRecipes()
}
}
private func recipesFiltered() -> [Recipe] {
guard !searchText.isEmpty else { return allRecipes }
return allRecipes.filter { recipe in
recipe.name.lowercased().contains(searchText.lowercased()) ||
(recipe.keywords != nil && recipe.keywords!.lowercased().contains(searchText.lowercased()))
}
}
}