Creating and updating recipes works in the new edit view

This commit is contained in:
VincentMeilinger
2024-03-04 11:58:16 +01:00
parent aa45bbdbd8
commit 597477544d
7 changed files with 132 additions and 131 deletions

View File

@@ -102,19 +102,33 @@ struct RecipeView: View {
.navigationTitle(viewModel.showTitle ? viewModel.recipe.name : "")
.toolbar {
if viewModel.editMode {
// Cancel Button
ToolbarItem(placement: .topBarLeading) {
Button("Cancel") {
viewModel.editMode = false
}
}
// Upload Button
ToolbarItem(placement: .topBarTrailing) {
Button {
// TODO: POST edited recipe
if viewModel.newRecipe {
presentationMode.wrappedValue.dismiss()
} else {
viewModel.editMode = false
Task {
if viewModel.newRecipe {
if let res = await uploadNewRecipe() {
viewModel.alertType = res
viewModel.presentAlert = true
} else {
presentationMode.wrappedValue.dismiss()
}
} else {
if let res = await uploadEditedRecipe() {
viewModel.alertType = res
viewModel.presentAlert = true
} else {
viewModel.editMode = false
}
}
}
} label: {
if viewModel.newRecipe {
@@ -124,6 +138,8 @@ struct RecipeView: View {
}
}
}
// Delete Button
if !viewModel.newRecipe {
ToolbarItem(placement: .topBarTrailing) {
Menu {

View File

@@ -12,21 +12,43 @@ import SwiftUI
struct RecipeDurationSection: View {
@ObservedObject var viewModel: RecipeView.ViewModel
@State var presentPopover: Bool = false
var body: some View {
if viewModel.editMode {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 200, maximum: .infinity), alignment: .leading)]) {
EditableDurationView(time: viewModel.observableRecipeDetail.prepTime, title: LocalizedStringKey("Preparation"))
EditableDurationView(time: viewModel.observableRecipeDetail.cookTime, title: LocalizedStringKey("Cooking"))
EditableDurationView(time: viewModel.observableRecipeDetail.totalTime, title: LocalizedStringKey("Total time"))
}
} else {
if !viewModel.editMode {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 200, maximum: .infinity), alignment: .leading)]) {
DurationView(time: viewModel.observableRecipeDetail.prepTime, title: LocalizedStringKey("Preparation"))
DurationView(time: viewModel.observableRecipeDetail.cookTime, title: LocalizedStringKey("Cooking"))
DurationView(time: viewModel.observableRecipeDetail.totalTime, title: LocalizedStringKey("Total time"))
}
} else {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 200, maximum: .infinity), alignment: .leading)]) {
Button {
presentPopover.toggle()
} label: {
DurationView(time: viewModel.observableRecipeDetail.prepTime, title: LocalizedStringKey("Preparation"))
}
Button {
presentPopover.toggle()
} label: {
DurationView(time: viewModel.observableRecipeDetail.cookTime, title: LocalizedStringKey("Cooking"))
}
Button {
presentPopover.toggle()
} label: {
DurationView(time: viewModel.observableRecipeDetail.totalTime, title: LocalizedStringKey("Total time"))
}
}
.popover(isPresented: $presentPopover) {
EditableDurationView(
prepTime: viewModel.observableRecipeDetail.prepTime,
cookTime: viewModel.observableRecipeDetail.cookTime,
totalTime: viewModel.observableRecipeDetail.totalTime
)
}
}
}
}
@@ -52,48 +74,30 @@ fileprivate struct DurationView: View {
}
fileprivate struct EditableDurationView: View {
@ObservedObject var time: DurationComponents
@State var title: LocalizedStringKey
@State var presentPopoverView: Bool = false
@State var hour: Int = 0
@State var minute: Int = 0
@ObservedObject var prepTime: DurationComponents
@ObservedObject var cookTime: DurationComponents
@ObservedObject var totalTime: DurationComponents
var body: some View {
VStack(alignment: .leading) {
HStack {
SecondaryLabel(text: title)
Spacer()
}
Button {
presentPopoverView.toggle()
} label: {
ScrollView {
VStack(alignment: .leading) {
HStack {
Image(systemName: "clock")
.foregroundStyle(.secondary)
Text(time.displayString)
.lineLimit(1)
SecondaryLabel(text: "Preparation")
Spacer()
}
TimePickerView(selectedHour: $prepTime.hourComponent, selectedMinute: $prepTime.minuteComponent)
SecondaryLabel(text: "Cooking")
TimePickerView(selectedHour: $cookTime.hourComponent, selectedMinute: $cookTime.minuteComponent)
SecondaryLabel(text: "Total")
TimePickerView(selectedHour: $totalTime.hourComponent, selectedMinute: $totalTime.minuteComponent)
}
}
.padding()
.popover(isPresented: $presentPopoverView) {
TimePickerPopoverView(selectedHour: $hour, selectedMinute: $minute)
}
.onChange(of: presentPopoverView) { presentPopover in
if !presentPopover {
time.hourComponent = String(hour)
time.minuteComponent = String(minute)
}
}
.onAppear {
minute = Int(time.minuteComponent) ?? 0
hour = Int(time.hourComponent) ?? 0
.padding()
}
}
}
fileprivate struct TimePickerPopoverView: View {
fileprivate struct TimePickerView: View {
@Binding var selectedHour: Int
@Binding var selectedMinute: Int

View File

@@ -14,14 +14,19 @@ struct RecipeMetadataSection: View {
@EnvironmentObject var appState: AppState
@ObservedObject var viewModel: RecipeView.ViewModel
@State var categories: [String] = []
@State var keywords: [RecipeKeyword] = []
var categories: [String] {
appState.categories.map({ category in category.name })
}
@State var presentKeywordSheet: Bool = false
@State var presentServingsPopover: Bool = false
@State var presentCategoryPopover: Bool = false
var body: some View {
VStack(alignment: .leading) {
// Category
//CategoryPickerView(items: $categories, input: $viewModel.observableRecipeDetail.recipeCategory, titleKey: "Category")
SecondaryLabel(text: "Category")
HStack {
@@ -29,13 +34,16 @@ struct RecipeMetadataSection: View {
.lineLimit(1)
.textFieldStyle(.roundedBorder)
Button {
presentCategoryPopover.toggle()
} label: {
Text("Choose")
Picker("Choose", selection: $viewModel.observableRecipeDetail.recipeCategory) {
Text("").tag("")
ForEach(categories, id: \.self) { item in
Text(item)
}
}
.pickerStyle(.menu)
}
// Keywords
SecondaryLabel(text: "Keywords")
if !viewModel.observableRecipeDetail.keywords.isEmpty {
@@ -54,7 +62,7 @@ struct RecipeMetadataSection: View {
Image(systemName: "chevron.right")
}
// Servings / Yield
VStack(alignment: .leading) {
SecondaryLabel(text: "Servings")
Button {
@@ -63,22 +71,16 @@ struct RecipeMetadataSection: View {
Text("\(viewModel.observableRecipeDetail.recipeYield) serving(s)")
.lineLimit(1)
}
.popover(isPresented: $presentServingsPopover) {
PickerPopoverView(value: $viewModel.observableRecipeDetail.recipeYield, items: 0..<99, titleKey: "Servings")
}
}
}
.padding()
.background(Rectangle().foregroundStyle(Color.white.opacity(0.1)))
.task {
categories = appState.categories.map({ category in category.name })
}
.sheet(isPresented: $presentKeywordSheet) {
KeywordPickerView(title: "Keywords", searchSuggestions: appState.allKeywords, selection: $viewModel.observableRecipeDetail.keywords)
}
.popover(isPresented: $presentServingsPopover) {
PickerPopoverView(value: $viewModel.observableRecipeDetail.recipeYield, items: 0..<99, titleKey: "Servings")
}
.popover(isPresented: $presentCategoryPopover) {
PickerPopoverView(value: $viewModel.observableRecipeDetail.recipeCategory, items: categories, titleKey: "Category")
}
}
}
@@ -95,7 +97,7 @@ fileprivate struct PickerPopoverView<Item: Hashable & CustomStringConvertible, C
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: 100, height: 150)
.frame(width: 150, height: 150)
.clipped()
}
.padding()