Skip to content

Commit f470986

Browse files
committed
Merge branch 'main' into matt/runtimeDownload
2 parents ec4dc2b + b650261 commit f470986

18 files changed

Lines changed: 743 additions & 460 deletions

Xcodes.xcodeproj/project.pbxproj

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,21 @@
99
/* Begin PBXBuildFile section */
1010
36741BFD291E4FDB00A85AAE /* DownloadPreferencePane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36741BFC291E4FDB00A85AAE /* DownloadPreferencePane.swift */; };
1111
36741BFF291E50F500A85AAE /* FileError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36741BFE291E50F500A85AAE /* FileError.swift */; };
12-
536CFDD2263C94DE00026CE0 /* SignedInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536CFDD1263C94DE00026CE0 /* SignedInView.swift */; };
12+
536CFDD2263C94DE00026CE0 /* SignedInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536CFDD1263C94DE00026CE0 /* SignedInView.swift */; };
1313
536CFDD4263C9A8000026CE0 /* XcodesSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536CFDD3263C9A8000026CE0 /* XcodesSheet.swift */; };
1414
53CBAB2C263DCC9100410495 /* XcodesAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53CBAB2B263DCC9100410495 /* XcodesAlert.swift */; };
1515
63EAA4EB259944450046AB8F /* ProgressButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63EAA4EA259944450046AB8F /* ProgressButton.swift */; };
16+
B0403CF02AD92D7B00137C09 /* ReleaseNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */; };
17+
B0403CF22AD934B600137C09 /* CompatibilityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF12AD934B600137C09 /* CompatibilityView.swift */; };
18+
B0403CF42AD9381D00137C09 /* SDKsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF32AD9381D00137C09 /* SDKsView.swift */; };
19+
B0403CF62AD9849E00137C09 /* CompilersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF52AD9849E00137C09 /* CompilersView.swift */; };
20+
B0403CF82AD991F800137C09 /* UnselectedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF72AD991F800137C09 /* UnselectedView.swift */; };
21+
B0403CFA2AD9942A00137C09 /* NotInstalledStateButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CF92AD9942A00137C09 /* NotInstalledStateButtons.swift */; };
22+
B0403CFC2AD9A6BF00137C09 /* InstalledStateButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CFB2AD9A6BF00137C09 /* InstalledStateButtons.swift */; };
23+
B0403CFE2ADA712C00137C09 /* InfoPaneControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0403CFD2ADA712C00137C09 /* InfoPaneControls.swift */; };
24+
B0C6AD042AD6E65700E64698 /* ReleaseDateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C6AD032AD6E65700E64698 /* ReleaseDateView.swift */; };
25+
B0C6AD0B2AD9178E00E64698 /* IdenticalBuildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C6AD0A2AD9178E00E64698 /* IdenticalBuildView.swift */; };
26+
B0C6AD0D2AD91D7900E64698 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C6AD0C2AD91D7900E64698 /* IconView.swift */; };
1627
CA11E7BA2598476C00D2EE1C /* XcodeCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */; };
1728
CA2518EC25A7FF2B00F08414 /* AppStateUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2518EB25A7FF2B00F08414 /* AppStateUpdateTests.swift */; };
1829
CA25192A25A9644800F08414 /* XcodeInstallState.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA25192925A9644800F08414 /* XcodeInstallState.swift */; };
@@ -195,6 +206,17 @@
195206
A0187D39285792D1002F46F9 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
196207
AAB037D32839BD4700017680 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
197208
AB4EB0DE28541FA000FF3B1D /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
209+
B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseNotesView.swift; sourceTree = "<group>"; };
210+
B0403CF12AD934B600137C09 /* CompatibilityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompatibilityView.swift; sourceTree = "<group>"; };
211+
B0403CF32AD9381D00137C09 /* SDKsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKsView.swift; sourceTree = "<group>"; };
212+
B0403CF52AD9849E00137C09 /* CompilersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompilersView.swift; sourceTree = "<group>"; };
213+
B0403CF72AD991F800137C09 /* UnselectedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnselectedView.swift; sourceTree = "<group>"; };
214+
B0403CF92AD9942A00137C09 /* NotInstalledStateButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotInstalledStateButtons.swift; sourceTree = "<group>"; };
215+
B0403CFB2AD9A6BF00137C09 /* InstalledStateButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstalledStateButtons.swift; sourceTree = "<group>"; };
216+
B0403CFD2ADA712C00137C09 /* InfoPaneControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPaneControls.swift; sourceTree = "<group>"; };
217+
B0C6AD032AD6E65700E64698 /* ReleaseDateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseDateView.swift; sourceTree = "<group>"; };
218+
B0C6AD0A2AD9178E00E64698 /* IdenticalBuildView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdenticalBuildView.swift; sourceTree = "<group>"; };
219+
B0C6AD0C2AD91D7900E64698 /* IconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconView.swift; sourceTree = "<group>"; };
198220
B648F22B2810C1130096781B /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
199221
C0AE7FA4283002DC00DA63D2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
200222
CA11E7B92598476C00D2EE1C /* XcodeCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeCommands.swift; sourceTree = "<group>"; };
@@ -623,8 +645,19 @@
623645
E8E98A9425D863B100EC89A0 /* InfoPane */ = {
624646
isa = PBXGroup;
625647
children = (
648+
B0403CEF2AD92D7B00137C09 /* ReleaseNotesView.swift */,
649+
B0403CF32AD9381D00137C09 /* SDKsView.swift */,
650+
B0403CF52AD9849E00137C09 /* CompilersView.swift */,
651+
B0403CF12AD934B600137C09 /* CompatibilityView.swift */,
626652
CAFBDC67259A308B003DCC5A /* InfoPane.swift */,
653+
B0403CFD2ADA712C00137C09 /* InfoPaneControls.swift */,
654+
B0403CF72AD991F800137C09 /* UnselectedView.swift */,
655+
B0403CF92AD9942A00137C09 /* NotInstalledStateButtons.swift */,
656+
B0403CFB2AD9A6BF00137C09 /* InstalledStateButtons.swift */,
627657
E8E98A9525D863D700EC89A0 /* InstallationStepDetailView.swift */,
658+
B0C6AD032AD6E65700E64698 /* ReleaseDateView.swift */,
659+
B0C6AD0A2AD9178E00E64698 /* IdenticalBuildView.swift */,
660+
B0C6AD0C2AD91D7900E64698 /* IconView.swift */,
628661
E832EAF72B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift */,
629662
);
630663
path = InfoPane;
@@ -853,7 +886,9 @@
853886
CABFAA492593162500380FEE /* Bundle+InfoPlistValues.swift in Sources */,
854887
CA9FF8662595130600E47BAF /* View+IsHidden.swift in Sources */,
855888
CAE4248C259A68B800B8B246 /* Optional+IsNotNil.swift in Sources */,
889+
B0C6AD0D2AD91D7900E64698 /* IconView.swift in Sources */,
856890
CA9FF9362595B44700E47BAF /* HelperClient.swift in Sources */,
891+
B0C6AD042AD6E65700E64698 /* ReleaseDateView.swift in Sources */,
857892
CAA8587C25A2B37900ACF8C0 /* IsTesting.swift in Sources */,
858893
CABFA9CA2592EEEA00380FEE /* AppState+Update.swift in Sources */,
859894
CA44901F2463AD34003D8213 /* Tag.swift in Sources */,
@@ -870,12 +905,16 @@
870905
CAA1CB45255A5B60003FD669 /* SignIn2FAView.swift in Sources */,
871906
CABFA9C52592EEEA00380FEE /* FileManager+.swift in Sources */,
872907
CABFA9CD2592EEEA00380FEE /* Foundation.swift in Sources */,
908+
B0403CFC2AD9A6BF00137C09 /* InstalledStateButtons.swift in Sources */,
873909
36741BFF291E50F500A85AAE /* FileError.swift in Sources */,
874910
CA9FF8872595607900E47BAF /* InstalledXcode.swift in Sources */,
911+
B0403CF22AD934B600137C09 /* CompatibilityView.swift in Sources */,
912+
B0403CFE2ADA712C00137C09 /* InfoPaneControls.swift in Sources */,
875913
53CBAB2C263DCC9100410495 /* XcodesAlert.swift in Sources */,
876914
CA61A6E0259835580008926E /* Xcode.swift in Sources */,
877915
CAE4247F259A666100B8B246 /* MainWindow.swift in Sources */,
878916
CA452BB0259FD9770072DFA4 /* ProgressIndicator.swift in Sources */,
917+
B0403CF02AD92D7B00137C09 /* ReleaseNotesView.swift in Sources */,
879918
CAFE4AB425B7D3AF0064FE51 /* AdvancedPreferencePane.swift in Sources */,
880919
CA9FF84E2595079F00E47BAF /* ScrollingTextView.swift in Sources */,
881920
E832EAF82B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift in Sources */,
@@ -895,20 +934,25 @@
895934
CABFAA2D2592FBFC00380FEE /* Configure.swift in Sources */,
896935
CA73510D257BFCEF00EA9CF8 /* NSAttributedString+.swift in Sources */,
897936
CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */,
937+
B0403CF42AD9381D00137C09 /* SDKsView.swift in Sources */,
898938
CAC9F92D25BCDA4400B4965F /* HelperInstallState.swift in Sources */,
899939
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */,
900940
CAC281CD259F97FA00B8AB0B /* ObservingProgressIndicator.swift in Sources */,
901941
CABFA9C22592EEEA00380FEE /* Publisher+Resumable.swift in Sources */,
942+
B0C6AD0B2AD9178E00E64698 /* IdenticalBuildView.swift in Sources */,
902943
CAFBDC68259A308B003DCC5A /* InfoPane.swift in Sources */,
944+
B0403CF82AD991F800137C09 /* UnselectedView.swift in Sources */,
903945
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */,
904946
CAA1CB4D255A5CFD003FD669 /* SignInPhoneListView.swift in Sources */,
905947
CAFBDC6C259A3098003DCC5A /* View+Conditional.swift in Sources */,
906948
CABFA9CF2592EEEA00380FEE /* Process.swift in Sources */,
907949
CAFFFED8259CDA5000903F81 /* XcodeListViewRow.swift in Sources */,
908950
CABFA9C72592EEEA00380FEE /* Entry+.swift in Sources */,
951+
B0403CFA2AD9942A00137C09 /* NotInstalledStateButtons.swift in Sources */,
909952
CAE424B4259A764700B8B246 /* AppState+Install.swift in Sources */,
910953
CAE42487259A68A300B8B246 /* XcodeListCategory.swift in Sources */,
911954
CAA858C425A2BE4E00ACF8C0 /* Downloader.swift in Sources */,
955+
B0403CF62AD9849E00137C09 /* CompilersView.swift in Sources */,
912956
E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */,
913957
CA9FF87B2595293E00E47BAF /* DataSource.swift in Sources */,
914958
CABFA9C92592EEEA00380FEE /* URLRequest+Apple.swift in Sources */,

Xcodes/Backend/AppState.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -564,10 +564,10 @@ class AppState: ObservableObject {
564564
)
565565
}
566566

567-
func reveal(xcode: Xcode) {
567+
func reveal(_ path: Path?) {
568568
// TODO: show error if not
569-
guard let installedXcodePath = xcode.installedPath else { return }
570-
NSWorkspace.shared.activateFileViewerSelecting([installedXcodePath.url])
569+
guard let path = path else { return }
570+
NSWorkspace.shared.activateFileViewerSelecting([path.url])
571571
}
572572

573573
func reveal(path: String) {
@@ -653,8 +653,8 @@ class AppState: ObservableObject {
653653
NSPasteboard.general.setString(installedXcodePath.string, forType: .string)
654654
}
655655

656-
func copyReleaseNote(xcode: Xcode) {
657-
guard let url = xcode.releaseNotesURL else { return }
656+
func copyReleaseNote(from url: URL?) {
657+
guard let url = url else { return }
658658
NSPasteboard.general.declareTypes([.URL, .string], owner: nil)
659659
NSPasteboard.general.writeObjects([url as NSURL])
660660
NSPasteboard.general.setString(url.absoluteString, forType: .string)

Xcodes/Backend/XcodeCommands.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ struct RevealButton: View {
152152

153153
private func reveal() {
154154
guard let xcode = xcode else { return }
155-
appState.reveal(xcode: xcode)
155+
appState.reveal(xcode.installedPath)
156156
}
157157
}
158158

@@ -174,8 +174,9 @@ struct CopyPathButton: View {
174174
}
175175

176176
struct CopyReleaseNoteButton: View {
177+
let url: URL?
178+
177179
@EnvironmentObject var appState: AppState
178-
let xcode: Xcode?
179180

180181
var body: some View {
181182
Button(action: copyReleaseNote) {
@@ -185,8 +186,8 @@ struct CopyReleaseNoteButton: View {
185186
}
186187

187188
private func copyReleaseNote() {
188-
guard let xcode = xcode else { return }
189-
appState.copyReleaseNote(xcode: xcode)
189+
guard let url = url else { return }
190+
appState.copyReleaseNote(from: url)
190191
}
191192
}
192193

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// CompatibilityView.swift
3+
// Xcodes
4+
//
5+
// Created by Duong Thai on 13/10/2023.
6+
// Copyright © 2023 Robots and Pencils. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
struct CompatibilityView: View {
12+
let requiredMacOSVersion: String?
13+
14+
var body: some View {
15+
if let requiredMacOSVersion = requiredMacOSVersion {
16+
VStack(alignment: .leading) {
17+
Text("Compatibility")
18+
.font(.headline)
19+
Text(String(format: localizeString("MacOSRequirement"), requiredMacOSVersion))
20+
.font(.subheadline)
21+
}
22+
} else {
23+
EmptyView()
24+
}
25+
}
26+
}
27+
28+
#Preview {
29+
CompatibilityView(requiredMacOSVersion: "10.15.4")
30+
.padding()
31+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// CompilersView.swift
3+
// Xcodes
4+
//
5+
// Created by Duong Thai on 13/10/2023.
6+
// Copyright © 2023 Robots and Pencils. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
import struct XCModel.Compilers
11+
12+
struct CompilersView: View {
13+
let compilers: Compilers?
14+
15+
var body: some View {
16+
if let compilers = compilers {
17+
VStack(alignment: .leading) {
18+
Text("Compilers").font(.headline)
19+
Text(Self.content(from: compilers)).font(.subheadline)
20+
}
21+
} else {
22+
EmptyView()
23+
}
24+
}
25+
26+
static func content(from compilers: Compilers) -> String {
27+
[ ("Swift", compilers.swift),
28+
("Clang", compilers.clang),
29+
("LLVM", compilers.llvm),
30+
("LLVM GCC", compilers.llvm_gcc),
31+
("GCC", compilers.gcc)
32+
].compactMap { // remove nil compiler
33+
guard $0.1 != nil, // has version array
34+
!$0.1!.isEmpty // has at least 1 version
35+
else { return nil }
36+
37+
let numbers = $0.1!.compactMap { $0.number } // remove nil number
38+
guard !numbers.isEmpty // has at least 1 number
39+
else { return nil }
40+
41+
// description for each type of compilers
42+
return "\($0.0): \(numbers.joined(separator: ", "))"
43+
}.joined(separator: "\n")
44+
}
45+
}
46+
47+
#Preview {
48+
let compilers = Compilers(
49+
gcc: .init(number: "4"),
50+
llvm_gcc: .init(number: "213"),
51+
llvm: .init(number: "2.3"),
52+
clang: .init(number: "7.3"),
53+
swift: .init(number: "5.3.2")
54+
)
55+
56+
return CompilersView(compilers: compilers)
57+
.padding()
58+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// IconView.swift
3+
// Xcodes
4+
//
5+
// Created by Duong Thai on 11/10/2023.
6+
// Copyright © 2023 Robots and Pencils. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
import Path
11+
12+
struct IconView: View {
13+
let installState: XcodeInstallState
14+
15+
var body: some View {
16+
if case let .installed(path) = installState {
17+
Image(nsImage: NSWorkspace.shared.icon(forFile: path.string))
18+
} else {
19+
Image(systemName: "app.fill")
20+
.resizable()
21+
.frame(width: 32, height: 32)
22+
.foregroundColor(.secondary)
23+
}
24+
}
25+
}
26+
27+
#Preview("Installed") {
28+
IconView(installState: XcodeInstallState.installed(Path("/Applications/Xcode.app")!))
29+
.frame(width: 300, height: 100)
30+
.padding()
31+
}
32+
33+
#Preview("Not Installed") {
34+
IconView(installState: XcodeInstallState.notInstalled)
35+
.frame(width: 300, height: 100)
36+
.padding()
37+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// IdenticalBuildView.swift
3+
// Xcodes
4+
//
5+
// Created by Duong Thai on 11/10/2023.
6+
// Copyright © 2023 Robots and Pencils. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
import Version
11+
12+
struct IdenticalBuildsView: View {
13+
let builds: [Version]
14+
private let isEmpty: Bool
15+
private let accessibilityDescription: String
16+
17+
var body: some View {
18+
if isEmpty {
19+
EmptyView()
20+
} else {
21+
VStack(alignment: .leading) {
22+
HStack {
23+
Text("IdenticalBuilds")
24+
Image(systemName: "square.fill.on.square.fill")
25+
.foregroundColor(.secondary)
26+
.accessibility(hidden: true)
27+
.help("IdenticalBuilds.help")
28+
}
29+
.font(.headline)
30+
31+
ForEach(builds, id: \.description) { version in
32+
Text("\(version.appleDescription)")
33+
.font(.subheadline)
34+
}
35+
}
36+
.accessibilityElement()
37+
.accessibility(label: Text("IdenticalBuilds"))
38+
.accessibility(value: Text(accessibilityDescription))
39+
.accessibility(hint: Text("IdenticalBuilds.help"))
40+
}
41+
}
42+
43+
init(builds: [Version]) {
44+
self.builds = builds
45+
self.isEmpty = builds.isEmpty
46+
self.accessibilityDescription = builds
47+
.map(\.appleDescription)
48+
.joined(separator: ", ")
49+
}
50+
}
51+
52+
let builds: [Version] = [.init(xcodeVersion: "15.0")!, .init(xcodeVersion: "15.1")!]
53+
54+
#Preview("Has Some Builds") {
55+
IdenticalBuildsView(builds: builds)
56+
.padding()
57+
}
58+
59+
#Preview("No Build") {
60+
IdenticalBuildsView(builds: [])
61+
.padding()
62+
}

0 commit comments

Comments
 (0)