Swiftgram/submodules/Display/Display/KeyboardManager.swift
Peter 8f5a4f7dc1 Add 'submodules/Display/' from commit '7bd11013ea936e3d49d937550d599f5816d32560'
git-subtree-dir: submodules/Display
git-subtree-mainline: 9bc996374ffdad37aef175427db72731c9551dcf
git-subtree-split: 7bd11013ea936e3d49d937550d599f5816d32560
2019-06-11 18:44:37 +01:00

128 lines
5.2 KiB
Swift

import Foundation
import UIKit
import AsyncDisplayKit
#if BUCK
import DisplayPrivate
#endif
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 previousPositionAnimationMirrorSource: CATracingLayer?
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
}
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
}
if let tracingLayer = firstResponderView.layer as? CATracingLayer, firstResponderDisableAutomaticKeyboardHandling.isEmpty {
if let previousPositionAnimationMirrorSource = self.previousPositionAnimationMirrorSource, previousPositionAnimationMirrorSource !== tracingLayer {
previousPositionAnimationMirrorSource.setPositionAnimationMirrorTarget(nil)
}
tracingLayer.setPositionAnimationMirrorTarget(keyboardWindow.layer)
self.previousPositionAnimationMirrorSource = tracingLayer
} else if let previousPositionAnimationMirrorSource = self.previousPositionAnimationMirrorSource {
previousPositionAnimationMirrorSource.setPositionAnimationMirrorTarget(nil)
self.previousPositionAnimationMirrorSource = nil
}
} else {
keyboardWindow.layer.sublayerTransform = CATransform3DIdentity
if let previousPositionAnimationMirrorSource = self.previousPositionAnimationMirrorSource {
previousPositionAnimationMirrorSource.setPositionAnimationMirrorTarget(nil)
self.previousPositionAnimationMirrorSource = nil
}
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
}
}