Skip to content

Commit 0f55a77

Browse files
committed
Update download-all progress view to use gauge.
1 parent 4c83d1a commit 0f55a77

File tree

1 file changed

+45
-22
lines changed

1 file changed

+45
-22
lines changed

Shared/Supporting Files/Views/DownloadOfflineResourcesView.swift

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,26 @@ struct DownloadOfflineResourcesView: View {
2222
/// The action to dismiss the view.
2323
@Environment(\.dismiss) private var dismiss
2424

25+
/// The progress of a download-all operation.
26+
@State private var downloadAllProgress: Progress?
27+
2528
/// The view models for the on-demand resource requests.
2629
@State private var onDemandResources: [String: OnDemandResource] = [:]
2730

28-
/// The current state of the "download all on-demand resources" request.
29-
@State private var downloadAllRequestState: OnDemandResource.RequestState = .notStarted
30-
3131
/// A Boolean value indicating whether all of the `onDemandResources` have successfully downloaded.
32-
private var allResourcesAreDownloaded: Bool {
33-
guard !onDemandResources.isEmpty else { return false }
34-
return onDemandResources.values
35-
.allSatisfy { $0.requestState == .downloaded }
32+
private var allResourcesAreDownloaded: Bool { uniqueRequestStates == [.downloaded] }
33+
34+
/// A Boolean value indicating whether there is an on going download-all operation.
35+
private var isDownloadingAll: Bool { downloadAllProgress != nil }
36+
37+
/// A Boolean value indicating whether there is an in progress download.
38+
private var isDownloadingResource: Bool { uniqueRequestStates.contains(.inProgress) }
39+
40+
/// The distinct request states of all on-demand resources.
41+
private var uniqueRequestStates: Set<OnDemandResource.RequestState> {
42+
onDemandResources.values.reduce(into: Set()) { result, resource in
43+
result.insert(resource.requestState)
44+
}
3645
}
3746

3847
/// Returns the on-demand resource for the given sample.
@@ -45,24 +54,24 @@ struct DownloadOfflineResourcesView: View {
4554
Form {
4655
Section {
4756
Button {
48-
downloadAllRequestState = .inProgress
57+
downloadAllProgress = Progress()
4958
} label: {
5059
Label {
5160
Text("Download All")
5261
} icon: {
53-
switch downloadAllRequestState {
54-
case .inProgress:
55-
ProgressView()
56-
case .downloaded:
62+
if let downloadAllProgress {
63+
ProgressView(downloadAllProgress)
64+
.progressViewStyle(GaugeProgressViewStyle())
65+
} else if allResourcesAreDownloaded {
5766
Image(systemName: "checkmark.circle")
5867
.foregroundStyle(.secondary)
59-
default:
68+
} else {
6069
Image(systemName: "arrow.down.circle")
6170
}
6271
}
6372
.frame(maxWidth: .infinity)
6473
}
65-
.disabled(onDemandResources.isEmpty || downloadAllRequestState != .notStarted || allResourcesAreDownloaded)
74+
.disabled(onDemandResources.isEmpty || isDownloadingAll || allResourcesAreDownloaded)
6675
}
6776
Section {
6877
List(samples, id: \.name) { sample in
@@ -78,7 +87,7 @@ struct DownloadOfflineResourcesView: View {
7887
.navigationBarTitleDisplayMode(.inline)
7988
.toolbar {
8089
ToolbarItem(placement: .confirmationAction) {
81-
if onDemandResources.values.contains(where: { $0.requestState == .inProgress }) {
90+
if isDownloadingResource {
8291
Button("Cancel") {
8392
for resource in onDemandResources.values where resource.requestState == .inProgress {
8493
resource.cancel()
@@ -108,13 +117,13 @@ struct DownloadOfflineResourcesView: View {
108117
return resources
109118
}
110119
}
111-
.task(id: downloadAllRequestState) {
112-
guard downloadAllRequestState == .inProgress else { return }
120+
.task(id: isDownloadingAll) {
121+
guard isDownloadingAll else { return }
113122
await downloadAll()
114123
}
115-
.onChange(of: allResourcesAreDownloaded) {
116-
guard allResourcesAreDownloaded else { return }
117-
downloadAllRequestState = .downloaded
124+
.onChange(of: isDownloadingResource) {
125+
guard isDownloadingAll, !isDownloadingResource else { return }
126+
downloadAllProgress = nil
118127
}
119128
}
120129
}
@@ -123,8 +132,13 @@ struct DownloadOfflineResourcesView: View {
123132
/// - Note: The system may purge the resources at any time after the request object is deallocated.
124133
private func downloadAll() async {
125134
await withTaskGroup { group in
126-
for resource in onDemandResources.values where resource.isDownloadable {
127-
group.addTask(operation: resource.download)
135+
for resource in onDemandResources.values {
136+
if resource.isDownloadable {
137+
group.addTask(operation: resource.download)
138+
downloadAllProgress?.addChildUnits(resource.progress)
139+
} else if resource.requestState == .inProgress {
140+
downloadAllProgress?.addChildUnits(resource.progress)
141+
}
128142
}
129143
}
130144

@@ -197,3 +211,12 @@ private struct GaugeProgressViewStyle: ProgressViewStyle {
197211
}
198212
}
199213
}
214+
215+
private extension Progress {
216+
/// Adds a process object and its unit count as a suboperation of a progress tree.
217+
/// - Parameter progress: The progress instance to add to the progress tree.
218+
func addChildUnits(_ progress: Progress) {
219+
addChild(progress, withPendingUnitCount: progress.totalUnitCount)
220+
totalUnitCount += progress.totalUnitCount
221+
}
222+
}

0 commit comments

Comments
 (0)