gh-XcodesOrg-XcodesApp/Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift
2025-09-14 12:32:16 +02:00

157 lines
5.3 KiB
Swift

import SwiftUI
import Version
import Path
struct XcodeMajorVersionRow: View {
let majorVersionGroup: XcodeMajorVersionGroup
let isExpanded: Bool
let onToggleExpanded: () -> Void
let appState: AppState
var body: some View {
HStack {
Button(action: onToggleExpanded) {
HStack(spacing: 8) {
Image(systemName: isExpanded ? "chevron.down" : "chevron.right")
.font(.caption.weight(.semibold))
.foregroundColor(.secondary)
majorVersionIcon
VStack(alignment: .leading, spacing: 2) {
Text("Xcode \(majorVersionGroup.displayName)")
.font(.body.weight(.medium))
if let latestRelease = majorVersionGroup.latestRelease {
Text("Latest: \(latestRelease.description)")
.font(.caption)
.foregroundColor(.secondary)
}
}
Spacer()
}
}
.buttonStyle(.plain)
selectControl()
.padding(.trailing, 16)
installControl()
}
.padding(.vertical, 8)
.background(Color.clear)
.contentShape(Rectangle())
}
@ViewBuilder
var majorVersionIcon: some View {
if let latestRelease = majorVersionGroup.latestRelease {
if let icon = latestRelease.icon {
Image(nsImage: icon)
.resizable()
.frame(width: 32, height: 32)
} else {
Image("xcode")
.resizable()
.frame(width: 32, height: 32)
.opacity(0.7)
}
} else {
Image("xcode-beta")
.resizable()
.frame(width: 32, height: 32)
.opacity(0.7)
}
}
@ViewBuilder
func selectControl() -> some View {
if let selectedVersion = majorVersionGroup.selectedVersion {
if selectedVersion.selected {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
.help("ActiveVersionDescription")
} else {
EmptyView()
}
} else if majorVersionGroup.hasInstalled {
EmptyView()
} else {
EmptyView()
}
}
@ViewBuilder
func installControl() -> some View {
if majorVersionGroup.hasInstalling {
if let installingVersion = majorVersionGroup.versions.first(where: { $0.installState.installing }) {
if case let .installing(installationStep) = installingVersion.installState {
InstallationStepRowView(
installationStep: installationStep,
highlighted: false,
cancel: { appState.presentedAlert = .cancelInstall(xcode: installingVersion) }
)
}
}
} else if let latestRelease = majorVersionGroup.latestRelease {
switch latestRelease.installState {
case .installed:
Button("Open") { appState.open(xcode: latestRelease) }
.textCase(.uppercase)
.buttonStyle(AppStoreButtonStyle(primary: true, highlighted: false))
.help("OpenDescription")
case .notInstalled:
Button("Install Latest Release") {
appState.checkMinVersionAndInstall(id: latestRelease.id)
}
.textCase(.uppercase)
.buttonStyle(AppStoreButtonStyle(primary: false, highlighted: false))
.help("InstallLatestReleaseDescription")
case .installing:
EmptyView()
}
}
}
}
struct XcodeMajorVersionRow_Previews: PreviewProvider {
static var previews: some View {
let sampleXcodes = [
Xcode(version: Version("16.4.0")!, installState: .installed(Path("/Applications/Xcode-16.4.0.app")!), selected: true, icon: nil),
Xcode(version: Version("16.3.0")!, installState: .notInstalled, selected: false, icon: nil),
Xcode(version: Version("16.2.0")!, installState: .notInstalled, selected: false, icon: nil),
]
let minorVersionGroups = [
XcodeMinorVersionGroup(
majorVersion: 16,
minorVersion: 4,
versions: [sampleXcodes[0]]
),
XcodeMinorVersionGroup(
majorVersion: 16,
minorVersion: 3,
versions: [sampleXcodes[1]]
),
XcodeMinorVersionGroup(
majorVersion: 16,
minorVersion: 2,
versions: [sampleXcodes[2]]
)
]
let majorVersionGroup = XcodeMajorVersionGroup(
majorVersion: 16,
minorVersionGroups: minorVersionGroups,
isExpanded: false
)
XcodeMajorVersionRow(
majorVersionGroup: majorVersionGroup,
isExpanded: false,
onToggleExpanded: {},
appState: AppState()
)
.previewLayout(.sizeThatFits)
}
}