diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 8603bbe2fe..ea6037d58b 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -5136,43 +5136,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private func openPeer(peerId: PeerId, navigation: ChatControllerInteractionNavigateToPeer) { - let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) - |> deliverOnMainQueue).startStandalone(next: { [weak self] peer in - guard let self, let peer = peer else { - return - } - - switch navigation { - case .default: - if let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), keepStack: .always)) - } - case let .chat(_, subject, peekData): - if let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), subject: subject, keepStack: .always, peekData: peekData)) - } - case .info: - if peer.restrictionText(platform: "ios", contentSettings: self.context.currentContentSettings.with { $0 }) == nil { - if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) { - (self.controller?.navigationController as? NavigationController)?.pushViewController(infoController) - } - } - case let .withBotStartPayload(startPayload): - if let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), botStart: startPayload)) - } - case let .withAttachBot(attachBotStart): - if let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), attachBotStart: attachBotStart)) - } - case let .withBotApp(botAppStart): - if let navigationController = self.controller?.navigationController as? NavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), botAppStart: botAppStart)) - } - } - }) + guard let navigationController = self.controller?.navigationController as? NavigationController else { + return + } + PeerInfoScreenImpl.openPeer(context: self.context, peerId: peerId, navigation: navigation, navigationController: navigationController) } - + private func openPeerMention(_ name: String, navigation: ChatControllerInteractionNavigateToPeer = .default) { let disposable: MetaDisposable if let resolvePeerByNameDisposable = self.resolvePeerByNameDisposable { @@ -5311,17 +5280,55 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro guard let self else { return } - + let context = self.context + let peerId = self.peerId let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings), fullSize: true) - let controller = standaloneWebAppController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, params: params, threadId: nil, openUrl: { [weak self] url, concealed, commit in - self?.openUrl(url: url, concealed: concealed, external: false, forceExternal: true, commit: commit) + + var openUrlImpl: ((String, Bool, @escaping () -> Void) -> Void)? + var presentImpl: ((ViewController, Any?) -> Void)? + + let controller = standaloneWebAppController(context: context, updatedPresentationData: self.controller?.updatedPresentationData, params: params, threadId: nil, openUrl: { url, concealed, commit in + openUrlImpl?(url, concealed, commit) }, requestSwitchInline: { _, _, _ in }, getNavigationController: { [weak self] in - return self?.controller?.navigationController as? NavigationController + return (self?.controller?.navigationController as? NavigationController) ?? context.sharedContext.mainWindow?.viewController as? NavigationController }) controller.navigationPresentation = .flatModal self.controller?.push(controller) + openUrlImpl = { [weak self, weak controller] url, concealed, commit in + let _ = openUserGeneratedUrl(context: context, peerId: peerId, url: url, concealed: concealed, present: { [weak self] c in + self?.controller?.present(c, in: .window(.root)) + }, openResolved: { result in + var navigationController: NavigationController? + if let current = self?.controller?.navigationController as? NavigationController { + navigationController = current + } else if let current = controller?.navigationController as? NavigationController { + navigationController = current + } + context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in + if let navigationController { + PeerInfoScreenImpl.openPeer(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 + presentImpl?(c, a) + }, dismissInput: { + context.sharedContext.mainWindow?.viewController?.view.endEditing(false) + }, contentContext: nil, progress: nil, completion: nil) + }) + } + presentImpl = { [weak controller] c, a in + controller?.present(c, in: .window(.root), with: a) + } + if installed { Queue.mainQueue().after(0.3, { let text: String @@ -12372,6 +12379,33 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc self.controllerNode.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode) } + static func openPeer(context: AccountContext, peerId: PeerId, navigation: ChatControllerInteractionNavigateToPeer, navigationController: NavigationController) { + let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> deliverOnMainQueue).startStandalone(next: { peer in + guard let peer else { + return + } + switch navigation { + case .default: + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), keepStack: .always)) + case let .chat(_, subject, peekData): + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: subject, keepStack: .always, peekData: peekData)) + case .info: + if peer.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) == nil { + if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) { + navigationController.pushViewController(infoController) + } + } + case let .withBotStartPayload(startPayload): + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botStart: startPayload)) + case let .withAttachBot(attachBotStart): + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), attachBotStart: attachBotStart)) + case let .withBotApp(botAppStart): + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botAppStart: botAppStart)) + } + }) + } + public static func displayChatNavigationMenu(context: AccountContext, chatNavigationStack: [ChatNavigationStackItem], nextFolderId: Int32?, parentController: ViewController, backButtonView: UIView, navigationController: NavigationController, gesture: ContextGesture) { let peerMap = EngineDataMap( Set(chatNavigationStack.map(\.peerId)).map(TelegramEngine.EngineData.Item.Peer.Peer.init) diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index f79c3a2295..e73b473521 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -178,7 +178,7 @@ final class SharedApplicationContext { let notificationManager: SharedNotificationManager let wakeupManager: SharedWakeupManager let overlayMediaController: ViewController & OverlayMediaController - var minimizedContainer: MinimizedContainer? + var minimizedContainer: [AccountRecordId: MinimizedContainer] = [:] init(sharedContext: SharedAccountContextImpl, notificationManager: SharedNotificationManager, wakeupManager: SharedWakeupManager) { self.sharedContext = sharedContext diff --git a/submodules/TelegramUI/Sources/ApplicationContext.swift b/submodules/TelegramUI/Sources/ApplicationContext.swift index bb989c7cc0..4d6aaf8e47 100644 --- a/submodules/TelegramUI/Sources/ApplicationContext.swift +++ b/submodules/TelegramUI/Sources/ApplicationContext.swift @@ -169,9 +169,12 @@ final class AuthorizedApplicationContext { self.notificationController = NotificationContainerController(context: context) self.rootController = TelegramRootController(context: context) - self.rootController.minimizedContainer = self.sharedApplicationContext.minimizedContainer + self.rootController.minimizedContainer = self.sharedApplicationContext.minimizedContainer[context.account.id] self.rootController.minimizedContainerUpdated = { [weak self] minimizedContainer in - self?.sharedApplicationContext.minimizedContainer = minimizedContainer + guard let self else { + return + } + self.sharedApplicationContext.minimizedContainer[self.context.account.id] = minimizedContainer } self.rootController.globalOverlayControllersUpdated = { [weak self] in diff --git a/submodules/WebUI/BUILD b/submodules/WebUI/BUILD index ae4a135088..be4bbf2ff8 100644 --- a/submodules/WebUI/BUILD +++ b/submodules/WebUI/BUILD @@ -34,7 +34,8 @@ swift_library( "//submodules/Markdown:Markdown", "//submodules/TextFormat:TextFormat", "//submodules/LocalAuth", - "//submodules/InstantPageCache" + "//submodules/InstantPageCache", + "//submodules/OpenInExternalAppUI" ], visibility = [ "//visibility:public", diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 574919ba3f..b6fda299c4 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -25,6 +25,7 @@ import QrCodeUI import InstantPageUI import InstantPageCache import LocalAuth +import OpenInExternalAppUI private let durgerKingBotIds: [Int64] = [5104055776, 2200339955] @@ -158,7 +159,7 @@ public class WebAppCancelButtonNode: ASDisplayNode { let color = self.color ?? self.theme.rootController.navigationBar.accentTextColor self.arrowNode.isHidden = state == .cancel - self.labelNode.attributedText = NSAttributedString(string: state == .cancel ? self.strings.Common_Cancel : self.strings.Common_Back, font: Font.regular(17.0), textColor: color) + self.labelNode.attributedText = NSAttributedString(string: state == .cancel ? self.strings.Common_Close : self.strings.Common_Back, font: Font.regular(17.0), textColor: color) let labelSize = self.labelNode.updateLayout(CGSize(width: 120.0, height: 56.0)) @@ -941,6 +942,8 @@ public final class WebAppController: ViewController, AttachmentContainable { } let tryInstantView = json["try_instant_view"] as? Bool ?? false + let tryBrowser = json["try_browser"] as? String + if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0 { self.webView?.lastTouchTimestamp = nil if tryInstantView { @@ -964,6 +967,40 @@ public final class WebAppController: ViewController, AttachmentContainable { } }) } else { + var url = url + if let tryBrowser { + let openInOptions = availableOpenInOptions(context: self.context, item: .url(url: url)) + var matchingOption: OpenInOption? + for option in openInOptions { + if case let .other(identifier, _, _, _) = option.application { + switch tryBrowser { + case "safari": + break + case "chrome": + if identifier == "chrome" { + matchingOption = option + break + } + case "firefox": + if ["firefox", "firefoxFocus"].contains(identifier) { + matchingOption = option + break + } + case "opera": + if ["operaMini", "operaTouch"].contains(identifier) { + matchingOption = option + break + } + default: + break + } + } + } + if let matchingOption, case let .openUrl(newUrl) = matchingOption.action() { + url = newUrl + } + } + self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {}) } } @@ -1920,9 +1957,9 @@ public final class WebAppController: ViewController, AttachmentContainable { guard let self, let chatPeer else { return } - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(chatPeer), completion: { _ in - completion() + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(chatPeer), keepStack: .always, completion: { _ in })) + completion() }) } }