mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Bot ads improvements
This commit is contained in:
parent
30e4041149
commit
193699c7fd
@ -13138,7 +13138,7 @@ Sorry for the inconvenience.";
|
||||
"AttachmentMenu.AddDocument" = "Add Document";
|
||||
|
||||
"Chat.BotAd.Title" = "Ad";
|
||||
"Chat.BotAd.Remove" = "remove";
|
||||
"Chat.BotAd.WhatIsThis" = "what's this?";
|
||||
|
||||
"ChatList.Search.TopAppsInfo" = "Which apps are included here? [Learn >]()";
|
||||
|
||||
|
@ -29,6 +29,9 @@ swift_library(
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
"//submodules/PresentationDataUtils",
|
||||
"//submodules/ContextUI",
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/TelegramUI/Components/Ads/AdsReportScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -124,6 +124,39 @@ final class GiftOptionsScreenComponent: Component {
|
||||
private let tabSelector = ComponentView<Empty>()
|
||||
private var starsFilter: StarsFilter = .all
|
||||
|
||||
private var _effectiveStarGifts: ([StarGift], StarsFilter)?
|
||||
private var effectiveStarGifts: [StarGift]? {
|
||||
get {
|
||||
if case .all = self.starsFilter {
|
||||
return self.state?.starGifts
|
||||
} else {
|
||||
if let (currentGifts, currentFilter) = self._effectiveStarGifts, currentFilter == self.starsFilter {
|
||||
return currentGifts
|
||||
} else if let allGifts = self.state?.starGifts {
|
||||
let filteredGifts: [StarGift] = allGifts.filter {
|
||||
switch self.starsFilter {
|
||||
case .all:
|
||||
return true
|
||||
case .limited:
|
||||
if $0.availability != nil {
|
||||
return true
|
||||
}
|
||||
case let .stars(stars):
|
||||
if $0.price == stars {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
self._effectiveStarGifts = (filteredGifts, self.starsFilter)
|
||||
return filteredGifts
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var isUpdating: Bool = false
|
||||
|
||||
private var starsStateDisposable: Disposable?
|
||||
@ -243,7 +276,7 @@ final class GiftOptionsScreenComponent: Component {
|
||||
}
|
||||
|
||||
let visibleBounds = self.scrollView.bounds.insetBy(dx: 0.0, dy: -10.0)
|
||||
if let starGifts = self.state?.starGifts {
|
||||
if let starGifts = self.effectiveStarGifts {
|
||||
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
||||
|
||||
let optionSpacing: CGFloat = 10.0
|
||||
@ -262,19 +295,6 @@ final class GiftOptionsScreenComponent: Component {
|
||||
}
|
||||
|
||||
if isVisible {
|
||||
switch self.starsFilter {
|
||||
case .all:
|
||||
break
|
||||
case .limited:
|
||||
if gift.availability == nil {
|
||||
continue
|
||||
}
|
||||
case let .stars(stars):
|
||||
if gift.price != stars {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let itemId = AnyHashable(gift.id)
|
||||
validIds.append(itemId)
|
||||
|
||||
@ -898,9 +918,9 @@ final class GiftOptionsScreenComponent: Component {
|
||||
contentHeight += tabSelectorSize.height
|
||||
contentHeight += 19.0
|
||||
|
||||
if let starGifts = state.starGifts {
|
||||
if let starGifts = self.effectiveStarGifts {
|
||||
self.starsItemsOrigin = contentHeight
|
||||
|
||||
|
||||
let starsOptionSize = CGSize(width: optionWidth, height: 154.0)
|
||||
contentHeight += ceil(CGFloat(starGifts.count) / 3.0) * starsOptionSize.height
|
||||
contentHeight += 66.0
|
||||
|
@ -198,10 +198,10 @@ final class ChatAdPanelNode: ASDisplayNode {
|
||||
self.theme = interfaceState.theme
|
||||
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
|
||||
self.removeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 15.0, color: interfaceState.theme.chat.inputPanel.panelControlAccentColor.withMultipliedAlpha(0.1))
|
||||
self.removeTextNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_BotAd_Remove, font: Font.regular(11.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
|
||||
self.removeTextNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_BotAd_WhatIsThis, font: Font.regular(11.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
|
||||
}
|
||||
|
||||
self.contextContainer.isGestureEnabled = true
|
||||
self.contextContainer.isGestureEnabled = false
|
||||
|
||||
let panelHeight: CGFloat
|
||||
if let message = interfaceState.adMessage {
|
||||
|
@ -3963,189 +3963,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId, media: media, fullscreen: fullscreen)
|
||||
self.controllerInteraction?.openUrl(ChatControllerInteraction.OpenUrl(url: adAttribute.url, concealed: false, external: true, progress: progress))
|
||||
}, adContextAction: { [weak self] message, sourceNode, gesture in
|
||||
guard let self, let adAttribute = message.adAttribute else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let controllerInteraction = self.controllerInteraction
|
||||
let chatPresentationInterfaceState = self.presentationInterfaceState
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var actions: [ContextMenuItem] = []
|
||||
if adAttribute.sponsorInfo != nil || adAttribute.additionalInfo != nil {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfo, textColor: .primary, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Channels"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { c, _ in
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, textColor: .primary, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, iconPosition: .left, action: { c, _ in
|
||||
c?.popItems()
|
||||
})))
|
||||
|
||||
subItems.append(.separator)
|
||||
|
||||
if let sponsorInfo = adAttribute.sponsorInfo {
|
||||
subItems.append(.action(ContextMenuActionItem(text: sponsorInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
UIPasteboard.general.string = sponsorInfo
|
||||
|
||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied)
|
||||
controllerInteraction?.displayUndo(content)
|
||||
})
|
||||
})))
|
||||
}
|
||||
if let additionalInfo = adAttribute.additionalInfo {
|
||||
subItems.append(.action(ContextMenuActionItem(text: additionalInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
UIPasteboard.general.string = additionalInfo
|
||||
|
||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied)
|
||||
controllerInteraction?.displayUndo(content)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
actions.append(.separator)
|
||||
var isBot = false
|
||||
if let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
||||
isBot = true
|
||||
}
|
||||
|
||||
if adAttribute.canReport {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AboutAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
var isBot = false
|
||||
if let self, let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
||||
isBot = true
|
||||
}
|
||||
self?.effectiveNavigationController?.pushViewController(AdsInfoScreen(context: context, mode: isBot ? .bot : .channel))
|
||||
})))
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_ReportAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if case let .options(title, options) = result {
|
||||
self?.effectiveNavigationController?.pushViewController(
|
||||
AdsReportScreen(
|
||||
context: context,
|
||||
peerId: message.id.peerId,
|
||||
opaqueId: adAttribute.opaqueId,
|
||||
title: title,
|
||||
options: options,
|
||||
completed: { [weak self] in
|
||||
self?.removeAd(opaqueId: adAttribute.opaqueId)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
})))
|
||||
|
||||
actions.append(.separator)
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_RemoveAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
controllerInteraction?.openNoAdsDemo()
|
||||
})
|
||||
})))
|
||||
} else {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Info, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
self?.effectiveNavigationController?.pushViewController(AdInfoScreen(context: context, forceDark: true))
|
||||
})))
|
||||
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
if !chatPresentationInterfaceState.isPremium && !premiumConfiguration.isPremiumDisabled {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Hide, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { [weak self] c, _ in
|
||||
c?.dismiss(completion: {
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: false, action: {
|
||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: false, dismissed: nil)
|
||||
replaceImpl?(controller)
|
||||
}, dismissed: nil)
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
self?.effectiveNavigationController?.pushViewController(controller)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
actions.append(.separator)
|
||||
|
||||
if chatPresentationInterfaceState.copyProtectionEnabled {
|
||||
} else {
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuCopy, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak controllerInteraction] _, f in
|
||||
var messageEntities: [MessageTextEntity]?
|
||||
var restrictedText: String?
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||
messageEntities = attribute.entities
|
||||
}
|
||||
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
||||
restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
if let restrictedText = restrictedText {
|
||||
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
||||
} else {
|
||||
if let translationState = chatPresentationInterfaceState.translationState, translationState.isEnabled,
|
||||
let translation = message.attributes.first(where: { ($0 as? TranslationMessageAttribute)?.toLang == translationState.toLang }) as? TranslationMessageAttribute, !translation.text.isEmpty {
|
||||
storeMessageTextInPasteboard(translation.text, entities: translation.entities)
|
||||
} else {
|
||||
storeMessageTextInPasteboard(message.text, entities: messageEntities)
|
||||
}
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.2, {
|
||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_MessageCopied)
|
||||
controllerInteraction?.displayUndo(content)
|
||||
})
|
||||
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
if let author = message.author, let addressName = author.addressName {
|
||||
let link = "https://t.me/\(addressName)"
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak controllerInteraction] _, f in
|
||||
UIPasteboard.general.string = link
|
||||
|
||||
Queue.mainQueue().after(0.2, {
|
||||
controllerInteraction?.displayUndo(.linkCopied(text: presentationData.strings.Conversation_LinkCopied))
|
||||
})
|
||||
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
let controller = AdsInfoScreen(
|
||||
context: context,
|
||||
mode: isBot ? .bot : .channel,
|
||||
message: message
|
||||
)
|
||||
controller.removeAd = { [weak self] opaqueId in
|
||||
self?.removeAd(opaqueId: opaqueId)
|
||||
}
|
||||
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: self, sourceView: sourceNode.view, insets: .zero, contentInsets: .zero)), items: .single(ContextController.Items(content: .list(actions))), gesture: gesture)
|
||||
self.presentInGlobalOverlay(contextController)
|
||||
self.effectiveNavigationController?.pushViewController(controller)
|
||||
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in
|
||||
guard let self else {
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user