Skip to content

Commit a237958

Browse files
committed
fix data dependency, preview performance and layout out of InfoPane
- I move `UnselectedView` out to: 1. narrow data dependency 2. `InfoPane` should only care about displaying data, not whether an `Xcode` is selected
1 parent 4e55aac commit a237958

2 files changed

Lines changed: 142 additions & 156 deletions

File tree

Xcodes/Frontend/InfoPane/InfoPane.swift

Lines changed: 128 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -6,178 +6,153 @@ import struct XCModel.Compilers
66
import struct XCModel.SDKs
77

88
struct InfoPane: View {
9-
@EnvironmentObject var appState: AppState
10-
let selectedXcodeID: Xcode.ID?
9+
let xcode: Xcode
1110

1211
var body: some View {
13-
if let xcode = appState.allXcodes.first(where: { $0.id == selectedXcodeID }) {
14-
ScrollView {
15-
VStack(alignment: .leading, spacing: 16) {
16-
IconView(installState: xcode.installState)
17-
.frame(maxWidth: .infinity, alignment: .center)
12+
ScrollView {
13+
VStack(alignment: .leading, spacing: 16) {
14+
IconView(installState: xcode.installState)
15+
.frame(maxWidth: .infinity, alignment: .center)
1816

19-
Text(verbatim: "Xcode \(xcode.description) \(xcode.version.buildMetadataIdentifiersDisplay)")
20-
.font(.title)
17+
Text(verbatim: "Xcode \(xcode.description) \(xcode.version.buildMetadataIdentifiersDisplay)")
18+
.font(.title)
2119

22-
switch xcode.installState {
23-
case .notInstalled:
24-
NotInstalledStateButtons(
25-
downloadFileSizeString: xcode.downloadFileSizeString,
26-
id: xcode.id
27-
)
28-
case let .installing(installationStep):
29-
InstallationStepDetailView(installationStep: installationStep)
30-
CancelInstallButton(xcode: xcode)
31-
case .installed:
32-
InstalledStateButtons(xcode: xcode)
33-
}
34-
35-
Divider()
20+
switch xcode.installState {
21+
case .notInstalled:
22+
NotInstalledStateButtons(
23+
downloadFileSizeString: xcode.downloadFileSizeString,
24+
id: xcode.id
25+
)
26+
case let .installing(installationStep):
27+
InstallationStepDetailView(installationStep: installationStep)
28+
CancelInstallButton(xcode: xcode)
29+
case .installed:
30+
InstalledStateButtons(xcode: xcode)
31+
}
3632

37-
Group {
38-
ReleaseNotesView(url: xcode.releaseNotesURL)
39-
ReleaseDateView(date: xcode.releaseDate)
40-
IdenticalBuildsView(builds: xcode.identicalBuilds)
41-
CompatibilityView(requiredMacOSVersion: xcode.requiredMacOSVersion)
42-
SDKsView(sdks: xcode.sdks)
43-
CompilersView(compilers: xcode.compilers)
44-
}
33+
Divider()
4534

46-
Spacer()
35+
Group {
36+
ReleaseNotesView(url: xcode.releaseNotesURL)
37+
ReleaseDateView(date: xcode.releaseDate)
38+
IdenticalBuildsView(builds: xcode.identicalBuilds)
39+
CompatibilityView(requiredMacOSVersion: xcode.requiredMacOSVersion)
40+
SDKsView(sdks: xcode.sdks)
41+
CompilersView(compilers: xcode.compilers)
4742
}
48-
.padding()
43+
44+
Spacer()
4945
}
50-
.frame(minWidth: 200, maxWidth: .infinity)
51-
} else {
52-
UnselectedView()
5346
}
5447
}
5548
}
5649

5750
struct InfoPane_Previews: PreviewProvider {
5851
static var previews: some View {
59-
Group {
60-
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
61-
.environmentObject(configure(AppState()) {
62-
$0.allXcodes = [
63-
.init(
64-
version: Version(major: 12, minor: 3, patch: 0),
65-
installState: .installed(Path("/Applications/Xcode-12.3.0.app")!),
66-
selected: true,
67-
icon: NSWorkspace.shared.icon(forFile: "/Applications/Xcode-12.3.0.app"),
68-
requiredMacOSVersion: "10.15.4",
69-
releaseNotesURL: URL(string: "https://developer.apple.com/documentation/xcode-release-notes/xcode-12_3-release-notes/")!,
70-
releaseDate: Date(),
71-
sdks: SDKs(
72-
macOS: .init(number: "11.1"),
73-
iOS: .init(number: "14.3"),
74-
watchOS: .init(number: "7.3"),
75-
tvOS: .init(number: "14.3")
76-
),
77-
compilers: Compilers(
78-
gcc: .init(number: "4"),
79-
llvm_gcc: .init(number: "213"),
80-
llvm: .init(number: "2.3"),
81-
clang: .init(number: "7.3"),
82-
swift: .init(number: "5.3.2")
83-
),
84-
downloadFileSize: 242_342_424
85-
),
86-
]
87-
})
88-
.previewDisplayName("Populated, Installed, Selected")
52+
WrapperView()
53+
}
54+
}
8955

90-
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
91-
.environmentObject(configure(AppState()) {
92-
$0.allXcodes = [
93-
.init(
94-
version: Version(major: 12, minor: 3, patch: 0),
95-
installState: .installed(Path("/Applications/Xcode-12.3.0.app")!),
96-
selected: false,
97-
icon: NSWorkspace.shared.icon(forFile: "/Applications/Xcode-12.3.0.app"),
98-
sdks: SDKs(
99-
macOS: .init(number: "11.1"),
100-
iOS: .init(number: "14.3"),
101-
watchOS: .init(number: "7.3"),
102-
tvOS: .init(number: "14.3")
103-
),
104-
compilers: Compilers(
105-
gcc: .init(number: "4"),
106-
llvm_gcc: .init(number: "213"),
107-
llvm: .init(number: "2.3"),
108-
clang: .init(number: "7.3"),
109-
swift: .init(number: "5.3.2")
110-
),
111-
downloadFileSize: 242_342_424
112-
),
113-
]
114-
})
115-
.previewDisplayName("Populated, Installed, Unselected")
56+
private struct WrapperView: View {
57+
@State var name: PreviewName = .Populated_Installed_Selected
11658

117-
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
59+
var body: some View {
60+
VStack {
61+
InfoPane(xcode: xcode)
11862
.environmentObject(configure(AppState()) {
119-
$0.allXcodes = [
120-
.init(
121-
version: Version(major: 12, minor: 3, patch: 0),
122-
installState: .notInstalled,
123-
selected: false,
124-
icon: nil,
125-
sdks: SDKs(
126-
macOS: .init(number: "11.1"),
127-
iOS: .init(number: "14.3"),
128-
watchOS: .init(number: "7.3"),
129-
tvOS: .init(number: "14.3")
130-
),
131-
compilers: Compilers(
132-
gcc: .init(number: "4"),
133-
llvm_gcc: .init(number: "213"),
134-
llvm: .init(number: "2.3"),
135-
clang: .init(number: "7.3"),
136-
swift: .init(number: "5.3.2")
137-
),
138-
downloadFileSize: 242_342_424
139-
),
140-
]
63+
$0.allXcodes = [xcode]
14164
})
142-
.previewDisplayName("Populated, Uninstalled")
65+
.border(.red)
66+
.frame(width: 300, height: 400)
67+
Spacer()
68+
Picker("Preview Name", selection: $name) {
69+
ForEach(PreviewName.allCases) {
70+
Text($0.rawValue).tag($0)
71+
}
72+
}
73+
.pickerStyle(.inline)
74+
}
75+
.frame(maxWidth: .infinity)
76+
.padding()
77+
}
14378

144-
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]))
145-
.environmentObject(configure(AppState()) {
146-
$0.allXcodes = [
147-
.init(
148-
version: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]),
149-
installState: .installed(Path("/Applications/Xcode-12.3.0.app")!),
150-
selected: false,
151-
icon: nil,
152-
sdks: nil,
153-
compilers: nil
154-
),
155-
]
156-
})
157-
.previewDisplayName("Basic, installed")
79+
var xcode: Xcode { xcodeDict[name]! }
80+
}
15881

159-
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]))
160-
.environmentObject(configure(AppState()) {
161-
$0.allXcodes = [
162-
.init(
163-
version: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]),
164-
installState: .installing(.downloading(progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40; $0.throughput = 232_323_232; $0.fileCompletedCount = 2_323_004; $0.fileTotalCount = 1_193_939_393 })),
165-
selected: false,
166-
icon: nil,
167-
sdks: nil,
168-
compilers: nil
169-
),
170-
]
171-
})
172-
.previewDisplayName("Basic, installing")
82+
private enum PreviewName: String, CaseIterable, Identifiable {
83+
case Populated_Installed_Selected
84+
case Populated_Installed_Unselected
85+
case Populated_Uninstalled
86+
case Basic_Installed
87+
case Basic_Installing
17388

174-
InfoPane(selectedXcodeID: nil)
175-
.environmentObject(configure(AppState()) {
176-
$0.allXcodes = [
177-
]
178-
})
179-
.previewDisplayName("Empty")
180-
}
181-
.frame(maxWidth: 300)
182-
}
89+
var id: PreviewName { self }
18390
}
91+
92+
private var xcodeDict: [PreviewName: Xcode] = [
93+
.Populated_Installed_Selected: .init(
94+
version: _versionNoMeta,
95+
installState: .installed(Path(_path)!),
96+
selected: true,
97+
icon: NSWorkspace.shared.icon(forFile: _path),
98+
requiredMacOSVersion: _requiredMacOSVersion,
99+
releaseNotesURL: URL(string: "https://developer.apple.com/documentation/xcode-release-notes/xcode-12_3-release-notes/")!,
100+
releaseDate: Date(),
101+
sdks: _sdks,
102+
compilers: _compilers,
103+
downloadFileSize: _downloadFileSize
104+
),
105+
.Populated_Installed_Unselected: .init(
106+
version: _versionNoMeta,
107+
installState: .installed(Path(_path)!),
108+
selected: false,
109+
icon: NSWorkspace.shared.icon(forFile: _path),
110+
sdks: _sdks,
111+
compilers: _compilers,
112+
downloadFileSize: _downloadFileSize
113+
),
114+
.Populated_Uninstalled: .init(
115+
version: Version(major: 12, minor: 3, patch: 0),
116+
installState: .notInstalled,
117+
selected: false,
118+
icon: nil,
119+
sdks: _sdks,
120+
compilers: _compilers,
121+
downloadFileSize: _downloadFileSize
122+
),
123+
.Basic_Installed: .init(
124+
version: _versionWithMeta,
125+
installState: .installed(Path(_path)!),
126+
selected: false,
127+
icon: nil,
128+
sdks: nil,
129+
compilers: nil
130+
),
131+
.Basic_Installing: .init(
132+
version: _versionWithMeta,
133+
installState: .installing(.downloading(progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40; $0.throughput = 232_323_232; $0.fileCompletedCount = 2_323_004; $0.fileTotalCount = 1_193_939_393 })),
134+
selected: false,
135+
icon: nil,
136+
sdks: nil,
137+
compilers: nil
138+
),
139+
]
140+
141+
private let _versionNoMeta = Version(major: 12, minor: 3, patch: 0)
142+
private let _versionWithMeta = Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"])
143+
private let _path = "/Applications/Xcode-12.3.0.app"
144+
private let _requiredMacOSVersion = "10.15.4"
145+
private let _sdks = SDKs(
146+
macOS: .init(number: "11.1"),
147+
iOS: .init(number: "14.3"),
148+
watchOS: .init(number: "7.3"),
149+
tvOS: .init(number: "14.3")
150+
)
151+
private let _compilers = Compilers(
152+
gcc: .init(number: "4"),
153+
llvm_gcc: .init(number: "213"),
154+
llvm: .init(number: "2.3"),
155+
clang: .init(number: "7.3"),
156+
swift: .init(number: "5.3.2")
157+
)
158+
private let _downloadFileSize: Int64 = 242_342_424

Xcodes/Frontend/MainWindow.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,15 @@ struct MainWindow: View {
2727
}
2828

2929
if isShowingInfoPane {
30-
InfoPane(selectedXcodeID: selectedXcodeID)
31-
.frame(minWidth: 300, maxWidth: .infinity)
30+
Group {
31+
if let xcode = xcode {
32+
InfoPane(xcode: xcode)
33+
} else {
34+
UnselectedView()
35+
}
36+
}
37+
.padding()
38+
.frame(minWidth: 300, maxWidth: .infinity)
3239
}
3340
}
3441
.mainToolbar(
@@ -59,7 +66,11 @@ struct MainWindow: View {
5966
// FB8954571 focusedValue(_:_:) on List row doesn't propagate value to @FocusedValue
6067
.focusedValue(\.selectedXcode, SelectedXcode(appState.allXcodes.first { $0.id == selectedXcodeID }))
6168
}
62-
69+
70+
private var xcode: Xcode? {
71+
appState.allXcodes.first(where: { $0.id == selectedXcodeID })
72+
}
73+
6374
private var subtitleText: Text {
6475
if let lastUpdated = lastUpdated.map(Date.init(timeIntervalSince1970:)) {
6576
return Text("\(localizeString("UpdatedAt")) \(lastUpdated, style: .date) \(lastUpdated, style: .time)")

0 commit comments

Comments
 (0)