Skip to content

Instantly share code, notes, and snippets.

@JetForMe
Last active March 21, 2024 21:24
Show Gist options
  • Save JetForMe/470be5a57bd690af370785a88e4f7b16 to your computer and use it in GitHub Desktop.
Save JetForMe/470be5a57bd690af370785a88e4f7b16 to your computer and use it in GitHub Desktop.
Dealing with @bindable Being Non-Optional
/**
The idea is to be able to invoke `ReminderDetailsWrapper` (forgive the naming, it’s
the result of the organic growth of this thing) with either the ID of an object to edit,
or nil, in which case it will create a new one. In both cases, it has to create a new
`ModelContext` on which to make the changes, and it only saves if the user taps the
“Save” button.
Some of thie could be improved if things could be loaded in `init()`, but that gets
called far too often as SwiftUI rebuilds the view hierarchy.
*/
struct
ReminderDetailsWrapper : View
{
let reminderToEdit : PersistentIdentifier?
var
body: some View
{
Group
{
if let reminder = self.reminder,
let context = self.editContext
{
ReminderDetailsView(reminder: reminder)
.modelContext(context)
}
else
{
EmptyView()
}
}
.onAppear
{
do
{
// Create a context in which to work…
self.editContext = ModelContext(self.modelContext.container)
self.editContext?.undoManager = UndoManager()
// If ``reminderToEdit`` is not nil, load it,
// otherwise, create a new one…
if let reminderID = self.reminderToEdit
{
self.reminder = self.editContext!.registeredModel(for: reminderID)
}
else
{
self.reminder = try self.model.newReminder(in: self.editContext!)
}
}
catch
{
print("Unable to load or create new reminder: \(error.localizedDescription)")
}
}
}
@State private var editContext : ModelContext?
@State private var reminder : CMReminder?
@EnvironmentObject private var model : CMModel
@Environment(\.modelContext) private var modelContext
}
struct
ReminderDetailsView: View
{
@Bindable var reminder : CMReminder
var
body: some View
{
NavigationStack
{
EditReminderForm(reminder: self.reminder)
.navigationTitle(Text("Set Reminder"))
.toolbar
{
ToolbarItem(placement: .navigationBarLeading)
{
Button("Close", action: close)
}
ToolbarItem(placement: .navigationBarTrailing)
{
Button("Save", action: save)
}
}
.interactiveDismissDisabled(self.isModified)
.confirmationDialog("Discard Changes?", isPresented: self.$isPresentingConfirmation)
{
Button("Discard", role: .destructive) { self.dismiss() }
Button("Keep Editing", role: .cancel) { }
}
}
}
func
close()
{
if self.isModified
{
self.isPresentingConfirmation = true
}
else
{
self.dismiss()
}
}
func
save()
{
Task
{
do
{
try await self.model.register(reminder: self.reminder)
try self.modelContext.save()
self.dismiss()
}
catch
{
print("Unable to save reminder changes: \(error.localizedDescription)")
// TODO: Display an error alert
}
}
}
@Query(sort: \CMVehicle.name) private var vehicles : [CMVehicle]
private var isModified : Bool { self.modelContext.undoManager!.canUndo }
@State private var isPresentingConfirmation = false
@EnvironmentObject private var model : CMModel
@Environment(\.modelContext) private var modelContext
@Environment(\.dismiss) private var dismiss
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment