Further code posted in response to @DelawareMathGuy's comment on my original post:
struct CourseEditView: View {
@Environment(\.colorScheme) var colorScheme
var backgroundColor: Color {
Color(uiColor: (colorScheme == .dark ? .systemBackground : .secondarySystemBackground))
}
enum Field: Hashable {
case name
}
@ObservedObject var vm: CourseEditViewModel
@FocusState private var nameFieldFocused: Field?
init(isPreview: Bool, course: Course? = nil) {
self.vm = CourseEditViewModel(manager: isPreview ? PersistenceManager.preview : PersistenceManager.shared, course: course)
}
var body: some View {
VStack {
Form {
HStack {
LabelledTextField(value: $vm.name, label: "Course name")
.focused($nameFieldFocused, equals: .name)
if !vm.isValid {
Image(systemName: "exclamationmark.triangle.fill").foregroundColor(.yellow)
}
}
Section {
List {
ForEach(vm.cards, id: \.teeColour) { card in
NavigationLink(destination: {
CardDetailsView(viewModel: CardDetailsViewModel(manager: vm.persistenceManager, course: vm.course!, card: card))
}, label: {
CardLinkView(card: card)
})
}
// .onDelete(perform: deleteCards)
}
} header: {
HStack {
if vm.isValid {
Text("CARDS")
Spacer()
NavigationLink {
CardDetailsView(viewModel: CardDetailsViewModel(manager: vm.persistenceManager, course: vm.course!))
} label: {
HStack(spacing: 4) {
Image(systemName: "plus")
.font(.title2)
Text("Add card")
}
.foregroundColor(.accentColor)
}
}
}
}
}
.padding(.top)
.navigationTitle("Add/edit Course")
.onAppear {
if !vm.isValid {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
nameFieldFocused = .name
}
}
vm.refresh()
}
}
.background(backgroundColor)
}
}
class CourseEditViewModel: ObservableObject {
var course: Course?
@Published var name: String = "" {
didSet {
isValid = !name.isEmpty
if isValid {
saveChanges()
}
}
}
@Published var isValid: Bool = false
var cards: [Card] {
course?.courseCards.sorted(by: { $0.teeColourOrder < $1.teeColourOrder }) ?? []
}
private (set) var persistenceManager: PersistenceManager
private var isInitialising: Bool = true
init(manager: PersistenceManager, course: Course? = nil) {
self.persistenceManager = manager
if course != nil {
self.course = course
self.name = course?.name ?? "Unknown"
}
isInitialising = false
}
func refresh() {
objectWillChange.send()
}
func saveChanges() {
guard !isInitialising else { return }
var saved = false
if let course = self.course {
course.name = name
saved = persistenceManager.applyChanges()
} else {
let course = persistenceManager.courseRepository.new { course in
course.id = UUID()
course.name = self.name
}
saved = persistenceManager.applyChanges()
if saved {
self.course = course
}
}
if !saved {
persistenceManager.rollback()
}
}
}