diff --git a/Sources/ExtensionKit/Combine/Publisher.swift b/Sources/ExtensionKit/Combine/Publisher.swift index 3e4d2a6..4a3e76d 100644 --- a/Sources/ExtensionKit/Combine/Publisher.swift +++ b/Sources/ExtensionKit/Combine/Publisher.swift @@ -1,5 +1,6 @@ import Combine import Foundation +import UIKit public extension Publisher where Failure == Never { @@ -22,4 +23,21 @@ public extension Publisher where Failure == Never { result(.success(output)) }) } + +} + +extension Publisher where Failure == Never { + + /// Subscribe to keyboard notifications and receive `Notification.KeyboardInfo` on updates + static var keyboardInfo: AnyPublisher { + let willShow = NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification) + .map { $0.keyboardInfo } + + let willHide = NotificationCenter.default.publisher(for: UIApplication.keyboardWillHideNotification) + .map { _ in Notification.KeyboardInfo() } + + return Publishers.MergeMany(willShow, willHide) + .eraseToAnyPublisher() + } + } diff --git a/Sources/ExtensionKit/Foundation/Notification.swift b/Sources/ExtensionKit/Foundation/Notification.swift new file mode 100644 index 0000000..cf4576b --- /dev/null +++ b/Sources/ExtensionKit/Foundation/Notification.swift @@ -0,0 +1,36 @@ +import Foundation +import UIKit + +extension Notification { + + /// Struct modeling keyboard updates + public struct KeyboardInfo { + /// Keyboard height + public var height: CGFloat = 0 + /// Keyboard animation curve + public var animationCurve: UIView.AnimationCurve = UIView.AnimationCurve.easeInOut + /// Keyboard animation duration + public var animationDuration: TimeInterval = 0.0 + /// Is the keyboard visible + public var isVisible: Bool { + height != 0 + } + } + + /// Get keyboard info updates + var keyboardInfo: KeyboardInfo { + var info = KeyboardInfo() + if let value = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { + info.height = value.height + } + if let value = userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber { + if let curve = UIView.AnimationCurve(rawValue: value.intValue) { + info.animationCurve = curve + } + } + if let value = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber { + info.animationDuration = value.doubleValue + } + return info + } +} diff --git a/Sources/ExtensionKit/SwiftUI/KeyboardStateModifier.swift b/Sources/ExtensionKit/SwiftUI/KeyboardStateModifier.swift index eab4ab6..9550a6b 100644 --- a/Sources/ExtensionKit/SwiftUI/KeyboardStateModifier.swift +++ b/Sources/ExtensionKit/SwiftUI/KeyboardStateModifier.swift @@ -1,26 +1,20 @@ +import Combine import SwiftUI /// Get keyboard status updates struct KeyboardStateModifier: ViewModifier { - - @Binding var isVisible: Bool - - init(_ isVisible: Binding) { - _isVisible = isVisible - } - - private let keyboardWillAppear = NotificationCenter.default - .publisher(for: UIResponder.keyboardWillShowNotification) - .map { _ -> Bool in true } - - private let keyboardWillHide = NotificationCenter.default - .publisher(for: UIResponder.keyboardWillHideNotification) - .map { _ -> Bool in false } - - func body(content: Content) -> some View { - content - .onReceive(keyboardWillAppear.merge(with: keyboardWillHide)) { - self.isVisible = $0 - } - } + + @Binding var keyboardInfo: Notification.KeyboardInfo + + init(_ keyboardInfo: Binding) { + _keyboardInfo = keyboardInfo + } + + func body(content: Content) -> some View { + content + .onReceive( + AnyPublisher.keyboardInfo, + assignTo: $keyboardInfo + ) + } } diff --git a/Sources/ExtensionKit/SwiftUI/View.swift b/Sources/ExtensionKit/SwiftUI/View.swift index ec8bfc0..3a56a32 100644 --- a/Sources/ExtensionKit/SwiftUI/View.swift +++ b/Sources/ExtensionKit/SwiftUI/View.swift @@ -341,8 +341,8 @@ public extension View { /// Receive keyboard status updates /// - Parameter isVisible: is keyboard visible /// - Returns: View - func keyboardState(isVisible: Binding) -> some View { - self.modifier(KeyboardStateModifier(isVisible)) + func keyboardState(info: Binding) -> some View { + self.modifier(KeyboardStateModifier(info)) } /// Debug print