I am creating a View that may or may not receive a binding:
import SwiftUI
struct AssignmentEditMenu: View {
@EnvironmentObject var planner: Planner
@Environment(\.dismiss) var dismiss
var isEditing // set to true if assignment is not nil
var assignment: Binding<Assignment>?
@State var newAssignment = assignment ?? Assignment()
// if assignment is not nil, create a copy of it and set newAssignment equal to the copy
// if assignment is nil, initialize a new struct and set newAssignment equal to it
var body: some View {
NavigationView {
Form {
nameSection
dateSection
}
.navigationTitle(Text("New Assignment"))
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(isEditing ? "Add" : "Done") {
isEditing ? (assignment = newAssignment) : planner.addAssignment(newAssignment)
dismiss()
}
}
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss()
}
}
}
}
}
var nameSection: some View {
Section {
TextField("Name", text: $newAssignment.name)
Picker("Course", selection: $newAssignment.course) {
ForEach(planner.courses) { course in
Text("\(course.name)").tag(course)
}
}
}
}
var dateSection: some View {
Section {
DatePicker(
selection: $newAssignment.assignedDate,
displayedComponents: [.date, .hourAndMinute]
) {
Text("Assigned:")
.lineLimit(1)
.allowsTightening(true)
}
DatePicker(
selection: $newAssignment.dueDate
) {
Text("Due:")
.lineLimit(1)
.allowsTightening(true)
}
}
}
}
What I am trying to do is if a binding to an Assignment
is passed in here, then the View is in Edit Mode. newAssignment
will be set to the same values as the assignment
binding but not reference it at all. It will collect changes and when complete, set that assignment
binding equal to itself, thus saving the changes. The reason for using newAssignment
is so that if the user cancels (this view will be a sheet) changes are discarded since newAssignment
is a @State var.
When no Assignment
binding is passed in the View is in Create mode. newAssignment
collects the changes and is added to the store via planner
.
Assignment
implementation:
struct Assignment: Identifiable, Equatable, Hashable {
var name: String
var assignedDate: Date
var dueDate: Date
var course: Course
var percentCompleted: Double
let id: UUID
init(
name: String = "",
assignedDate: Date = Date(),
dueDate: Date = Calendar.current.nextDate(after: Date(), matching: .init(hour: 0, minute: 0), matchingPolicy: .strict)!,
course: Course = Course()
) {
self.name = name
self.assignedDate = assignedDate
self.dueDate = dueDate
self.course = course
self.id = UUID()
self.percentCompleted = 0.0
}
}
struct Course: Identifiable, Equatable, Hashable {
var name: String
let id: UUID
init(_ name: String = "Course") {
self.name = name
self.id = UUID()
}
}
CodePudding user response:
Add a custom init. With that, newAssignment
var is also not needed.
struct AssignmentEditMenu: View {
@EnvironmentObject var planner: Planner
@Environment(\.dismiss) var dismiss
var isEditing // set to true if assignment is not nil
var assignment: Binding<Assignment>
init(a: Binding<Assignment> = .constant(Assignment())) {
assignment = a
}
.....
}