Skip to content

Commit

Permalink
Set up overall progress object
Browse files Browse the repository at this point in the history
to track both downloading and unarchiving and reflect this in dock progress
  • Loading branch information
senmu committed Sep 18, 2023
1 parent de35bed commit 622fac6
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
40 changes: 32 additions & 8 deletions Xcodes/Backend/AppState+Install.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ extension AppState {

Logger.appState.info("Using \(downloader) downloader")

setupDockProgress()

return validateSession()
.flatMap { _ in
self.getXcodeArchive(installationType, downloader: downloader)
Expand All @@ -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() }
Expand Down Expand Up @@ -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) }
Expand Down Expand Up @@ -152,7 +157,7 @@ extension AppState {
cookies
)
progressChanged(progress)
updateDockIcon(withProgress: progress)

return publisher
.map { _ in destination.url }
.eraseToAnyPublisher()
Expand All @@ -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()
Expand All @@ -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 {
Expand Down Expand Up @@ -423,6 +426,9 @@ extension AppState {
}
self.presentedAlert = .privilegedHelper
}

unxipProgress.completedUnitCount = AppState.totalProgressUnits
resetDockProgressTracking()

return helperInstallConsentSubject
.flatMap {
Expand Down Expand Up @@ -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) {
Expand Down
16 changes: 14 additions & 2 deletions Xcodes/Backend/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 622fac6

Please sign in to comment.