From 8cf2d0c78c2176e34dfdae0ed6ff4c90bb67bea7 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 31 Mar 2022 12:07:05 +0400 Subject: [PATCH] Web app improvements --- .../Sources/AttachmentContainer.swift | 3 ++ .../ContainedViewLayoutTransition.swift | 10 +++++ submodules/TelegramUI/Sources/OpenUrl.swift | 10 ++--- .../UrlHandling/Sources/UrlHandling.swift | 2 +- submodules/WebUI/BUILD | 1 + .../WebUI/Sources/WebAppController.swift | 43 ++++++++++++++++--- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/submodules/AttachmentUI/Sources/AttachmentContainer.swift b/submodules/AttachmentUI/Sources/AttachmentContainer.swift index bf9228a777..edac0408b5 100644 --- a/submodules/AttachmentUI/Sources/AttachmentContainer.swift +++ b/submodules/AttachmentUI/Sources/AttachmentContainer.swift @@ -296,6 +296,9 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate { listNode.scroller.setContentOffset(CGPoint(), animated: false) } else if let scrollView = scrollView { scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false) + Queue.mainQueue().after(0.01, { + scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false) + }) } self.update(layout: layout, controllers: controllers, coveredByModalTransition: coveredByModalTransition, transition: .animated(duration: 0.3, curve: .easeInOut)) diff --git a/submodules/Display/Source/ContainedViewLayoutTransition.swift b/submodules/Display/Source/ContainedViewLayoutTransition.swift index a330e56e73..d8eff6b30c 100644 --- a/submodules/Display/Source/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Source/ContainedViewLayoutTransition.swift @@ -105,6 +105,16 @@ public extension CGRect { } public extension ContainedViewLayoutTransition { + func animation() -> CABasicAnimation? { + switch self { + case .immediate: + return nil + case let .animated(duration, curve): + let animation = CALayer().makeAnimation(from: 0.0 as NSNumber, to: 1.0 as NSNumber, keyPath: "position", timingFunction: curve.timingFunction, duration: duration, delay: 0.0, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: false, additive: false, completion: { _ in }) + return animation as? CABasicAnimation + } + } + func updateFrame(node: ASDisplayNode, frame: CGRect, force: Bool = false, beginWithCurrentState: Bool = false, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) { if frame.origin.x.isNaN { return diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 7b1fc0164e..d2d2751ab3 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -620,7 +620,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur var post: String? var voiceChat: String? var attach: String? - var setAttach: String? + var startAttach: String? if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { @@ -645,8 +645,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur } } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { voiceChat = "" - } else if queryItem.name == "setattach" { - setAttach = "" + } else if queryItem.name == "startattach" { + startAttach = "" } } } @@ -675,8 +675,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur } } else if let attach = attach { result += "?attach=\(attach)" - } else if let _ = setAttach { - result += "?setattach" + } else if let _ = startAttach { + result += "?startattach" } convertedUrl = result } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 6955a6ad7d..dfc2a83c33 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -204,7 +204,7 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { } } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { return .peerName(peerName, .voiceChat(nil)) - } else if queryItem.name == "setattach" { + } else if queryItem.name == "startattach" { return .setAttach(peerName) } } diff --git a/submodules/WebUI/BUILD b/submodules/WebUI/BUILD index 9e90e0ae6b..87cb0fac7e 100644 --- a/submodules/WebUI/BUILD +++ b/submodules/WebUI/BUILD @@ -22,6 +22,7 @@ swift_library( "//submodules/HexColor:HexColor", "//submodules/PhotoResources:PhotoResources", "//submodules/ShimmerEffect:ShimmerEffect", + "//submodules/LegacyComponents:LegacyComponents", ], visibility = [ "//visibility:public", diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 1b1a24710e..d1a7a758e8 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -15,6 +15,7 @@ import PresentationDataUtils import HexColor import ShimmerEffect import PhotoResources +import LegacyComponents private class WeakGameScriptMessageHandler: NSObject, WKScriptMessageHandler { private let f: (WKScriptMessage) -> () @@ -163,8 +164,8 @@ public final class WebAppController: ViewController, AttachmentContainable { strongSelf.handleScriptMessage(message) } }, name: "performAction") - //-webkit-user-select:none - let selectionString = "var css = '*{-webkit-touch-callout:none;}';" + + let selectionString = "var css = '*{-webkit-touch-callout:none;} :not(input):not(textarea){-webkit-user-select:none;}';" + " var head = document.head || document.getElementsByTagName('head')[0];" + " var style = document.createElement('style'); style.type = 'text/css';" + " style.appendChild(document.createTextNode(css)); head.appendChild(style);" @@ -338,11 +339,39 @@ public final class WebAppController: ViewController, AttachmentContainable { self.controller?.navigationBar?.updateBackgroundAlpha(min(30.0, contentOffset) / 30.0, transition: .immediate) } + private var animationProgress: CGFloat = 0.0 func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { if let webView = self.webView { - transition.updateFrame(view: webView, frame: 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 case .immediate = transition { - webView.layoutSubviews() + let frame = 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 case let .animated(duration, curve) = transition, let springAnimation = transition.animation(), webView.frame != frame { + let initial = webView.frame + + let animation = POPBasicAnimation() + animation.property = (POPAnimatableProperty.property(withName: "frame", initializer: { property in + property?.readBlock = { node, values in + values?.pointee = (node as! Node).animationProgress + } + property?.writeBlock = { node, values in + (node as! Node).animationProgress = values!.pointee + var mappedValue = values!.pointee + switch curve { + case .spring: + mappedValue = springAnimationValueAt(springAnimation, mappedValue) + default: + break + } + let currentFrame = CGRect.interpolator()(initial, frame, mappedValue) as! CGRect + (node as! Node).webView?.frame = currentFrame + } + property?.threshold = 0.01 + }) as! POPAnimatableProperty) + animation.fromValue = 0.0 as NSNumber + animation.toValue = 1.0 as NSNumber + animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) + animation.duration = duration * Double(springAnimation.speed) + self.pop_add(animation, forKey: "frame") + } else { + webView.frame = frame } } @@ -391,11 +420,11 @@ public final class WebAppController: ViewController, AttachmentContainable { } switch eventName { - case "webview_data_send": + case "web_app_data_send": if let eventData = body["eventData"] as? String { self.handleSendData(data: eventData) } - case "webview_close": + case "web_app_close": self.controller?.dismiss() default: break