Fix settings page dismissing immediately by replacing multiple isPresented navigation destinations with value-based NavigationPath
The settings view was being popped immediately after push because multiple navigationDestination(isPresented:) modifiers on the same view caused SwiftUI to reset bindings when appState published changes. Replaced with a single navigationDestination(for: SidebarDestination.self) using an explicit NavigationStack(path:). Also fixed @ObservedObject -> @StateObject on SettingsView.ViewModel, added AllRecipesListView/AllRecipesCategoryCardView, and added translations for new strings. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// AllRecipesListView.swift
|
||||
// Nextcloud Cookbook iOS Client
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AllRecipesListView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@EnvironmentObject var groceryList: GroceryList
|
||||
@Binding var showEditView: Bool
|
||||
@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(.nextcloudBlue)
|
||||
}.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)
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Button {
|
||||
showEditView = true
|
||||
} 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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user