Skip to content

Commit

Permalink
feature: Use NavigationSplitView rather than TabView for iPad #6 (#279)
Browse files Browse the repository at this point in the history
* feature: changed tabview to navigationsplitview for iPad and MacOS.

* fix: required changes applied

* fix: bug when reopening navigation split view didn't reopen last opened tab
  • Loading branch information
windrunner21 authored Jul 8, 2024
1 parent 81573a8 commit cb560d6
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 19 deletions.
25 changes: 25 additions & 0 deletions Basic-Car-Maintenance/Shared/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,9 @@
}
}
}
},
"Basic Car" : {

},
"Can't Delete Last Vehicle" : {
"localizations" : {
Expand Down Expand Up @@ -4048,6 +4051,17 @@
}
}
},
"Sidebar" : {
"extractionState" : "stale",
"localizations" : {
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "Боковая панель"
}
}
}
},
"Sign Out" : {
"localizations" : {
"be" : {
Expand Down Expand Up @@ -4725,6 +4739,17 @@
}
}
},
"Unexpected error occured." : {
"extractionState" : "stale",
"localizations" : {
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "Произошла ошибка."
}
}
}
},
"Update" : {
"comment" : "Label for submit button on form to update an existing entry",
"localizations" : {
Expand Down
111 changes: 92 additions & 19 deletions Basic-Car-Maintenance/Shared/MainView/Views/MainTabView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,38 @@
import SwiftUI
import SwiftData

enum TabSelection: Int {
enum TabSelection: Int, Identifiable, CaseIterable {
var id: Self { self }

case dashboard = 0
case odometer = 1
case settings = 2
}

extension TabSelection {
var label: LocalizedStringKey {
switch self {
case .dashboard:
return "Dashboard"
case .odometer:
return "Odometer"
case .settings:
return "Settings"
}
}

var image: String {
switch self {
case .dashboard:
return SFSymbol.dashboard
case .odometer:
return SFSymbol.gauge
case .settings:
return SFSymbol.gear
}
}
}

@MainActor
struct MainTabView: View {
@Query var acknowledgedAlerts: [AcknowledgedAlert]
Expand All @@ -24,28 +50,27 @@ struct MainTabView: View {

@AppStorage("lastTabOpen") var selectedTab = TabSelection.dashboard

@State private var selectedTabId: TabSelection.ID? = .dashboard
@State private var columnVisibility = NavigationSplitViewVisibility.automatic

@State var authenticationViewModel = AuthenticationViewModel()
@State var viewModel = MainTabViewModel()

init() {
_selectedTabId = State(initialValue: selectedTab)
}

var body: some View {
TabView(selection: $selectedTab) {
DashboardView(userUID: authenticationViewModel.user?.uid)
.tag(TabSelection.dashboard)
.tabItem {
Label("Dashboard", systemImage: SFSymbol.dashboard)
}

OdometerView(userUID: authenticationViewModel.user?.uid)
.tag(TabSelection.odometer)
.tabItem {
Label("Odometer", systemImage: SFSymbol.gauge)
}

SettingsView(authenticationViewModel: authenticationViewModel)
.tag(TabSelection.settings)
.tabItem {
Label("Settings", systemImage: SFSymbol.gear)
}
Group {
#if os(iOS)
if UIDevice.current.userInterfaceIdiom == .pad {
navigationSplitView()
} else {
tabView()
}
#else
navigationSplitView()
#endif
}
.sheet(item: $viewModel.alert) { alert in
AlertView(alert: alert)
Expand Down Expand Up @@ -73,6 +98,9 @@ struct MainTabView: View {
guard let id = newValue?.id else { return }
saveNewAlert(id)
}
.onChange(of: selectedTabId ?? TabSelection.dashboard) { _, newValue in
selectedTab = newValue
}
}

/// Save newly acknowledged alert to DB
Expand All @@ -81,6 +109,51 @@ struct MainTabView: View {
let acknowledgedAlert = AcknowledgedAlert(id: id)
context.insert(acknowledgedAlert)
}

/// Save screen content for specific selection
/// - Parameter selection: tab selection enum value
@ViewBuilder
private func selectionContent(for selection: TabSelection) -> some View {
switch selection {
case .dashboard:
DashboardView(userUID: authenticationViewModel.user?.uid)
case .odometer:
OdometerView(userUID: authenticationViewModel.user?.uid)
case .settings:
SettingsView(authenticationViewModel: authenticationViewModel)
}
}

/// Primarily used on iPad and Mac devices
/// - Returns: `NavigationSplitView` navigation
@ViewBuilder
private func navigationSplitView() -> some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
List(TabSelection.allCases, selection: $selectedTabId) { tabSelection in
Label(tabSelection.label, systemImage: tabSelection.image)
}
.navigationTitle("Basic Car")
} detail: {
if let tabSelection = selectedTabId {
selectionContent(for: tabSelection)
.tag(tabSelection)
}
}
}

/// Primarily used on iPhone devices
/// - Returns: `TabView` navigation
@ViewBuilder func tabView() -> some View {
TabView(selection: $selectedTab) {
ForEach(TabSelection.allCases) { tabSelection in
selectionContent(for: tabSelection)
.tag(tabSelection)
.tabItem {
Label(tabSelection.label, systemImage: tabSelection.image)
}
}
}
}
}

#Preview {
Expand Down

0 comments on commit cb560d6

Please sign in to comment.