From 88e5ff8f6b104550786f352d83ee22c3550823dd Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 5 Apr 2025 19:18:54 +0400 Subject: [PATCH 1/2] Various improvements --- .../Sources/OpenInOptions.swift | 7 ++ .../Sources/ChatMessageBubbleItemNode.swift | 5 +- .../Sources/ChatMessageItemCommon.swift | 2 - .../Components/Chat/QuickShareScreen/BUILD | 1 + .../Sources/QuickShareScreen.swift | 34 ++-------- .../Sources/QuickShareToastScreen.swift | 68 ++++++++++++++++--- .../Sources/TopMessageReactions.swift | 6 +- .../Sources/StarsTransferScreen.swift | 1 - .../Chat/ChatControllerPaidMessage.swift | 3 +- .../Chat/ChatControllerQuickShare.swift | 63 +++++++++-------- .../TelegramUI/Sources/ChatController.swift | 4 ++ 11 files changed, 120 insertions(+), 74 deletions(-) diff --git a/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift b/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift index cdc9c00032..b335164ac4 100644 --- a/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift +++ b/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift @@ -235,6 +235,13 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope } } })) + options.append(OpenInOption(identifier: "yangoMaps", application: .other(title: "Yango Maps", identifier: 1665672451, scheme: "yangomaps", store: nil), action: { + if let _ = directions { + return .openUrl(url: "yangomaps://build_route_on_map?lat_to=\(lat)&lon_to=\(lon)") + } else { + return .openUrl(url: "yangomaps://maps.yango.com/?pt=\(lon),\(lat)&z=16") + } + })) options.append(OpenInOption(identifier: "yandexMaps", application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: { if let _ = directions { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 181736089e..e3b1394167 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -264,8 +264,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([ } else if let _ = media as? TelegramMediaExpiredContent { result.removeAll() result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) - needReactions = false - return (result, false, false) + break inner } else if let _ = media as? TelegramMediaPoll { result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) needReactions = false @@ -2735,6 +2734,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI default: centerAligned = true } + } else if let _ = media as? TelegramMediaExpiredContent { + centerAligned = true } break } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageItemCommon/Sources/ChatMessageItemCommon.swift b/submodules/TelegramUI/Components/Chat/ChatMessageItemCommon/Sources/ChatMessageItemCommon.swift index 852f601241..38c0ff482f 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageItemCommon/Sources/ChatMessageItemCommon.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageItemCommon/Sources/ChatMessageItemCommon.swift @@ -299,8 +299,6 @@ public func canAddMessageReactions(message: Message) -> Bool { if story.isMention { return false } - } else if let _ = media as? TelegramMediaExpiredContent { - return false } } return true diff --git a/submodules/TelegramUI/Components/Chat/QuickShareScreen/BUILD b/submodules/TelegramUI/Components/Chat/QuickShareScreen/BUILD index c1ed545428..1822500c99 100644 --- a/submodules/TelegramUI/Components/Chat/QuickShareScreen/BUILD +++ b/submodules/TelegramUI/Components/Chat/QuickShareScreen/BUILD @@ -24,6 +24,7 @@ swift_library( "//submodules/AppBundle", "//submodules/PresentationDataUtils", "//submodules/TelegramUI/Components/LottieComponent", + "//submodules/TelegramUI/Components/PlainButtonComponent", "//submodules/AvatarNode", ], visibility = [ diff --git a/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareScreen.swift b/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareScreen.swift index fb7fa471e6..02024baeb3 100644 --- a/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareScreen.swift +++ b/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareScreen.swift @@ -22,22 +22,19 @@ private final class QuickShareScreenComponent: Component { let context: AccountContext let sourceNode: ASDisplayNode let gesture: ContextGesture - let openPeer: (EnginePeer.Id) -> Void - let completion: (EnginePeer.Id) -> Void + let completion: (EnginePeer, CGRect) -> Void let ready: Promise init( context: AccountContext, sourceNode: ASDisplayNode, gesture: ContextGesture, - openPeer: @escaping (EnginePeer.Id) -> Void, - completion: @escaping (EnginePeer.Id) -> Void, + completion: @escaping (EnginePeer, CGRect) -> Void, ready: Promise ) { self.context = context self.sourceNode = sourceNode self.gesture = gesture - self.openPeer = openPeer self.completion = completion self.ready = ready } @@ -184,24 +181,9 @@ private final class QuickShareScreenComponent: Component { func highlightGestureFinished(performAction: Bool) { if let selectedPeerId = self.selectedPeerId, performAction { - if let component = self.component, let peer = self.peers?.first(where: { $0.id == selectedPeerId }), let view = self.items[selectedPeerId]?.view as? ItemComponent.View, let controller = self.environment?.controller() { - controller.window?.forEachController({ controller in - if let controller = controller as? QuickShareToastScreen { - controller.dismiss() - } - }) - let toastScreen = QuickShareToastScreen( - context: component.context, - peer: peer, - sourceFrame: view.convert(view.bounds, to: nil), - action: { - component.openPeer(peer.id) - } - ) - controller.present(toastScreen, in: .window(.root)) + if let component = self.component, let peer = self.peers?.first(where: { $0.id == selectedPeerId }), let view = self.items[selectedPeerId]?.view as? ItemComponent.View { + component.completion(peer, view.convert(view.bounds, to: nil)) view.avatarNode.isHidden = true - - component.completion(peer.id) } self.animateOut { @@ -296,7 +278,7 @@ private final class QuickShareScreenComponent: Component { if theme.overallDarkAppearance { self.backgroundView.updateColor(color: theme.contextMenu.backgroundColor, forceKeepBlur: true, transition: .immediate) - self.backgroundTintView.backgroundColor = UIColor(white: 1.0, alpha: 0.5) + self.backgroundTintView.backgroundColor = .clear } else { self.backgroundView.updateColor(color: .clear, forceKeepBlur: true, transition: .immediate) self.backgroundTintView.backgroundColor = theme.contextMenu.backgroundColor @@ -411,8 +393,7 @@ public class QuickShareScreen: ViewControllerComponentContainer { context: AccountContext, sourceNode: ASDisplayNode, gesture: ContextGesture, - openPeer: @escaping (EnginePeer.Id) -> Void, - completion: @escaping (EnginePeer.Id) -> Void + completion: @escaping (EnginePeer, CGRect) -> Void ) { let componentReady = Promise() @@ -422,7 +403,6 @@ public class QuickShareScreen: ViewControllerComponentContainer { context: context, sourceNode: sourceNode, gesture: gesture, - openPeer: openPeer, completion: completion, ready: componentReady ), @@ -528,7 +508,7 @@ private final class ItemComponent: Component { private weak var state: EmptyComponentState? override init(frame: CGRect) { - self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 14.0)) + self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 26.0)) self.backgroundNode = NavigationBackgroundNode(color: .clear) super.init(frame: frame) diff --git a/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift b/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift index 04d10d5eb6..8864d62ac6 100644 --- a/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift +++ b/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift @@ -14,18 +14,19 @@ import MultilineTextComponent import AvatarNode import Markdown import LottieComponent +import PlainButtonComponent private final class QuickShareToastScreenComponent: Component { let context: AccountContext let peer: EnginePeer let sourceFrame: CGRect - let action: () -> Void + let action: (QuickShareToastScreen.Action) -> Void init( context: AccountContext, peer: EnginePeer, sourceFrame: CGRect, - action: @escaping () -> Void + action: @escaping (QuickShareToastScreen.Action) -> Void ) { self.context = context self.peer = peer @@ -51,6 +52,7 @@ private final class QuickShareToastScreenComponent: Component { private let animation = ComponentView() private let content = ComponentView() + private let actionButton = ComponentView() private var isUpdating: Bool = false private var component: QuickShareToastScreenComponent? @@ -93,7 +95,8 @@ private final class QuickShareToastScreenComponent: Component { guard let component = self.component else { return } - component.action() + component.action(.info) + self.doneTimer?.invalidate() self.environment?.controller()?.dismiss() } @@ -187,10 +190,10 @@ private final class QuickShareToastScreenComponent: Component { if self.component == nil { self.doneTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false, block: { [weak self] _ in - guard let self else { + guard let self, let controller = self.environment?.controller() as? QuickShareToastScreen else { return } - self.environment?.controller()?.dismiss() + controller.dismissWithCommitAction() }) } @@ -230,6 +233,29 @@ private final class QuickShareToastScreenComponent: Component { tooltipText = environment.strings.Conversation_ForwardTooltip_Chat_One(component.peer.compactDisplayTitle).string } + let actionButtonSize = self.actionButton.update( + transition: .immediate, + component: AnyComponent(PlainButtonComponent( + content: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString(string: "Undo", font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor.withMultiplied(hue: 0.933, saturation: 0.61, brightness: 1.0))) + )), + effectAlignment: .center, + contentInsets: UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0), + action: { [weak self] in + guard let self, let _ = self.component else { + return + } + self.doneTimer?.invalidate() + self.environment?.controller()?.dismiss() + }, + animateAlpha: true, + animateScale: false, + animateContents: false + )), + environment: {}, + containerSize: CGSize(width: availableContentSize.width - contentInsets.left - contentInsets.right - spacing - iconSize.width, height: availableContentSize.height) + ) + let contentSize = self.content.update( transition: transition, component: AnyComponent(MultilineTextComponent(text: .markdown( @@ -279,6 +305,13 @@ private final class QuickShareToastScreenComponent: Component { transition.setFrame(view: contentView, frame: CGRect(origin: CGPoint(x: contentInsets.left + iconSize.width + spacing, y: floor((contentHeight - contentSize.height) * 0.5)), size: contentSize)) } + if let actionButtonView = self.actionButton.view { + if actionButtonView.superview == nil { + self.backgroundView.addSubview(actionButtonView) + } + transition.setFrame(view: actionButtonView, frame: CGRect(origin: CGPoint(x: availableContentSize.width - contentInsets.right - 16.0 - actionButtonSize.width, y: floor((contentHeight - actionButtonSize.height) * 0.5)), size: actionButtonSize)) + } + let size = CGSize(width: availableContentSize.width, height: contentHeight) let backgroundFrame = CGRect(origin: CGPoint(x: containerInsets.left, y: availableSize.height - containerInsets.bottom - size.height), size: size) @@ -301,16 +334,24 @@ private final class QuickShareToastScreenComponent: Component { } } -final class QuickShareToastScreen: ViewControllerComponentContainer { +public final class QuickShareToastScreen: ViewControllerComponentContainer { + public enum Action { + case info + case commit + } + private var processedDidAppear: Bool = false private var processedDidDisappear: Bool = false - init( + private let action: (Action) -> Void + + public init( context: AccountContext, peer: EnginePeer, sourceFrame: CGRect, - action: @escaping () -> Void + action: @escaping (Action) -> Void ) { + self.action = action super.init( context: context, component: QuickShareToastScreenComponent( @@ -334,11 +375,11 @@ final class QuickShareToastScreen: ViewControllerComponentContainer { deinit { } - override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) } - override func viewDidAppear(_ animated: Bool) { + public override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if !self.processedDidAppear { @@ -353,7 +394,12 @@ final class QuickShareToastScreen: ViewControllerComponentContainer { super.dismiss() } - override func dismiss(completion: (() -> Void)? = nil) { + public func dismissWithCommitAction() { + self.action(.commit) + self.dismiss() + } + + public override func dismiss(completion: (() -> Void)? = nil) { if !self.processedDidDisappear { self.processedDidDisappear = true diff --git a/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift b/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift index d817a3b4b7..0f549ecfeb 100644 --- a/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift +++ b/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift @@ -15,9 +15,9 @@ public func peerMessageAllowedReactions(context: AccountContext, message: Messag return .single((.all, false)) } - if message.containsSecretMedia { - return .single((AllowedReactions.set(Set()), false)) - } +// if message.containsSecretMedia { +// return .single((AllowedReactions.set(Set()), false)) +// } return combineLatest( context.engine.data.get( diff --git a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift index d556d7a17c..0dafcc6410 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift @@ -593,7 +593,6 @@ private final class SheetContent: CombinedComponent { return } starsContext.add(balance: StarsAmount(value: stars, nanos: 0)) - let _ = (starsContext.onUpdate |> deliverOnMainQueue).start(next: { completion() diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift index 16d06cfde1..b7a20e66e7 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift @@ -71,7 +71,8 @@ extension ChatControllerImpl { guard let self else { return } - let controller = self.context.sharedContext.makeStarsPurchaseScreen(context: self.context, starsContext: starsContext, options: options, purpose: .sendMessage(peerId: peer.id, requiredStars: totalAmount), completion: { _ in + let controller = self.context.sharedContext.makeStarsPurchaseScreen(context: self.context, starsContext: starsContext, options: options, purpose: .sendMessage(peerId: peer.id, requiredStars: totalAmount), completion: { stars in + starsContext.add(balance: StarsAmount(value: stars, nanos: 0)) let _ = (starsContext.onUpdate |> deliverOnMainQueue).start(next: { completion(false) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerQuickShare.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerQuickShare.swift index 202366bcb3..33ae49c27e 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerQuickShare.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerQuickShare.swift @@ -12,39 +12,48 @@ extension ChatControllerImpl { context: self.context, sourceNode: node, gesture: gesture, - openPeer: { [weak self] peerId in + completion: { [weak self] peer, sourceFrame in guard let self else { return } - let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let self else { - return + self.window?.forEachController({ controller in + if let controller = controller as? QuickShareToastScreen { + controller.dismissWithCommitAction() } - self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil) }) - }, - completion: { [weak self] peerId in - guard let self else { - return - } - let enqueueMessage = StandaloneSendEnqueueMessage( - content: .forward(forward: StandaloneSendEnqueueMessage.Forward( - sourceId: id, - threadId: nil - )), - replyToMessageId: nil + let toastScreen = QuickShareToastScreen( + context: self.context, + peer: peer, + sourceFrame: sourceFrame, + action: { [weak self] action in + guard let self else { + return + } + switch action { + case .info: + self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil) + case .commit: + let enqueueMessage = StandaloneSendEnqueueMessage( + content: .forward(forward: StandaloneSendEnqueueMessage.Forward( + sourceId: id, + threadId: nil + )), + replyToMessageId: nil + ) + let _ = (standaloneSendEnqueueMessages( + accountPeerId: self.context.account.peerId, + postbox: self.context.account.postbox, + network: self.context.account.network, + stateManager: self.context.account.stateManager, + auxiliaryMethods: self.context.account.auxiliaryMethods, + peerId: peer.id, + threadId: nil, + messages: [enqueueMessage] + )).startStandalone() + } + } ) - let _ = (standaloneSendEnqueueMessages( - accountPeerId: self.context.account.peerId, - postbox: self.context.account.postbox, - network: self.context.account.network, - stateManager: self.context.account.stateManager, - auxiliaryMethods: self.context.account.auxiliaryMethods, - peerId: peerId, - threadId: nil, - messages: [enqueueMessage] - )).startStandalone() + self.present(toastScreen, in: .window(.root)) } ) self.presentInGlobalOverlay(controller) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index c989df76e6..9b6582e675 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -134,6 +134,7 @@ import AdsReportScreen import AdUI import ChatMessagePaymentAlertController import TelegramCallsUI +import QuickShareScreen public enum ChatControllerPeekActions { case standard @@ -10740,6 +10741,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let controller = controller as? UndoOverlayController { controller.dismissWithCommitAction() } + if let controller = controller as? QuickShareToastScreen { + controller.dismissWithCommitAction() + } }) self.forEachController({ controller in if let controller = controller as? UndoOverlayController { From 2242097992f2bd9b0ad889554a97d2fc074242ae Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 6 Apr 2025 15:04:29 +0400 Subject: [PATCH 2/2] Various improvements --- Telegram/BUILD | 1 + .../Chat/ChatControllerOpenWebApp.swift | 157 +++++++++--------- .../TelegramUI/Sources/ChatController.swift | 1 - .../WebUI/Sources/WebAppController.swift | 4 +- 4 files changed, 78 insertions(+), 85 deletions(-) diff --git a/Telegram/BUILD b/Telegram/BUILD index 8080e9225a..04eb005bdd 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -1811,6 +1811,7 @@ plist_fragment( ucbrowser dolphin instagram-stories + yangomaps LSRequiresIPhoneOS diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift index 583e2babda..4fd515139d 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift @@ -243,9 +243,6 @@ func openWebAppImpl( return navigationController ?? (context.sharedContext.mainWindow?.viewController as? NavigationController) }) controller.navigationPresentation = .flatModal - if let parentController = parentController as? ChatControllerImpl { - parentController.currentWebAppController = controller - } parentController.push(controller) presentImpl = { [weak controller] c, a in @@ -297,9 +294,6 @@ func openWebAppImpl( return navigationController ?? (context.sharedContext.mainWindow?.viewController as? NavigationController) }) controller.navigationPresentation = .flatModal - if let parentController = parentController as? ChatControllerImpl { - parentController.currentWebAppController = controller - } parentController.push(controller) presentImpl = { [weak controller] c, a in @@ -355,7 +349,7 @@ public extension ChatControllerImpl { self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, botPeer: EnginePeer(peer), chatPeer: EnginePeer(peer), threadId: self.chatLocation.threadId, buttonText: buttonText, url: url, simple: simple, source: source, skipTermsOfService: false, payload: nil) } - static func botRequestSwitchInline(context: AccountContext, controller: ChatControllerImpl?, peerId: EnginePeer.Id, botAddress: String, query: String, chatTypes: [ReplyMarkupButtonRequestPeerType]?, completion: @escaping () -> Void) -> Void { + fileprivate static func botRequestSwitchInline(context: AccountContext, controller: ChatControllerImpl?, peerId: EnginePeer.Id, botAddress: String, query: String, chatTypes: [ReplyMarkupButtonRequestPeerType]?, completion: @escaping () -> Void) -> Void { let activateSwitchInline: (EnginePeer?) -> Void = { selectedPeer in var chatController: ChatControllerImpl? if let current = controller { @@ -429,7 +423,7 @@ public extension ChatControllerImpl { }) } - static func botOpenUrl(context: AccountContext, peerId: EnginePeer.Id, controller: ChatControllerImpl?, url: String, concealed: Bool, forceUpdate: Bool, present: @escaping (ViewController, Any?) -> Void, commit: @escaping () -> Void = {}) { + fileprivate static func botOpenUrl(context: AccountContext, peerId: EnginePeer.Id, controller: ChatControllerImpl?, url: String, concealed: Bool, forceUpdate: Bool, present: @escaping (ViewController, Any?) -> Void, commit: @escaping () -> Void = {}) { if let controller { controller.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) } else { @@ -437,41 +431,52 @@ public extension ChatControllerImpl { present(c, nil) }, openResolved: { result in var navigationController: NavigationController? - if let current = controller?.navigationController as? NavigationController { - navigationController = current - } else if let main = context.sharedContext.mainWindow?.viewController as? NavigationController { + if let main = context.sharedContext.mainWindow?.viewController as? NavigationController { navigationController = main } - context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: forceUpdate, openPeer: { peer, navigation in - if let navigationController { - ChatControllerImpl.botOpenPeer(context: context, peerId: peer.id, navigation: navigation, navigationController: navigationController) - } - commit() - }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: { peerId, invite, call in - }, - present: { c, a in - present(c, a) - }, dismissInput: { - context.sharedContext.mainWindow?.viewController?.view.endEditing(false) - }, contentContext: nil, progress: nil, completion: nil) + if case let .peer(peer, navigation) = result, case let .withBotApp(botApp) = navigation, let botPeer = peer.flatMap(EnginePeer.init), let parentController = navigationController?.viewControllers.last as? ViewController { + self.presentBotApp(context: context, parentController: parentController, botApp: botApp.botApp, botPeer: botPeer, payload: botApp.payload, mode: botApp.mode) + } else { + context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: forceUpdate, openPeer: { peer, navigation in + if let navigationController { + ChatControllerImpl.botOpenPeer(context: context, peerId: peer.id, navigation: navigation, navigationController: navigationController) + } + commit() + }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: { peerId, invite, call in + }, present: { c, a in + present(c, a) + }, dismissInput: { + context.sharedContext.mainWindow?.viewController?.view.endEditing(false) + }, contentContext: nil, progress: nil, completion: nil) + } }) } } func presentBotApp(botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, concealed: Bool = false, commit: @escaping () -> Void = {}) { - guard let peerId = self.chatLocation.peerId else { - return + ChatControllerImpl.presentBotApp(context: self.context, parentController: self, botApp: botApp, botPeer: botPeer, payload: payload, mode: mode, concealed: concealed, commit: commit) + } + + fileprivate static func presentBotApp(context: AccountContext, parentController: ViewController, botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, concealed: Bool = false, commit: @escaping () -> Void = {}) { + let chatController = parentController as? ChatControllerImpl + let peerId: EnginePeer.Id + let threadId = chatController?.chatLocation.threadId + if let chatPeerId = chatController?.chatLocation.peerId { + peerId = chatPeerId + } else { + peerId = botPeer.id } - self.attachmentController?.dismiss(animated: true, completion: nil) + + chatController?.attachmentController?.dismiss(animated: true, completion: nil) + + let updatedPresentationData = chatController?.updatedPresentationData + let presentationData = updatedPresentationData?.0 ?? context.sharedContext.currentPresentationData.with { $0 } if let botApp { - let openBotApp: (Bool, Bool, BotAppSettings?) -> Void = { [weak self] allowWrite, justInstalled, appSettings in - guard let strongSelf = self else { - return - } + let openBotApp: (Bool, Bool, BotAppSettings?) -> Void = { [weak parentController, weak chatController] allowWrite, justInstalled, appSettings in commit() - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { + chatController?.updateChatPresentationInterfaceState(animated: true, interactive: true, { return $0.updatedTitlePanelContext { if !$0.contains(where: { switch $0 { @@ -489,10 +494,10 @@ public extension ChatControllerImpl { } }) - let updateProgress = { [weak self] in + let updateProgress = { [weak chatController] in Queue.mainQueue().async { - if let strongSelf = self { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { + if let chatController { + chatController.updateChatPresentationInterfaceState(animated: true, interactive: true, { return $0.updatedTitlePanelContext { if let index = $0.firstIndex(where: { switch $0 { @@ -514,63 +519,56 @@ public extension ChatControllerImpl { } let botAddress = botPeer.addressName ?? "" - strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), compact: mode == .compact, fullscreen: mode == .fullscreen, allowWrite: allowWrite) + let _ = ((context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(presentationData.theme), compact: mode == .compact, fullscreen: mode == .fullscreen, allowWrite: allowWrite) |> afterDisposed { updateProgress() }) - |> deliverOnMainQueue).startStrict(next: { [weak self] result in - guard let strongSelf = self else { - return - } - let context = strongSelf.context + |> deliverOnMainQueue).startStandalone(next: { [weak parentController, weak chatController] result in let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, botVerified: botPeer.isVerified, botAddress: botPeer.addressName ?? "", appName: botApp.shortName, url: result.url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings), fullSize: result.flags.contains(.fullSize), isFullscreen: result.flags.contains(.fullScreen), appSettings: appSettings) var presentImpl: ((ViewController, Any?) -> Void)? - let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, forceUpdate, commit in - ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in + let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { url, concealed, forceUpdate, commit in + ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: chatController, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in presentImpl?(c, a) }, commit: commit) - }, requestSwitchInline: { [weak self] query, chatTypes, completion in - ChatControllerImpl.botRequestSwitchInline(context: context, controller: self, peerId: peerId, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion) - }, completion: { [weak self] in - self?.chatDisplayNode.historyNode.scrollToEndOfHistory() - }, getNavigationController: { [weak self] in - return self?.effectiveNavigationController ?? context.sharedContext.mainWindow?.viewController as? NavigationController + }, requestSwitchInline: { query, chatTypes, completion in + ChatControllerImpl.botRequestSwitchInline(context: context, controller: chatController, peerId: peerId, botAddress: botAddress, query: query, chatTypes: chatTypes, completion: completion) + }, completion: { + chatController?.chatDisplayNode.historyNode.scrollToEndOfHistory() + }, getNavigationController: { + if let navigationController = parentController?.navigationController as? NavigationController { + return navigationController + } else { + return context.sharedContext.mainWindow?.viewController as? NavigationController + } }) controller.navigationPresentation = .flatModal - strongSelf.currentWebAppController = controller - strongSelf.push(controller) - + parentController?.push(controller) + presentImpl = { [weak controller] c, a in controller?.present(c, in: .window(.root), with: a) } if justInstalled { - let content: UndoOverlayContent = .succeed(text: strongSelf.presentationData.strings.WebApp_ShortcutsSettingsAdded(botPeer.compactDisplayTitle).string, timeout: 5.0, customUndoText: nil) - controller.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: false, position: .top, action: { _ in return false }), in: .current) + let content: UndoOverlayContent = .succeed(text: presentationData.strings.WebApp_ShortcutsSettingsAdded(botPeer.compactDisplayTitle).string, timeout: 5.0, customUndoText: nil) + controller.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, position: .top, action: { _ in return false }), in: .current) } - }, error: { [weak self] error in - if let strongSelf = self { - strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + }, error: { [weak parentController] error in + parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { })]), in: .window(.root)) - } - })) + }) } let _ = combineLatest( queue: Queue.mainQueue(), - ApplicationSpecificNotice.getBotGameNotice(accountManager: self.context.sharedContext.accountManager, peerId: botPeer.id), - self.context.engine.messages.attachMenuBots(), - self.context.engine.messages.getAttachMenuBot(botId: botPeer.id, cached: true) + ApplicationSpecificNotice.getBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id), + context.engine.messages.attachMenuBots(), + context.engine.messages.getAttachMenuBot(botId: botPeer.id, cached: true) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) }, - self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotAppSettings(id: botPeer.id)) - ).startStandalone(next: { [weak self] noticed, attachMenuBots, attachMenuBot, appSettings in - guard let self else { - return - } - + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotAppSettings(id: botPeer.id)) + ).startStandalone(next: { [weak parentController, weak chatController] noticed, attachMenuBots, attachMenuBot, appSettings in var isAttachMenuBotInstalled: Bool? if let _ = attachMenuBot { if let _ = attachMenuBots.first(where: { $0.peer.id == botPeer.id && !$0.flags.contains(.notActivated) }) { @@ -580,43 +578,40 @@ public extension ChatControllerImpl { } } - let context = self.context if !noticed || botApp.flags.contains(.notActivated) || isAttachMenuBotInstalled == false { if let isAttachMenuBotInstalled, let attachMenuBot { if !isAttachMenuBotInstalled { - let controller = webAppTermsAlertController(context: context, updatedPresentationData: self.updatedPresentationData, bot: attachMenuBot, completion: { allowWrite in + let controller = webAppTermsAlertController(context: context, updatedPresentationData: updatedPresentationData, bot: attachMenuBot, completion: { allowWrite in let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone() let _ = (context.engine.messages.addBotToAttachMenu(botId: botPeer.id, allowWrite: allowWrite) - |> deliverOnMainQueue).startStandalone(error: { _ in + |> deliverOnMainQueue).startStandalone(error: { _ in }, completed: { openBotApp(allowWrite, true, appSettings) }) }) - self.present(controller, in: .window(.root)) + parentController?.present(controller, in: .window(.root)) } else { openBotApp(false, false, appSettings) } } else { - let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: self.updatedPresentationData, peer: botPeer, requestWriteAccess: botApp.flags.contains(.notActivated) && botApp.flags.contains(.requiresWriteAccess), completion: { allowWrite in + let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: updatedPresentationData, peer: botPeer, requestWriteAccess: botApp.flags.contains(.notActivated) && botApp.flags.contains(.requiresWriteAccess), completion: { allowWrite in let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone() openBotApp(allowWrite, false, appSettings) - }, showMore: { [weak self] in - if let self { - self.openResolved(result: .peer(botPeer._asPeer(), .info(nil)), sourceMessageId: nil) - } - }, openTerms: { [weak self] in - if let self { - self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: self.presentationData.strings.WebApp_LaunchTermsConfirmation_URL, forceExternal: false, presentationData: self.presentationData, navigationController: self.effectiveNavigationController, dismissInput: {}) + }, showMore: chatController == nil ? nil : { [weak chatController] in + if let chatController { + chatController.openResolved(result: .peer(botPeer._asPeer(), .info(nil)), sourceMessageId: nil) } + }, openTerms: { + context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.WebApp_LaunchTermsConfirmation_URL, forceExternal: false, presentationData: presentationData, navigationController: parentController?.navigationController as? NavigationController, dismissInput: {}) }) - self.present(controller, in: .window(.root)) + parentController?.present(controller, in: .window(.root)) } } else { openBotApp(false, false, appSettings) } }) } else { - self.context.sharedContext.openWebApp(context: self.context, parentController: self, updatedPresentationData: self.updatedPresentationData, botPeer: botPeer, chatPeer: nil, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: false, payload: payload) + context.sharedContext.openWebApp(context: context, parentController: parentController, updatedPresentationData: updatedPresentationData, botPeer: botPeer, chatPeer: nil, threadId: nil, buttonText: "", url: "", simple: true, source: .generic, skipTermsOfService: false, payload: payload) } } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 9b6582e675..f2c780dd82 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -545,7 +545,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let chatLocationContextHolder: Atomic weak var attachmentController: AttachmentController? - weak var currentWebAppController: ViewController? weak var currentImportMessageTooltip: UndoOverlayController? diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index f11573857d..fdc900c25c 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -1062,9 +1062,7 @@ public final class WebAppController: ViewController, AttachmentContainable { case "web_app_open_tg_link": if let json = json, let path = json["path_full"] as? String { let forceRequest = json["force_request"] as? Bool ?? false - controller.openUrl("https://t.me\(path)", false, forceRequest, { [weak controller] in - let _ = controller -// controller?.dismiss() + controller.openUrl("https://t.me\(path)", false, forceRequest, { }) } case "web_app_open_invoice":