Skip to content

Instantly share code, notes, and snippets.

@khanlou
Created June 27, 2024 23:27
Show Gist options
  • Save khanlou/0e5fcbfb83899d51b27401cecb1616d4 to your computer and use it in GitHub Desktop.
Save khanlou/0e5fcbfb83899d51b27401cecb1616d4 to your computer and use it in GitHub Desktop.
extension Button {
@MainActor
init(asyncAction: @escaping () async throws -> Void, loading: Binding<Bool>? = nil, error: Binding<Error?>? = nil, label: () -> Label) {
self.init(action: {
Task(tracking: loading, error: error) {
try await asyncAction()
}
}, label: label)
}
}
struct ErrorHandler: ViewModifier {
let error: Binding<Error?>
func body(content: Content) -> some View {
let nsError = (error.wrappedValue as NSError?)
return content
.alert(
nsError?.localizedFailureReason ?? "An error occurred",
isPresented: Binding(get: { error.wrappedValue != nil }, set: { _ in error.wrappedValue = nil }),
actions: {
Button("OK", action: {})
},
message: { Text(nsError?.localizedDescription ?? "") }
)
}
}
extension View {
@ViewBuilder
func displayError(_ error: Binding<Error?>) -> some View {
if error.wrappedValue is CancellationError { self }
else { self.modifier(ErrorHandler(error: error)) }
}
}
struct LoadingModifier: ViewModifier {
var isLoading: Bool
func body(content: Content) -> some View {
content
.disabled(self.isLoading)
.overlay {
ZStack {
if isLoading {
ProgressView()
Color.black.opacity(0.5)
}
}
.ignoresSafeArea(.all)
}
}
}
extension View {
func isLoading(_ isLoading: Bool) -> some View {
self
.modifier(LoadingModifier(isLoading: isLoading))
}
}
extension Task {
@discardableResult
@MainActor
init(tracking isLoading: Binding<Bool>?, error: Binding<Error?>?, _ task: @MainActor @escaping () async throws -> Void) where Failure == any Error, Success == Void {
self.init(operation: { @MainActor in
do {
isLoading?.wrappedValue = true
defer { isLoading?.wrappedValue = false }
return try await task()
} catch let err {
error?.wrappedValue = err
}
})
}
}
Button(asyncAction: createBoard, loading: $isLoading, error: $error) {
Text("Create").bold()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment