From 93f819f2f3b5ba88c406e2d4b1155fd62c4e1564 Mon Sep 17 00:00:00 2001 From: Brandon Evans Date: Sun, 3 Jan 2021 20:17:23 -0700 Subject: [PATCH] Add downloaders to SettingsView --- Xcodes.xcodeproj/project.pbxproj | 4 +++ Xcodes/Backend/AppState+Install.swift | 8 ++---- Xcodes/Backend/AppState.swift | 2 +- Xcodes/Backend/Downloader.swift | 16 +++++++++++ Xcodes/SettingsView.swift | 38 ++++++++++++++++++++++++--- 5 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 Xcodes/Backend/Downloader.swift diff --git a/Xcodes.xcodeproj/project.pbxproj b/Xcodes.xcodeproj/project.pbxproj index b597144..c1c5663 100644 --- a/Xcodes.xcodeproj/project.pbxproj +++ b/Xcodes.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ CAA8589325A2B77E00ACF8C0 /* aria2c in Copy aria2c */ = {isa = PBXBuildFile; fileRef = CAA8588025A2B63A00ACF8C0 /* aria2c */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; CAA8589B25A2B83000ACF8C0 /* Aria2CError.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA8589A25A2B83000ACF8C0 /* Aria2CError.swift */; }; CAA858DB25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz in Resources */ = {isa = PBXBuildFile; fileRef = CAA858DA25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz */; }; + CAA858C425A2BE4E00ACF8C0 /* Downloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA858C325A2BE4E00ACF8C0 /* Downloader.swift */; }; CABFA9BB2592EEEA00380FEE /* DateFormatter+.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9BA2592EEEA00380FEE /* DateFormatter+.swift */; }; CABFA9BD2592EEEA00380FEE /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9A92592EEE900380FEE /* Environment.swift */; }; CABFA9BF2592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABFA9B32592EEEA00380FEE /* URLSession+DownloadTaskPublisher.swift */; }; @@ -194,6 +195,7 @@ CAA8588A25A2B69300ACF8C0 /* aria2c.LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = aria2c.LICENSE; sourceTree = ""; }; CAA8589A25A2B83000ACF8C0 /* Aria2CError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Aria2CError.swift; sourceTree = ""; }; CAA858DA25A3E11F00ACF8C0 /* aria2-release-1.35.0.tar.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = "aria2-release-1.35.0.tar.gz"; sourceTree = ""; }; + CAA858C325A2BE4E00ACF8C0 /* Downloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Downloader.swift; sourceTree = ""; }; CABFA9A02592EAF500380FEE /* R&PLogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "R&PLogo.png"; sourceTree = ""; }; CABFA9A12592EAFB00380FEE /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; CABFA9A32592ED5700380FEE /* Apple.paw */ = {isa = PBXFileReference; lastKnownFileType = file; name = Apple.paw; path = ../xcodes/Apple.paw; sourceTree = ""; }; @@ -394,6 +396,7 @@ CA9FF87A2595293E00E47BAF /* DataSource.swift */, CABFA9BA2592EEEA00380FEE /* DateFormatter+.swift */, CABFA9B92592EEEA00380FEE /* Downloads.swift */, + CAA858C325A2BE4E00ACF8C0 /* Downloader.swift */, CABFA9B22592EEEA00380FEE /* Entry+.swift */, CABFA9A92592EEE900380FEE /* Environment.swift */, CABFA9B82592EEEA00380FEE /* FileManager+.swift */, @@ -753,6 +756,7 @@ CAE424B4259A764700B8B246 /* AppState+Install.swift in Sources */, CAE42487259A68A300B8B246 /* XcodeListCategory.swift in Sources */, CABFAA2C2592FBFC00380FEE /* SettingsView.swift in Sources */, + CAA858C425A2BE4E00ACF8C0 /* Downloader.swift in Sources */, CA9FF87B2595293E00E47BAF /* DataSource.swift in Sources */, CABFA9C92592EEEA00380FEE /* URLRequest+Apple.swift in Sources */, CABFAA432593104F00380FEE /* AboutView.swift in Sources */, diff --git a/Xcodes/Backend/AppState+Install.swift b/Xcodes/Backend/AppState+Install.swift index c61c8de..17e4c3a 100644 --- a/Xcodes/Backend/AppState+Install.swift +++ b/Xcodes/Backend/AppState+Install.swift @@ -90,7 +90,8 @@ extension AppState { else { let destination = Path.xcodesApplicationSupport/"Xcode-\(availableXcode.version).\(availableXcode.filename.suffix(fromLast: "."))" switch downloader { - case .aria2(let aria2Path): + case .aria2: + let aria2Path = Path(url: Bundle.main.url(forAuxiliaryExecutable: "aria2c")!)! return downloadXcodeWithAria2( availableXcode, to: destination, @@ -430,10 +431,5 @@ public enum InstallationType { case version(AvailableXcode) } -public enum Downloader { - case urlSession - case aria2(Path) -} - let XcodeTeamIdentifier = "59GAB85EFG" let XcodeCertificateAuthority = ["Software Signing", "Apple Code Signing Certification Authority", "Apple Root CA"] diff --git a/Xcodes/Backend/AppState.swift b/Xcodes/Backend/AppState.swift index 03a6217..7a1e7de 100644 --- a/Xcodes/Backend/AppState.swift +++ b/Xcodes/Backend/AppState.swift @@ -256,7 +256,7 @@ class AppState: ObservableObject { .mapError { $0 as Error } } .flatMap { [unowned self] in - self.install(.version(availableXcode), downloader: .aria2(Path(url: Bundle.main.url(forAuxiliaryExecutable: "aria2c")!)!)) + self.install(.version(availableXcode), downloader: .aria2) } .sink( receiveCompletion: { [unowned self] completion in diff --git a/Xcodes/Backend/Downloader.swift b/Xcodes/Backend/Downloader.swift new file mode 100644 index 0000000..41eb680 --- /dev/null +++ b/Xcodes/Backend/Downloader.swift @@ -0,0 +1,16 @@ +import Foundation +import Path + +public enum Downloader: String, CaseIterable, Identifiable, CustomStringConvertible { + case aria2 + case urlSession + + public var id: Self { self } + + public var description: String { + switch self { + case .urlSession: return "URLSession" + case .aria2: return "aria2" + } + } +} diff --git a/Xcodes/SettingsView.swift b/Xcodes/SettingsView.swift index 6a8212f..e754ab7 100644 --- a/Xcodes/SettingsView.swift +++ b/Xcodes/SettingsView.swift @@ -4,6 +4,7 @@ import SwiftUI struct SettingsView: View { @EnvironmentObject var appState: AppState @AppStorage("dataSource") var dataSource: DataSource = .xcodeReleases + @AppStorage("downloader") var downloader: Downloader = .aria2 var body: some View { VStack(alignment: .leading) { @@ -34,7 +35,21 @@ struct SettingsView: View { .labelsHidden() AttributedText(dataSourceFootnote) - .font(.footnote) + } + .frame(maxWidth: .infinity, alignment: .leading) + } + + GroupBox(label: Text("Downloader")) { + VStack(alignment: .leading) { + Picker("Downloader", selection: $downloader) { + ForEach(Downloader.allCases) { downloader in + Text(downloader.description) + .tag(downloader) + } + } + .labelsHidden() + + AttributedText(downloaderFootnote) } .frame(maxWidth: .infinity, alignment: .leading) } @@ -64,8 +79,8 @@ struct SettingsView: View { } .padding() .navigationTitle("Settings") - .frame(width: 300) - .frame(minHeight: 300) + .frame(width: 400) + .frame(minHeight: 500) } private var dataSourceFootnote: NSAttributedString { @@ -84,6 +99,23 @@ struct SettingsView: View { attributedString.addAttribute(.link, value: URL(string: "https://xcodereleases.com")!, range: NSRange(string.range(of: "Xcode Releases")!, in: string)) return attributedString } + + private var downloaderFootnote: NSAttributedString { + let string = """ + aria2 uses up to 16 connections to download Xcode 3-5x faster than URLSession. It's bundled as an executable along with its source code within Xcodes to comply with its GPLv2 license. + + URLSession is the default Apple API for making URL requests. + """ + let attributedString = NSMutableAttributedString( + string: string, + attributes: [ + .font: NSFont.preferredFont(forTextStyle: .footnote, options: [:]), + .foregroundColor: NSColor.labelColor + ] + ) + attributedString.addAttribute(.link, value: URL(string: "https://github.com/aria2/aria2")!, range: NSRange(string.range(of: "aria2")!, in: string)) + return attributedString + } } struct SettingsView_Previews: PreviewProvider {