mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Major and minor version collapsable lists implemented
This commit is contained in:
parent
6a0e521bc2
commit
3747f2151f
7 changed files with 490 additions and 9 deletions
|
|
@ -7,6 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
05AB7F172E76C96E007C5CFE /* XcodeMajorVersionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AB7F162E76C96E007C5CFE /* XcodeMajorVersionRow.swift */; };
|
||||
05AB7F192E76CD8C007C5CFE /* XcodeMinorVersionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AB7F182E76CD8C007C5CFE /* XcodeMinorVersionRow.swift */; };
|
||||
15F5B8902CCF09B900705E2F /* CryptoKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15F5B88F2CCF09B900705E2F /* CryptoKit.framework */; };
|
||||
33027E342CA8C18800CB387C /* LibFido2Swift in Frameworks */ = {isa = PBXBuildFile; productRef = 334A932B2CA885A400A5E079 /* LibFido2Swift */; };
|
||||
3328073F2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3328073E2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift */; };
|
||||
|
|
@ -192,6 +194,8 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
05AB7F162E76C96E007C5CFE /* XcodeMajorVersionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeMajorVersionRow.swift; sourceTree = "<group>"; };
|
||||
05AB7F182E76CD8C007C5CFE /* XcodeMinorVersionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XcodeMinorVersionRow.swift; sourceTree = "<group>"; };
|
||||
15F5B88F2CCF09B900705E2F /* CryptoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoKit.framework; path = System/Library/Frameworks/CryptoKit.framework; sourceTree = SDKROOT; };
|
||||
3328073E2CA5E2C80036F691 /* SignInSecurityKeyPinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInSecurityKeyPinView.swift; sourceTree = "<group>"; };
|
||||
332807402CA5EA820036F691 /* SignInSecurityKeyTouchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInSecurityKeyTouchView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -476,6 +480,8 @@
|
|||
CA44901E2463AD34003D8213 /* Tag.swift */,
|
||||
CAE42486259A68A300B8B246 /* XcodeListCategory.swift */,
|
||||
CAD2E7A32449574E00113D76 /* XcodeListView.swift */,
|
||||
05AB7F162E76C96E007C5CFE /* XcodeMajorVersionRow.swift */,
|
||||
05AB7F182E76CD8C007C5CFE /* XcodeMinorVersionRow.swift */,
|
||||
CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */,
|
||||
E8D0296E284B029800647641 /* BottomStatusBar.swift */,
|
||||
);
|
||||
|
|
@ -856,6 +862,7 @@
|
|||
" -p \"${SRCROOT}/Xcodes.xcodeproj\" \\",
|
||||
" -o \"${SRCROOT}/Xcodes/Resources/Licenses.rtf\"",
|
||||
"",
|
||||
"",
|
||||
);
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
|
@ -880,6 +887,7 @@
|
|||
CAFBDC4E2599B33D003DCC5A /* MainToolbar.swift in Sources */,
|
||||
CA11E7BA2598476C00D2EE1C /* XcodeCommands.swift in Sources */,
|
||||
CAA8589B25A2B83000ACF8C0 /* Aria2CError.swift in Sources */,
|
||||
05AB7F192E76CD8C007C5CFE /* XcodeMinorVersionRow.swift in Sources */,
|
||||
536CFDD2263C94DE00026CE0 /* SignedInView.swift in Sources */,
|
||||
CABFAA492593162500380FEE /* Bundle+InfoPlistValues.swift in Sources */,
|
||||
CA9FF8662595130600E47BAF /* View+IsHidden.swift in Sources */,
|
||||
|
|
@ -918,6 +926,7 @@
|
|||
CA452BB0259FD9770072DFA4 /* ProgressIndicator.swift in Sources */,
|
||||
B0403CF02AD92D7B00137C09 /* ReleaseNotesView.swift in Sources */,
|
||||
CAFE4AB425B7D3AF0064FE51 /* AdvancedPreferencePane.swift in Sources */,
|
||||
05AB7F172E76C96E007C5CFE /* XcodeMajorVersionRow.swift in Sources */,
|
||||
CA9FF84E2595079F00E47BAF /* ScrollingTextView.swift in Sources */,
|
||||
E832EAF82B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift in Sources */,
|
||||
CABFA9C12592EEEA00380FEE /* Version+.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
|
|
@ -85,5 +85,97 @@ struct Xcode: Identifiable, CustomStringConvertible {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct XcodeMinorVersionGroup: Identifiable {
|
||||
let majorVersion: Int
|
||||
let minorVersion: Int
|
||||
let versions: [Xcode]
|
||||
var isExpanded: Bool = false
|
||||
|
||||
var id: String {
|
||||
"\(majorVersion).\(minorVersion)"
|
||||
}
|
||||
|
||||
var latestRelease: Xcode? {
|
||||
versions
|
||||
.filter { $0.version.isNotPrerelease }
|
||||
.sorted { $0.version < $1.version }
|
||||
.last
|
||||
}
|
||||
|
||||
var displayName: String {
|
||||
"\(majorVersion).\(minorVersion)"
|
||||
}
|
||||
|
||||
var hasInstalled: Bool {
|
||||
versions.contains { $0.installState.installed }
|
||||
}
|
||||
|
||||
var hasInstalling: Bool {
|
||||
versions.contains { $0.installState.installing }
|
||||
}
|
||||
|
||||
var selectedVersion: Xcode? {
|
||||
versions.first { $0.selected }
|
||||
}
|
||||
}
|
||||
|
||||
struct XcodeMajorVersionGroup: Identifiable {
|
||||
let majorVersion: Int
|
||||
let minorVersionGroups: [XcodeMinorVersionGroup]
|
||||
var isExpanded: Bool = false
|
||||
|
||||
var id: Int {
|
||||
majorVersion
|
||||
}
|
||||
|
||||
var versions: [Xcode] {
|
||||
minorVersionGroups.flatMap { $0.versions }
|
||||
}
|
||||
|
||||
var latestRelease: Xcode? {
|
||||
versions
|
||||
.filter { $0.version.isNotPrerelease }
|
||||
.sorted { $0.version < $1.version }
|
||||
.last
|
||||
}
|
||||
|
||||
var displayName: String {
|
||||
"\(majorVersion)"
|
||||
}
|
||||
|
||||
var hasInstalled: Bool {
|
||||
minorVersionGroups.contains { $0.hasInstalled }
|
||||
}
|
||||
|
||||
var hasInstalling: Bool {
|
||||
minorVersionGroups.contains { $0.hasInstalling }
|
||||
}
|
||||
|
||||
var selectedVersion: Xcode? {
|
||||
minorVersionGroups.compactMap { $0.selectedVersion }.first
|
||||
}
|
||||
}
|
||||
|
||||
extension Array where Element == Xcode {
|
||||
func groupedByMajorVersion() -> [XcodeMajorVersionGroup] {
|
||||
let majorGroups = Dictionary(grouping: self) { $0.version.major }
|
||||
return majorGroups.map { majorVersion, xcodes in
|
||||
let minorGroups = Dictionary(grouping: xcodes) { $0.version.minor }
|
||||
let minorVersionGroups = minorGroups.map { minorVersion, minorXcodes in
|
||||
XcodeMinorVersionGroup(
|
||||
majorVersion: majorVersion,
|
||||
minorVersion: minorVersion,
|
||||
versions: minorXcodes.sorted { $0.version > $1.version }
|
||||
)
|
||||
}.sorted { $0.minorVersion > $1.minorVersion }
|
||||
|
||||
return XcodeMajorVersionGroup(
|
||||
majorVersion: majorVersion,
|
||||
minorVersionGroups: minorVersionGroups
|
||||
)
|
||||
}.sorted { $0.majorVersion > $1.majorVersion }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ struct XcodeListView: View {
|
|||
private let architecture: XcodeListArchitecture
|
||||
private let isInstalledOnly: Bool
|
||||
@AppStorage(PreferenceKey.allowedMajorVersions.rawValue) private var allowedMajorVersions = Int.max
|
||||
@State private var expandedMajorVersions = Set<Int>()
|
||||
@State private var expandedMinorVersions = Set<String>()
|
||||
|
||||
init(selectedXcodeID: Binding<Xcode.ID?>, searchText: String, category: XcodeListCategory, isInstalledOnly: Bool, architecture: XcodeListArchitecture) {
|
||||
self._selectedXcodeID = selectedXcodeID
|
||||
|
|
@ -29,12 +31,12 @@ struct XcodeListView: View {
|
|||
case .beta:
|
||||
xcodes = appState.allXcodes.filter { $0.version.isPrerelease }
|
||||
}
|
||||
|
||||
|
||||
if architecture == .appleSilicon {
|
||||
xcodes = xcodes.filter { $0.architectures == [.arm64] }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
let latestMajor = xcodes.sorted(\.version)
|
||||
.filter { $0.version.isNotPrerelease }
|
||||
.last?
|
||||
|
|
@ -54,17 +56,69 @@ struct XcodeListView: View {
|
|||
if !searchText.isEmpty {
|
||||
xcodes = xcodes.filter { $0.description.contains(searchText) }
|
||||
}
|
||||
|
||||
|
||||
if isInstalledOnly {
|
||||
xcodes = xcodes.filter { $0.installState.installed }
|
||||
}
|
||||
|
||||
|
||||
return xcodes
|
||||
}
|
||||
|
||||
var majorVersionGroups: [XcodeMajorVersionGroup] {
|
||||
visibleXcodes.groupedByMajorVersion()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
List(visibleXcodes, selection: $selectedXcodeID) { xcode in
|
||||
XcodeListViewRow(xcode: xcode, selected: selectedXcodeID == xcode.id, appState: appState)
|
||||
List(selection: $selectedXcodeID) {
|
||||
ForEach(majorVersionGroups) { majorVersionGroup in
|
||||
let isMajorExpanded = expandedMajorVersions.contains(majorVersionGroup.majorVersion)
|
||||
|
||||
XcodeMajorVersionRow(
|
||||
majorVersionGroup: majorVersionGroup,
|
||||
isExpanded: isMajorExpanded,
|
||||
onToggleExpanded: {
|
||||
if isMajorExpanded {
|
||||
expandedMajorVersions.remove(majorVersionGroup.majorVersion)
|
||||
// Collapse all minor versions when major version is collapsed
|
||||
for minorGroup in majorVersionGroup.minorVersionGroups {
|
||||
expandedMinorVersions.remove(minorGroup.id)
|
||||
}
|
||||
} else {
|
||||
expandedMajorVersions.insert(majorVersionGroup.majorVersion)
|
||||
}
|
||||
},
|
||||
appState: appState
|
||||
)
|
||||
.tag(majorVersionGroup.selectedVersion?.id)
|
||||
|
||||
if isMajorExpanded {
|
||||
ForEach(majorVersionGroup.minorVersionGroups) { minorVersionGroup in
|
||||
let isMinorExpanded = expandedMinorVersions.contains(minorVersionGroup.id)
|
||||
|
||||
XcodeMinorVersionRow(
|
||||
minorVersionGroup: minorVersionGroup,
|
||||
isExpanded: isMinorExpanded,
|
||||
onToggleExpanded: {
|
||||
if isMinorExpanded {
|
||||
expandedMinorVersions.remove(minorVersionGroup.id)
|
||||
} else {
|
||||
expandedMinorVersions.insert(minorVersionGroup.id)
|
||||
}
|
||||
},
|
||||
appState: appState
|
||||
)
|
||||
.tag(minorVersionGroup.selectedVersion?.id)
|
||||
|
||||
if isMinorExpanded {
|
||||
ForEach(minorVersionGroup.versions) { xcode in
|
||||
XcodeListViewRow(xcode: xcode, selected: selectedXcodeID == xcode.id, appState: appState)
|
||||
.padding(.leading, 40)
|
||||
.tag(xcode.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
.safeAreaInset(edge: .bottom, spacing: 0) {
|
||||
|
|
|
|||
157
Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift
Normal file
157
Xcodes/Frontend/XcodeList/XcodeMajorVersionRow.swift
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
140
Xcodes/Frontend/XcodeList/XcodeMinorVersionRow.swift
Normal file
140
Xcodes/Frontend/XcodeList/XcodeMinorVersionRow.swift
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import SwiftUI
|
||||
import Version
|
||||
import Path
|
||||
|
||||
struct XcodeMinorVersionRow: View {
|
||||
let minorVersionGroup: XcodeMinorVersionGroup
|
||||
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)
|
||||
|
||||
minorVersionIcon
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Xcode \(minorVersionGroup.displayName)")
|
||||
.font(.callout.weight(.medium))
|
||||
|
||||
if let latestRelease = minorVersionGroup.latestRelease {
|
||||
Text("Latest: \(latestRelease.description)")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
selectControl()
|
||||
.padding(.trailing, 16)
|
||||
installControl()
|
||||
}
|
||||
.padding(.vertical, 6)
|
||||
.padding(.leading, 20)
|
||||
.background(Color.clear)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var minorVersionIcon: some View {
|
||||
if let latestRelease = minorVersionGroup.latestRelease {
|
||||
if let icon = latestRelease.icon {
|
||||
Image(nsImage: icon)
|
||||
.resizable()
|
||||
.frame(width: 28, height: 28)
|
||||
} else {
|
||||
Image("xcode")
|
||||
.resizable()
|
||||
.frame(width: 28, height: 28)
|
||||
.opacity(0.6)
|
||||
}
|
||||
} else {
|
||||
Image("xcode-beta")
|
||||
.resizable()
|
||||
.frame(width: 28, height: 28)
|
||||
.opacity(0.6)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func selectControl() -> some View {
|
||||
if let selectedVersion = minorVersionGroup.selectedVersion {
|
||||
if selectedVersion.selected {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
.help("ActiveVersionDescription")
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
} else if minorVersionGroup.hasInstalled {
|
||||
EmptyView()
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func installControl() -> some View {
|
||||
if minorVersionGroup.hasInstalling {
|
||||
if let installingVersion = minorVersionGroup.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 = minorVersionGroup.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") {
|
||||
appState.checkMinVersionAndInstall(id: latestRelease.id)
|
||||
}
|
||||
.textCase(.uppercase)
|
||||
.buttonStyle(AppStoreButtonStyle(primary: false, highlighted: false))
|
||||
.help("InstallLatestVersionDescription")
|
||||
case .installing:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct XcodeMinorVersionRow_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.4.1")!, installState: .notInstalled, selected: false, icon: nil),
|
||||
]
|
||||
|
||||
let minorVersionGroup = XcodeMinorVersionGroup(
|
||||
majorVersion: 16,
|
||||
minorVersion: 4,
|
||||
versions: sampleXcodes,
|
||||
isExpanded: false
|
||||
)
|
||||
|
||||
XcodeMinorVersionRow(
|
||||
minorVersionGroup: minorVersionGroup,
|
||||
isExpanded: false,
|
||||
onToggleExpanded: {},
|
||||
appState: AppState()
|
||||
)
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
|
|
@ -10845,6 +10845,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Install Latest" : {
|
||||
"comment" : "A button that installs the latest Xcode version.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Install Latest Release" : {
|
||||
"comment" : "A button that installs the latest release of Xcode.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Install Universal" : {
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
|
|
@ -13587,6 +13595,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"InstallLatestReleaseDescription" : {
|
||||
"comment" : "A button label that instructs the user to install the latest release of Xcode.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"InstallLatestVersionDescription" : {
|
||||
"comment" : "A button label that instructs the user to install the latest version of Xcode.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"InstallPathDescription" : {
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
|
|
@ -13836,6 +13852,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Latest: %@" : {
|
||||
"comment" : "A sublabel within the Xcode major version row that shows the description of the latest release in that version group.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"License" : {
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
|
|
@ -23687,6 +23707,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Xcode %@" : {
|
||||
"comment" : "A title and optional subtitle for a row in the checkout view, displaying the Xcode version and its latest release.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Xcodes" : {
|
||||
"localizations" : {
|
||||
"ar" : {
|
||||
|
|
@ -23806,5 +23830,5 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
"version" : "1.1"
|
||||
}
|
||||
Loading…
Reference in a new issue