diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index f85d7b974b..da0a67d6af 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -12593,9 +12593,7 @@ Sorry for the inconvenience."; "AccessDenied.LocationWeather" = "Telegram needs access to your location so that you can add the weather widget to your stories.\n\nPlease go to Settings > Privacy > Location Services and set Telegram to ON."; -"Story.Editor.TooltipWeatherLimitValue_1" = "**%@** weather stickers"; -"Story.Editor.TooltipWeatherLimitValue_any" = "**%@** weather stickers"; -"Story.Editor.TooltipWeatherLimitText" = "You can't add more than %@ to a story."; +"Story.Editor.TooltipWeatherLimitText" = "You can't add more than one weather sticker to a story."; "WebBrowser.AddressPlaceholder" = "Enter URL"; diff --git a/submodules/BrowserUI/Sources/BrowserScreen.swift b/submodules/BrowserUI/Sources/BrowserScreen.swift index c1d0d9ff8a..2b0df2a489 100644 --- a/submodules/BrowserUI/Sources/BrowserScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserScreen.swift @@ -775,12 +775,18 @@ public class BrowserScreen: ViewController, MinimizableController { self.presentationState = f(self.presentationState) self.requestLayout(transition: transition) } - + func pushContent(_ content: BrowserScreen.Subject, transition: ComponentTransition) { let browserContent: BrowserContent switch content { case let .webPage(url): - browserContent = BrowserWebContent(context: self.context, presentationData: self.presentationData, url: url) + let webContent = BrowserWebContent(context: self.context, presentationData: self.presentationData, url: url) + webContent.cancelInteractiveTransitionGestures = { [weak self] in + if let self, let view = self.controller?.view { + cancelInteractiveTransitionGestures(view: view) + } + } + browserContent = webContent case let .instantPage(webPage, anchor, sourceLocation): let instantPageContent = BrowserInstantPageContent(context: self.context, presentationData: self.presentationData, webPage: webPage, anchor: anchor, url: webPage.content.url ?? "", sourceLocation: sourceLocation) instantPageContent.openPeer = { [weak self] peer in @@ -1582,3 +1588,19 @@ private final class BrowserContentComponent: Component { return view.update(component: self, availableSize: availableSize, transition: transition) } } + +private func cancelInteractiveTransitionGestures(view: UIView) { + if let gestureRecognizers = view.gestureRecognizers { + for gesture in gestureRecognizers { + if let gesture = gesture as? InteractiveTransitionGestureRecognizer { + gesture.cancel() + } else if let scrollView = gesture.view as? UIScrollView, gesture.isEnabled, scrollView.tag == 0x5C4011 { + gesture.isEnabled = false + gesture.isEnabled = true + } + } + } + if let superview = view.superview { + cancelInteractiveTransitionGestures(view: superview) + } +} diff --git a/submodules/BrowserUI/Sources/BrowserWebContent.swift b/submodules/BrowserUI/Sources/BrowserWebContent.swift index ac1e939f04..438236dd96 100644 --- a/submodules/BrowserUI/Sources/BrowserWebContent.swift +++ b/submodules/BrowserUI/Sources/BrowserWebContent.swift @@ -127,6 +127,28 @@ final class WebView: WKWebView { override var safeAreaInsets: UIEdgeInsets { return UIEdgeInsets(top: 0.0, left: 0.0, bottom: self.customBottomInset, right: 0.0) } + + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + var result = super.point(inside: point, with: event) + if !result && point.x > 0.0 && point.y < self.frame.width && point.y > 0.0 && point.y < self.frame.height + 83.0 { + result = true + } + return result + } +} + +private class WeakScriptMessageHandler: NSObject, WKScriptMessageHandler { + private let f: (WKScriptMessage) -> () + + init(_ f: @escaping (WKScriptMessage) -> ()) { + self.f = f + + super.init() + } + + func userContentController(_ controller: WKUserContentController, didReceive scriptMessage: WKScriptMessage) { + self.f(scriptMessage) + } } final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate { @@ -160,6 +182,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU var present: (ViewController, Any?) -> Void = { _, _ in } var presentInGlobalOverlay: (ViewController) -> Void = { _ in } var getNavigationController: () -> NavigationController? = { return nil } + var cancelInteractiveTransitionGestures: () -> Void = {} private var tempFile: TempBoxFile? @@ -185,8 +208,17 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU let contentController = WKUserContentController() let videoScript = WKUserScript(source: videoSource, injectionTime: .atDocumentStart, forMainFrameOnly: false) contentController.addUserScript(videoScript) + let touchScript = WKUserScript(source: setupTouchObservers, injectionTime: .atDocumentStart, forMainFrameOnly: false) + contentController.addUserScript(touchScript) configuration.userContentController = contentController + var handleScriptMessageImpl: ((WKScriptMessage) -> Void)? + let eventProxyScript = WKUserScript(source: eventProxySource, injectionTime: .atDocumentStart, forMainFrameOnly: false) + contentController.addUserScript(eventProxyScript) + contentController.add(WeakScriptMessageHandler { message in + handleScriptMessageImpl?(message) + }, name: "performAction") + self.webView = WebView(frame: CGRect(), configuration: configuration) self.webView.allowsLinkPreview = true @@ -240,11 +272,27 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU } self.addSubview(self.webView) - self.webView.interactiveTransitionGestureRecognizerTest = { [weak self] point -> Bool in + self.webView.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in if let self, self.webView.canGoBack { return true + } else { + return false } - return point.x > 44.0 + } + + self.webView.interactiveTransitionGestureRecognizerTest = { [weak self] point in + if let self { + if let result = self.webView.hitTest(point, with: nil), let scrollView = findScrollView(view: result), scrollView.isDescendant(of: self.webView) { + if scrollView.contentSize.width > scrollView.frame.width, scrollView.contentOffset.x > -scrollView.contentInset.left { + return true + } + } + } + return false + } + + handleScriptMessageImpl = { [weak self] message in + self?.handleScriptMessage(message) } } @@ -263,6 +311,22 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self.faviconDisposable.dispose() } + private func handleScriptMessage(_ message: WKScriptMessage) { + guard let body = message.body as? [String: Any] else { + return + } + guard let eventName = body["eventName"] as? String else { + return + } + + switch eventName { + case "cancellingTouch": + self.cancelInteractiveTransitionGestures() + default: + break + } + } + func updatePresentationData(_ presentationData: PresentationData) { self.presentationData = presentationData if #available(iOS 15.0, *) { @@ -523,7 +587,6 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self.updateState { $0.withUpdatedEstimatedProgress(self.webView.estimatedProgress) } } else if keyPath == "canGoBack" { self.updateState { $0.withUpdatedCanGoBack(self.webView.canGoBack) } - self.webView.disablesInteractiveTransitionGestureRecognizer = self.webView.canGoBack } else if keyPath == "canGoForward" { self.updateState { $0.withUpdatedCanGoForward(self.webView.canGoForward) } } else if keyPath == "hasOnlySecureContent" { @@ -1201,6 +1264,76 @@ function disconnectObserver() { } """ +let setupTouchObservers = +""" +(function() { + function saveOriginalCssProperties(element) { + while (element) { + const computedStyle = window.getComputedStyle(element); + const propertiesToSave = ['transform', 'top', 'left']; + + element._originalProperties = {}; + + for (const property of propertiesToSave) { + element._originalProperties[property] = computedStyle.getPropertyValue(property); + } + + element = element.parentElement; + } + } + + function checkForCssChanges(element) { + while (element) { + if (!element._originalProperties) return false; + const computedStyle = window.getComputedStyle(element); + const modifiedProperties = ['transform', 'top', 'left']; + + for (const property of modifiedProperties) { + if (computedStyle.getPropertyValue(property) !== element._originalProperties[property]) { + return true; + } + } + + element = element.parentElement; + } + + return false; + } + + function clearOriginalCssProperties(element) { + while (element) { + delete element._originalProperties; + element = element.parentElement; + } + } + + let touchedElement = null; + + document.addEventListener('touchstart', function(event) { + touchedElement = event.target; + saveOriginalCssProperties(touchedElement); + }, { passive: true }); + + document.addEventListener('touchmove', function(event) { + if (checkForCssChanges(touchedElement)) { + TelegramWebviewProxy.postEvent("cancellingTouch", {}) + console.log('CSS properties changed during touchmove'); + } + }, { passive: true }); + + document.addEventListener('touchend', function() { + clearOriginalCssProperties(touchedElement); + touchedElement = null; + }, { passive: true }); +})(); +""" + +private let eventProxySource = "var TelegramWebviewProxyProto = function() {}; " + + "TelegramWebviewProxyProto.prototype.postEvent = function(eventName, eventData) { " + + "window.webkit.messageHandlers.performAction.postMessage({'eventName': eventName, 'eventData': eventData}); " + + "}; " + +"var TelegramWebviewProxy = new TelegramWebviewProxyProto();" + @available(iOS 16.0, *) final class BrowserSearchOptions: UITextSearchOptions { override var wordMatchMethod: UITextSearchOptions.WordMatchMethod { diff --git a/submodules/Display/Source/Navigation/NavigationModalContainer.swift b/submodules/Display/Source/Navigation/NavigationModalContainer.swift index 91dc19258f..185ac4432b 100644 --- a/submodules/Display/Source/Navigation/NavigationModalContainer.swift +++ b/submodules/Display/Source/Navigation/NavigationModalContainer.swift @@ -90,6 +90,7 @@ final class NavigationModalContainer: ASDisplayNode, ASScrollViewDelegate, ASGes self.scrollNode.view.delaysContentTouches = false self.scrollNode.view.clipsToBounds = false self.scrollNode.view.delegate = self.wrappedScrollViewDelegate + self.scrollNode.view.tag = 0x5C4011 let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] _ in guard let strongSelf = self, !strongSelf.isDismissed else { diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index d4f897c57e..49f044c0b2 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -4654,7 +4654,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate return } - let maxWeatherCount = 3 + let maxWeatherCount = 1 var currentWeatherCount = 0 self.entitiesView.eachView { entityView in if entityView.entity is DrawingWeatherEntity { @@ -6290,12 +6290,10 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let context = self.context let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let limit: Int32 = 3 - let value = presentationData.strings.Story_Editor_TooltipWeatherLimitValue(limit) let content: UndoOverlayContent = .info( title: nil, - text: presentationData.strings.Story_Editor_TooltipWeatherLimitText(value).string, + text: presentationData.strings.Story_Editor_TooltipWeatherLimitText.string, timeout: nil, customUndoText: nil ) diff --git a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift index 02de03e48c..2676399bd6 100644 --- a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift +++ b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift @@ -645,28 +645,30 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { ) } - let flashButton = flashButton.update( - component: CameraButton( - content: flashContentComponent, - minSize: CGSize(width: 44.0, height: 44.0), - isExclusive: false, - action: { [weak state] in - if let state { - state.toggleFlashMode() - Queue.mainQueue().justDispatch { - flashAction.invoke(Void()) + if !environment.metrics.isTablet { + let flashButton = flashButton.update( + component: CameraButton( + content: flashContentComponent, + minSize: CGSize(width: 44.0, height: 44.0), + isExclusive: false, + action: { [weak state] in + if let state { + state.toggleFlashMode() + Queue.mainQueue().justDispatch { + flashAction.invoke(Void()) + } } } - } - ), - availableSize: availableSize, - transition: context.transition - ) - context.add(flashButton - .position(CGPoint(x: flipButton.size.width + 8.0 + flashButton.size.width / 2.0 + 11.0, y: availableSize.height - flashButton.size.height / 2.0 - 8.0)) - .appear(.default(scale: true, alpha: true)) - .disappear(.default(scale: true, alpha: true)) - ) + ), + availableSize: availableSize, + transition: context.transition + ) + context.add(flashButton + .position(CGPoint(x: flipButton.size.width + 8.0 + flashButton.size.width / 2.0 + 11.0, y: availableSize.height - flashButton.size.height / 2.0 - 8.0)) + .appear(.default(scale: true, alpha: true)) + .disappear(.default(scale: true, alpha: true)) + ) + } } if showViewOnce { diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index b4bba91d9d..1a6292104e 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -413,12 +413,11 @@ public final class WebAppController: ViewController, AttachmentContainable { } func checkBotIdAndUrl(_ url: String) { - //1985737506 - if url.hasPrefix("https://walletbot.me"), let botId = self.controller?.botId.id._internalGetInt64Value(), botId != 1985737506 { - let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: "Bot id mismatch, please report steps to app developer", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { - })]) - self.controller?.present(alertController, in: .window(.root)) - } +// if url.hasPrefix("https://walletbot.me"), let botId = self.controller?.botId.id._internalGetInt64Value(), botId != 1985737506 { +// let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: "Bot id mismatch, please report steps to app developer", actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { +// })]) +// self.controller?.present(alertController, in: .window(.root)) +// } } @objc fileprivate func mainButtonPressed() {