From 50b48b78234b218f401cd75ea68d140f0b6fbbe8 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 26 Jul 2024 15:05:20 +0200 Subject: [PATCH 1/3] Various fixes --- submodules/BrowserUI/BUILD | 1 + .../Sources/BrowserAddressListComponent.swift | 247 +++++++++++------- 2 files changed, 160 insertions(+), 88 deletions(-) diff --git a/submodules/BrowserUI/BUILD b/submodules/BrowserUI/BUILD index f03e31beb4..b49526f0c2 100644 --- a/submodules/BrowserUI/BUILD +++ b/submodules/BrowserUI/BUILD @@ -47,6 +47,7 @@ swift_library( "//submodules/SearchUI", "//submodules/SearchBarNode", "//submodules/TelegramUI/Components/SaveProgressScreen", + "//submodules/TelegramUI/Components/ListActionItemComponent", ], visibility = [ "//visibility:public", diff --git a/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift b/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift index fadb799c85..b07f068e49 100644 --- a/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserAddressListComponent.swift @@ -10,6 +10,7 @@ import AccountContext import TelegramPresentationData import ContextUI import UndoUI +import ListActionItemComponent final class BrowserAddressListComponent: Component { let context: AccountContext @@ -69,6 +70,7 @@ final class BrowserAddressListComponent: Component { var insets: UIEdgeInsets var itemHeight: CGFloat var itemCount: Int + var hasMore: Bool var totalHeight: CGFloat @@ -76,14 +78,21 @@ final class BrowserAddressListComponent: Component { id: Int, insets: UIEdgeInsets, itemHeight: CGFloat, - itemCount: Int + itemCount: Int, + hasMore: Bool ) { self.id = id self.insets = insets self.itemHeight = itemHeight self.itemCount = itemCount + self.hasMore = hasMore - self.totalHeight = insets.top + itemHeight * CGFloat(itemCount) + insets.bottom + var totalHeight = insets.top + itemHeight * CGFloat(itemCount) + insets.bottom + if hasMore { + totalHeight -= itemHeight + totalHeight += 44.0 + } + self.totalHeight = totalHeight } } @@ -123,6 +132,7 @@ final class BrowserAddressListComponent: Component { final class View: UIView, UIScrollViewDelegate { struct State { let recent: [TelegramMediaWebpage] + let isRecentExpanded: Bool let bookmarks: [Message] } @@ -145,6 +155,7 @@ final class BrowserAddressListComponent: Component { private var stateDisposable: Disposable? private var stateValue: State? + private let isRecentExpanded = ValuePromise(false) override init(frame: CGRect) { super.init(frame: frame) @@ -274,16 +285,28 @@ final class BrowserAddressListComponent: Component { } for i in 0 ..< section.itemCount { - let itemFrame = CGRect(origin: CGPoint(x: sideInset, y: sectionOffset + section.insets.top + CGFloat(i) * section.itemHeight), size: CGSize(width: itemLayout.containerSize.width, height: section.itemHeight)) + var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: sectionOffset + section.insets.top + CGFloat(i) * section.itemHeight), size: CGSize(width: itemLayout.containerSize.width, height: section.itemHeight)) if !visibleBounds.intersects(itemFrame) { continue } - + + var isMore = false + if section.hasMore && i == 3 { + isMore = true + itemFrame.size.height = 44.0 + } + var id: String = "" if section.id == 0 { id = "recent_\(state.recent[i].content.url ?? "")" + if isMore { + id = "recent_more" + } } else if section.id == 1 { id = "bookmark_\(state.bookmarks[i].id.id)" + if isMore { + id = "bookmark_more" + } } let itemId = AnyHashable(id) @@ -301,99 +324,137 @@ final class BrowserAddressListComponent: Component { self.visibleItems[itemId] = visibleItem } - var webPage: TelegramMediaWebpage? - var itemMessage: Message? - - if section.id == 0 { - webPage = state.recent[i] - } else if section.id == 1 { - let message = state.bookmarks[i] - if let primaryUrl = getPrimaryUrl(message: message) { - if let media = message.media.first(where: { $0 is TelegramMediaWebpage }) as? TelegramMediaWebpage { - webPage = media + if isMore { + let _ = visibleItem.update( + transition: itemTransition, + component: AnyComponent( + ListActionItemComponent( + theme: component.theme, + title: AnyComponent(Text( + text: component.strings.WebBrowser_AddressBar_ShowMore, + font: Font.regular(17.0), + color: component.theme.list.itemAccentColor + )), + leftIcon: .custom( + AnyComponentWithIdentity( + id: "icon", + component: AnyComponent(Image( + image: PresentationResourcesItemList.downArrowImage(component.theme), + size: CGSize(width: 30.0, height: 30.0) + )) + ), + false + ), + accessory: nil, + action: { [weak self] _ in + self?.isRecentExpanded.set(true) + }, + highlighting: .default, + updateIsHighlighted: { view, _ in + + }) + ), + environment: {}, + containerSize: itemFrame.size + ) + } else { + var webPage: TelegramMediaWebpage? + var itemMessage: Message? + + if section.id == 0 { + webPage = state.recent[i] + } else if section.id == 1 { + let message = state.bookmarks[i] + if let primaryUrl = getPrimaryUrl(message: message) { + if let media = message.media.first(where: { $0 is TelegramMediaWebpage }) as? TelegramMediaWebpage { + webPage = media + } else { + webPage = TelegramMediaWebpage(webpageId: MediaId(namespace: 0, id: 0), content: .Loaded(TelegramMediaWebpageLoadedContent(url: primaryUrl, displayUrl: "", hash: 0, type: nil, websiteName: "", title: message.text, text: "", embedUrl: nil, embedType: nil, embedSize: nil, duration: nil, author: nil, isMediaLargeByDefault: nil, image: nil, file: nil, story: nil, attributes: [], instantPage: nil))) + } + itemMessage = message } else { - webPage = TelegramMediaWebpage(webpageId: MediaId(namespace: 0, id: 0), content: .Loaded(TelegramMediaWebpageLoadedContent(url: primaryUrl, displayUrl: "", hash: 0, type: nil, websiteName: "", title: message.text, text: "", embedUrl: nil, embedType: nil, embedSize: nil, duration: nil, author: nil, isMediaLargeByDefault: nil, image: nil, file: nil, story: nil, attributes: [], instantPage: nil))) + continue } - itemMessage = message - } else { - continue } - } - let performAction = component.performAction - let _ = visibleItem.update( - transition: itemTransition, - component: AnyComponent( - BrowserAddressListItemComponent( - context: component.context, - theme: component.theme, - webPage: webPage!, - message: itemMessage, - hasNext: true, - insets: component.insets, - action: { - if let url = webPage?.content.url { - performAction.invoke(.navigateTo(url)) - } - }, - contextAction: { [weak self] webPage, message, sourceView, gesture in - guard let self, let component = self.component, let url = webPage.content.url else { - return - } - - let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } - - var itemList: [ContextMenuItem] = [] - itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_CopyLink, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - UIPasteboard.general.string = url - if let self, let component = self.component { - component.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false })) + let performAction = component.performAction + let _ = visibleItem.update( + transition: itemTransition, + component: AnyComponent( + BrowserAddressListItemComponent( + context: component.context, + theme: component.theme, + webPage: webPage!, + message: itemMessage, + hasNext: true, + insets: component.insets, + action: { + if let url = webPage?.content.url { + performAction.invoke(.navigateTo(url)) } - }))) - - if let message { - itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_DeleteBookmark, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) + }, + contextAction: { [weak self] webPage, message, sourceView, gesture in + guard let self, let component = self.component, let url = webPage.content.url else { + return + } + + let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } + + var itemList: [ContextMenuItem] = [] + itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_CopyLink, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in - f(.dismissWithoutContent) - + f(.default) + + UIPasteboard.general.string = url if let self, let component = self.component { - let _ = component.context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).startStandalone() + component.presentInGlobalOverlay(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false })) } }))) - } else { - itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_RemoveRecent, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) - }, action: { [weak self] _, f in - f(.dismissWithoutContent) - - if let self, let component = self.component, let url = webPage.content.url { - let _ = removeRecentlyVisitedLink(engine: component.context.engine, url: url).startStandalone() - } - }))) - } - - let items = ContextController.Items(content: .list(itemList)) - let controller = ContextController( - presentationData: presentationData, - source: .extracted(BrowserAddressListContextExtractedContentSource(contentView: sourceView)), - items: .single(items), - recognizer: nil, - gesture: gesture - ) - component.presentInGlobalOverlay(controller) - }) - ), - environment: {}, - containerSize: itemFrame.size - ) + + if let message { + itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_DeleteBookmark, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) + }, action: { [weak self] _, f in + f(.dismissWithoutContent) + + if let self, let component = self.component { + let _ = component.context.engine.messages.deleteMessagesInteractively(messageIds: [message.id], type: .forEveryone).startStandalone() + } + }))) + } else { + itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.WebBrowser_RemoveRecent, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) + }, action: { [weak self] _, f in + f(.dismissWithoutContent) + + if let self, let component = self.component, let url = webPage.content.url { + let _ = removeRecentlyVisitedLink(engine: component.context.engine, url: url).startStandalone() + } + }))) + } + + let items = ContextController.Items(content: .list(itemList)) + let controller = ContextController( + presentationData: presentationData, + source: .extracted(BrowserAddressListContextExtractedContentSource(contentView: sourceView)), + items: .single(items), + recognizer: nil, + gesture: gesture + ) + component.presentInGlobalOverlay(controller) + }) + ), + environment: {}, + containerSize: itemFrame.size + ) + } if let itemView = visibleItem.view { if itemView.superview == nil { self.itemContainerView.addSubview(itemView) + if !transition.animation.isImmediate { + transition.animateAlpha(view: itemView, from: 0.0, to: 1.0) + } } itemTransition.setFrame(view: itemView, frame: itemFrame) } @@ -447,8 +508,9 @@ final class BrowserAddressListComponent: Component { if self.component == nil { self.stateDisposable = combineLatest(queue: Queue.mainQueue(), recentlyVisitedLinks(engine: component.context.engine), + self.isRecentExpanded.get(), component.context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: component.context.account.peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil, tag: .tag(.webPage)) - ).start(next: { [weak self] recent, view in + ).start(next: { [weak self] recent, isRecentExpanded, view in guard let self else { return } @@ -461,6 +523,7 @@ final class BrowserAddressListComponent: Component { let isFirstTime = self.stateValue == nil self.stateValue = State( recent: recent, + isRecentExpanded: isRecentExpanded, bookmarks: bookmarks ) self.state?.updated(transition: isFirstTime ? .immediate : .easeInOut(duration: 0.25)) @@ -510,11 +573,18 @@ final class BrowserAddressListComponent: Component { var sections: [ItemLayout.Section] = [] if let state = self.stateValue { if !state.recent.isEmpty { + var recentCount = state.recent.count + var hasMore = false + if recentCount > 4 && !state.isRecentExpanded { + recentCount = 4 + hasMore = true + } sections.append(ItemLayout.Section( id: 0, insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 0.0, right: 0.0), itemHeight: addressItemSize.height, - itemCount: state.recent.count + itemCount: recentCount, + hasMore: hasMore )) } if !state.bookmarks.isEmpty { @@ -522,7 +592,8 @@ final class BrowserAddressListComponent: Component { id: 1, insets: UIEdgeInsets(top: 28.0, left: 0.0, bottom: 0.0, right: 0.0), itemHeight: addressItemSize.height, - itemCount: state.bookmarks.count + itemCount: state.bookmarks.count, + hasMore: false )) } } From 7f29c3e95c385d9e7ebea067f6f0b5ef67d5f8c3 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 26 Jul 2024 16:10:03 +0200 Subject: [PATCH 2/3] Various fixes --- .../BrowserUI/Sources/BrowserWebContent.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/submodules/BrowserUI/Sources/BrowserWebContent.swift b/submodules/BrowserUI/Sources/BrowserWebContent.swift index acf2633086..ac1e939f04 100644 --- a/submodules/BrowserUI/Sources/BrowserWebContent.swift +++ b/submodules/BrowserUI/Sources/BrowserWebContent.swift @@ -239,6 +239,13 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self.webView.isInspectable = true } self.addSubview(self.webView) + + self.webView.interactiveTransitionGestureRecognizerTest = { [weak self] point -> Bool in + if let self, self.webView.canGoBack { + return true + } + return point.x > 44.0 + } } required init?(coder: NSCoder) { @@ -1204,3 +1211,14 @@ final class BrowserSearchOptions: UITextSearchOptions { return .caseInsensitive } } + +private func findScrollView(view: UIView?) -> UIScrollView? { + if let view = view { + if let view = view as? UIScrollView { + return view + } + return findScrollView(view: view.superview) + } else { + return nil + } +} From 8e219193d0cd6b681433e153503b6249b09fd35d Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 26 Jul 2024 17:29:12 +0200 Subject: [PATCH 3/3] Various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 4 +- .../BrowserUI/Sources/BrowserScreen.swift | 26 +++- .../BrowserUI/Sources/BrowserWebContent.swift | 139 +++++++++++++++++- .../Navigation/NavigationModalContainer.swift | 1 + .../Sources/MediaEditorScreen.swift | 6 +- .../Sources/VideoMessageCameraScreen.swift | 42 +++--- .../WebUI/Sources/WebAppController.swift | 11 +- 7 files changed, 191 insertions(+), 38 deletions(-) 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() {