mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Add trailing inspector pane
This commit is contained in:
parent
2316a19bd4
commit
ba0c429766
10 changed files with 416 additions and 42 deletions
|
|
@ -72,6 +72,8 @@
|
|||
CAFBDB912598FE80003DCC5A /* SelectedXcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDB902598FE80003DCC5A /* SelectedXcode.swift */; };
|
||||
CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDB942598FE96003DCC5A /* FocusedValues.swift */; };
|
||||
CAFBDC4E2599B33D003DCC5A /* MainToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */; };
|
||||
CAFBDC68259A308B003DCC5A /* InspectorPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDC67259A308B003DCC5A /* InspectorPane.swift */; };
|
||||
CAFBDC6C259A3098003DCC5A /* View+Conditional.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFBDC6B259A3098003DCC5A /* View+Conditional.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -191,6 +193,8 @@
|
|||
CAFBDB942598FE96003DCC5A /* FocusedValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusedValues.swift; sourceTree = "<group>"; };
|
||||
CAFBDBA525990C76003DCC5A /* SimpleXPCApp.LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = SimpleXPCApp.LICENSE; sourceTree = "<group>"; };
|
||||
CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainToolbar.swift; sourceTree = "<group>"; };
|
||||
CAFBDC67259A308B003DCC5A /* InspectorPane.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorPane.swift; sourceTree = "<group>"; };
|
||||
CAFBDC6B259A3098003DCC5A /* View+Conditional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Conditional.swift"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -295,6 +299,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
CA39711824495F0E00AFFB77 /* AppStoreButtonStyle.swift */,
|
||||
CAFBDC67259A308B003DCC5A /* InspectorPane.swift */,
|
||||
CAFBDC4D2599B33D003DCC5A /* MainToolbar.swift */,
|
||||
CA44901E2463AD34003D8213 /* Tag.swift */,
|
||||
CAD2E7A32449574E00113D76 /* XcodeListView.swift */,
|
||||
|
|
@ -344,6 +349,7 @@
|
|||
CAA1CB50255A5D16003FD669 /* SignIn */,
|
||||
CABFAA142592F73000380FEE /* XcodeList */,
|
||||
CABFAA2A2592FBFC00380FEE /* SettingsView.swift */,
|
||||
CAFBDC6B259A3098003DCC5A /* View+Conditional.swift */,
|
||||
CA9FF8652595130600E47BAF /* View+IsHidden.swift */,
|
||||
);
|
||||
path = Frontend;
|
||||
|
|
@ -633,7 +639,9 @@
|
|||
CA73510D257BFCEF00EA9CF8 /* NSAttributedString+.swift in Sources */,
|
||||
CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */,
|
||||
CABFA9C22592EEEA00380FEE /* Promise+.swift in Sources */,
|
||||
CAFBDC68259A308B003DCC5A /* InspectorPane.swift in Sources */,
|
||||
CAA1CB4D255A5CFD003FD669 /* SignInPhoneListView.swift in Sources */,
|
||||
CAFBDC6C259A3098003DCC5A /* View+Conditional.swift in Sources */,
|
||||
CABFA9CF2592EEEA00380FEE /* Process.swift in Sources */,
|
||||
CABFA9C72592EEEA00380FEE /* Entry+.swift in Sources */,
|
||||
CABFAA2C2592FBFC00380FEE /* SettingsView.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -170,7 +170,11 @@ extension AppState {
|
|||
version: version,
|
||||
url: downloadURL,
|
||||
filename: String(downloadURL.path.suffix(fromLast: "/")),
|
||||
releaseDate: releaseDate
|
||||
releaseDate: releaseDate,
|
||||
requiredMacOSVersion: xcReleasesXcode.requires,
|
||||
releaseNotesURL: xcReleasesXcode.links?.notes?.url,
|
||||
sdks: xcReleasesXcode.sdks,
|
||||
compilers: xcReleasesXcode.compilers
|
||||
)
|
||||
}
|
||||
return xcodes
|
||||
|
|
|
|||
|
|
@ -274,12 +274,17 @@ class AppState: ObservableObject {
|
|||
.sorted(by: >)
|
||||
.map { xcodeVersion in
|
||||
let installedXcode = installedXcodes.first(where: { xcodeVersion.isEquivalentForDeterminingIfInstalled(toInstalled: $0.version) })
|
||||
let availableXcode = xcodes.first { $0.version == xcodeVersion }
|
||||
return Xcode(
|
||||
version: xcodeVersion,
|
||||
installState: installedXcodes.contains(where: { xcodeVersion.isEquivalentForDeterminingIfInstalled(toInstalled: $0.version) }) ? .installed : .notInstalled,
|
||||
selected: false,
|
||||
path: installedXcode?.path.string,
|
||||
icon: (installedXcode?.path.string).map(NSWorkspace.shared.icon(forFile:))
|
||||
icon: (installedXcode?.path.string).map(NSWorkspace.shared.icon(forFile:)),
|
||||
requiredMacOSVersion: availableXcode?.requiredMacOSVersion,
|
||||
releaseNotesURL: availableXcode?.releaseNotesURL,
|
||||
sdks: availableXcode?.sdks,
|
||||
compilers: availableXcode?.compilers
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import Foundation
|
||||
import Version
|
||||
import struct XCModel.SDKs
|
||||
import struct XCModel.Compilers
|
||||
|
||||
/// A version of Xcode that's available for installation
|
||||
public struct AvailableXcode: Codable {
|
||||
|
|
@ -7,11 +9,28 @@ public struct AvailableXcode: Codable {
|
|||
public let url: URL
|
||||
public let filename: String
|
||||
public let releaseDate: Date?
|
||||
public let requiredMacOSVersion: String?
|
||||
public let releaseNotesURL: URL?
|
||||
public let sdks: SDKs?
|
||||
public let compilers: Compilers?
|
||||
|
||||
public init(version: Version, url: URL, filename: String, releaseDate: Date?) {
|
||||
public init(
|
||||
version: Version,
|
||||
url: URL,
|
||||
filename: String,
|
||||
releaseDate: Date?,
|
||||
requiredMacOSVersion: String? = nil,
|
||||
releaseNotesURL: URL? = nil,
|
||||
sdks: SDKs? = nil,
|
||||
compilers: Compilers? = nil
|
||||
) {
|
||||
self.version = version
|
||||
self.url = url
|
||||
self.filename = filename
|
||||
self.releaseDate = releaseDate
|
||||
self.requiredMacOSVersion = requiredMacOSVersion
|
||||
self.releaseNotesURL = releaseNotesURL
|
||||
self.sdks = sdks
|
||||
self.compilers = compilers
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import AppKit
|
||||
import Foundation
|
||||
import Version
|
||||
import struct XCModel.SDKs
|
||||
import struct XCModel.Compilers
|
||||
|
||||
struct Xcode: Identifiable, CustomStringConvertible {
|
||||
let version: Version
|
||||
|
|
@ -8,6 +10,32 @@ struct Xcode: Identifiable, CustomStringConvertible {
|
|||
let selected: Bool
|
||||
let path: String?
|
||||
let icon: NSImage?
|
||||
let requiredMacOSVersion: String?
|
||||
let releaseNotesURL: URL?
|
||||
let sdks: SDKs?
|
||||
let compilers: Compilers?
|
||||
|
||||
init(
|
||||
version: Version,
|
||||
installState: XcodeInstallState,
|
||||
selected: Bool,
|
||||
path: String?,
|
||||
icon: NSImage?,
|
||||
requiredMacOSVersion: String? = nil,
|
||||
releaseNotesURL: URL? = nil,
|
||||
sdks: SDKs? = nil,
|
||||
compilers: Compilers? = nil
|
||||
) {
|
||||
self.version = version
|
||||
self.installState = installState
|
||||
self.selected = selected
|
||||
self.path = path
|
||||
self.icon = icon
|
||||
self.requiredMacOSVersion = requiredMacOSVersion
|
||||
self.releaseNotesURL = releaseNotesURL
|
||||
self.sdks = sdks
|
||||
self.compilers = compilers
|
||||
}
|
||||
|
||||
var id: Version { version }
|
||||
var installed: Bool { installState == .installed }
|
||||
|
|
|
|||
12
Xcodes/Frontend/View+Conditional.swift
Normal file
12
Xcodes/Frontend/View+Conditional.swift
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
@ViewBuilder
|
||||
func `if`<Other: View>(_ predicate: Bool, then: (Self) -> Other) -> some View {
|
||||
if predicate {
|
||||
then(self)
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
265
Xcodes/Frontend/XcodeList/InspectorPane.swift
Normal file
265
Xcodes/Frontend/XcodeList/InspectorPane.swift
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
import AppKit
|
||||
import SwiftUI
|
||||
import Version
|
||||
import struct XCModel.SDKs
|
||||
import struct XCModel.Compilers
|
||||
|
||||
struct InspectorPane: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@SwiftUI.Environment(\.openURL) var openURL: OpenURLAction
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if let xcode = appState.allXcodes.first(where: { $0.id == appState.selectedXcodeID }) {
|
||||
VStack(spacing: 16) {
|
||||
icon(for: xcode)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text("Xcode \(xcode.description)")
|
||||
.font(.title)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
if let path = xcode.path {
|
||||
HStack {
|
||||
Text(path)
|
||||
Button(action: { appState.reveal(id: xcode.id) }) {
|
||||
Image(systemName: "arrow.right.circle.fill")
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
|
||||
HStack {
|
||||
if xcode.selected {
|
||||
Button("Selected", action: {})
|
||||
.disabled(true)
|
||||
} else {
|
||||
SelectButton(xcode: xcode)
|
||||
}
|
||||
|
||||
LaunchButton(xcode: xcode)
|
||||
}
|
||||
} else {
|
||||
InstallButton(xcode: xcode)
|
||||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
releaseNotes(for: xcode)
|
||||
compatibility(for: xcode)
|
||||
sdks(for: xcode)
|
||||
compilers(for: xcode)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
} else {
|
||||
empty
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(minWidth: 200, maxWidth: .infinity)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func icon(for xcode: Xcode) -> some View {
|
||||
if let path = xcode.path {
|
||||
Image(nsImage: NSWorkspace.shared.icon(forFile: path))
|
||||
} else {
|
||||
Image(systemName: "app.fill")
|
||||
.resizable()
|
||||
.frame(width: 32, height: 32)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func releaseNotes(for xcode: Xcode) -> some View {
|
||||
if let releaseNotesURL = xcode.releaseNotesURL {
|
||||
Button(action: { openURL(releaseNotesURL) }) {
|
||||
Label("Release Notes", systemImage: "link")
|
||||
}
|
||||
.buttonStyle(LinkButtonStyle())
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func compatibility(for xcode: Xcode) -> some View {
|
||||
if let requiredMacOSVersion = xcode.requiredMacOSVersion {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Compatibility")
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text("Requires macOS \(requiredMacOSVersion) or later")
|
||||
.font(.subheadline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func sdks(for xcode: Xcode) -> some View {
|
||||
if let sdks = xcode.sdks {
|
||||
VStack(alignment: .leading) {
|
||||
Text("SDKs")
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
ForEach([
|
||||
("macOS", \SDKs.macOS),
|
||||
("iOS", \.iOS),
|
||||
("watchOS", \.watchOS),
|
||||
("tvOS", \.tvOS),
|
||||
], id: \.0) { row in
|
||||
if let sdk = sdks[keyPath: row.1] {
|
||||
Text("\(row.0): \(sdk.compactMap { $0.number }.joined(separator: ", "))")
|
||||
.font(.subheadline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func compilers(for xcode: Xcode) -> some View {
|
||||
if let compilers = xcode.compilers {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Compilers")
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
ForEach([
|
||||
("Swift", \Compilers.swift),
|
||||
("Clang", \.clang),
|
||||
("LLVM", \.llvm),
|
||||
("LLVM GCC", \.llvm_gcc),
|
||||
("GCC", \.gcc),
|
||||
], id: \.0) { row in
|
||||
if let sdk = compilers[keyPath: row.1] {
|
||||
Text("\(row.0): \(sdk.compactMap { $0.number }.joined(separator: ", "))")
|
||||
.font(.subheadline)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var empty: some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
Text("No Xcode Selected")
|
||||
.font(.title)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InspectorPane_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
InspectorPane()
|
||||
.environmentObject(configure(AppState()) {
|
||||
$0.allXcodes = [
|
||||
.init(
|
||||
version: Version(major: 12, minor: 3, patch: 0),
|
||||
installState: .installed,
|
||||
selected: true,
|
||||
path: "/Applications/Xcode-12.3.0.app",
|
||||
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/")!,
|
||||
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")
|
||||
))
|
||||
]
|
||||
$0.selectedXcodeID = Version(major: 12, minor: 3, patch: 0)
|
||||
})
|
||||
.previewDisplayName("Populated, Installed, Selected")
|
||||
|
||||
InspectorPane()
|
||||
.environmentObject(configure(AppState()) {
|
||||
$0.allXcodes = [
|
||||
.init(
|
||||
version: Version(major: 12, minor: 3, patch: 0),
|
||||
installState: .installed,
|
||||
selected: false,
|
||||
path: "/Applications/Xcode-12.3.0.app",
|
||||
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")
|
||||
))
|
||||
]
|
||||
$0.selectedXcodeID = Version(major: 12, minor: 3, patch: 0)
|
||||
})
|
||||
.previewDisplayName("Populated, Installed, Unselected")
|
||||
|
||||
InspectorPane()
|
||||
.environmentObject(configure(AppState()) {
|
||||
$0.allXcodes = [
|
||||
.init(
|
||||
version: Version(major: 12, minor: 3, patch: 0),
|
||||
installState: .notInstalled,
|
||||
selected: false,
|
||||
path: nil,
|
||||
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")
|
||||
))
|
||||
]
|
||||
$0.selectedXcodeID = Version(major: 12, minor: 3, patch: 0)
|
||||
})
|
||||
.previewDisplayName("Populated, Uninstalled")
|
||||
|
||||
InspectorPane()
|
||||
.environmentObject(configure(AppState()) {
|
||||
$0.allXcodes = [
|
||||
]
|
||||
$0.selectedXcodeID = nil
|
||||
})
|
||||
.previewDisplayName("Empty")
|
||||
}
|
||||
.frame(maxWidth: 300)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import SwiftUI
|
|||
struct MainToolbarModifier: ViewModifier {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@Binding var category: XcodeListView.Category
|
||||
@Binding var isShowingInfoPane: Bool
|
||||
@Binding var searchText: String
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
|
|
@ -35,6 +36,16 @@ struct MainToolbarModifier: ViewModifier {
|
|||
}
|
||||
}
|
||||
|
||||
Button(action: { isShowingInfoPane.toggle() }) {
|
||||
if isShowingInfoPane {
|
||||
Label("Inspector", systemImage: "info.circle.fill")
|
||||
.foregroundColor(.accentColor)
|
||||
} else {
|
||||
Label("Inspector", systemImage: "info.circle")
|
||||
}
|
||||
}
|
||||
.keyboardShortcut(KeyboardShortcut("i", modifiers: [.command, .option]))
|
||||
|
||||
TextField("Search...", text: $searchText)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.frame(width: 200)
|
||||
|
|
@ -44,9 +55,16 @@ struct MainToolbarModifier: ViewModifier {
|
|||
|
||||
extension View {
|
||||
func mainToolbar(
|
||||
category: Binding<XcodeListView.Category>,
|
||||
category: Binding<XcodeListView.Category>,
|
||||
isShowingInfoPane: Binding<Bool>,
|
||||
searchText: Binding<String>
|
||||
) -> some View {
|
||||
self.modifier(MainToolbarModifier(category: category, searchText: searchText))
|
||||
self.modifier(
|
||||
MainToolbarModifier(
|
||||
category: category,
|
||||
isShowingInfoPane: isShowingInfoPane,
|
||||
searchText: searchText
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ struct XcodeListView: View {
|
|||
@State private var selection: Xcode.ID?
|
||||
@State private var searchText: String = ""
|
||||
@AppStorage("lastUpdated") private var lastUpdated: Double?
|
||||
@AppStorage("xcodeListCategory") private var category: Category = .all
|
||||
@SceneStorage("isShowingInfoPane") private var isShowingInfoPane = false
|
||||
@SceneStorage("xcodeListCategory") private var category: Category = .all
|
||||
|
||||
var visibleXcodes: [Xcode] {
|
||||
var xcodes: [Xcode]
|
||||
|
|
@ -40,47 +41,60 @@ struct XcodeListView: View {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
List(visibleXcodes, selection: $appState.selectedXcodeID) { xcode in
|
||||
HStack {
|
||||
appIconView(for: xcode)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(xcode.description)
|
||||
.font(.body)
|
||||
HSplitView {
|
||||
List(visibleXcodes, selection: $appState.selectedXcodeID) { xcode in
|
||||
HStack {
|
||||
appIconView(for: xcode)
|
||||
|
||||
Text(verbatim: xcode.path ?? "")
|
||||
.font(.caption)
|
||||
.foregroundColor(appState.selectedXcodeID == xcode.id ? Color(NSColor.selectedMenuItemTextColor) : Color(NSColor.secondaryLabelColor))
|
||||
VStack(alignment: .leading) {
|
||||
Text(xcode.description)
|
||||
.font(.body)
|
||||
|
||||
Text(verbatim: xcode.path ?? "")
|
||||
.font(.caption)
|
||||
.foregroundColor(appState.selectedXcodeID == xcode.id ? Color(NSColor.selectedMenuItemTextColor) : Color(NSColor.secondaryLabelColor))
|
||||
}
|
||||
|
||||
if xcode.selected {
|
||||
Tag(text: "SELECTED")
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(xcode.installed ? "INSTALLED" : "INSTALL") {
|
||||
print("Installing...")
|
||||
}
|
||||
.buttonStyle(AppStoreButtonStyle(installed: xcode.installed,
|
||||
highlighted: appState.selectedXcodeID == xcode.id))
|
||||
.disabled(xcode.installed)
|
||||
}
|
||||
|
||||
if xcode.selected {
|
||||
Tag(text: "SELECTED")
|
||||
.foregroundColor(.green)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(xcode.installed ? "INSTALLED" : "INSTALL") {
|
||||
print("Installing...")
|
||||
}
|
||||
.buttonStyle(AppStoreButtonStyle(installed: xcode.installed,
|
||||
highlighted: appState.selectedXcodeID == xcode.id))
|
||||
.disabled(xcode.installed)
|
||||
}
|
||||
.contextMenu {
|
||||
InstallButton(xcode: xcode)
|
||||
|
||||
Divider()
|
||||
|
||||
if xcode.installed {
|
||||
SelectButton(xcode: xcode)
|
||||
LaunchButton(xcode: xcode)
|
||||
RevealButton(xcode: xcode)
|
||||
CopyPathButton(xcode: xcode)
|
||||
.contextMenu {
|
||||
InstallButton(xcode: xcode)
|
||||
|
||||
Divider()
|
||||
|
||||
if xcode.installed {
|
||||
SelectButton(xcode: xcode)
|
||||
LaunchButton(xcode: xcode)
|
||||
RevealButton(xcode: xcode)
|
||||
CopyPathButton(xcode: xcode)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 300)
|
||||
.layoutPriority(1)
|
||||
|
||||
InspectorPane()
|
||||
.frame(minWidth: 300, maxWidth: .infinity)
|
||||
.frame(width: isShowingInfoPane ? nil : 0)
|
||||
.isHidden(!isShowingInfoPane)
|
||||
}
|
||||
.mainToolbar(category: $category, searchText: $searchText)
|
||||
.mainToolbar(
|
||||
category: $category,
|
||||
isShowingInfoPane: $isShowingInfoPane,
|
||||
searchText: $searchText
|
||||
)
|
||||
.navigationSubtitle(subtitleText)
|
||||
.frame(minWidth: 200, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
|
||||
.alert(item: $appState.error) { error in
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ struct XcodesApp: App {
|
|||
var body: some Scene {
|
||||
WindowGroup("Xcodes") {
|
||||
XcodeListView()
|
||||
.frame(minWidth: 600)
|
||||
.environmentObject(appState)
|
||||
// This is intentionally used on a View, and not on a WindowGroup,
|
||||
// so that it's triggered when an individual window's phase changes instead of all window phases.
|
||||
|
|
|
|||
Loading…
Reference in a new issue