mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Web app improvements
This commit is contained in:
parent
1113279e17
commit
d86a8785b0
@ -9913,3 +9913,9 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Gallery.ViewOncePhotoTooltip" = "This photo can only be viewed once.";
|
||||
"Gallery.ViewOnceVideoTooltip" = "This video can only be viewed once.";
|
||||
|
||||
"WebApp.DisclaimerTitle" = "Warning";
|
||||
"WebApp.DisclaimerText" = "You are about to use a mini app operated by an independent party not affiliated with Telegram. You must agree to the Terms of Use of mini apps to continue.";
|
||||
"WebApp.DisclaimerAgree" = "I agree to the [Terms of Use]()";
|
||||
"WebApp.DisclaimerContinue" = "Continue";
|
||||
"WebApp.Disclaimer_URL" = "https://telegram.org/tos/mini-apps";
|
||||
|
@ -55,6 +55,7 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
public static let showInAttachMenu = Flags(rawValue: 1 << 2)
|
||||
public static let showInSettings = Flags(rawValue: 1 << 3)
|
||||
public static let showInSettingsDisclaimer = Flags(rawValue: 1 << 4)
|
||||
public static let notActivated = Flags(rawValue: 1 << 5)
|
||||
}
|
||||
|
||||
public struct PeerFlags: OptionSet, Codable {
|
||||
@ -320,6 +321,9 @@ func managedSynchronizeAttachMenuBots(accountPeerId: PeerId, postbox: Postbox, n
|
||||
}
|
||||
}
|
||||
var flags: AttachMenuBots.Bot.Flags = []
|
||||
if (apiFlags & (1 << 0)) != 0 {
|
||||
flags.insert(.notActivated)
|
||||
}
|
||||
if (apiFlags & (1 << 1)) != 0 {
|
||||
flags.insert(.hasSettings)
|
||||
}
|
||||
@ -590,6 +594,7 @@ public final class BotApp: Equatable, Codable {
|
||||
|
||||
public static let notActivated = Flags(rawValue: 1 << 0)
|
||||
public static let requiresWriteAccess = Flags(rawValue: 1 << 1)
|
||||
public static let hasSettings = Flags(rawValue: 1 << 2)
|
||||
}
|
||||
|
||||
public let id: Int64
|
||||
@ -729,6 +734,9 @@ func _internal_getBotApp(account: Account, reference: BotAppReference) -> Signal
|
||||
if (botAppFlags & (1 << 1)) != 0 {
|
||||
appFlags.insert(.requiresWriteAccess)
|
||||
}
|
||||
if (botAppFlags & (1 << 2)) != 0 {
|
||||
appFlags.insert(.hasSettings)
|
||||
}
|
||||
return .single(BotApp(id: id, accessHash: accessHash, shortName: shortName, title: title, description: description, photo: telegramMediaImageFromApiPhoto(photo), document: document.flatMap(telegramMediaFileFromApiDocument), hash: hash, flags: appFlags))
|
||||
case .botAppNotModified:
|
||||
return .complete()
|
||||
|
@ -1793,7 +1793,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
}*/
|
||||
payload = nil
|
||||
fromAttachMenu = true
|
||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false, forceHasSettings: false)
|
||||
let theme = component.theme
|
||||
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
||||
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)
|
||||
|
@ -4220,7 +4220,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
|
||||
}
|
||||
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, fromAttachMenu: false, isInline: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: true, fromAttachMenu: false, isInline: false, isSimple: false, forceHasSettings: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||
@ -4291,7 +4291,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: isInline, isSimple: true)
|
||||
let params = WebAppParameters(peerId: peerId, botId: botId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: isInline, isSimple: true, forceHasSettings: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||
@ -4331,7 +4331,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false, forceHasSettings: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||
}, completion: { [weak self] in
|
||||
@ -13181,7 +13181,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peerId, botId: peerId, botName: botApp.title, url: url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: false, forceHasSettings: false)
|
||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||
@ -13418,7 +13418,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
} else {
|
||||
let _ = (context.engine.messages.getAttachMenuBot(botId: botId)
|
||||
|> deliverOnMainQueue).start(next: { bot in
|
||||
let controller = addWebAppToAttachmentController(context: context, peerName: bot.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { allowWrite in
|
||||
let controller = webAppTermsAlertController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, peer: bot.peer, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { allowWrite in
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: botId, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
|
||||
@ -13749,7 +13749,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
payload = botPayload
|
||||
fromAttachMenu = false
|
||||
}
|
||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false)
|
||||
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: fromAttachMenu, isInline: false, isSimple: false, forceHasSettings: false)
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageId, threadId: strongSelf.chatLocation.threadId)
|
||||
controller.openUrl = { [weak self] url, concealed, commit in
|
||||
|
@ -558,16 +558,10 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
}
|
||||
case let .premiumOffer(reference):
|
||||
dismissInput()
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
let isPremium = peer?.isPremium ?? false
|
||||
if !isPremium {
|
||||
let controller = PremiumIntroScreen(context: context, source: .deeplink(reference))
|
||||
if let navigationController = navigationController {
|
||||
navigationController.pushViewController(controller, animated: true)
|
||||
}
|
||||
}
|
||||
})
|
||||
case let .joinVoiceChat(peerId, invite):
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
@ -626,7 +620,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
return (chooseTypes?.isEmpty ?? true) ? nil : chooseTypes
|
||||
}
|
||||
|
||||
if let bot = attachMenuBots.first(where: { $0.peer.id == peerId }) {
|
||||
if let bot = attachMenuBots.first(where: { $0.peer.id == peerId }), !bot.flags.contains(.notActivated) {
|
||||
let choose = filterChooseTypes(choose, peerTypes: bot.peerTypes)
|
||||
|
||||
if let choose = choose {
|
||||
@ -675,7 +669,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
|> deliverOnMainQueue).start(next: { bot in
|
||||
let choose = filterChooseTypes(choose, peerTypes: bot.peerTypes)
|
||||
|
||||
let controller = addWebAppToAttachmentController(context: context, peerName: bot.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { allowWrite in
|
||||
let controller = webAppTermsAlertController(context: context, updatedPresentationData: updatedPresentationData, peer: bot.peer, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { allowWrite in
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: peerId, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
presentError(presentationData.strings.WebApp_AddToAttachmentUnavailableError)
|
||||
|
@ -4636,7 +4636,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
|
||||
let proceed = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
@ -4649,7 +4648,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let params = WebAppParameters(peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, url: url, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: true)
|
||||
let params = WebAppParameters(peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, url: url, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, fromMenu: false, fromAttachMenu: false, isInline: false, isSimple: true, forceHasSettings: bot.flags.contains(.hasSettings))
|
||||
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)
|
||||
}, requestSwitchInline: { _, _, _ in
|
||||
@ -4667,9 +4666,21 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
if bot.flags.contains(.showInSettingsDisclaimer) {
|
||||
let alertController = webAppTermsAlertController(context: self.context, updatedPresentationData: controller.updatedPresentationData, peer: bot.peer, completion: {
|
||||
let alertController = webAppTermsAlertController(context: self.context, updatedPresentationData: controller.updatedPresentationData, peer: bot.peer, requestWriteAccess: bot.flags.contains(.requiresWriteAccess), completion: { [weak self] allowWrite in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if bot.flags.contains(.notActivated) {
|
||||
let _ = (self.context.engine.messages.addBotToAttachMenu(botId: bot.peer.id, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
|
||||
}, completed: {
|
||||
proceed()
|
||||
})
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
})
|
||||
controller.present(alertController, in: .window(.root))
|
||||
} else {
|
||||
proceed()
|
||||
|
@ -32,6 +32,7 @@ swift_library(
|
||||
"//submodules/InstantPageUI:InstantPageUI",
|
||||
"//submodules/CheckNode:CheckNode",
|
||||
"//submodules/Markdown:Markdown",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -182,6 +182,7 @@ public struct WebAppParameters {
|
||||
let fromAttachMenu: Bool
|
||||
let isInline: Bool
|
||||
let isSimple: Bool
|
||||
let forceHasSettings: Bool
|
||||
|
||||
public init(
|
||||
peerId: PeerId,
|
||||
@ -195,7 +196,8 @@ public struct WebAppParameters {
|
||||
fromMenu: Bool,
|
||||
fromAttachMenu: Bool,
|
||||
isInline: Bool,
|
||||
isSimple: Bool
|
||||
isSimple: Bool,
|
||||
forceHasSettings: Bool
|
||||
) {
|
||||
self.peerId = peerId
|
||||
self.botId = botId
|
||||
@ -209,6 +211,7 @@ public struct WebAppParameters {
|
||||
self.fromAttachMenu = fromAttachMenu
|
||||
self.isInline = isInline
|
||||
self.isSimple = isSimple
|
||||
self.forceHasSettings = forceHasSettings
|
||||
}
|
||||
}
|
||||
|
||||
@ -1309,6 +1312,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
private let fromAttachMenu: Bool
|
||||
private let isInline: Bool
|
||||
private let isSimple: Bool
|
||||
private let forceHasSettings: Bool
|
||||
private let keepAliveSignal: Signal<Never, KeepWebViewError>?
|
||||
private let replyToMessageId: MessageId?
|
||||
private let threadId: Int64?
|
||||
@ -1335,6 +1339,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
self.fromAttachMenu = params.fromAttachMenu
|
||||
self.isInline = params.isInline
|
||||
self.isSimple = params.isSimple
|
||||
self.forceHasSettings = params.forceHasSettings
|
||||
self.keepAliveSignal = params.keepAliveSignal
|
||||
self.replyToMessageId = replyToMessageId
|
||||
self.threadId = threadId
|
||||
@ -1446,6 +1451,8 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
|
||||
let peerId = self.peerId
|
||||
let botId = self.botId
|
||||
let url = self.url
|
||||
let forceHasSettings = self.forceHasSettings
|
||||
|
||||
let items = context.engine.messages.attachMenuBots()
|
||||
|> take(1)
|
||||
@ -1454,7 +1461,18 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
||||
|
||||
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId})
|
||||
|
||||
if self?.url == nil, let attachMenuBot = attachMenuBot, attachMenuBot.flags.contains(.hasSettings) {
|
||||
let hasSettings: Bool
|
||||
if url == nil {
|
||||
if forceHasSettings {
|
||||
hasSettings = true
|
||||
} else {
|
||||
hasSettings = attachMenuBot?.flags.contains(.hasSettings) == true
|
||||
}
|
||||
} else {
|
||||
hasSettings = false
|
||||
}
|
||||
|
||||
if hasSettings {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Settings, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
|
@ -12,24 +12,25 @@ import AppBundle
|
||||
import AvatarNode
|
||||
import CheckNode
|
||||
import Markdown
|
||||
import TextFormat
|
||||
|
||||
private let textFont = Font.regular(13.0)
|
||||
private let boldTextFont = Font.semibold(13.0)
|
||||
|
||||
private func formattedText(_ text: String, color: UIColor, linkColor: UIColor, textAlignment: NSTextAlignment = .natural) -> NSAttributedString {
|
||||
return parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: color), bold: MarkdownAttributeSet(font: boldTextFont, textColor: color), link: MarkdownAttributeSet(font: textFont, textColor: linkColor), linkAttribute: { _ in return nil}), textAlignment: textAlignment)
|
||||
return parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: color), bold: MarkdownAttributeSet(font: boldTextFont, textColor: color), link: MarkdownAttributeSet(font: textFont, textColor: linkColor), linkAttribute: { _ in return (TelegramTextAttributes.URL, "") }), textAlignment: textAlignment)
|
||||
}
|
||||
|
||||
private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureRecognizerDelegate {
|
||||
private let strings: PresentationStrings
|
||||
private let title: String
|
||||
private let text: String
|
||||
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let textNode: ASTextNode
|
||||
private let textNode: ImmediateTextNode
|
||||
|
||||
private let acceptTermsCheckNode: InteractiveCheckNode
|
||||
private let acceptTermsLabelNode: ASTextNode
|
||||
private let acceptTermsLabelNode: ImmediateTextNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
@ -50,6 +51,8 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
var openTerms: () -> Void = {}
|
||||
|
||||
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, title: String, text: String, actions: [TextAlertAction]) {
|
||||
self.strings = strings
|
||||
self.title = title
|
||||
@ -60,14 +63,14 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
self.titleNode.maximumNumberOfLines = 1
|
||||
self.titleNode.textAlignment = .center
|
||||
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.lineSpacing = 0.1
|
||||
|
||||
self.acceptTermsCheckNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: theme.accentColor, strokeColor: theme.contrastColor, borderColor: theme.controlBorderColor, overlayBorder: false, hasInset: false, hasShadow: false))
|
||||
self.acceptTermsLabelNode = ASTextNode()
|
||||
self.acceptTermsLabelNode = ImmediateTextNode()
|
||||
self.acceptTermsLabelNode.maximumNumberOfLines = 4
|
||||
self.acceptTermsLabelNode.isUserInteractionEnabled = true
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
@ -114,17 +117,60 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.acceptTermsLabelNode.highlightAttributeAction = { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
self.acceptTermsLabelNode.tapAttributeAction = { [weak self] attributes, _ in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||
self?.openTerms()
|
||||
}
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.acceptTermsLabelNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.acceptTap(_:))))
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.acceptTap(_:)))
|
||||
tapGesture.delegate = self
|
||||
self.view.addGestureRecognizer(tapGesture)
|
||||
}
|
||||
|
||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
let location = gestureRecognizer.location(in: self.acceptTermsLabelNode.view)
|
||||
if self.acceptTermsLabelNode.bounds.contains(location) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if !self.bounds.contains(point) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let (_, attributes) = self.acceptTermsLabelNode.attributesAtPoint(self.view.convert(point, to: self.acceptTermsLabelNode.view)) {
|
||||
if attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] == nil {
|
||||
return self.view
|
||||
}
|
||||
}
|
||||
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
@objc private func acceptTap(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||
let location = gestureRecognizer.location(in: self.acceptTermsLabelNode.view)
|
||||
if self.acceptTermsCheckNode.isUserInteractionEnabled {
|
||||
if let attributes = self.acceptTermsLabelNode.attributesAtPoint(location)?.1 {
|
||||
if attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.acceptedTerms = !self.acceptedTerms
|
||||
}
|
||||
}
|
||||
@ -133,8 +179,20 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.semibold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
let text = "I agree to the [Terms of Use]()"
|
||||
self.acceptTermsLabelNode.attributedText = formattedText(text, color: theme.primaryColor, linkColor: theme.accentColor)
|
||||
let attributedAgreeText = parseMarkdownIntoAttributedString(
|
||||
self.strings.WebApp_DisclaimerAgree,
|
||||
attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: textFont, textColor: theme.primaryColor),
|
||||
bold: MarkdownAttributeSet(font: boldTextFont, textColor: theme.primaryColor),
|
||||
link: MarkdownAttributeSet(font: textFont, textColor: theme.accentColor),
|
||||
linkAttribute: { contents in
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
self.acceptTermsLabelNode.attributedText = attributedAgreeText
|
||||
self.acceptTermsLabelNode.linkHighlightColor = theme.accentColor.withAlphaComponent(0.2)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
@ -163,7 +221,7 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
|
||||
var entriesHeight: CGFloat = 0.0
|
||||
|
||||
let textSize = self.textNode.measure(CGSize(width: size.width - 48.0, height: size.height))
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: size.width - 48.0, height: size.height))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
|
||||
origin.y += textSize.height
|
||||
|
||||
@ -175,7 +233,7 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
let condensedSize = CGSize(width: size.width - 76.0, height: size.height)
|
||||
|
||||
let spacing: CGFloat = 12.0
|
||||
let acceptTermsSize = self.acceptTermsLabelNode.measure(condensedSize)
|
||||
let acceptTermsSize = self.acceptTermsLabelNode.updateLayout(condensedSize)
|
||||
let acceptTermsTotalWidth = checkSize.width + spacing + acceptTermsSize.width
|
||||
let acceptTermsOriginX = floorToScreenPixels((size.width - acceptTermsTotalWidth) / 2.0)
|
||||
|
||||
@ -267,7 +325,13 @@ private final class WebAppTermsAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func webAppTermsAlertController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peer: EnginePeer, completion: @escaping () -> Void) -> AlertController {
|
||||
public func webAppTermsAlertController(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?,
|
||||
peer: EnginePeer,
|
||||
requestWriteAccess: Bool,
|
||||
completion: @escaping (Bool) -> Void
|
||||
) -> AlertController {
|
||||
let theme = defaultDarkColorPresentationTheme
|
||||
let presentationData: PresentationData
|
||||
if let updatedPresentationData {
|
||||
@ -278,18 +342,21 @@ public func webAppTermsAlertController(context: AccountContext, updatedPresentat
|
||||
let strings = presentationData.strings
|
||||
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: "Continue", action: {
|
||||
completion()
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .defaultAction, title: presentationData.strings.WebApp_DisclaimerContinue, action: {
|
||||
completion(false)
|
||||
dismissImpl?(true)
|
||||
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
})]
|
||||
|
||||
let title = "Warning"
|
||||
let text = "You are about to use a mini app operated by an independent party not affiliated with Telegram. You must agree to the Terms of Use of mini apps to continue."
|
||||
let title = presentationData.strings.WebApp_DisclaimerTitle
|
||||
let text = presentationData.strings.WebApp_DisclaimerText
|
||||
|
||||
let contentNode = WebAppTermsAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, title: title, text: text, actions: actions)
|
||||
|
||||
contentNode.openTerms = {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.WebApp_Disclaimer_URL, forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {
|
||||
})
|
||||
}
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||
dismissImpl = { [weak controller] animated in
|
||||
if animated {
|
||||
|
@ -88,9 +88,9 @@ final class WebAppWebView: WKWebView {
|
||||
return point.x > 30.0
|
||||
}
|
||||
self.allowsBackForwardNavigationGestures = false
|
||||
if #available(iOS 16.4, *) {
|
||||
self.isInspectable = true
|
||||
}
|
||||
// if #available(iOS 16.4, *) {
|
||||
// self.isInspectable = true
|
||||
// }
|
||||
|
||||
handleScriptMessageImpl = { [weak self] message in
|
||||
if let strongSelf = self {
|
||||
|
Loading…
x
Reference in New Issue
Block a user