Files
Nextcloud-Cookbook-iOS/Nextcloud Cookbook iOS Client/Views/Recipes/RecipeViewSections/RecipeInstructionSection.swift
Hendrik Hogertz 1536174586 Redesign recipe creation and edit view with Form-based layout and URL import
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>
2026-02-15 03:29:20 +01:00

90 lines
2.5 KiB
Swift

//
// RecipeInstructionSection.swift
// Nextcloud Cookbook iOS Client
//
// Created by Vincent Meilinger on 01.03.24.
//
import Foundation
import SwiftUI
// MARK: - RecipeView Instructions Section
struct RecipeInstructionSection: View {
@ObservedObject var viewModel: RecipeView.ViewModel
var body: some View {
VStack(alignment: .leading) {
HStack {
SecondaryLabel(text: LocalizedStringKey("Instructions"))
Spacer()
}
ForEach(viewModel.observableRecipeDetail.recipeInstructions.indices, id: \.self) { ix in
RecipeInstructionListItem(instruction: $viewModel.observableRecipeDetail.recipeInstructions[ix], index: ix+1)
}
}
.padding()
}
}
// MARK: - Recipe Edit Instruction Section (Form-based)
struct RecipeEditInstructionSection: View {
@Binding var instructions: [String]
var body: some View {
Section {
ForEach(instructions.indices, id: \.self) { index in
HStack(alignment: .top) {
Text("\(index + 1).")
.foregroundStyle(.secondary)
.monospacedDigit()
TextField("Step \(index + 1)", text: $instructions[index], axis: .vertical)
.lineLimit(1...10)
Image(systemName: "line.3.horizontal")
.foregroundStyle(.tertiary)
.padding(.top, 4)
}
}
.onDelete { indexSet in
instructions.remove(atOffsets: indexSet)
}
.onMove { from, to in
instructions.move(fromOffsets: from, toOffset: to)
}
Button {
instructions.append("")
} label: {
Label("Add Step", systemImage: "plus.circle.fill")
}
} header: {
Text("Instructions")
}
}
}
fileprivate struct RecipeInstructionListItem: View {
@Binding var instruction: String
@State var index: Int
@State var isSelected: Bool = false
var body: some View {
HStack(alignment: .top) {
Text("\(index)")
.monospaced()
Text(instruction)
}.padding(4)
.foregroundStyle(isSelected ? Color.secondary : Color.primary)
.onTapGesture {
isSelected.toggle()
}
.animation(.easeInOut, value: isSelected)
}
}