Set up overall progress object

to track both downloading and unarchiving and reflect this in dock progress
This commit is contained in:
Sam Lu 2023-09-15 14:56:36 -06:00
parent de35bed9fa
commit 622fac605c
No known key found for this signature in database
GPG key ID: 1F967FCCCCED5DDC
2 changed files with 46 additions and 10 deletions

View file

@ -44,6 +44,8 @@ extension AppState {
Logger.appState.info("Using \(downloader) downloader")
setupDockProgress()
return validateSession()
.flatMap { _ in
self.getXcodeArchive(installationType, downloader: downloader)
@ -52,6 +54,8 @@ extension AppState {
self.installArchivedXcode(xcode, at: url)
}
.catch { error -> AnyPublisher<InstalledXcode, Swift.Error> in
self.resetDockProgressTracking()
switch error {
case InstallationError.damagedXIP(let damagedXIPURL):
guard attemptNumber < 1 else { return Fail(error: error).eraseToAnyPublisher() }
@ -100,6 +104,7 @@ extension AppState {
self.downloadOrUseExistingArchive(for: availableXcode, downloader: downloader, progressChanged: { [unowned self] progress in
DispatchQueue.main.async {
self.setInstallationStep(of: availableXcode.version, to: .downloading(progress: progress))
self.overallProgress.addChild(progress, withPendingUnitCount: AppState.totalProgressUnits - AppState.unxipProgressWeight)
}
})
.map { return (availableXcode, $0) }
@ -152,7 +157,7 @@ extension AppState {
cookies
)
progressChanged(progress)
updateDockIcon(withProgress: progress)
return publisher
.map { _ in destination.url }
.eraseToAnyPublisher()
@ -162,12 +167,12 @@ extension AppState {
let resumeDataPath = Path.xcodesApplicationSupport/"Xcode-\(availableXcode.version).resumedata"
let persistedResumeData = Current.files.contents(atPath: resumeDataPath.string)
return attemptResumableTask(maximumRetryCount: 3) { [weak self] resumeData -> AnyPublisher<URL, Error> in
return attemptResumableTask(maximumRetryCount: 3) { resumeData -> AnyPublisher<URL, Error> in
let (progress, publisher) = Current.network.downloadTask(with: availableXcode.url,
to: destination.url,
resumingWith: resumeData ?? persistedResumeData)
progressChanged(progress)
self?.updateDockIcon(withProgress: progress)
return publisher
.map { $0.saveLocation }
.eraseToAnyPublisher()
@ -177,13 +182,11 @@ extension AppState {
})
.eraseToAnyPublisher()
}
private func updateDockIcon(withProgress progress: Progress) {
DockProgress.style = .bar
DockProgress.progressInstance = progress
}
public func installArchivedXcode(_ availableXcode: AvailableXcode, at archiveURL: URL) -> AnyPublisher<InstalledXcode, Error> {
unxipProgress.completedUnitCount = 0
overallProgress.addChild(unxipProgress, withPendingUnitCount: AppState.unxipProgressWeight)
do {
let destinationURL = Path.installDirectory.join("Xcode-\(availableXcode.version.descriptionWithoutBuildMetadata).app").url
switch archiveURL.pathExtension {
@ -423,6 +426,9 @@ extension AppState {
}
self.presentedAlert = .privilegedHelper
}
unxipProgress.completedUnitCount = AppState.totalProgressUnits
resetDockProgressTracking()
return helperInstallConsentSubject
.flatMap {
@ -463,6 +469,24 @@ extension AppState {
.eraseToAnyPublisher()
}
// MARK: - Dock Progress Tracking
private func setupDockProgress() {
DockProgress.progressInstance = nil
DockProgress.style = .bar
let progress = Progress(totalUnitCount: AppState.totalProgressUnits)
progress.kind = .file
progress.fileOperationKind = .downloading
overallProgress = progress
DockProgress.progressInstance = overallProgress
}
func resetDockProgressTracking() {
DockProgress.progress = 1 // Only way to completely remove overlay with DockProgress is setting progress to complete
}
// MARK: -
func setInstallationStep(of version: Version, to step: InstallationStep) {

View file

@ -107,6 +107,19 @@ class AppState: ObservableObject {
private var selectPublisher: AnyCancellable?
private var uninstallPublisher: AnyCancellable?
private var autoInstallTimer: Timer?
// MARK: - Dock Progress Tracking
public static let totalProgressUnits = Int64(10)
public static let unxipProgressWeight = Int64(1)
var overallProgress = Progress()
var unxipProgress = {
let progress = Progress(totalUnitCount: totalProgressUnits)
progress.kind = .file
progress.fileOperationKind = .copying
return progress
}()
// MARK: -
var dataSource: DataSource {
@ -491,8 +504,7 @@ class AppState: ObservableObject {
// Cancel the publisher
installationPublishers[id] = nil
// Remove dock icon progress indicator
DockProgress.progress = 1 // Only way to completely remove overlay with DockProgress is setting progress to complete
resetDockProgressTracking()
// If the download is cancelled by the user, clean up the download files that aria2 creates.
// This isn't done as part of the publisher with handleEvents(receiveCancel:) because it shouldn't happen when e.g. the app quits.