taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit f0f7ebb029efc1bf465d02da1e8ee9b229fb9092
parent f7ea0aab29fcf2e1f165ad0c747a6053ca12fb1c
Author: Marc Stibane <marc@taler.net>
Date:   Mon, 17 Feb 2025 08:54:52 +0100

hide SwiftUI TabBar forever

Diffstat:
MTalerWallet1/Views/Main/MainView.swift | 75+++++++++++++++++++++++++++++++++++++++++++--------------------------------
MTalerWallet1/Views/ViewModifier/View+TabBar.swift | 3++-
2 files changed, 45 insertions(+), 33 deletions(-)

diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -247,6 +247,7 @@ extension MainView { @State private var shouldReloadBalances = 0 @State private var shouldReloadTransactions = 0 @State private var shouldReloadPending = 0 + @State private var tabBarHeight: CGFloat = 0 @State private var selectedTab: Tab = .balances @State private var showKycAlert: Bool = false @State private var kycURI: URL? @@ -305,22 +306,8 @@ extension MainView { private static func className() -> String {"\(self)"} private static var name: String { Self.className() } - var body: some View { -#if PRINT_CHANGES - // "@self" marks that the view value itself has changed, and "@identity" marks that the - // identity of the view has changed (that is, that the persistent data associated with - // the view has been recycled for a new instance of the same type) - if #available(iOS 17.1, *) { - // logs at INFO level, “com.apple.SwiftUI” subsystem, category “Changed Body Properties” - let _ = Self._logChanges() - } else { - let _ = Self._printChanges() - } - let delay: UInt = 0 // set to 5 to test delayed currency information -#else - let delay: UInt = 0 // no delay for release builds -#endif - /// Destinations for the 4 actions + private var tabContent: some View { + /// Destinations for the 4 actions let sendDest = SendAmountV(stack: stack.push(Self.name), selectedBalance: $selectedBalance, // if nil shows currency picker amountLastUsed: $amountLastUsed, // currency needs to be updated! @@ -338,7 +325,7 @@ extension MainView { amountToTransfer: $amountToTransfer, exchange: $exchange, // only for withdraw-exchange isSheet: false) - /// each NavigationView needs its own NavLinks + /// each NavigationView needs its own NavLinks let balanceActions = Group { // actionSelected will hide the tabBar NavLink(1, $tabBarModel.actionSelected) { sendDest } NavLink(2, $tabBarModel.actionSelected) { requestDest } @@ -351,7 +338,7 @@ extension MainView { NavLink(7, $tabBarModel.actionSelected) { depositDest } NavLink(8, $tabBarModel.actionSelected) { manualWithdrawDest } } - /// tab titles, and invisible tabItems which are only used for a11y + /// tab titles, and invisible tabItems which are only used for a11y let balancesTitle = Tab.balances.title // "Balances" let actionTitle = Tab.actions.title // "Actions" let settingsTitle = Tab.settings.title // "Settings" @@ -361,7 +348,7 @@ extension MainView { .accessibilityLabel(actionTitle) let a11ySettingsTab = Label(Tab.settings).labelStyle(.titleOnly) .accessibilityLabel(settingsTitle) - /// NavigationViews for Balances & Settings + /// NavigationViews for Balances & Settings let balancesStack = NavigationView { BalancesListView(stack: stack.push(balancesTitle), orientation: $orientation, @@ -376,7 +363,40 @@ extension MainView { navTitle: settingsTitle) .background(settingsActions) }.navigationViewStyle(.stack) - /// our custom tabBar with the Actions button in the middle + /// the tabItems (EMPTYSTRING .titleOnly) could indeed be omitted and the app would work the same - but are needed for accessibilityLabel + return TabView(selection: tabSelection()) { + balancesStack.id(viewState.rootViewId) // change rootViewId to trigger popToRootView behaviour + .tag(Tab.balances) + .tabItem { a11yBalanceTab } + .keepTabViewHeight(in: $tabBarHeight) + Color.clear // can't use EmptyView because then VoiceOver wouldn't have the Actions tab + .tag(Tab.actions) + .tabItem { a11yActionsTab } + .keepTabViewHeight(in: $tabBarHeight) + settingsStack.id(viewState2.rootViewId) // change rootViewId to trigger popToRootView behaviour + .tag(Tab.settings) + .tabItem { a11ySettingsTab } + .keepTabViewHeight(in: $tabBarHeight) + } // TabView + } + + var body: some View { +#if PRINT_CHANGES + // "@self" marks that the view value itself has changed, and "@identity" marks that the + // identity of the view has changed (that is, that the persistent data associated with + // the view has been recycled for a new instance of the same type) + if #available(iOS 17.1, *) { + // logs at INFO level, “com.apple.SwiftUI” subsystem, category “Changed Body Properties” + let _ = Self._logChanges() + } else { + let _ = Self._printChanges() + } + let delay: UInt = 0 // set to 5 to test delayed currency information +#else + let delay: UInt = 0 // no delay for release builds +#endif + + /// our custom tabBar with the Actions button in the middle let tabBarView = TabBarView(selection: tabSelection(), userAction: $userAction, hidden: $tabBarModel.tabBarHidden) { logger.log("onActionTab") showActionSheet = true @@ -386,18 +406,9 @@ extension MainView { } /// custom tabBar is rendered on top of the TabView, and overlaps its tabBar ZStack(alignment: .bottom) { - /// the tabItems (EMPTYSTRING .titleOnly) could indeed be omitted and the app would work the same - but are needed for accessibilityLabel - TabView(selection: tabSelection()) { - balancesStack.id(viewState.rootViewId) // change rootViewId to trigger popToRootView behaviour - .tag(Tab.balances) - .tabItem { a11yBalanceTab } - Color.clear // can't use EmptyView because then VoiceOver wouldn't have the Actions tab - .tag(Tab.actions) - .tabItem { a11yActionsTab } - settingsStack.id(viewState2.rootViewId) // change rootViewId to trigger popToRootView behaviour - .tag(Tab.settings) - .tabItem { a11ySettingsTab } - } // TabView + tabContent + .hideTabBar + .environment(\.tabBarHeight, tabBarHeight) tabBarView .ignoresSafeArea(.keyboard, edges: .bottom) .accessibilityHidden(true) // for a11y we use the original tabBar, not our custom one diff --git a/TalerWallet1/Views/ViewModifier/View+TabBar.swift b/TalerWallet1/Views/ViewModifier/View+TabBar.swift @@ -62,7 +62,8 @@ extension View { let onePixel: CGFloat = 1/3 let separatorHeight: CGFloat = tabViewHeightShouldIncludeSeparator ? onePixel : 0 DispatchQueue.main.async { - storage.wrappedValue = tabBar.bounds.height + separatorHeight + // -4 still hides the "visible" tabBar, but leaves it available for A11Y voiceOver + storage.wrappedValue = tabBar.bounds.height + separatorHeight - 4 } }) }