diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index b1fc7dab20..e8e14d9434 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -262,7 +262,7 @@ public final class WebAppController: ViewController, AttachmentContainable { } func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { - Queue.mainQueue().after(0.65, { + Queue.mainQueue().after(1.0, { let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .linear) transition.updateAlpha(layer: webView.layer, alpha: 1.0) if let placeholderNode = self.placeholderNode { @@ -283,9 +283,14 @@ public final class WebAppController: ViewController, AttachmentContainable { decisionHandler(.prompt) } + private var targetContentOffset: CGPoint? func scrollViewDidScroll(_ scrollView: UIScrollView) { let contentOffset = scrollView.contentOffset.y self.controller?.navigationBar?.updateBackgroundAlpha(min(30.0, contentOffset) / 30.0, transition: .immediate) + + if let targetContentOffset = self.targetContentOffset, scrollView.contentOffset != targetContentOffset { + scrollView.contentOffset = targetContentOffset + } } private var validLayout: (ContainerViewLayout, CGFloat)? @@ -298,8 +303,15 @@ public final class WebAppController: ViewController, AttachmentContainable { let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: navigationBarHeight), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - navigationBarHeight - layout.intrinsicInsets.bottom - layout.additionalInsets.bottom))) if previousLayout != nil && (previousLayout?.inputHeight ?? 0.0).isZero, let inputHeight = layout.inputHeight, inputHeight > 44.0, transition.isAnimated { + webView.scrollToActiveElement(layout: layout, transition: transition) Queue.mainQueue().after(0.4, { + let contentOffset = webView.scrollView.contentOffset transition.updateFrame(view: webView, frame: frame) + webView.scrollView.contentOffset = contentOffset + self.targetContentOffset = contentOffset + Queue.mainQueue().after(0.1) { + self.targetContentOffset = nil + } }) } else { transition.updateFrame(view: webView, frame: frame) diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index 51192c310a..57c4e7772c 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -4,6 +4,10 @@ import Display import WebKit import SwiftSignalKit +private let findActiveElementY = """ +document.activeElement.getBoundingClientRect().y +""" + private class WeakGameScriptMessageHandler: NSObject, WKScriptMessageHandler { private let f: (WKScriptMessage) -> () @@ -104,6 +108,10 @@ final class WebAppWebView: WKWebView { } contentView?.removeInteraction(dragInteraction) }) + + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) } } @@ -122,6 +130,29 @@ final class WebAppWebView: WKWebView { self.didTouchOnce = true } + func scrollToActiveElement(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + self.evaluateJavaScript(findActiveElementY, completionHandler: { result, _ in + if let result = result as? CGFloat { + Queue.mainQueue().async { + let convertedY = result - self.scrollView.contentOffset.y + let viewportHeight = self.frame.height - (layout.inputHeight ?? 0.0) + if convertedY < 0.0 || convertedY > viewportHeight { + let targetOffset: CGFloat + if convertedY < 0.0 { + targetOffset = max(0.0, result - 36.0) + } else { + targetOffset = max(0.0, result + 60.0 - viewportHeight) + } + transition.animateView({ + self.scrollView.contentOffset = CGPoint(x: 0.0, y: targetOffset) + }) +// transition.updateBounds(layer: self.scrollView.layer, bounds: CGRect(x: 0.0, y: targetOffset, width: self.scrollView.layer.bounds.width, height: self.scrollView.layer.bounds.height)) + } + } + } + }) + } + override var inputAccessoryView: UIView? { return nil }