mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
162 lines
5.5 KiB
Swift
162 lines
5.5 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import UIKitRuntimeUtils
|
|
|
|
struct KeyboardSurface {
|
|
let host: UIView
|
|
}
|
|
|
|
private func getFirstResponder(_ view: UIView) -> UIView? {
|
|
if view.isFirstResponder {
|
|
return view
|
|
} else {
|
|
for subview in view.subviews {
|
|
if let result = getFirstResponder(subview) {
|
|
return result
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
class KeyboardManager {
|
|
private let host: StatusBarHost
|
|
|
|
private weak var previousFirstResponderView: UIView?
|
|
private var interactiveInputOffset: CGFloat = 0.0
|
|
|
|
var surfaces: [KeyboardSurface] = [] {
|
|
didSet {
|
|
self.updateSurfaces(oldValue)
|
|
}
|
|
}
|
|
|
|
init(host: StatusBarHost) {
|
|
self.host = host
|
|
}
|
|
|
|
func getCurrentKeyboardHeight() -> CGFloat {
|
|
guard let keyboardView = self.host.keyboardView else {
|
|
return 0.0
|
|
}
|
|
if !isViewVisibleInHierarchy(keyboardView) {
|
|
return 0.0
|
|
}
|
|
return keyboardView.bounds.height
|
|
}
|
|
|
|
func updateInteractiveInputOffset(_ offset: CGFloat, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
|
guard let keyboardView = self.host.keyboardView else {
|
|
return
|
|
}
|
|
|
|
self.interactiveInputOffset = offset
|
|
|
|
let previousBounds = keyboardView.bounds
|
|
let updatedBounds = CGRect(origin: CGPoint(x: 0.0, y: -offset), size: previousBounds.size)
|
|
keyboardView.layer.bounds = updatedBounds
|
|
if transition.isAnimated {
|
|
transition.animateOffsetAdditive(layer: keyboardView.layer, offset: previousBounds.minY - updatedBounds.minY, completion: completion)
|
|
} else {
|
|
completion()
|
|
}
|
|
|
|
//transition.updateSublayerTransformOffset(layer: keyboardView.layer, offset: CGPoint(x: 0.0, y: offset))
|
|
}
|
|
|
|
private func updateSurfaces(_ previousSurfaces: [KeyboardSurface]) {
|
|
guard let keyboardWindow = self.host.keyboardWindow else {
|
|
return
|
|
}
|
|
|
|
var firstResponderView: UIView?
|
|
var firstResponderDisableAutomaticKeyboardHandling: UIResponderDisableAutomaticKeyboardHandling = []
|
|
for surface in self.surfaces {
|
|
if let view = getFirstResponder(surface.host) {
|
|
firstResponderView = surface.host
|
|
firstResponderDisableAutomaticKeyboardHandling = view.disableAutomaticKeyboardHandling
|
|
break
|
|
}
|
|
}
|
|
|
|
if let firstResponderView = firstResponderView {
|
|
let containerOrigin = firstResponderView.convert(CGPoint(), to: nil)
|
|
var filteredTranslation = containerOrigin.x
|
|
if firstResponderDisableAutomaticKeyboardHandling.contains(.forward) {
|
|
filteredTranslation = max(0.0, filteredTranslation)
|
|
}
|
|
if firstResponderDisableAutomaticKeyboardHandling.contains(.backward) {
|
|
filteredTranslation = min(0.0, filteredTranslation)
|
|
}
|
|
let horizontalTranslation = CATransform3DMakeTranslation(filteredTranslation, 0.0, 0.0)
|
|
let currentTransform = keyboardWindow.layer.sublayerTransform
|
|
if !CATransform3DEqualToTransform(horizontalTranslation, currentTransform) {
|
|
//print("set to \(CGPoint(x: containerOrigin.x, y: self.interactiveInputOffset))")
|
|
keyboardWindow.layer.sublayerTransform = horizontalTranslation
|
|
}
|
|
} else {
|
|
keyboardWindow.layer.sublayerTransform = CATransform3DIdentity
|
|
if let previousFirstResponderView = previousFirstResponderView {
|
|
if previousFirstResponderView.window == nil {
|
|
keyboardWindow.isHidden = true
|
|
keyboardWindow.layer.cancelAnimationsRecursive(key: "position")
|
|
keyboardWindow.layer.cancelAnimationsRecursive(key: "bounds")
|
|
keyboardWindow.isHidden = false
|
|
}
|
|
}
|
|
}
|
|
|
|
self.previousFirstResponderView = firstResponderView
|
|
}
|
|
}
|
|
|
|
private func endAnimations(view: UIView) {
|
|
view.layer.removeAllAnimations()
|
|
for subview in view.subviews {
|
|
endAnimations(view: subview)
|
|
}
|
|
}
|
|
|
|
func viewTreeContainsFirstResponder(view: UIView) -> Bool {
|
|
if view.isFirstResponder {
|
|
return true
|
|
} else {
|
|
for subview in view.subviews {
|
|
if viewTreeContainsFirstResponder(view: subview) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
final class KeyboardViewManager {
|
|
private let host: StatusBarHost
|
|
|
|
init(host: StatusBarHost) {
|
|
self.host = host
|
|
}
|
|
|
|
func dismissEditingWithoutAnimation(view: UIView) {
|
|
if viewTreeContainsFirstResponder(view: view) {
|
|
view.endEditing(true)
|
|
if let keyboardWindow = self.host.keyboardWindow {
|
|
for view in keyboardWindow.subviews {
|
|
endAnimations(view: view)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func update(leftEdge: CGFloat, transition: ContainedViewLayoutTransition) {
|
|
guard let keyboardWindow = self.host.keyboardWindow else {
|
|
return
|
|
}
|
|
let t = keyboardWindow.layer.sublayerTransform
|
|
let currentOffset = CGPoint(x: t.m41, y: t.m42)
|
|
transition.updateSublayerTransformOffset(layer: keyboardWindow.layer, offset: CGPoint(x: leftEdge, y: currentOffset.y), completion: { _ in
|
|
})
|
|
}
|
|
}
|