taler-ios

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

commit 5f928e3589d73d5cb7a2217e3b90b6875d298eb6
parent 7289ab69641337fea1004ac3a77d51f853f70386
Author: Marc Stibane <marc@taler.net>
Date:   Tue, 17 Sep 2024 21:28:25 +0200

KeyboardShowingEnvironment

Diffstat:
MTalerWallet.xcodeproj/project.pbxproj | 6++++++
MTalerWallet1/Controllers/PublicConstants.swift | 2--
MTalerWallet1/Controllers/TalerWallet1App.swift | 1+
ATalerWallet1/Helper/View+Keyboard.swift | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MTalerWallet1/Views/Actions/ActionsSheet.swift | 4----
MTalerWallet1/Views/Banking/ManualWithdraw.swift | 2--
MTalerWallet1/Views/HelperViews/TabBarView.swift | 15+++------------
MTalerWallet1/Views/Main/MainView.swift | 3++-
8 files changed, 90 insertions(+), 21 deletions(-)

diff --git a/TalerWallet.xcodeproj/project.pbxproj b/TalerWallet.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 4E16E12329F3BB99008B9C86 /* CurrencySpecification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E16E12229F3BB99008B9C86 /* CurrencySpecification.swift */; }; 4E18539A2BDAE6D40034F3BA /* LocalConsole in Frameworks */ = {isa = PBXBuildFile; productRef = 4E1853992BDAE6D40034F3BA /* LocalConsole */; }; 4E18539C2BDAE6E50034F3BA /* LocalConsole in Frameworks */ = {isa = PBXBuildFile; productRef = 4E18539B2BDAE6E50034F3BA /* LocalConsole */; }; + 4E1A59E12C99C5D700842BBF /* View+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1A59E02C99C5D700842BBF /* View+Keyboard.swift */; }; + 4E1A59E22C99C5D700842BBF /* View+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1A59E02C99C5D700842BBF /* View+Keyboard.swift */; }; 4E2254972A822B8100E41D29 /* payment_received.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 4E2254952A822B8100E41D29 /* payment_received.m4a */; }; 4E2254982A822B8100E41D29 /* payment_sent.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 4E2254962A822B8100E41D29 /* payment_sent.m4a */; }; 4E2B337D2C8B1D5500186A3E /* ActionsSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2B337C2C8B1D5500186A3E /* ActionsSheet.swift */; }; @@ -355,6 +357,7 @@ 4E0A71132C396D86002485BB /* Error+debugDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+debugDescription.swift"; sourceTree = "<group>"; }; 4E0A71172C3AB099002485BB /* IconBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconBadge.swift; sourceTree = "<group>"; }; 4E16E12229F3BB99008B9C86 /* CurrencySpecification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrencySpecification.swift; sourceTree = "<group>"; }; + 4E1A59E02C99C5D700842BBF /* View+Keyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Keyboard.swift"; sourceTree = "<group>"; }; 4E2254952A822B8100E41D29 /* payment_received.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = payment_received.m4a; sourceTree = "<group>"; }; 4E2254962A822B8100E41D29 /* payment_sent.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = payment_sent.m4a; sourceTree = "<group>"; }; 4E2B337C2C8B1D5500186A3E /* ActionsSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionsSheet.swift; sourceTree = "<group>"; }; @@ -689,6 +692,7 @@ 4EB095082989CB7C0043A8A1 /* View+dismissTop.swift */, 4E605DB62AB05E48002FB9A7 /* View+flippedDirection.swift */, 4E4F60A72C3BBF9F003BB669 /* View+Condition.swift */, + 4E1A59E02C99C5D700842BBF /* View+Keyboard.swift */, 4E3B4BC62A429F2A00CC88B8 /* View+Notification.swift */, 4E605DAE2AADDD13002FB9A7 /* UIScreen+screenSize.swift */, 4E363CBB2A237E0900D7E98C /* URL+id+iban.swift */, @@ -1202,6 +1206,7 @@ 4EC400892AE3E7E800DF72C7 /* AboutView.swift in Sources */, 4E3EAE282A990778009F1BE8 /* BalancesListView.swift in Sources */, 4E3EAE292A990778009F1BE8 /* WalletBackendError.swift in Sources */, + 4E1A59E12C99C5D700842BBF /* View+Keyboard.swift in Sources */, 4E3EAE2A2A990778009F1BE8 /* PendingRowView.swift in Sources */, 4E3EAE2B2A990778009F1BE8 /* LoadingView.swift in Sources */, 4E5D2C8B2C574CB0003F7A49 /* GradientBorder.swift in Sources */, @@ -1334,6 +1339,7 @@ 4EC4008A2AE3E7E800DF72C7 /* AboutView.swift in Sources */, 4EB0955D2989CBFE0043A8A1 /* BalancesListView.swift in Sources */, 4EB095212989CBCB0043A8A1 /* WalletBackendError.swift in Sources */, + 4E1A59E22C99C5D700842BBF /* View+Keyboard.swift in Sources */, 4EB0955E2989CBFE0043A8A1 /* PendingRowView.swift in Sources */, 4EB0956D2989CBFE0043A8A1 /* LoadingView.swift in Sources */, 4E5D2C8C2C574CB0003F7A49 /* GradientBorder.swift in Sources */, diff --git a/TalerWallet1/Controllers/PublicConstants.swift b/TalerWallet1/Controllers/PublicConstants.swift @@ -126,6 +126,4 @@ extension Notification.Name { static let RequestAction = Notification.Name("requestAction") static let DepositAction = Notification.Name("depositAction") static let WithdrawAction = Notification.Name("withdrawAction") - static let HideTabBarView = Notification.Name("hideTabBarView") - static let ShowTabBarView = Notification.Name("showTabBarView") } diff --git a/TalerWallet1/Controllers/TalerWallet1App.swift b/TalerWallet1/Controllers/TalerWallet1App.swift @@ -42,6 +42,7 @@ struct TalerWallet1App: App { .environmentObject(viewState2) // popToRoot .environmentObject(controller) .environmentObject(model) + .addKeyboardVisibilityToEnvironment() /// external events are taler:// or payto:// URLs passed to this app /// we handle them in .onOpenURL in MainView.swift .handlesExternalEvents(preferring: ["*"], allowing: ["*"]) diff --git a/TalerWallet1/Helper/View+Keyboard.swift b/TalerWallet1/Helper/View+Keyboard.swift @@ -0,0 +1,78 @@ +// MIT License +// Copyright Codelaby https://stackoverflow.com/users/3464919/codelaby +// +// 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. +// +import Foundation +import SwiftUI +import Combine + +public extension View { + /// Sets an environment value for keyboardShowing + /// Access this in any child view with + /// @Environment(\.keyboardShowing) var keyboardShowing + func addKeyboardVisibilityToEnvironment() -> some View { + modifier(KeyboardVisibility()) + } +} + +private struct KeyboardShowingEnvironmentKey: EnvironmentKey { + static let defaultValue: Bool = false +} + +extension EnvironmentValues { + var keyboardShowing: Bool { + get { self[KeyboardShowingEnvironmentKey.self] } + set { self[KeyboardShowingEnvironmentKey.self] = newValue } + } +} + +private final class KeyboardMonitor: ObservableObject { + @Published var isKeyboardShowing: Bool = false + private var cancellables = Set<AnyCancellable>() + + init() { + NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification) + .map { _ in true } + .assign(to: \.isKeyboardShowing, on: self) + .store(in: &cancellables) + + NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification) + .map { _ in false } + .assign(to: \.isKeyboardShowing, on: self) + .store(in: &cancellables) + } +} + +private struct KeyboardVisibility: ViewModifier { + @StateObject private var keyboardMonitor = KeyboardMonitor() + + fileprivate func body(content: Content) -> some View { + content + .environment(\.keyboardShowing, keyboardMonitor.isKeyboardShowing) + } +} + +// Usage +// App +// WindowGroup { +// ContentView() +// .addKeyboardVisibilityToEnvironment() +// +// View +// @Environment(\.keyboardShowing) var keyboardShowing +// ... +// Text("Keyboard present: \(keyboardShowing.description)" ) diff --git a/TalerWallet1/Views/Actions/ActionsSheet.swift b/TalerWallet1/Views/Actions/ActionsSheet.swift @@ -88,10 +88,6 @@ struct ActionsSheet: View { amountToTransfer: $amountToTransfer) // does still have the wrong currency .padding(.bottom, 12) } - .task { - print("ActionsSheet.task❓HideTabBarView") - NotificationCenter.default.post(name: .HideTabBarView, object: nil) - } } } // MARK: - diff --git a/TalerWallet1/Views/Banking/ManualWithdraw.swift b/TalerWallet1/Views/Banking/ManualWithdraw.swift @@ -118,8 +118,6 @@ struct ManualWithdraw: View { stack: stack.push()) } symLog.log("❗️ \(navTitle) onAppear") - print("ManualWithdraw.task❓HideTabBarView") - NotificationCenter.default.post(name: .HideTabBarView, object: nil) } .onDisappear { symLog.log("❗️ \(navTitle) onDisappear") diff --git a/TalerWallet1/Views/HelperViews/TabBarView.swift b/TalerWallet1/Views/HelperViews/TabBarView.swift @@ -11,8 +11,9 @@ struct TabBarView: View { @Binding var selection: Tab let onActionTab: () -> Void + @Environment(\.keyboardShowing) var keyboardShowing + @AppStorage("minimalistic") var minimalistic: Bool = false - @State private var isHidden = 0 private func tabBarItem(for tab: Tab) -> some View { VStack(spacing: 0) { @@ -50,7 +51,7 @@ struct TabBarView: View { var body: some View { Group { - if isHidden > 0 { + if keyboardShowing { EmptyView() } else { HStack(alignment: .bottom) { @@ -70,16 +71,6 @@ struct TabBarView: View { .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.bottom)) } } - .onNotification(.HideTabBarView) { - isHidden += 1 - print("❗️HideTabBarView \(isHidden)") - } - .onNotification(.ShowTabBarView) { - if isHidden > 0 { - isHidden -= 1 - print("❗️ShowTabBarView \(isHidden)") - } - } } } // MARK: - diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -395,7 +395,7 @@ extension MainView { // .ignoresSafeArea(.keyboard, edges: .bottom) // .padding(.bottom, 10) tabBarView -// .ignoresSafeArea(.keyboard, edges: .bottom) + .ignoresSafeArea(.keyboard, edges: .bottom) } .frame(maxWidth: .infinity, maxHeight: .infinity) @@ -418,6 +418,7 @@ extension MainView { actions: { openKycButton dismissAlertButton }, message: { Text("Tap the button to go to the KYC website.") }) +// .sheet(isPresented: $showActionSheet, onDismiss: { tabBarView.show() }) { .sheet(isPresented: $showActionSheet) { let content = VStack { ActionsSheet(stack: stack.push(),