mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Switch to NavigationSplitView
This commit is contained in:
parent
638543070b
commit
7070575a32
6 changed files with 148 additions and 63 deletions
|
|
@ -114,8 +114,8 @@
|
|||
E689540325BE8C64000EBCEA /* DockProgress in Frameworks */ = {isa = PBXBuildFile; productRef = E689540225BE8C64000EBCEA /* DockProgress */; };
|
||||
E81D7EA02805250100A205FC /* Collection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81D7E9F2805250100A205FC /* Collection+.swift */; };
|
||||
E832EAF82B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832EAF72B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift */; };
|
||||
E84B7D0D2B296A8900DBDA2B /* NavigationSplitViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84B7D0C2B296A8900DBDA2B /* NavigationSplitViewWrapper.swift */; };
|
||||
E84CF8C12B0FEB8300ECA259 /* RuntimesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84CF8C02B0FEB8300ECA259 /* RuntimesView.swift */; };
|
||||
E872EE4E2808D4F100D3DD8B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E872EE502808D4F100D3DD8B /* Localizable.strings */; };
|
||||
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87AB3C42939B65E00D72F43 /* Hardware.swift */; };
|
||||
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
|
||||
E89342FA25EDCC17007CF557 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89342F925EDCC17007CF557 /* NotificationManager.swift */; };
|
||||
|
|
@ -310,9 +310,9 @@
|
|||
CAFFFEEE259CEAC400903F81 /* RingProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RingProgressViewStyle.swift; sourceTree = "<group>"; };
|
||||
E81D7E9F2805250100A205FC /* Collection+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+.swift"; sourceTree = "<group>"; };
|
||||
E832EAF72B0FBCF4001B570D /* RuntimeInstallationStepDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimeInstallationStepDetailView.swift; sourceTree = "<group>"; };
|
||||
E84B7D0C2B296A8900DBDA2B /* NavigationSplitViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSplitViewWrapper.swift; sourceTree = "<group>"; };
|
||||
E84CF8C02B0FEB8300ECA259 /* RuntimesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuntimesView.swift; sourceTree = "<group>"; };
|
||||
E856BB73291EDD3D00DC438B /* XcodesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = XcodesKit; path = Xcodes/XcodesKit; sourceTree = "<group>"; };
|
||||
E872EE4F2808D4F100D3DD8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
E87AB3C42939B65E00D72F43 /* Hardware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hardware.swift; sourceTree = "<group>"; };
|
||||
E87DD6EA25D053FA00D86808 /* Progress+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+.swift"; sourceTree = "<group>"; };
|
||||
E89342F925EDCC17007CF557 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -373,6 +373,7 @@
|
|||
CA452BAF259FD9770072DFA4 /* ProgressIndicator.swift */,
|
||||
536CFDD3263C9A8000026CE0 /* XcodesSheet.swift */,
|
||||
53CBAB2B263DCC9100410495 /* XcodesAlert.swift */,
|
||||
E84B7D0C2B296A8900DBDA2B /* NavigationSplitViewWrapper.swift */,
|
||||
);
|
||||
path = Common;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -921,6 +922,7 @@
|
|||
E8B20CBF2A2EDEC20057D816 /* SDKs+Xcode.swift in Sources */,
|
||||
CA9FF877259528CC00E47BAF /* Version+XcodeReleases.swift in Sources */,
|
||||
CABFAA2D2592FBFC00380FEE /* Configure.swift in Sources */,
|
||||
E84B7D0D2B296A8900DBDA2B /* NavigationSplitViewWrapper.swift in Sources */,
|
||||
CA73510D257BFCEF00EA9CF8 /* NSAttributedString+.swift in Sources */,
|
||||
CAFBDB952598FE96003DCC5A /* FocusedValues.swift in Sources */,
|
||||
B0403CF42AD9381D00137C09 /* SDKsView.swift in Sources */,
|
||||
|
|
@ -1040,7 +1042,7 @@
|
|||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
|
@ -1227,7 +1229,7 @@
|
|||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
|
@ -1285,7 +1287,7 @@
|
|||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
|
|
|
|||
46
Xcodes/Frontend/Common/NavigationSplitViewWrapper.swift
Normal file
46
Xcodes/Frontend/Common/NavigationSplitViewWrapper.swift
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// NavigationSplitViewWrapper.swift
|
||||
// Xcodes
|
||||
//
|
||||
// Created by Matt Kiazyk on 2023-12-12.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct NavigationSplitViewWrapper<Sidebar, Detail>: View where Sidebar: View, Detail: View {
|
||||
private var sidebar: Sidebar
|
||||
private var detail: Detail
|
||||
|
||||
init(
|
||||
@ViewBuilder sidebar: () -> Sidebar,
|
||||
@ViewBuilder detail: () -> Detail
|
||||
) {
|
||||
self.sidebar = sidebar()
|
||||
self.detail = detail()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if #available(iOS 16, macOS 13, tvOS 16, watchOS 9, visionOS 1, *) {
|
||||
// Use the latest API available
|
||||
NavigationSplitView {
|
||||
|
||||
if #available(macOS 14, *) {
|
||||
sidebar
|
||||
.toolbar(removing: .sidebarToggle)
|
||||
} else {
|
||||
sidebar
|
||||
}
|
||||
} detail: {
|
||||
detail
|
||||
}
|
||||
} else {
|
||||
// Alternative code for earlier versions of OS.
|
||||
NavigationView {
|
||||
// The first column is the sidebar.
|
||||
sidebar
|
||||
detail
|
||||
}
|
||||
.navigationViewStyle(.columns)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import ErrorHandling
|
||||
import SwiftUI
|
||||
import XcodesKit
|
||||
import Path
|
||||
import Version
|
||||
|
||||
struct MainWindow: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
|
|
@ -16,7 +18,7 @@ struct MainWindow: View {
|
|||
@AppStorage("isInstalledOnly") private var isInstalledOnly = false
|
||||
|
||||
var body: some View {
|
||||
HSplitView {
|
||||
NavigationSplitViewWrapper {
|
||||
XcodeListView(selectedXcodeID: $selectedXcodeID, searchText: searchText, category: category, isInstalledOnly: isInstalledOnly)
|
||||
.frame(minWidth: 300)
|
||||
.layoutPriority(1)
|
||||
|
|
@ -26,25 +28,73 @@ struct MainWindow: View {
|
|||
primaryButton: .destructive(Text("Uninstall"), action: { self.appState.uninstall(xcode: xcode) }),
|
||||
secondaryButton: .cancel(Text("Cancel")))
|
||||
}
|
||||
|
||||
if isShowingInfoPane {
|
||||
Group {
|
||||
if let xcode = xcode {
|
||||
InfoPane(xcode: xcode)
|
||||
.searchable(text: $searchText, placement: .sidebar)
|
||||
.mainToolbar(
|
||||
category: $category,
|
||||
isInstalledOnly: $isInstalledOnly,
|
||||
isShowingInfoPane: $isShowingInfoPane
|
||||
)
|
||||
} detail: {
|
||||
Group {
|
||||
if let xcode = xcode {
|
||||
InfoPane(xcode: xcode)
|
||||
} else {
|
||||
UnselectedView()
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.toolbar {
|
||||
ToolbarItemGroup {
|
||||
Button(action: { appState.presentedSheet = .signIn }, label: {
|
||||
Label("Login", systemImage: "person.circle")
|
||||
})
|
||||
.help("LoginDescription")
|
||||
if #available(macOS 14, *) {
|
||||
SettingsLink(label: {
|
||||
Label("Preferences", systemImage: "gearshape")
|
||||
})
|
||||
.help("PreferencesDescription")
|
||||
} else {
|
||||
UnselectedView()
|
||||
Button(action: {
|
||||
if #available(macOS 13, *) {
|
||||
NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
|
||||
} else {
|
||||
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
|
||||
}
|
||||
}, label: {
|
||||
Label("Preferences", systemImage: "gearshape")
|
||||
})
|
||||
.help("PreferencesDescription")
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.frame(minWidth: 300, maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.mainToolbar(
|
||||
category: $category,
|
||||
isInstalledOnly: $isInstalledOnly,
|
||||
isShowingInfoPane: $isShowingInfoPane,
|
||||
searchText: $searchText
|
||||
)
|
||||
|
||||
// HSplitView {
|
||||
// XcodeListView(selectedXcodeID: $selectedXcodeID, searchText: searchText, category: category, isInstalledOnly: isInstalledOnly)
|
||||
// .frame(minWidth: 300)
|
||||
// .layoutPriority(1)
|
||||
// .alert(item: $appState.xcodeBeingConfirmedForUninstallation) { xcode in
|
||||
// Alert(title: Text(String(format: localizeString("Alert.Uninstall.Title"), xcode.description)),
|
||||
// message: Text("Alert.Uninstall.Message"),
|
||||
// primaryButton: .destructive(Text("Uninstall"), action: { self.appState.uninstall(xcode: xcode) }),
|
||||
// secondaryButton: .cancel(Text("Cancel")))
|
||||
// }
|
||||
// .searchable(text: $searchText)
|
||||
//
|
||||
// if isShowingInfoPane {
|
||||
// Group {
|
||||
// if let xcode = xcode {
|
||||
// InfoPane(xcode: xcode)
|
||||
// } else {
|
||||
// UnselectedView()
|
||||
// }
|
||||
// }
|
||||
// .padding()
|
||||
// .frame(minWidth: 300, maxWidth: .infinity)
|
||||
// }
|
||||
// }
|
||||
|
||||
.bottomStatusBar()
|
||||
.padding([.top], 0)
|
||||
.navigationSubtitle(subtitleText)
|
||||
|
|
@ -197,6 +247,16 @@ struct MainWindow: View {
|
|||
|
||||
struct MainWindow_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MainWindow()
|
||||
MainWindow().environmentObject({ () -> AppState in
|
||||
let a = AppState()
|
||||
a.allXcodes = [
|
||||
Xcode(version: Version("12.0.0+1234A")!, identicalBuilds: [Version("12.0.0+1234A")!, Version("12.0.0-RC+1234A")!], installState: .installed(Path("/Applications/Xcode-12.3.0.app")!), selected: false, icon: nil),
|
||||
Xcode(version: Version("12.3.0")!, installState: .installed(Path("/Applications/Xcode-12.3.0.app")!), selected: true, icon: nil),
|
||||
Xcode(version: Version("12.2.0")!, installState: .notInstalled, selected: false, icon: nil),
|
||||
Xcode(version: Version("12.1.0")!, installState: .installing(.downloading(progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40 })), selected: false, icon: nil),
|
||||
Xcode(version: Version("12.0.0")!, installState: .installed(Path("/Applications/Xcode-12.3.0.app")!), selected: false, icon: nil),
|
||||
]
|
||||
return a
|
||||
}())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ struct MainToolbarModifier: ViewModifier {
|
|||
@Binding var category: XcodeListCategory
|
||||
@Binding var isInstalledOnly: Bool
|
||||
@Binding var isShowingInfoPane: Bool
|
||||
@Binding var searchText: String
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
|
|
@ -14,10 +13,6 @@ struct MainToolbarModifier: ViewModifier {
|
|||
|
||||
private var toolbar: some ToolbarContent {
|
||||
ToolbarItemGroup {
|
||||
Button(action: { appState.presentedSheet = .signIn }, label: {
|
||||
Label("Login", systemImage: "person.circle")
|
||||
})
|
||||
.help("LoginDescription")
|
||||
|
||||
ProgressButton(
|
||||
isInProgress: appState.isUpdating,
|
||||
|
|
@ -27,7 +22,7 @@ struct MainToolbarModifier: ViewModifier {
|
|||
}
|
||||
.keyboardShortcut(KeyEquivalent("r"))
|
||||
.help("RefreshDescription")
|
||||
|
||||
Spacer()
|
||||
Button(action: {
|
||||
switch category {
|
||||
case .all: category = .release
|
||||
|
|
@ -75,39 +70,18 @@ struct MainToolbarModifier: ViewModifier {
|
|||
}
|
||||
.help("FilterInstalledDescription")
|
||||
|
||||
Button(action: { isShowingInfoPane.toggle() }) {
|
||||
if isShowingInfoPane {
|
||||
Label("Info", systemImage: "info.circle.fill")
|
||||
.foregroundColor(.accentColor)
|
||||
} else {
|
||||
Label("Info", systemImage: "info.circle")
|
||||
}
|
||||
}
|
||||
.keyboardShortcut(KeyboardShortcut("i", modifiers: [.command, .option]))
|
||||
.help("InfoDescription")
|
||||
// Button(action: { isShowingInfoPane.toggle() }) {
|
||||
// if isShowingInfoPane {
|
||||
// Label("Info", systemImage: "info.circle.fill")
|
||||
// .foregroundColor(.accentColor)
|
||||
// } else {
|
||||
// Label("Info", systemImage: "info.circle")
|
||||
// }
|
||||
// }
|
||||
// .keyboardShortcut(KeyboardShortcut("i", modifiers: [.command, .option]))
|
||||
// .help("InfoDescription")
|
||||
|
||||
if #available(macOS 14, *) {
|
||||
SettingsLink(label: {
|
||||
Label("Preferences", systemImage: "gearshape")
|
||||
})
|
||||
.help("PreferencesDescription")
|
||||
} else {
|
||||
Button(action: {
|
||||
if #available(macOS 13, *) {
|
||||
NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil)
|
||||
} else {
|
||||
NSApp.sendAction(Selector(("showPreferencesWindow:")), to: nil, from: nil)
|
||||
}
|
||||
}, label: {
|
||||
Label("Preferences", systemImage: "gearshape")
|
||||
})
|
||||
.help("PreferencesDescription")
|
||||
}
|
||||
|
||||
TextField("Search", text: $searchText)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.frame(width: 200)
|
||||
.help("SearchDescription")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,15 +90,13 @@ extension View {
|
|||
func mainToolbar(
|
||||
category: Binding<XcodeListCategory>,
|
||||
isInstalledOnly: Binding<Bool>,
|
||||
isShowingInfoPane: Binding<Bool>,
|
||||
searchText: Binding<String>
|
||||
isShowingInfoPane: Binding<Bool>
|
||||
) -> some View {
|
||||
self.modifier(
|
||||
MainToolbarModifier(
|
||||
category: category,
|
||||
isInstalledOnly: isInstalledOnly,
|
||||
isShowingInfoPane: isShowingInfoPane,
|
||||
searchText: searchText
|
||||
isShowingInfoPane: isShowingInfoPane
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct XcodeListView: View {
|
|||
List(visibleXcodes, selection: $selectedXcodeID) { xcode in
|
||||
XcodeListViewRow(xcode: xcode, selected: selectedXcodeID == xcode.id, appState: appState)
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8193,6 +8193,7 @@
|
|||
}
|
||||
},
|
||||
"Info" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -8299,6 +8300,7 @@
|
|||
}
|
||||
},
|
||||
"InfoDescription" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -16125,6 +16127,7 @@
|
|||
}
|
||||
},
|
||||
"Search" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -16237,6 +16240,7 @@
|
|||
}
|
||||
},
|
||||
"SearchDescription" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
|
|
|
|||
Loading…
Reference in a new issue