mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Replace ObservingDownloadStatsView with ObservingProgressIndicator
This more closely replicates the default look and feel of SwiftUI.ProgressView, but with explicit control over whether localizedAdditionalDescription is shown and without the label above the progress view that displays a fileOperationKind string.
This commit is contained in:
parent
e638547900
commit
1469dfa56b
4 changed files with 41 additions and 99 deletions
|
|
@ -102,7 +102,6 @@
|
|||
E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8977EA225C11E1500835F80 /* PreferencesView.swift */; };
|
||||
E8E98A9025D8631800EC89A0 /* InstallationStepRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBC3FF259AC17F00E2A3D8 /* InstallationStepRowView.swift */; };
|
||||
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */; };
|
||||
E8F0838625D873A400A4C470 /* ObservingDownloadStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8F0838525D873A400A4C470 /* ObservingDownloadStatsView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -265,7 +264,6 @@
|
|||
E87DD6EA25D053FA00D86808 /* Progress+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+.swift"; sourceTree = "<group>"; };
|
||||
E8977EA225C11E1500835F80 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
||||
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepDetailView.swift; sourceTree = "<group>"; };
|
||||
E8F0838525D873A400A4C470 /* ObservingDownloadStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservingDownloadStatsView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -557,7 +555,6 @@
|
|||
children = (
|
||||
CAFBDC67259A308B003DCC5A /* InfoPane.swift */,
|
||||
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */,
|
||||
E8F0838525D873A400A4C470 /* ObservingDownloadStatsView.swift */,
|
||||
);
|
||||
path = InfoPane;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -797,7 +794,6 @@
|
|||
CA73510D257BFCEF00EA9CF8 /* NSAttributedString+.swift in Sources */,
|
||||
CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */,
|
||||
CAC9F92D25BCDA4400B4965F /* HelperInstallState.swift in Sources */,
|
||||
E8F0838625D873A400A4C470 /* ObservingDownloadStatsView.swift in Sources */,
|
||||
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */,
|
||||
CAC281CD259F97FA00B8AB0B /* ObservingProgressIndicator.swift in Sources */,
|
||||
CABFA9C22592EEEA00380FEE /* Publisher+Resumable.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -8,16 +8,19 @@ import SwiftUI
|
|||
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
|
||||
style: NSProgressIndicator.Style,
|
||||
showsAdditionalDescription: Bool = false
|
||||
) {
|
||||
_progress = StateObject(wrappedValue: ProgressWrapper(progress: progress))
|
||||
self.controlSize = controlSize
|
||||
self.style = style
|
||||
self.showsAdditionalDescription = showsAdditionalDescription
|
||||
}
|
||||
|
||||
class ProgressWrapper: ObservableObject {
|
||||
|
|
@ -26,23 +29,31 @@ public struct ObservingProgressIndicator: View {
|
|||
|
||||
init(progress: Progress) {
|
||||
self.progress = progress
|
||||
cancellable = progress
|
||||
.publisher(for: \.completedUnitCount)
|
||||
.receive(on: RunLoop.main)
|
||||
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 {
|
||||
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")
|
||||
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.localizedAdditionalDescription.isEmpty == false {
|
||||
Text(progress.progress.localizedAdditionalDescription)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +68,20 @@ struct ObservingProgressBar_Previews: PreviewProvider {
|
|||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ struct InstallationStepDetailView: View {
|
|||
case let .downloading(progress):
|
||||
Text("Step \(installationStep.stepNumber) of \(installationStep.stepCount): \(installationStep.message)")
|
||||
.font(.title2)
|
||||
ObservingDownloadStatsView(
|
||||
ObservingProgressIndicator(
|
||||
progress,
|
||||
controlSize: .regular,
|
||||
style: .bar
|
||||
style: .bar,
|
||||
showsAdditionalDescription: true
|
||||
)
|
||||
|
||||
case .unarchiving, .moving, .trashingArchive, .checkingSecurity, .finishing:
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
|
||||
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 ObservingDownloadStatsView: View {
|
||||
let controlSize: NSControl.ControlSize
|
||||
let style: NSProgressIndicator.Style
|
||||
@StateObject private var progress: ProgressWrapper
|
||||
|
||||
public init(
|
||||
_ progress: Progress,
|
||||
controlSize: NSControl.ControlSize,
|
||||
style: NSProgressIndicator.Style
|
||||
) {
|
||||
_progress = StateObject(wrappedValue: ProgressWrapper(progress: progress))
|
||||
self.controlSize = controlSize
|
||||
self.style = style
|
||||
}
|
||||
|
||||
class ProgressWrapper: ObservableObject {
|
||||
var progress: Progress
|
||||
var cancellable: AnyCancellable!
|
||||
|
||||
init(progress: Progress) {
|
||||
self.progress = progress
|
||||
cancellable = progress
|
||||
.publisher(for: \.completedUnitCount)
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] _ in self?.objectWillChange.send() }
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
|
||||
VStack{
|
||||
HStack {
|
||||
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")
|
||||
Text("\(Int((progress.progress.fractionCompleted * 100)))%")
|
||||
}
|
||||
HStack {
|
||||
if let fileCompletedCount = progress.progress.fileCompletedCount, let fileTotalCount = progress.progress.fileTotalCount {
|
||||
Text("\(ByteCountFormatter.string(fromByteCount: Int64(fileCompletedCount), countStyle: .file)) of \(ByteCountFormatter.string(fromByteCount: Int64(fileTotalCount), countStyle: .file))")
|
||||
}
|
||||
if let throughput = progress.progress.throughput {
|
||||
Text(" at \(ByteCountFormatter.string(fromByteCount: Int64(throughput), countStyle: .binary))/sec")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14.0, macOS 11.0, *)
|
||||
struct ObservingDownloadStats_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
ObservingDownloadStatsView(
|
||||
configure(Progress(totalUnitCount: 100)) {
|
||||
$0.completedUnitCount = 40; $0.throughput = 9211681; $0.fileCompletedCount = 84844492; $0.fileTotalCount = 11944848484
|
||||
},
|
||||
controlSize: .small,
|
||||
style: .bar
|
||||
)
|
||||
}
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue