Tusker/Tusker/Screens/Preferences/Notifications/TriStateToggle.swift

80 lines
1.9 KiB
Swift

//
// TriStateToggle.swift
// Tusker
//
// Created by Shadowfacts on 4/7/24.
// Copyright © 2024 Shadowfacts. All rights reserved.
//
import SwiftUI
struct TriStateToggle: View {
let titleKey: LocalizedStringKey
@available(iOS, obsoleted: 16.0, message: "Switch to LabeledContent")
let labelHidden: Bool
@Binding var mode: Mode
let onChange: (Bool) async -> Void
init(_ titleKey: LocalizedStringKey, labelHidden: Bool = false, mode: Binding<Mode>, onChange: @escaping (Bool) async -> Void) {
self.titleKey = titleKey
self.labelHidden = labelHidden
self._mode = mode
self.onChange = onChange
}
var body: some View {
content
}
@ViewBuilder
private var content: some View {
if #available(iOS 16.0, *) {
LabeledContent(titleKey) {
toggleOrSpinner
}
} else if labelHidden {
toggleOrSpinner
} else {
HStack {
Text(titleKey)
Spacer()
toggleOrSpinner
}
}
}
@ViewBuilder
private var toggleOrSpinner: some View {
ZStack {
Toggle(titleKey, isOn: Binding {
mode == .on
} set: { newValue in
mode = .loading
Task {
await onChange(newValue)
mode = newValue ? .on : .off
}
})
.labelsHidden()
.opacity(mode == .loading ? 0 : 1)
if mode == .loading {
ProgressView()
}
}
}
enum Mode {
case off
case loading
case on
}
}
#Preview {
@State var mode = TriStateToggle.Mode.on
return TriStateToggle("", mode: $mode) { _ in
try! await Task.sleep(nanoseconds: NSEC_PER_SEC)
}
}