From 43405ce029021c2ca4d40bc6241c5625504c7912 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 1 Apr 2022 16:32:16 +0400 Subject: [PATCH] Web app improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 3 + .../Sources/ThemedTextAlertController.swift | 4 +- .../Sources/AlertTheme.swift | 8 +- .../Source/Signal_Mapping.swift | 2 +- .../Messages/AttachMenuBots.swift | 30 +++-- .../TelegramUI/Sources/ChatController.swift | 108 +++++++++++------- .../TelegramUI/Sources/OpenResolvedUrl.swift | 5 +- 7 files changed, 98 insertions(+), 62 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 536c49be26..7ec732ccd9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7417,6 +7417,9 @@ Sorry for the inconvenience."; "WebApp.AddToAttachmentAlreadyAddedError" = "This bot is already added in the attachment menu."; +"WebApp.OpenWebViewAlertTitle" = "Open Web App"; +"WebApp.OpenWebViewAlertText" = "**%@** would like to open its web app to proceed.\n\nIt will be able to access your **IP address** and basic device info."; + "WebApp.MessagePreview" = "Message Preview"; "WebApp.Send" = "Send"; diff --git a/submodules/AlertUI/Sources/ThemedTextAlertController.swift b/submodules/AlertUI/Sources/ThemedTextAlertController.swift index 8cd9de35ac..99c962e8f9 100644 --- a/submodules/AlertUI/Sources/ThemedTextAlertController.swift +++ b/submodules/AlertUI/Sources/ThemedTextAlertController.swift @@ -13,8 +13,8 @@ public final class AlertControllerContext { } } -public func textAlertController(alertContext: AlertControllerContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController { - let controller = standardTextAlertController(theme: alertContext.theme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissOnOutsideTap: dismissOnOutsideTap) +public func textAlertController(alertContext: AlertControllerContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true) -> AlertController { + let controller = standardTextAlertController(theme: alertContext.theme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, parseMarkdown: parseMarkdown, dismissOnOutsideTap: dismissOnOutsideTap) let presentationDataDisposable = alertContext.themeSignal.start(next: { [weak controller] theme in controller?.theme = theme }) diff --git a/submodules/PresentationDataUtils/Sources/AlertTheme.swift b/submodules/PresentationDataUtils/Sources/AlertTheme.swift index bba15a695f..8de1164e1c 100644 --- a/submodules/PresentationDataUtils/Sources/AlertTheme.swift +++ b/submodules/PresentationDataUtils/Sources/AlertTheme.swift @@ -5,11 +5,11 @@ import AccountContext import SwiftSignalKit import TelegramPresentationData -public func textAlertController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, forceTheme: PresentationTheme? = nil, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController { - return textAlertController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, forceTheme: forceTheme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissOnOutsideTap: dismissOnOutsideTap) +public func textAlertController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, forceTheme: PresentationTheme? = nil, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true) -> AlertController { + return textAlertController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, forceTheme: forceTheme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, parseMarkdown: parseMarkdown, dismissOnOutsideTap: dismissOnOutsideTap) } -public func textAlertController(sharedContext: SharedAccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, forceTheme: PresentationTheme? = nil, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController { +public func textAlertController(sharedContext: SharedAccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, forceTheme: PresentationTheme? = nil, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true) -> AlertController { var presentationData = updatedPresentationData?.initial ?? sharedContext.currentPresentationData.with { $0 } if let forceTheme = forceTheme { presentationData = presentationData.withUpdated(theme: forceTheme) @@ -21,7 +21,7 @@ public func textAlertController(sharedContext: SharedAccountContext, updatedPres presentationData = presentationData.withUpdated(theme: forceTheme) } return AlertControllerTheme(presentationData: presentationData) - }), title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissOnOutsideTap: dismissOnOutsideTap) + }), title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, parseMarkdown: parseMarkdown, dismissOnOutsideTap: dismissOnOutsideTap) } public func textAlertController(sharedContext: SharedAccountContext, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController { diff --git a/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Mapping.swift b/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Mapping.swift index d0680b9f97..b5faf1458b 100644 --- a/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Mapping.swift +++ b/submodules/SSignalKit/SwiftSignalKit/Source/Signal_Mapping.swift @@ -35,7 +35,7 @@ public func flatMap(_ f: @escaping (T) -> R) -> (Signal) -> Sign return Signal { subscriber in return signal.start(next: { next in if let next = next { - subscriber.putNext(f(next)) + subscriber.putNext(f(next)) } else { subscriber.putNext(nil) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift index f6025eb842..78ab97ebb1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AttachMenuBots.swift @@ -188,20 +188,20 @@ private func setCachedAttachMenuBots(transaction: Transaction, attachMenuBots: A } } -func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Signal { - let poll = Signal { subscriber in - let signal: Signal = cachedAttachMenuBots(postbox: postbox) +func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Signal { + let poll = Signal { subscriber in + let signal: Signal = cachedAttachMenuBots(postbox: postbox) |> mapToSignal { current in return (network.request(Api.functions.messages.getAttachMenuBots(hash: current?.hash ?? 0)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } - |> mapToSignal { result -> Signal in + |> mapToSignal { result -> Signal in guard let result = result else { return .complete() } - return postbox.transaction { transaction in + return postbox.transaction { transaction -> Void in switch result { case let .attachMenuBots(hash, bots, users): var peers: [Peer] = [] @@ -237,11 +237,14 @@ func managedSynchronizeAttachMenuBots(postbox: Postbox, network: Network) -> Sig case .attachMenuBotsNotModified: break } - } |> ignoreValues + return Void() + } }) } - return signal.start(completed: { + return signal.start(next: { value in + subscriber.putNext(value) + }, completed: { subscriber.putCompletion() }) } @@ -273,9 +276,16 @@ func _internal_addBotToAttachMenu(postbox: Postbox, network: Network, botId: Pee |> `catch` { error -> Signal in return .single(false) } - |> afterCompleted { - let _ = (managedSynchronizeAttachMenuBots(postbox: postbox, network: network) - |> take(1)).start() + |> mapToSignal { value -> Signal in + if value { + return managedSynchronizeAttachMenuBots(postbox: postbox, network: network) + |> take(1) + |> map { _ -> Bool in + return true + } + } else { + return .single(value) + } } } |> switchToLatest diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 9830d1b5cd..8dc6162a2e 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3302,7 +3302,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } strongSelf.openResolved(result: .join(joinHash), sourceMessageId: nil) }, openWebView: { [weak self] buttonText, url, simple in - guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else { + guard let strongSelf = self, let peerId = strongSelf.chatLocation.peerId, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramUser else { return } @@ -3350,52 +3350,76 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } - 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 = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, buttonText: buttonText, keepAliveSignal: nil) - strongSelf.present(controller, in: .window(.root)) -// controller.getNavigationController = { [weak self] in -// return self?.effectiveNavigationController -// } -// 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)) - } - })) + let openWebView = { + 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 = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, buttonText: buttonText, keepAliveSignal: nil) + strongSelf.present(controller, in: .window(.root)) + // controller.getNavigationController = { [weak self] in + // return self?.effectiveNavigationController + // } + // 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, payload: nil, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), replyToMessageId: nil) + |> afterDisposed { + updateProgress() + }) + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let strongSelf = self else { + return + } + let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal) + strongSelf.present(controller, in: .window(.root)) + // let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, replyToMessageId: nil, iconFile: nil) + // controller.getNavigationController = { [weak self] in + // return self?.effectiveNavigationController + // } + // 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)) + } + })) + } + } + + if peer.flags.contains(.isVerified) { + openWebView() } else { - strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: url, payload: nil, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), replyToMessageId: nil) - |> afterDisposed { - updateProgress() - }) - |> deliverOnMainQueue).start(next: { [weak self] result in + let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id) + |> deliverOnMainQueue).start(next: { value in guard let strongSelf = self else { return } - let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal) - strongSelf.present(controller, in: .window(.root)) -// let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, replyToMessageId: nil, iconFile: nil) -// controller.getNavigationController = { [weak self] in -// return self?.effectiveNavigationController -// } -// 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)) + + if value { + openWebView() + } else { + strongSelf.present(textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: strongSelf.presentationData.strings.WebApp_OpenWebViewAlertTitle, text: strongSelf.presentationData.strings.WebApp_OpenWebViewAlertText(botName).string, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { + if let strongSelf = self { + let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id).start() + openWebView() + } + })], parseMarkdown: true), in: .window(.root), with: nil) } - })) + }) } }, requestMessageUpdate: { [weak self] id in if let strongSelf = self { diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index bcba6d43c3..4f8ec371d6 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -567,9 +567,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur return } let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peerIcon: icon, completion: { - let _ = context.engine.messages.addBotToAttachMenu(botId: peerId).start() - - Queue.mainQueue().after(1.0, { + let _ = (context.engine.messages.addBotToAttachMenu(botId: peerId) + |> deliverOnMainQueue).start(completed: { if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peer.id, payload: payload), useExisting: true)) }