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
This commit is contained in:
Duong Thai 2023-10-14 13:09:58 +07:00
parent 4e55aac679
commit a2379583ef
2 changed files with 150 additions and 164 deletions

View file

@ -6,178 +6,153 @@ import struct XCModel.Compilers
import struct XCModel.SDKs
struct InfoPane: View {
@EnvironmentObject var appState: AppState
let selectedXcodeID: Xcode.ID?
let xcode: Xcode
var body: some View {
if let xcode = appState.allXcodes.first(where: { $0.id == selectedXcodeID }) {
ScrollView {
VStack(alignment: .leading, spacing: 16) {
IconView(installState: xcode.installState)
.frame(maxWidth: .infinity, alignment: .center)
ScrollView {
VStack(alignment: .leading, spacing: 16) {
IconView(installState: xcode.installState)
.frame(maxWidth: .infinity, alignment: .center)
Text(verbatim: "Xcode \(xcode.description) \(xcode.version.buildMetadataIdentifiersDisplay)")
.font(.title)
Text(verbatim: "Xcode \(xcode.description) \(xcode.version.buildMetadataIdentifiersDisplay)")
.font(.title)
switch xcode.installState {
case .notInstalled:
NotInstalledStateButtons(
downloadFileSizeString: xcode.downloadFileSizeString,
id: xcode.id
)
case let .installing(installationStep):
InstallationStepDetailView(installationStep: installationStep)
CancelInstallButton(xcode: xcode)
case .installed:
InstalledStateButtons(xcode: xcode)
}
Divider()
Group {
ReleaseNotesView(url: xcode.releaseNotesURL)
ReleaseDateView(date: xcode.releaseDate)
IdenticalBuildsView(builds: xcode.identicalBuilds)
CompatibilityView(requiredMacOSVersion: xcode.requiredMacOSVersion)
SDKsView(sdks: xcode.sdks)
CompilersView(compilers: xcode.compilers)
}
Spacer()
switch xcode.installState {
case .notInstalled:
NotInstalledStateButtons(
downloadFileSizeString: xcode.downloadFileSizeString,
id: xcode.id
)
case let .installing(installationStep):
InstallationStepDetailView(installationStep: installationStep)
CancelInstallButton(xcode: xcode)
case .installed:
InstalledStateButtons(xcode: xcode)
}
.padding()
Divider()
Group {
ReleaseNotesView(url: xcode.releaseNotesURL)
ReleaseDateView(date: xcode.releaseDate)
IdenticalBuildsView(builds: xcode.identicalBuilds)
CompatibilityView(requiredMacOSVersion: xcode.requiredMacOSVersion)
SDKsView(sdks: xcode.sdks)
CompilersView(compilers: xcode.compilers)
}
Spacer()
}
.frame(minWidth: 200, maxWidth: .infinity)
} else {
UnselectedView()
}
}
}
struct InfoPane_Previews: PreviewProvider {
static var previews: some View {
Group {
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
.init(
version: Version(major: 12, minor: 3, patch: 0),
installState: .installed(Path("/Applications/Xcode-12.3.0.app")!),
selected: true,
icon: NSWorkspace.shared.icon(forFile: "/Applications/Xcode-12.3.0.app"),
requiredMacOSVersion: "10.15.4",
releaseNotesURL: URL(string: "https://developer.apple.com/documentation/xcode-release-notes/xcode-12_3-release-notes/")!,
releaseDate: Date(),
sdks: SDKs(
macOS: .init(number: "11.1"),
iOS: .init(number: "14.3"),
watchOS: .init(number: "7.3"),
tvOS: .init(number: "14.3")
),
compilers: Compilers(
gcc: .init(number: "4"),
llvm_gcc: .init(number: "213"),
llvm: .init(number: "2.3"),
clang: .init(number: "7.3"),
swift: .init(number: "5.3.2")
),
downloadFileSize: 242_342_424
),
]
})
.previewDisplayName("Populated, Installed, Selected")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
.init(
version: Version(major: 12, minor: 3, patch: 0),
installState: .installed(Path("/Applications/Xcode-12.3.0.app")!),
selected: false,
icon: NSWorkspace.shared.icon(forFile: "/Applications/Xcode-12.3.0.app"),
sdks: SDKs(
macOS: .init(number: "11.1"),
iOS: .init(number: "14.3"),
watchOS: .init(number: "7.3"),
tvOS: .init(number: "14.3")
),
compilers: Compilers(
gcc: .init(number: "4"),
llvm_gcc: .init(number: "213"),
llvm: .init(number: "2.3"),
clang: .init(number: "7.3"),
swift: .init(number: "5.3.2")
),
downloadFileSize: 242_342_424
),
]
})
.previewDisplayName("Populated, Installed, Unselected")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 0))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
.init(
version: Version(major: 12, minor: 3, patch: 0),
installState: .notInstalled,
selected: false,
icon: nil,
sdks: SDKs(
macOS: .init(number: "11.1"),
iOS: .init(number: "14.3"),
watchOS: .init(number: "7.3"),
tvOS: .init(number: "14.3")
),
compilers: Compilers(
gcc: .init(number: "4"),
llvm_gcc: .init(number: "213"),
llvm: .init(number: "2.3"),
clang: .init(number: "7.3"),
swift: .init(number: "5.3.2")
),
downloadFileSize: 242_342_424
),
]
})
.previewDisplayName("Populated, Uninstalled")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
.init(
version: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]),
installState: .installed(Path("/Applications/Xcode-12.3.0.app")!),
selected: false,
icon: nil,
sdks: nil,
compilers: nil
),
]
})
.previewDisplayName("Basic, installed")
InfoPane(selectedXcodeID: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]))
.environmentObject(configure(AppState()) {
$0.allXcodes = [
.init(
version: Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"]),
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 })),
selected: false,
icon: nil,
sdks: nil,
compilers: nil
),
]
})
.previewDisplayName("Basic, installing")
InfoPane(selectedXcodeID: nil)
.environmentObject(configure(AppState()) {
$0.allXcodes = [
]
})
.previewDisplayName("Empty")
}
.frame(maxWidth: 300)
WrapperView()
}
}
private struct WrapperView: View {
@State var name: PreviewName = .Populated_Installed_Selected
var body: some View {
VStack {
InfoPane(xcode: xcode)
.environmentObject(configure(AppState()) {
$0.allXcodes = [xcode]
})
.border(.red)
.frame(width: 300, height: 400)
Spacer()
Picker("Preview Name", selection: $name) {
ForEach(PreviewName.allCases) {
Text($0.rawValue).tag($0)
}
}
.pickerStyle(.inline)
}
.frame(maxWidth: .infinity)
.padding()
}
var xcode: Xcode { xcodeDict[name]! }
}
private enum PreviewName: String, CaseIterable, Identifiable {
case Populated_Installed_Selected
case Populated_Installed_Unselected
case Populated_Uninstalled
case Basic_Installed
case Basic_Installing
var id: PreviewName { self }
}
private var xcodeDict: [PreviewName: Xcode] = [
.Populated_Installed_Selected: .init(
version: _versionNoMeta,
installState: .installed(Path(_path)!),
selected: true,
icon: NSWorkspace.shared.icon(forFile: _path),
requiredMacOSVersion: _requiredMacOSVersion,
releaseNotesURL: URL(string: "https://developer.apple.com/documentation/xcode-release-notes/xcode-12_3-release-notes/")!,
releaseDate: Date(),
sdks: _sdks,
compilers: _compilers,
downloadFileSize: _downloadFileSize
),
.Populated_Installed_Unselected: .init(
version: _versionNoMeta,
installState: .installed(Path(_path)!),
selected: false,
icon: NSWorkspace.shared.icon(forFile: _path),
sdks: _sdks,
compilers: _compilers,
downloadFileSize: _downloadFileSize
),
.Populated_Uninstalled: .init(
version: Version(major: 12, minor: 3, patch: 0),
installState: .notInstalled,
selected: false,
icon: nil,
sdks: _sdks,
compilers: _compilers,
downloadFileSize: _downloadFileSize
),
.Basic_Installed: .init(
version: _versionWithMeta,
installState: .installed(Path(_path)!),
selected: false,
icon: nil,
sdks: nil,
compilers: nil
),
.Basic_Installing: .init(
version: _versionWithMeta,
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 })),
selected: false,
icon: nil,
sdks: nil,
compilers: nil
),
]
private let _versionNoMeta = Version(major: 12, minor: 3, patch: 0)
private let _versionWithMeta = Version(major: 12, minor: 3, patch: 1, buildMetadataIdentifiers: ["1234A"])
private let _path = "/Applications/Xcode-12.3.0.app"
private let _requiredMacOSVersion = "10.15.4"
private let _sdks = SDKs(
macOS: .init(number: "11.1"),
iOS: .init(number: "14.3"),
watchOS: .init(number: "7.3"),
tvOS: .init(number: "14.3")
)
private let _compilers = Compilers(
gcc: .init(number: "4"),
llvm_gcc: .init(number: "213"),
llvm: .init(number: "2.3"),
clang: .init(number: "7.3"),
swift: .init(number: "5.3.2")
)
private let _downloadFileSize: Int64 = 242_342_424

View file

@ -27,8 +27,15 @@ struct MainWindow: View {
}
if isShowingInfoPane {
InfoPane(selectedXcodeID: selectedXcodeID)
.frame(minWidth: 300, maxWidth: .infinity)
Group {
if let xcode = xcode {
InfoPane(xcode: xcode)
} else {
UnselectedView()
}
}
.padding()
.frame(minWidth: 300, maxWidth: .infinity)
}
}
.mainToolbar(
@ -59,7 +66,11 @@ struct MainWindow: View {
// FB8954571 focusedValue(_:_:) on List row doesn't propagate value to @FocusedValue
.focusedValue(\.selectedXcode, SelectedXcode(appState.allXcodes.first { $0.id == selectedXcodeID }))
}
private var xcode: Xcode? {
appState.allXcodes.first(where: { $0.id == selectedXcodeID })
}
private var subtitleText: Text {
if let lastUpdated = lastUpdated.map(Date.init(timeIntervalSince1970:)) {
return Text("\(localizeString("UpdatedAt")) \(lastUpdated, style: .date) \(lastUpdated, style: .time)")