Files
xcodesApp-mirror/Xcodes/Frontend/Common/ObservingProgressIndicator.swift

89 lines
3.2 KiB
Swift

import Combine
import SwiftUI
/// A ProgressIndicator that reflects the state of a Progress object.
/// This functionality is already built in to ProgressView,
/// but this implementation ensures that changes are received on the main thread.
@available(iOS 14.0, macOS 11.0, *)
public struct ObservingProgressIndicator: View {
let controlSize: NSControl.ControlSize
let style: NSProgressIndicator.Style
let showsAdditionalDescription: Bool
@StateObject private var progress: ProgressWrapper
public init(
_ progress: Progress,
controlSize: NSControl.ControlSize,
style: NSProgressIndicator.Style,
showsAdditionalDescription: Bool = false
) {
_progress = StateObject(wrappedValue: ProgressWrapper(progress: progress))
self.controlSize = controlSize
self.style = style
self.showsAdditionalDescription = showsAdditionalDescription
}
class ProgressWrapper: ObservableObject {
var progress: Progress
var cancellable: AnyCancellable!
init(progress: Progress) {
self.progress = progress
cancellable = progress.publisher(for: \.fractionCompleted)
.combineLatest(progress.publisher(for: \.localizedAdditionalDescription))
.throttle(for: 1.0, scheduler: DispatchQueue.main, latest: true)
.sink { [weak self] _ in self?.objectWillChange.send() }
}
}
public var body: some View {
VStack(alignment: .leading, spacing: 0) {
ProgressIndicator(
minValue: 0.0,
maxValue: 1.0,
doubleValue: progress.progress.fractionCompleted,
controlSize: controlSize,
isIndeterminate: progress.progress.isIndeterminate,
style: style
)
.help("Downloading: \(Int((progress.progress.fractionCompleted * 100)))% complete")
if showsAdditionalDescription, progress.progress.xcodesLocalizedDescription.isEmpty == false {
Text(progress.progress.xcodesLocalizedDescription)
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
}
@available(iOS 14.0, macOS 11.0, *)
struct ObservingProgressBar_Previews: PreviewProvider {
static var previews: some View {
Group {
ObservingProgressIndicator(
configure(Progress(totalUnitCount: 100)) {
$0.completedUnitCount = 40
},
controlSize: .small,
style: .spinning
)
ObservingProgressIndicator(
configure(Progress()) {
$0.kind = .file
$0.fileOperationKind = .downloading
$0.estimatedTimeRemaining = 123
$0.totalUnitCount = 11944848484
$0.completedUnitCount = 848444920
$0.throughput = 9211681
},
controlSize: .regular,
style: .bar,
showsAdditionalDescription: true
)
}
.previewLayout(.sizeThatFits)
}
}