mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-08 19:10:53 +00:00
Web app improvements
This commit is contained in:
parent
8f1811bad4
commit
f0e03a2a4c
@ -13,7 +13,6 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P
|
||||
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
|
||||
serializedThemeParams = .dataJSON(data: dataString)
|
||||
}
|
||||
|
||||
return postbox.transaction { transaction -> Signal<String, RequestSimpleWebViewError> in
|
||||
guard let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else {
|
||||
return .fail(.generic)
|
||||
@ -38,8 +37,12 @@ func _internal_requestSimpleWebView(postbox: Postbox, network: Network, botId: P
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
public enum KeepWebViewError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public enum RequestWebViewResult {
|
||||
case webViewResult(queryId: Int64, url: String)
|
||||
case webViewResult(queryId: Int64, url: String, keepAliveSignal: Signal<Never, KeepWebViewError>)
|
||||
case requestConfirmation(botIcon: TelegramMediaFile)
|
||||
}
|
||||
|
||||
@ -47,6 +50,29 @@ public enum RequestWebViewError {
|
||||
case generic
|
||||
}
|
||||
|
||||
private func keepWebView(network: Network, flags: Int32, peer: Api.InputPeer, bot: Api.InputUser, queryId: Int64, replyToMessageId: MessageId?) -> Signal<Never, KeepWebViewError> {
|
||||
let poll = Signal<Never, KeepWebViewError> { subscriber in
|
||||
let signal: Signal<Never, KeepWebViewError> = network.request(Api.functions.messages.prolongWebView(flags: flags, peer: peer, bot: bot, queryId: queryId, replyToMsgId: replyToMessageId?.id))
|
||||
|> mapError { _ -> KeepWebViewError in
|
||||
return .generic
|
||||
}
|
||||
|> ignoreValues
|
||||
|
||||
return signal.start(error: { error in
|
||||
subscriber.putError(error)
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
.complete()
|
||||
|> suspendAwareDelay(60.0, queue: Queue.concurrentDefaultQueue())
|
||||
|> then (poll)
|
||||
)
|
||||
|> restart
|
||||
}
|
||||
|
||||
func _internal_requestWebView(postbox: Postbox, network: Network, peerId: PeerId, botId: PeerId, url: String?, themeParams: [String: Any]?, replyToMessageId: MessageId?) -> Signal<RequestWebViewResult, RequestWebViewError> {
|
||||
var serializedThemeParams: Api.DataJSON?
|
||||
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
|
||||
@ -54,7 +80,7 @@ func _internal_requestWebView(postbox: Postbox, network: Network, peerId: PeerId
|
||||
}
|
||||
|
||||
return postbox.transaction { transaction -> Signal<RequestWebViewResult, RequestWebViewError> in
|
||||
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer), let bot = transaction.getPeer(botId), let inputUser = apiInputUser(bot) else {
|
||||
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer), let bot = transaction.getPeer(botId), let inputBot = apiInputUser(bot) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
@ -70,7 +96,7 @@ func _internal_requestWebView(postbox: Postbox, network: Network, peerId: PeerId
|
||||
flags |= (1 << 0)
|
||||
replyToMsgId = replyToMessageId.id
|
||||
}
|
||||
return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputUser, url: url, themeParams: serializedThemeParams, replyToMsgId: replyToMsgId))
|
||||
return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, themeParams: serializedThemeParams, replyToMsgId: replyToMsgId))
|
||||
|> mapError { _ -> RequestWebViewError in
|
||||
return .generic
|
||||
}
|
||||
@ -96,10 +122,34 @@ func _internal_requestWebView(postbox: Postbox, network: Network, peerId: PeerId
|
||||
|> castError(RequestWebViewError.self)
|
||||
|> switchToLatest
|
||||
case let .webViewResultUrl(queryId, url):
|
||||
return .single(.webViewResult(queryId: queryId, url: url))
|
||||
return .single(.webViewResult(queryId: queryId, url: url, keepAliveSignal: keepWebView(network: network, flags: flags, peer: inputPeer, bot: inputBot, queryId: queryId, replyToMessageId: replyToMessageId)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|> castError(RequestWebViewError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
public enum SendWebViewDataError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_sendWebViewData(postbox: Postbox, network: Network, stateManager: AccountStateManager, botId: PeerId, buttonText: String, data: String) -> Signal<Never, SendWebViewDataError> {
|
||||
return postbox.transaction { transaction -> Signal<Never, SendWebViewDataError> in
|
||||
guard let bot = transaction.getPeer(botId), let inputBot = apiInputUser(bot) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.sendWebViewData(bot: inputBot, randomId: Int64.random(in: Int64.min ... Int64.max), buttonText: buttonText, data: data))
|
||||
|> mapError { _ -> SendWebViewDataError in
|
||||
return .generic
|
||||
}
|
||||
|> map { updates -> Api.Updates in
|
||||
stateManager.addUpdates(updates)
|
||||
return updates
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|> castError(SendWebViewDataError.self)
|
||||
|> switchToLatest
|
||||
}
|
||||
|
@ -330,6 +330,11 @@ public extension TelegramEngine {
|
||||
return _internal_requestSimpleWebView(postbox: self.account.postbox, network: self.account.network, botId: botId, url: url, themeParams: themeParams)
|
||||
}
|
||||
|
||||
|
||||
public func sendWebViewData(botId: PeerId, buttonText: String, data: String) -> Signal<Never, SendWebViewDataError> {
|
||||
return _internal_sendWebViewData(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, botId: botId, buttonText: buttonText, data: data)
|
||||
}
|
||||
|
||||
public func addBotToAttachMenu(peerId: PeerId) -> Signal<Bool, NoError> {
|
||||
return _internal_addBotToAttachMenu(postbox: self.account.postbox, network: self.account.network, peerId: peerId)
|
||||
}
|
||||
|
@ -552,7 +552,7 @@ public final class PrincipalThemeAdditionalGraphics {
|
||||
public let chatBubbleActionButtonOutgoingProfileIconImage: UIImage
|
||||
public let chatBubbleActionButtonOutgoingAddToChatIconImage: UIImage
|
||||
public let chatBubbleActionButtonOutgoingWebAppIconImage: UIImage
|
||||
|
||||
|
||||
public let chatEmptyItemLockIcon: UIImage
|
||||
public let emptyChatListCheckIcon: UIImage
|
||||
|
||||
|
@ -263,6 +263,16 @@ public enum PresentationResourceKey: Int32 {
|
||||
case chatFreeCommentButtonIcon
|
||||
case chatFreeNavigateButtonIcon
|
||||
case chatFreeShareButtonIcon
|
||||
|
||||
case chatKeyboardActionButtonMessageIcon
|
||||
case chatKeyboardActionButtonLinkIcon
|
||||
case chatKeyboardActionButtonShareIcon
|
||||
case chatKeyboardActionButtonPhoneIcon
|
||||
case chatKeyboardActionButtonLocationIcon
|
||||
case chatKeyboardActionButtonPaymentIcon
|
||||
case chatKeyboardActionButtonProfileIcon
|
||||
case chatKeyboardActionButtonAddToChatIcon
|
||||
case chatKeyboardActionButtonWebAppIcon
|
||||
}
|
||||
|
||||
public enum PresentationResourceParameterKey: Hashable {
|
||||
|
@ -1198,4 +1198,58 @@ public struct PresentationResourcesChat {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/ShareIcon"), color: bubbleVariableColor(variableColor: theme.chat.message.shareButtonForegroundColor, wallpaper: wallpaper))
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonMessageIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonMessageIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotMessage"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonLinkIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonLinkIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotLink"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonShareIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonShareIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotShare"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonPhoneIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonPhoneIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotPhone"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonLocationIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonLocationIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotLocation"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonPaymentIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonPaymentIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotPayment"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonProfileIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonProfileIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotProfile"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonAddToChatIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonAddToChatIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotAddToChat"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatKeyboardActionButtonWebAppIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatKeyboardActionButtonWebAppIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/BotWebApp"), color: theme.chat.inputButtonPanel.buttonTextColor)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,12 @@ import AccountContext
|
||||
import ChatPresentationInterfaceState
|
||||
|
||||
private final class ChatButtonKeyboardInputButtonNode: ASButtonNode {
|
||||
var button: ReplyMarkupButton?
|
||||
var button: ReplyMarkupButton? {
|
||||
didSet {
|
||||
self.updateIcon()
|
||||
}
|
||||
}
|
||||
var iconNode: ASImageNode?
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
@ -20,12 +25,52 @@ private final class ChatButtonKeyboardInputButtonNode: ASButtonNode {
|
||||
self.updateTheme(theme: theme)
|
||||
}
|
||||
|
||||
private func updateIcon() {
|
||||
guard let theme = self.theme else {
|
||||
return
|
||||
}
|
||||
var iconImage: UIImage?
|
||||
if let button = self.button {
|
||||
switch button.action {
|
||||
case .openWebView:
|
||||
iconImage = PresentationResourcesChat.chatKeyboardActionButtonWebAppIconImage(theme)
|
||||
default:
|
||||
iconImage = nil
|
||||
}
|
||||
}
|
||||
|
||||
if iconImage != nil {
|
||||
if self.iconNode == nil {
|
||||
let iconNode = ASImageNode()
|
||||
iconNode.contentMode = .center
|
||||
self.iconNode = iconNode
|
||||
self.addSubnode(iconNode)
|
||||
}
|
||||
self.iconNode?.image = iconImage
|
||||
} else if let iconNode = self.iconNode {
|
||||
iconNode.removeFromSupernode()
|
||||
self.iconNode = nil
|
||||
}
|
||||
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
|
||||
func updateTheme(theme: PresentationTheme) {
|
||||
if theme !== self.theme {
|
||||
self.theme = theme
|
||||
|
||||
self.setBackgroundImage(PresentationResourcesChat.chatInputButtonPanelButtonImage(theme), for: [])
|
||||
self.setBackgroundImage(PresentationResourcesChat.chatInputButtonPanelButtonHighlightedImage(theme), for: [.highlighted])
|
||||
|
||||
self.updateIcon()
|
||||
}
|
||||
}
|
||||
|
||||
override func layout() {
|
||||
super.layout()
|
||||
|
||||
if let iconNode = self.iconNode {
|
||||
iconNode.frame = CGRect(x: self.frame.width - 16.0, y: 4.0, width: 12.0, height: 12.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,7 +261,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
|
||||
case let .openUserProfile(peerId):
|
||||
self.controllerInteraction.openPeer(peerId, .info, nil, nil)
|
||||
case let .openWebView(url, simple):
|
||||
self.controllerInteraction.openWebView(url, simple)
|
||||
self.controllerInteraction.openWebView(markupButton.title, url, simple)
|
||||
}
|
||||
if dismissIfOnce {
|
||||
if let message = self.message {
|
||||
|
@ -3301,7 +3301,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
strongSelf.openResolved(result: .join(joinHash), sourceMessageId: nil)
|
||||
}, openWebView: { [weak self] url, simple in
|
||||
}, openWebView: { [weak self] buttonText, url, simple in
|
||||
guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
|
||||
return
|
||||
}
|
||||
@ -3350,28 +3350,48 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: url, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), replyToMessageId: nil)
|
||||
|> afterDisposed {
|
||||
updateProgress()
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .webViewResult(queryId, url):
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: queryId)
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.push(controller)
|
||||
case .requestConfirmation:
|
||||
break
|
||||
}
|
||||
}, 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: {
|
||||
})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
if simple {
|
||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestSimpleWebView(botId: peerId, url: url, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme))
|
||||
|> afterDisposed {
|
||||
updateProgress()
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] url in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, buttonText: buttonText, keepAliveSignal: nil)
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.push(controller)
|
||||
}, 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: {
|
||||
})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: url, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), replyToMessageId: nil)
|
||||
|> afterDisposed {
|
||||
updateProgress()
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .webViewResult(queryId, url, keepAliveSignal):
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: queryId, buttonText: buttonText, keepAliveSignal: keepAliveSignal)
|
||||
controller.navigationPresentation = .modal
|
||||
strongSelf.push(controller)
|
||||
case .requestConfirmation:
|
||||
break
|
||||
}
|
||||
}, 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: {
|
||||
})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
}
|
||||
}, requestMessageUpdate: { [weak self] id in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
|
||||
@ -10809,7 +10829,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
completion(controller, nil)
|
||||
strongSelf.controllerNavigationDisposable.set(nil)
|
||||
case let .app(botId, botName, _):
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id, botId: botId, botName: botName, url: nil, queryId: nil)
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peer.id, botId: botId, botName: botName, url: nil, queryId: nil, buttonText: nil, keepAliveSignal: nil)
|
||||
completion(controller, nil)
|
||||
strongSelf.controllerNavigationDisposable.set(nil)
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ public final class ChatControllerInteraction {
|
||||
let commitEmojiInteraction: (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void
|
||||
let openLargeEmojiInfo: (String, String?, TelegramMediaFile) -> Void
|
||||
let openJoinLink: (String) -> Void
|
||||
let openWebView: (String, Bool) -> Void
|
||||
let openWebView: (String, String, Bool) -> Void
|
||||
|
||||
let requestMessageUpdate: (MessageId) -> Void
|
||||
let cancelInteractiveKeyboardGestures: () -> Void
|
||||
@ -231,7 +231,7 @@ public final class ChatControllerInteraction {
|
||||
commitEmojiInteraction: @escaping (MessageId, String, EmojiInteraction, TelegramMediaFile) -> Void,
|
||||
openLargeEmojiInfo: @escaping (String, String?, TelegramMediaFile) -> Void,
|
||||
openJoinLink: @escaping (String) -> Void,
|
||||
openWebView: @escaping (String, Bool) -> Void,
|
||||
openWebView: @escaping (String, String, Bool) -> Void,
|
||||
requestMessageUpdate: @escaping (MessageId) -> Void,
|
||||
cancelInteractiveKeyboardGestures: @escaping () -> Void,
|
||||
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
|
||||
@ -377,7 +377,7 @@ public final class ChatControllerInteraction {
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _ in
|
||||
}, openWebView: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
@ -855,7 +855,7 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
|
||||
case let .openUserProfile(peerId):
|
||||
item.controllerInteraction.openPeer(peerId, .info, nil, nil)
|
||||
case let .openWebView(url, simple):
|
||||
item.controllerInteraction.openWebView(url, simple)
|
||||
item.controllerInteraction.openWebView(button.title, url, simple)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +532,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _ in
|
||||
}, openWebView: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
||||
|
@ -159,7 +159,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _ in
|
||||
}, openWebView: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
@ -151,7 +151,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _ in
|
||||
}, openWebView: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: nil))
|
||||
|
@ -2266,7 +2266,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _ in
|
||||
}, openWebView: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
@ -1325,7 +1325,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}, commitEmojiInteraction: { _, _, _, _ in
|
||||
}, openLargeEmojiInfo: { _, _, _ in
|
||||
}, openJoinLink: { _ in
|
||||
}, openWebView: { _, _ in
|
||||
}, openWebView: { _, _, _ in
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
|
@ -59,10 +59,12 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
private let present: (ViewController, Any?) -> Void
|
||||
private var queryId: Int64?
|
||||
|
||||
init(context: AccountContext, controller: WebAppController, presentationData: PresentationData, peerId: PeerId, botId: PeerId, url: String?, queryId: Int64?, present: @escaping (ViewController, Any?) -> Void) {
|
||||
private var keepAliveDisposable: Disposable?
|
||||
|
||||
init(context: AccountContext, controller: WebAppController, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.context = context
|
||||
self.controller = controller
|
||||
self.presentationData = presentationData
|
||||
self.presentationData = controller.presentationData
|
||||
self.present = present
|
||||
|
||||
super.init()
|
||||
@ -127,22 +129,36 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
webView.scrollView.delegate = self
|
||||
self.webView = webView
|
||||
|
||||
if let url = url, let queryId = queryId {
|
||||
if let url = controller.url, let queryId = controller.queryId, let keepAliveSignal = controller.keepAliveSignal {
|
||||
self.queryId = queryId
|
||||
if let parsedUrl = URL(string: url) {
|
||||
self.webView?.load(URLRequest(url: parsedUrl))
|
||||
}
|
||||
|
||||
self.keepAliveDisposable = (keepAliveSignal
|
||||
|> deliverOnMainQueue).start(error: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controller?.dismiss()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let _ = (context.engine.messages.requestWebView(peerId: peerId, botId: botId, url: url, themeParams: generateWebAppThemeParams(presentationData.theme), replyToMessageId: nil)
|
||||
let _ = (context.engine.messages.requestWebView(peerId: controller.peerId, botId: controller.botId, url: controller.url, themeParams: generateWebAppThemeParams(presentationData.theme), replyToMessageId: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .webViewResult(queryId, url):
|
||||
case let .webViewResult(queryId, url, keepAliveSignal):
|
||||
if let parsedUrl = URL(string: url) {
|
||||
strongSelf.queryId = queryId
|
||||
strongSelf.webView?.load(URLRequest(url: parsedUrl))
|
||||
|
||||
strongSelf.keepAliveDisposable = (keepAliveSignal
|
||||
|> deliverOnMainQueue).start(error: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controller?.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
case .requestConfirmation:
|
||||
break
|
||||
@ -151,6 +167,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.keepAliveDisposable?.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
@ -218,7 +238,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
|
||||
switch eventName {
|
||||
case "webview_data_send":
|
||||
self.handleSendResultMessage()
|
||||
if let eventData = body["eventData"] as? String {
|
||||
self.handleSendData(data: eventData)
|
||||
}
|
||||
case "webview_close":
|
||||
self.controller?.dismiss()
|
||||
default:
|
||||
@ -226,6 +248,26 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
}
|
||||
|
||||
private var dismissed = false
|
||||
private func handleSendData(data string: String) {
|
||||
guard let controller = self.controller, let buttonText = controller.buttonText, !self.dismissed else {
|
||||
return
|
||||
}
|
||||
controller.dismiss()
|
||||
|
||||
if let data = string.data(using: .utf8), let jsonArray = try? JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [String: Any], let data = jsonArray["data"] {
|
||||
var resultString: String?
|
||||
if let string = data as? String {
|
||||
resultString = string
|
||||
} else if let data1 = try? JSONSerialization.data(withJSONObject: data, options: JSONSerialization.WritingOptions.prettyPrinted), let convertedString = String(data: data1, encoding: String.Encoding.utf8) {
|
||||
resultString = convertedString
|
||||
}
|
||||
if let resultString = resultString {
|
||||
let _ = (self.context.engine.messages.sendWebViewData(botId: controller.botId, buttonText: buttonText, data: resultString)).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendEvent(name: String, data: String) {
|
||||
let script = "window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data))"
|
||||
self.webView?.evaluateJavaScript(script, completionHandler: { _, _ in
|
||||
@ -257,33 +299,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
themeParamsString.append("}}")
|
||||
self.sendEvent(name: "theme_changed", data: themeParamsString)
|
||||
}
|
||||
|
||||
private func handleSendResultMessage() {
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
controller.dismiss()
|
||||
// guard let controller = self.controller, let queryId = self.queryId, self.currentAlertController == nil else {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// let _ = (self.context.engine.messages.getWebViewResult(peerId: controller.peerId, botId: controller.botId, queryId: queryId)
|
||||
// |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
// guard let strongSelf = self, let controller = strongSelf.controller else {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// let alertController = webAppPreviewResultController(context: strongSelf.context, to: controller.peerId, botId: controller.botId, result: result, completion: { [weak self] in
|
||||
// guard let strongSelf = self, let controller = strongSelf.controller else {
|
||||
// return
|
||||
// }
|
||||
// let _ = strongSelf.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: controller.peerId, botId: controller.botId, result: result)
|
||||
// controller.dismiss()
|
||||
// })
|
||||
// controller.present(alertController, in: .window(.root))
|
||||
// strongSelf.currentAlertController = alertController
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
private var controllerNode: Node {
|
||||
@ -298,17 +313,21 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
private let botId: PeerId
|
||||
private let url: String?
|
||||
private let queryId: Int64?
|
||||
private let buttonText: String?
|
||||
private let keepAliveSignal: Signal<Never, KeepWebViewError>?
|
||||
|
||||
private var presentationData: PresentationData
|
||||
fileprivate let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, botId: PeerId, botName: String, url: String?, queryId: Int64?) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, botId: PeerId, botName: String, url: String?, queryId: Int64?, buttonText: String?, keepAliveSignal: Signal<Never, KeepWebViewError>?) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.botId = botId
|
||||
self.url = url
|
||||
self.queryId = queryId
|
||||
self.buttonText = buttonText
|
||||
self.keepAliveSignal = keepAliveSignal
|
||||
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -432,7 +451,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = Node(context: self.context, controller: self, presentationData: self.presentationData, peerId: self.peerId, botId: self.botId, url: self.url, queryId: self.queryId, present: { [weak self] c, a in
|
||||
self.displayNode = Node(context: self.context, controller: self, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user