Tusker/Packages/TuskerComponents/Sources/TuskerComponents/AsyncPicker.swift

71 lines
1.8 KiB
Swift

//
// AsyncPicker.swift
// TuskerComponents
//
// Created by Shadowfacts on 4/9/24.
//
import SwiftUI
public struct AsyncPicker<V: Hashable, Content: View>: View {
let titleKey: LocalizedStringKey
let alignment: Alignment
@Binding var value: V
let onChange: (V) async -> Bool
let content: Content
@State private var isLoading = false
public init(_ titleKey: LocalizedStringKey, alignment: Alignment = .center, value: Binding<V>, onChange: @escaping (V) async -> Bool, @ViewBuilder content: () -> Content) {
self.titleKey = titleKey
self.alignment = alignment
self._value = value
self.onChange = onChange
self.content = content()
}
public var body: some View {
LabeledContent(titleKey) {
picker
}
}
private var picker: some View {
ZStack(alignment: alignment) {
Picker(titleKey, selection: Binding(get: {
value
}, set: { newValue in
let oldValue = value
value = newValue
isLoading = true
Task {
let operationCompleted = await onChange(newValue)
if !operationCompleted {
value = oldValue
}
isLoading = false
}
})) {
content
}
.labelsHidden()
.opacity(isLoading ? 0 : 1)
if isLoading {
ProgressView()
}
}
}
}
#Preview {
@State var value = 0
return AsyncPicker("", value: $value) { _ in
try! await Task.sleep(nanoseconds: NSEC_PER_SEC)
return true
} content: {
ForEach(0..<10) {
Text("\($0)").tag($0)
}
}
}