summaryrefslogtreecommitdiff
path: root/Hutch/App/RootView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Hutch/App/RootView.swift')
-rw-r--r--Hutch/App/RootView.swift71
1 files changed, 71 insertions, 0 deletions
diff --git a/Hutch/App/RootView.swift b/Hutch/App/RootView.swift
index c210d9d..80532a0 100644
--- a/Hutch/App/RootView.swift
+++ b/Hutch/App/RootView.swift
@@ -113,6 +113,11 @@ struct RootView: View {
Label("More", systemImage: "ellipsis.circle")
}
}
+ .modifier(SidebarAdaptableTabStyle())
+ .modifier(TabKeyboardShortcuts(selectedTab: Binding(
+ get: { appState.selectedTab },
+ set: { appState.selectedTab = $0 }
+ )))
.overlay {
if isResolvingDeepLink {
ZStack {
@@ -178,6 +183,29 @@ struct RootView: View {
case .ticket(let owner, let tracker, let ticketId):
resolveTicketLink(owner: owner, tracker: tracker, ticketId: ticketId)
+
+ case .buildsTab:
+ buildsPath = NavigationPath()
+ appState.selectedTab = .builds
+
+ case .repositoriesTab:
+ repoPath = NavigationPath()
+ appState.selectedTab = .repositories
+
+ case .trackersTab:
+ ticketsPath = NavigationPath()
+ appState.selectedTab = .tickets
+
+ case .systemStatus:
+ appState.navigateToSystemStatus()
+
+ case .lookup:
+ morePath = NavigationPath()
+ appState.selectedTab = .more
+ Task {
+ await settleNavigationTransition()
+ morePath.append(MoreRoute.lookup)
+ }
}
}
@@ -336,3 +364,46 @@ struct TicketDeepLinkTarget: Hashable {
let trackerRid: String
let ticketId: Int
}
+
+// MARK: - Keyboard Shortcuts for iPad + Hardware Keyboard
+
+/// Adds Cmd+1 through Cmd+5 keyboard shortcuts for tab switching on iPad.
+private struct TabKeyboardShortcuts: ViewModifier {
+ @Binding var selectedTab: AppState.Tab
+
+ private static let tabMap: [String: AppState.Tab] = [
+ "1": .home,
+ "2": .repositories,
+ "3": .tickets,
+ "4": .builds,
+ "5": .more,
+ ]
+
+ func body(content: Content) -> some View {
+ content
+ .onKeyPress(characters: .decimalDigits, phases: .down) { press in
+ guard press.modifiers == .command else { return .ignored }
+ let key = String(press.characters)
+ if let tab = Self.tabMap[key] {
+ selectedTab = tab
+ return .handled
+ }
+ return .ignored
+ }
+ }
+}
+
+// MARK: - iPad Sidebar Adaptable
+
+/// Applies `.tabViewStyle(.sidebarAdaptable)` on iOS 18+ so the tab bar
+/// becomes a full sidebar on iPad, while falling back to the standard tab
+/// bar on earlier releases.
+private struct SidebarAdaptableTabStyle: ViewModifier {
+ func body(content: Content) -> some View {
+ if #available(iOS 18.0, *) {
+ content.tabViewStyle(.sidebarAdaptable)
+ } else {
+ content
+ }
+ }
+}