Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions submodules/AccountContext/Sources/ChatController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -349,12 +349,16 @@ public struct ChatControllerInitialBotAppStart {
public let payload: String?
public let justInstalled: Bool
public let mode: ResolvedStartAppMode

public init(botApp: BotApp?, payload: String?, justInstalled: Bool, mode: ResolvedStartAppMode) {
// The `start` payload the link carried alongside `startapp`, used for the chat's Start button
// if the Mini App launch confirmation is dismissed.
public let botStartPayload: String?

public init(botApp: BotApp?, payload: String?, justInstalled: Bool, mode: ResolvedStartAppMode, botStartPayload: String? = nil) {
self.botApp = botApp
self.payload = payload
self.justInstalled = justInstalled
self.mode = mode
self.botStartPayload = botStartPayload
}
}

Expand Down
51 changes: 42 additions & 9 deletions submodules/TelegramUI/Sources/Chat/ChatControllerOpenWebApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ func openWebAppImpl(
source: ChatOpenWebViewSource,
skipTermsOfService: Bool,
payload: String?,
verifyAgeCompletion: ((Int) -> Void)?
verifyAgeCompletion: ((Int) -> Void)?,
launchDismissedWithoutConfirmation: (() -> Void)? = nil
) {
if context.isFrozen {
parentController.push(context.sharedContext.makeAccountFreezeInfoScreen(context: context))
Expand Down Expand Up @@ -386,6 +387,11 @@ func openWebAppImpl(
let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: updatedPresentationData, peer: botPeer, completion: { _ in
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
openWebView(false)
}, dismissedWithoutConfirmation: {
// The title panel's progress state is set before the confirmation is presented, and is
// otherwise only cleared once the web view request settles — which never happens here.
updateProgress()
launchDismissedWithoutConfirmation?()
}, showMore: nil, openTerms: {
if let navigationController = parentController.navigationController as? NavigationController {
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.WebApp_LaunchTermsConfirmation_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
Expand Down Expand Up @@ -673,7 +679,7 @@ public extension ChatControllerImpl {
navigationController = main
}
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)
self.presentBotApp(context: context, parentController: parentController, botApp: botApp.botApp, botPeer: botPeer, payload: botApp.payload, mode: botApp.mode, botStartPayload: botApp.botStartPayload)
} else {
context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: forceUpdate, openPeer: { peer, navigation in
if let navigationController {
Expand All @@ -691,11 +697,25 @@ public extension ChatControllerImpl {
}
}

func presentBotApp(botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, concealed: Bool = false, commit: @escaping () -> Void = {}) {
ChatControllerImpl.presentBotApp(context: self.context, parentController: self, botApp: botApp, botPeer: botPeer, payload: payload, mode: mode, concealed: concealed, commit: commit)
// Leaves the `start` payload that a link carried alongside `startapp` on the chat's Start button,
// so that dismissing the Mini App launch confirmation does not discard it.
internal func applyBotStartPayloadFallback(botPeerId: EnginePeer.Id, payload: String?) {
guard let payload, !payload.isEmpty else {
return
}
guard self.chatLocation.peerId == botPeerId else {
return
}
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
return state.updatedBotStartPayload(payload)
})
}

fileprivate static func presentBotApp(context: AccountContext, parentController: ViewController, botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, concealed: Bool = false, commit: @escaping () -> Void = {}) {

func presentBotApp(botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, botStartPayload: String? = nil, concealed: Bool = false, commit: @escaping () -> Void = {}) {
ChatControllerImpl.presentBotApp(context: self.context, parentController: self, botApp: botApp, botPeer: botPeer, payload: payload, mode: mode, botStartPayload: botStartPayload, concealed: concealed, commit: commit)
}

fileprivate static func presentBotApp(context: AccountContext, parentController: ViewController, botApp: BotApp?, botPeer: EnginePeer, payload: String?, mode: ResolvedStartAppMode, botStartPayload: String? = nil, concealed: Bool = false, commit: @escaping () -> Void = {}) {
let chatController = parentController as? ChatControllerImpl
let peerId: EnginePeer.Id
let threadId = chatController?.chatLocation.threadId
Expand All @@ -704,7 +724,13 @@ public extension ChatControllerImpl {
} else {
peerId = botPeer.id
}


// If the link carried a `start` payload alongside `startapp` and the user dismisses the Mini App
// launch confirmation, leave that payload on the chat's Start button instead of a bare /start.
let applyBotStartPayloadFallback: () -> Void = { [weak chatController] in
chatController?.applyBotStartPayloadFallback(botPeerId: botPeer.id, payload: botStartPayload)
}

var skipTermsOfService = false
if let whiteListedBots = context.currentAppConfiguration.with({ $0 }).data?["whitelisted_bots"] as? [Double] {
let botId = botPeer.id.id._internalGetInt64Value()
Expand Down Expand Up @@ -850,6 +876,8 @@ public extension ChatControllerImpl {
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)
}, dismissedWithoutConfirmation: {
applyBotStartPayloadFallback()
}, showMore: chatController == nil ? nil : { [weak chatController] in
if let chatController {
chatController.openResolved(result: .peer(botPeer._asPeer(), .info(nil)), sourceMessageId: nil)
Expand All @@ -865,7 +893,9 @@ public extension ChatControllerImpl {
}
})
} else {
context.sharedContext.openWebApp(
// Called directly rather than through SharedAccountContext.openWebApp (a plain forwarder to this
// function) so that the module-internal dismissal callback can be passed.
openWebAppImpl(
context: context,
parentController: parentController,
updatedPresentationData: updatedPresentationData,
Expand All @@ -878,7 +908,10 @@ public extension ChatControllerImpl {
source: .generic,
skipTermsOfService: false,
payload: payload,
verifyAgeCompletion: nil
verifyAgeCompletion: nil,
launchDismissedWithoutConfirmation: {
applyBotStartPayloadFallback()
}
)
}
}
Expand Down
11 changes: 8 additions & 3 deletions submodules/TelegramUI/Sources/ChatController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9810,12 +9810,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
if let botApp = botAppStart.botApp {
self.presentBotApp(botApp: botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode, concealed: concealed, commit: {
self.presentBotApp(botApp: botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode, botStartPayload: botAppStart.botStartPayload, concealed: concealed, commit: {
dismissWebAppControllers()
commit()
})
} else {
self.context.sharedContext.openWebApp(
// Called directly rather than through SharedAccountContext.openWebApp (a plain forwarder to
// this function) so that the module-internal dismissal callback can be passed.
openWebAppImpl(
context: self.context,
parentController: self,
updatedPresentationData: self.updatedPresentationData,
Expand All @@ -9828,7 +9830,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
source: .generic,
skipTermsOfService: false,
payload: botAppStart.payload,
verifyAgeCompletion: nil
verifyAgeCompletion: nil,
launchDismissedWithoutConfirmation: { [weak self] in
self?.applyBotStartPayloadFallback(botPeerId: peer.id, payload: botAppStart.botStartPayload)
}
)
commit()
}
Expand Down
6 changes: 3 additions & 3 deletions submodules/TelegramUI/Sources/NavigateToChatController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled)
}
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode)
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode, botStartPayload: botAppStart.botStartPayload)
}
params.setupController(controller)
found = true
Expand All @@ -246,7 +246,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
}
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
Queue.mainQueue().after(0.1) {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode)
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode, botStartPayload: botAppStart.botStartPayload)
}
}

Expand All @@ -260,7 +260,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam

if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
Queue.mainQueue().after(0.1) {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode)
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode, botStartPayload: botAppStart.botStartPayload)
}
}
}
Expand Down
Loading