taler-ios

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

commit f116d8a368967aaa5cafb9bd6c04181610d595d6
parent c257a73d6ae87e0326f32399224365d20887230e
Author: Marc Stibane <marc@taler.net>
Date:   Sat, 15 Mar 2025 20:54:51 +0100

remove TabBarHeight hack

Diffstat:
MTalerWallet.xcodeproj/project.pbxproj | 6------
MTalerWallet1/Views/Main/MainView.swift | 14++++----------
DTalerWallet1/Views/ViewModifier/View+TabBar.swift | 120-------------------------------------------------------------------------------
3 files changed, 4 insertions(+), 136 deletions(-)

diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj @@ -266,8 +266,6 @@ 4EB0956E2989CBFE0043A8A1 /* Model+Pending.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0954C2989CBFE0043A8A1 /* Model+Pending.swift */; }; 4EB230882D5E0FEC007CFBC4 /* View+DeviceRotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB230872D5E0FEC007CFBC4 /* View+DeviceRotation.swift */; }; 4EB230892D5E0FEC007CFBC4 /* View+DeviceRotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB230872D5E0FEC007CFBC4 /* View+DeviceRotation.swift */; }; - 4EB2308B2D607617007CFBC4 /* View+TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB2308A2D607617007CFBC4 /* View+TabBar.swift */; }; - 4EB2308C2D607617007CFBC4 /* View+TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB2308A2D607617007CFBC4 /* View+TabBar.swift */; }; 4EB3136129FEE79B007D68BC /* P2PReadyV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB3136029FEE79B007D68BC /* P2PReadyV.swift */; }; 4EB431672A1E55C700C5690E /* ManualWithdrawDone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB431662A1E55C700C5690E /* ManualWithdrawDone.swift */; }; 4EBA563F2A7FD9390084948B /* SuperScriptDigits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA563E2A7FD9390084948B /* SuperScriptDigits.swift */; }; @@ -502,7 +500,6 @@ 4EB0954A2989CBFE0043A8A1 /* LoadingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; }; 4EB0954C2989CBFE0043A8A1 /* Model+Pending.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Model+Pending.swift"; sourceTree = "<group>"; }; 4EB230872D5E0FEC007CFBC4 /* View+DeviceRotation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+DeviceRotation.swift"; sourceTree = "<group>"; }; - 4EB2308A2D607617007CFBC4 /* View+TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+TabBar.swift"; sourceTree = "<group>"; }; 4EB3136029FEE79B007D68BC /* P2PReadyV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = P2PReadyV.swift; sourceTree = "<group>"; }; 4EB431662A1E55C700C5690E /* ManualWithdrawDone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualWithdrawDone.swift; sourceTree = "<group>"; }; 4EBA563E2A7FD9390084948B /* SuperScriptDigits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuperScriptDigits.swift; sourceTree = "<group>"; }; @@ -618,7 +615,6 @@ 4E1A59E02C99C5D700842BBF /* View+Keyboard.swift */, 4E3B4BC62A429F2A00CC88B8 /* View+Notification.swift */, 4E7F85162D63185E00954C30 /* Environment+EdgeInsets.swift */, - 4EB2308A2D607617007CFBC4 /* View+TabBar.swift */, ); path = ViewModifier; sourceTree = "<group>"; @@ -1271,7 +1267,6 @@ 4E3EAE242A990778009F1BE8 /* QRGeneratorView.swift in Sources */, 4E3EAE252A990778009F1BE8 /* WithdrawAcceptDone.swift in Sources */, 4E3EAE262A990778009F1BE8 /* Transaction.swift in Sources */, - 4EB2308B2D607617007CFBC4 /* View+TabBar.swift in Sources */, 4E8EADA82C64744700C6CDC4 /* QRcodesForPayto.swift in Sources */, 4E605DB72AB05E48002FB9A7 /* View+flippedDirection.swift in Sources */, 4E983C2C2ADC416800FA9CC5 /* View+fitsSideBySide.swift in Sources */, @@ -1415,7 +1410,6 @@ 4EEC157329F8242800D46A03 /* QRGeneratorView.swift in Sources */, 4E5A88F72A3B9E5B00072618 /* WithdrawAcceptDone.swift in Sources */, 4EB095222989CBCB0043A8A1 /* Transaction.swift in Sources */, - 4EB2308C2D607617007CFBC4 /* View+TabBar.swift in Sources */, 4E8EADA92C64744700C6CDC4 /* QRcodesForPayto.swift in Sources */, 4E605DB82AB05E48002FB9A7 /* View+flippedDirection.swift in Sources */, 4E983C2D2ADC416800FA9CC5 /* View+fitsSideBySide.swift in Sources */, diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -248,7 +248,6 @@ extension MainView { @State private var shouldReloadBalances = 0 @State private var shouldReloadTransactions = 0 @State private var shouldReloadPending = 0 - @State private var tabBarHeight: CGFloat = 0 // SwiftUI tabBar height @State private var selectedTab: Tab = .balances @State private var showKycAlert: Bool = false @State private var kycURI: URL? @@ -369,15 +368,12 @@ extension MainView { balancesStack.id(viewState.rootViewId) // change rootViewId to trigger popToRootView behaviour .tag(Tab.balances) .tabItem { a11yBalanceTab } - .keepTabViewHeight(in: $tabBarHeight) Color.clear // can't use EmptyView: 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 } @@ -397,7 +393,7 @@ extension MainView { let delay: UInt = 0 // no delay for release builds #endif - /// our custom tabBar with the Actions button in the middle + // custom tabBar with the Actions button in the middle let tabBarView = TabBarView(selection: tabSelection(), userAction: $userAction, hidden: $tabBarModel.tabBarHidden) { logger.log("onActionTab") showActionSheet = true @@ -405,12 +401,10 @@ extension MainView { logger.log("onActionDrag: showScanner = true") showScanner = true } - /// custom tabBar is rendered on top of the TabView, and overlaps its tabBar + ZStack(alignment: .bottom) { - tabContent -// .hideTabBar($tabBarModel.tabBarHidden) // OIM? - .environment(\.tabBarHeight, tabBarHeight) - tabBarView + tabContent // incl. the (transparent) SwiftUI tabBar + tabBarView // custom tabBar is rendered on top of the TabView, and overlaps its tabBar .ignoresSafeArea(.keyboard, edges: .bottom) .accessibilityHidden(true) // for a11y we use the original tabBar, not our custom one } // ZStack diff --git a/TalerWallet1/Views/ViewModifier/View+TabBar.swift b/TalerWallet1/Views/ViewModifier/View+TabBar.swift @@ -1,120 +0,0 @@ -// MIT License -// Copyright 2021 alexis https://github.com/alexis-ag/swiftui_classic-tabview_show-hide -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software -// and associated documentation files (the "Software"), to deal in the Software without restriction, -// including without limitation the rights to use, copy, modify, merge, publish, distribute, -// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -/* - SwiftUI has quite poor TabView, it doesn't allow you to - set any icon size - set default colors for system icons and labels - place more complicated views than simple image - resize image for icon just in time - hide the tab bar when you don't need it - Idea: - place Swiftui TabView - hide it's tab bar forever, but use for storing content - show our own custom tab bar -*/ -import Foundation -import SwiftUI - -extension EnvironmentValues { - ///TabView raw height; does not include bottom safe area. - var tabBarHeight: CGFloat { - get { self[TabBarHeightEnvironmentKey.self] } - set { self[TabBarHeightEnvironmentKey.self] = newValue } - } -} - -struct TabBarHeightEnvironmentKey: EnvironmentKey { - static var defaultValue: CGFloat = 0 -} - - - -extension View { - /// Read TabView height from underlying UITabBarController and keep it in property passed by binding. - /// - /// # Usage - /// ``` - /// @State private var tabViewHeight: CGFloat = 0 - /// TabItem().keepTabViewHeight(in: $tabViewHeight) - /// ``` - func keepTabViewHeight( - in storage: Binding<CGFloat>, - includingSeparator tabViewHeightShouldIncludeSeparator: Bool = true - ) -> some View { - background(TabBarAccessor { tabBar in - let onePixel: CGFloat = 1/3 - let separatorHeight: CGFloat = tabViewHeightShouldIncludeSeparator ? onePixel : 0 - DispatchQueue.main.async { - // -4 still hides the "visible" SwiftUI tabBar, but leaves it available for A11Y voiceOver - // no longer necessary if we only hide the SwiftUI tabBar when our custom tabBar is hidden - storage.wrappedValue = tabBar.bounds.height + separatorHeight // - 4 - } - }) - } -} - -// Helper bridge to UIViewController to access enclosing UITabBarController -// and thus its UITabBar -struct TabBarAccessor: UIViewControllerRepresentable { - var callback: (UITabBar) -> Void - private let proxyController = ViewController() - - func makeUIViewController(context: UIViewControllerRepresentableContext<TabBarAccessor>) -> - UIViewController { - proxyController.callback = callback - return proxyController - } - - func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TabBarAccessor>) { - } - - typealias UIViewControllerType = UIViewController - - private class ViewController: UIViewController { - var callback: (UITabBar) -> Void = { _ in } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - if let tabBar = self.tabBarController { - self.callback(tabBar.tabBar) - } - } - } -} - -// MARK: - Content -extension View { - func hideTabBar(_ hidden: Binding<Int>) -> some View { - modifier(HideTabBarModifier(tabBarHidden: hidden)) - } -} - -struct HideTabBarModifier: ViewModifier { - @Binding var tabBarHidden: Int - @Environment(\.safeAreaEdgeInsets) private var safeAreaEdgeInsets - @Environment(\.tabBarHeight) private var tabBarHeight - - func body(content: Content) -> some View { - let padding = tabBarHidden == 0 ? 0 - : tabBarHeight - content - .padding(.bottom, -safeAreaEdgeInsets.bottom - padding) - } -}