Download stats for Aria2

This commit is contained in:
Matt Kiazyk 2021-02-13 11:20:26 -06:00
parent 2329098601
commit b06be4e3fa
No known key found for this signature in database
GPG key ID: 967DBC53389132D7
9 changed files with 270 additions and 38 deletions

View file

@ -75,7 +75,6 @@
CABFAA432593104F00380FEE /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFAA422593104F00380FEE /* AboutView.swift */; };
CABFAA492593162500380FEE /* Bundle+InfoPlistValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFAA482593162500380FEE /* Bundle+InfoPlistValues.swift */; };
CAC28188259EE27200B8AB0B /* CombineExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = CAC28187259EE27200B8AB0B /* CombineExpectations */; };
CAC281C8259F97E100B8AB0B /* InstallationStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAC281C7259F97E100B8AB0B /* InstallationStepView.swift */; };
CAC281CD259F97FA00B8AB0B /* ObservingProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAC281CC259F97FA00B8AB0B /* ObservingProgressIndicator.swift */; };
CAC281DA259F985100B8AB0B /* InstallationStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAC281D9259F985100B8AB0B /* InstallationStep.swift */; };
CAC281E2259FA44600B8AB0B /* Bundle+XcodesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAC281E1259FA44600B8AB0B /* Bundle+XcodesTests.swift */; };
@ -99,7 +98,11 @@
CAFE4AB425B7D3AF0064FE51 /* AdvancedPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFE4AB325B7D3AF0064FE51 /* AdvancedPreferencePane.swift */; };
CAFE4ABC25B7D54B0064FE51 /* UpdatesPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFE4ABB25B7D54B0064FE51 /* UpdatesPreferencePane.swift */; };
CAFFFED8259CDA5000903F81 /* XcodeListViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */; };
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
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 */
@ -227,7 +230,6 @@
CABFAA2B2592FBFC00380FEE /* Configure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Configure.swift; path = Xcodes/Backend/Configure.swift; sourceTree = SOURCE_ROOT; };
CABFAA422593104F00380FEE /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
CABFAA482593162500380FEE /* Bundle+InfoPlistValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+InfoPlistValues.swift"; sourceTree = "<group>"; };
CAC281C7259F97E100B8AB0B /* InstallationStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepView.swift; sourceTree = "<group>"; };
CAC281CC259F97FA00B8AB0B /* ObservingProgressIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservingProgressIndicator.swift; sourceTree = "<group>"; };
CAC281D9259F985100B8AB0B /* InstallationStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStep.swift; sourceTree = "<group>"; };
CAC281E1259FA44600B8AB0B /* Bundle+XcodesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+XcodesTests.swift"; sourceTree = "<group>"; };
@ -247,7 +249,7 @@
CAE42486259A68A300B8B246 /* XcodeListCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeListCategory.swift; sourceTree = "<group>"; };
CAE4248B259A68B800B8B246 /* Optional+IsNotNil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+IsNotNil.swift"; sourceTree = "<group>"; };
CAE424B3259A764700B8B246 /* AppState+Install.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AppState+Install.swift"; sourceTree = "<group>"; };
CAFBC3FF259AC17F00E2A3D8 /* InstallationStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepView.swift; sourceTree = "<group>"; };
CAFBC3FF259AC17F00E2A3D8 /* InstallationStepRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationStepRowView.swift; sourceTree = "<group>"; };
CAFBC421259ACF8000E2A3D8 /* ObservingProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservingProgressView.swift; sourceTree = "<group>"; };
CAFBDB902598FE80003DCC5A /* SelectedXcode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedXcode.swift; sourceTree = "<group>"; };
CAFBDB942598FE96003DCC5A /* FocusedValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusedValues.swift; sourceTree = "<group>"; };
@ -260,7 +262,10 @@
CAFE4ABB25B7D54B0064FE51 /* UpdatesPreferencePane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatesPreferencePane.swift; sourceTree = "<group>"; };
CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeListViewRow.swift; sourceTree = "<group>"; };
CAFFFEEE259CEAC400903F81 /* RingProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RingProgressViewStyle.swift; sourceTree = "<group>"; };
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 */
@ -387,14 +392,12 @@
isa = PBXGroup;
children = (
CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */,
CAFBDC67259A308B003DCC5A /* InfoPane.swift */,
CAFBC3FF259AC17F00E2A3D8 /* InstallationStepView.swift */,
CAFBC3FF259AC17F00E2A3D8 /* InstallationStepRowView.swift */,
CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */,
CA44901E2463AD34003D8213 /* Tag.swift */,
CAE42486259A68A300B8B246 /* XcodeListCategory.swift */,
CAD2E7A32449574E00113D76 /* XcodeListView.swift */,
CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */,
CAC281C7259F97E100B8AB0B /* InstallationStepView.swift */,
);
path = XcodeList;
sourceTree = "<group>";
@ -437,6 +440,7 @@
CA61A6DF259835580008926E /* Xcode.swift */,
CA25192925A9644800F08414 /* XcodeInstallState.swift */,
CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */,
E87DD6EA25D053FA00D86808 /* Progress+.swift */,
);
path = Backend;
sourceTree = "<group>";
@ -444,6 +448,7 @@
CABFAA1A2592F7D900380FEE /* Frontend */ = {
isa = PBXGroup;
children = (
E8E98A9425D863B100EC89A0 /* InfoPane */,
63EAA4E9259944340046AB8F /* Common */,
CA9FF8552595082000E47BAF /* About */,
CAFE4AAA25B7D29B0064FE51 /* Preferences */,
@ -547,6 +552,16 @@
path = Preferences;
sourceTree = "<group>";
};
E8E98A9425D863B100EC89A0 /* InfoPane */ = {
isa = PBXGroup;
children = (
CAFBDC67259A308B003DCC5A /* InfoPane.swift */,
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */,
E8F0838525D873A400A4C470 /* ObservingDownloadStatsView.swift */,
);
path = InfoPane;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -757,6 +772,7 @@
CABFA9BD2592EEEA00380FEE /* Environment.swift in Sources */,
CABFA9C32592EEEA00380FEE /* Downloads.swift in Sources */,
CAC281DA259F985100B8AB0B /* InstallationStep.swift in Sources */,
E8E98A9625D863D700EC89A0 /* InstallationStepDetailView.swift in Sources */,
CA378F992466567600A58CE0 /* AppState.swift in Sources */,
CAD2E7A42449574E00113D76 /* XcodeListView.swift in Sources */,
CAA1CB45255A5B60003FD669 /* SignIn2FAView.swift in Sources */,
@ -768,7 +784,6 @@
CAE4247F259A666100B8B246 /* MainWindow.swift in Sources */,
CA452BB0259FD9770072DFA4 /* ProgressIndicator.swift in Sources */,
CAFE4AB425B7D3AF0064FE51 /* AdvancedPreferencePane.swift in Sources */,
CAC281C8259F97E100B8AB0B /* InstallationStepView.swift in Sources */,
CA9FF84E2595079F00E47BAF /* ScrollingTextView.swift in Sources */,
CABFA9C12592EEEA00380FEE /* Version+.swift in Sources */,
CA9FF8522595080100E47BAF /* AcknowledgementsView.swift in Sources */,
@ -782,6 +797,8 @@
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 */,
CAFBDC68259A308B003DCC5A /* InfoPane.swift in Sources */,
@ -797,6 +814,7 @@
CA9FF87B2595293E00E47BAF /* DataSource.swift in Sources */,
CABFA9C92592EEEA00380FEE /* URLRequest+Apple.swift in Sources */,
CABFAA432593104F00380FEE /* AboutView.swift in Sources */,
E8E98A9025D8631800EC89A0 /* InstallationStepRowView.swift in Sources */,
CABFA9CC2592EEEA00380FEE /* Path+.swift in Sources */,
CAD2E7A22449574E00113D76 /* XcodesApp.swift in Sources */,
63EAA4EB259944450046AB8F /* ProgressButton.swift in Sources */,

View file

@ -45,6 +45,7 @@ public struct Shell {
"--stop-with-process=\(ProcessInfo.processInfo.processIdentifier)",
"--dir=\(destination.parent.string)",
"--out=\(destination.basename())",
"--human-readable=false", // sets the output to use bytes instead of formatting
url.absoluteString,
]
let stdOutPipe = Pipe()
@ -53,7 +54,7 @@ public struct Shell {
process.standardError = stdErrPipe
var progress = Progress(totalUnitCount: 100)
let observer = NotificationCenter.default.addObserver(
forName: .NSFileHandleDataAvailable,
object: nil,
@ -68,16 +69,8 @@ public struct Shell {
defer { handle.waitForDataInBackgroundAndNotify() }
let string = String(decoding: handle.availableData, as: UTF8.self)
let regex = try! NSRegularExpression(pattern: #"((?<percent>\d+)%\))"#)
let range = NSRange(location: 0, length: string.utf16.count)
guard
let match = regex.firstMatch(in: string, options: [], range: range),
let matchRange = Range(match.range(withName: "percent"), in: string),
let percentCompleted = Int64(string[matchRange])
else { return }
progress.completedUnitCount = percentCompleted
progress.updateFromAria2(string: string)
}
stdOutPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()

View file

@ -0,0 +1,78 @@
import Foundation
extension Progress {
func updateFromAria2(string: String) {
let range = NSRange(location: 0, length: string.utf16.count)
// MARK: Total Downloaded
let regexTotalDownloaded = try! NSRegularExpression(pattern: #"(?<= )(.*)(?=\/)"#)
if let match = regexTotalDownloaded.firstMatch(in: string, options: [], range: range),
let matchRange = Range(match.range(at: 0), in: string),
let totalDownloaded = Int(string[matchRange].replacingOccurrences(of: "B", with: "")) {
self.fileCompletedCount = totalDownloaded
self.completedUnitCount = Int64(totalDownloaded)
}
// MARK: Filesize
let regexTotalFileSize = try! NSRegularExpression(pattern: #"(?<=/)(.*)(?=\()"#)
if let match = regexTotalFileSize.firstMatch(in: string, options: [], range: range),
let matchRange = Range(match.range(at: 0), in: string),
let totalFileSize = Int(string[matchRange].replacingOccurrences(of: "B", with: "")) {
if totalFileSize > 0 {
self.fileTotalCount = totalFileSize
self.totalUnitCount = Int64(totalFileSize)
}
}
// MARK: PERCENT DOWNLOADED
// Since we get fractionCompleted from completedUnitCount + totalUnitCount, no need to process
// let regexPercent = try! NSRegularExpression(pattern: #"((?<percent>\d+)%\))"#)
// MARK: Speed
let regexSpeed = try! NSRegularExpression(pattern: #"(?<=DL:)(.*)(?= )"#)
if let match = regexSpeed.firstMatch(in: string, options: [], range: range),
let matchRange = Range(match.range(at: 0), in: string),
let speed = Int(string[matchRange].replacingOccurrences(of: "B", with: "")) {
self.throughput = speed
} else {
print("Could not find speed")
}
// MARK: Estimated Time Remaining
let regexETA = try! NSRegularExpression(pattern: #"(?<=ETA:)(?<days>\d*d)?(?<hours>\d*h)?(?<minutes>\d*m)?(?<seconds>\d*s)?"#)
if let match = regexETA.firstMatch(in: string, options: [], range: range) {
var seconds: Int = 0
if let matchRange = Range(match.range(withName: "days"), in: string),
let days = Int(string[matchRange].replacingOccurrences(of: "d", with: "")) {
seconds += (days * 60 * 60 * 24)
}
if let matchRange = Range(match.range(withName: "hours"), in: string),
let hours = Int(string[matchRange].replacingOccurrences(of: "h", with: "")) {
seconds += (hours * 60 * 60)
}
if let matchRange = Range(match.range(withName: "minutes"), in: string),
let minutes = Int(string[matchRange].replacingOccurrences(of: "m", with: "")) {
seconds += (minutes * 60)
}
if let matchRange = Range(match.range(withName: "seconds"), in: string),
let second = Int(string[matchRange].replacingOccurrences(of: "s", with: "")) {
seconds += (second)
}
self.estimatedTimeRemaining = TimeInterval(seconds)
}
}
}

View file

@ -27,7 +27,7 @@ public struct ObservingProgressIndicator: View {
init(progress: Progress) {
self.progress = progress
cancellable = progress
.publisher(for: \.fractionCompleted)
.publisher(for: \.completedUnitCount)
.receive(on: RunLoop.main)
.sink { [weak self] _ in self?.objectWillChange.send() }
}

View file

@ -51,13 +51,17 @@ struct InfoPane: View {
}
Divider()
releaseNotes(for: xcode)
identicalBuilds(for: xcode)
compatibility(for: xcode)
sdks(for: xcode)
compilers(for: xcode)
downloadFileSize(for: xcode)
Group{
releaseNotes(for: xcode)
identicalBuilds(for: xcode)
compatibility(for: xcode)
sdks(for: xcode)
compilers(for: xcode)
}
Group {
downloadFileSize(for: xcode)
downloadStats(for: xcode)
}
Spacer()
}
@ -210,6 +214,19 @@ struct InfoPane: View {
}
}
@ViewBuilder
private func downloadStats(for xcode: Xcode) -> some View {
switch xcode.installState {
case let .installing(installationStep):
Divider()
InstallationStepDetailView(
installationStep: installationStep
)
default:
EmptyView()
}
}
@ViewBuilder
private var empty: some View {
@ -252,7 +269,7 @@ struct InfoPane_Previews: PreviewProvider {
]
})
.previewDisplayName("Populated, Installed, Selected")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
@ -278,7 +295,7 @@ struct InfoPane_Previews: PreviewProvider {
]
})
.previewDisplayName("Populated, Installed, Unselected")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
@ -304,7 +321,7 @@ struct InfoPane_Previews: PreviewProvider {
]
})
.previewDisplayName("Populated, Uninstalled")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
@ -318,6 +335,20 @@ struct InfoPane_Previews: PreviewProvider {
]
})
.previewDisplayName("Basic, installed")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
.init(
version: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]),
installState: .installing(.downloading(progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40; $0.throughput = 232323232; $0.fileCompletedCount = 2323004; $0.fileTotalCount = 1193939393 })),
selected: false,
icon: nil,
sdks: nil,
compilers: nil)
]
})
.previewDisplayName("Basic, installing")
InfoPane(selectedXcodeID: nil)
.environmentObject(configure(AppState()) {

View file

@ -0,0 +1,35 @@
import SwiftUI
struct InstallationStepDetailView: View {
let installationStep: InstallationStep
var body: some View {
VStack {
switch installationStep {
case let .downloading(progress):
Text("Step \(installationStep.stepNumber) of \(installationStep.stepCount): \(installationStep.message)")
.font(.title2)
ObservingDownloadStatsView(
progress,
controlSize: .regular,
style: .bar
)
case .unarchiving, .moving, .trashingArchive, .checkingSecurity, .finishing:
ProgressView()
.scaleEffect(0.5)
}
}
.frame(minWidth: 80)
}
}
struct InstallDetailView_Previews: PreviewProvider {
static var previews: some View {
InstallationStepDetailView(
installationStep: .downloading(
progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40; $0.throughput = 9211681; $0.fileCompletedCount = 84844492; $0.fileTotalCount = 11944848484 }
)
)
}
}

View file

@ -0,0 +1,77 @@
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{
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")
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
},
controlSize: .small,
style: .spinning
)
}
.previewLayout(.sizeThatFits)
}
}

View file

@ -1,6 +1,6 @@
import SwiftUI
struct InstallationStepView: View {
struct InstallationStepRowView: View {
let installationStep: InstallationStep
let highlighted: Bool
let cancel: () -> Void
@ -42,7 +42,7 @@ struct InstallView_Previews: PreviewProvider {
Group {
ForEach(ColorScheme.allCases, id: \.self) { colorScheme in
Group {
InstallationStepView(
InstallationStepRowView(
installationStep: .downloading(
progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40 }
),
@ -50,31 +50,31 @@ struct InstallView_Previews: PreviewProvider {
cancel: {}
)
InstallationStepView(
InstallationStepRowView(
installationStep: .unarchiving,
highlighted: false,
cancel: {}
)
InstallationStepView(
InstallationStepRowView(
installationStep: .moving(destination: "/Applications"),
highlighted: false,
cancel: {}
)
InstallationStepView(
InstallationStepRowView(
installationStep: .trashingArchive,
highlighted: false,
cancel: {}
)
InstallationStepView(
InstallationStepRowView(
installationStep: .checkingSecurity,
highlighted: false,
cancel: {}
)
InstallationStepView(
InstallationStepRowView(
installationStep: .finishing,
highlighted: false,
cancel: {}
@ -87,7 +87,7 @@ struct InstallView_Previews: PreviewProvider {
ForEach(ColorScheme.allCases, id: \.self) { colorScheme in
Group {
InstallationStepView(
InstallationStepRowView(
installationStep: .downloading(
progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40 }
),

View file

@ -109,7 +109,7 @@ struct XcodeListViewRow: View {
.buttonStyle(AppStoreButtonStyle(primary: false, highlighted: selected))
.help("Install this version")
case let .installing(installationStep):
InstallationStepView(
InstallationStepRowView(
installationStep: installationStep,
highlighted: selected,
cancel: { appState.xcodeBeingConfirmedForInstallCancellation = xcode }