Various improvements

This commit is contained in:
Ilya Laktyushin 2024-08-10 18:41:17 +02:00
parent 8fdcb91bbc
commit d0156faede
19 changed files with 248 additions and 100 deletions

View File

@ -1045,6 +1045,8 @@ public protocol ChatController: ViewController {
func updateIsScrollingLockedAtTop(isScrollingLockedAtTop: Bool)
func playShakeAnimation()
func removeAd(opaqueId: Data)
}
public protocol ChatMessagePreviewItemNode: AnyObject {

View File

@ -17,18 +17,32 @@ public final class GalleryControllerActionInteraction {
public let openPeer: (EnginePeer) -> Void
public let openHashtag: (String?, String) -> Void
public let openBotCommand: (String) -> Void
public let openAd: (MessageId) -> Void
public let addContact: (String) -> Void
public let storeMediaPlaybackState: (MessageId, Double?, Double) -> Void
public let editMedia: (MessageId, [UIView], @escaping () -> Void) -> Void
public let updateCanReadHistory: (Bool) -> Void
public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (EnginePeer) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void, editMedia: @escaping (MessageId, [UIView], @escaping () -> Void) -> Void, updateCanReadHistory: @escaping (Bool) -> Void) {
public init(
openUrl: @escaping (String, Bool) -> Void,
openUrlIn: @escaping (String) -> Void,
openPeerMention: @escaping (String) -> Void,
openPeer: @escaping (EnginePeer) -> Void,
openHashtag: @escaping (String?, String) -> Void,
openBotCommand: @escaping (String) -> Void,
openAd: @escaping (MessageId) -> Void,
addContact: @escaping (String) -> Void,
storeMediaPlaybackState: @escaping (MessageId, Double?, Double) -> Void,
editMedia: @escaping (MessageId, [UIView], @escaping () -> Void) -> Void,
updateCanReadHistory: @escaping (Bool) -> Void)
{
self.openUrl = openUrl
self.openUrlIn = openUrlIn
self.openPeerMention = openPeerMention
self.openPeer = openPeer
self.openHashtag = openHashtag
self.openBotCommand = openBotCommand
self.openAd = openAd
self.addContact = addContact
self.storeMediaPlaybackState = storeMediaPlaybackState
self.editMedia = editMedia

View File

@ -69,7 +69,7 @@ public final class AdInfoScreen: ViewController {
self.controller = controller
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = controller.presentationData
self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1
@ -211,11 +211,16 @@ public final class AdInfoScreen: ViewController {
}
private let context: AccountContext
private var presentationData: PresentationData
fileprivate var presentationData: PresentationData
public init(context: AccountContext) {
public init(context: AccountContext, forceDark: Bool = false) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
var presentationData = context.sharedContext.currentPresentationData.with { $0 }
if forceDark {
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
}
self.presentationData = presentationData
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))

View File

@ -18,7 +18,7 @@ public enum PresentationContextType {
public final class PresentationContext {
private var _view: UIView?
var view: UIView? {
public var view: UIView? {
get {
return self._view
} set(value) {
@ -123,6 +123,9 @@ public final class PresentationContext {
return (containerLayout, CGRect(origin: CGPoint(), size: containerLayout.size))
}
public init() {
}
public func present(_ controller: ContainableController, on level: PresentationSurfaceLevel, blockInteraction: Bool = false, completion: @escaping () -> Void) {
let controllerReady = controller.ready.get()
|> filter({ $0 })

View File

@ -49,6 +49,9 @@ swift_library(
"//submodules/TooltipUI",
"//submodules/TelegramNotices",
"//submodules/Pasteboard",
"//submodules/AdUI",
"//submodules/TelegramUI/Components/Ads/AdsInfoScreen",
"//submodules/TelegramUI/Components/Ads/AdsReportScreen",
],
visibility = [
"//visibility:public",

View File

@ -29,6 +29,7 @@ import Pasteboard
import Speak
import TranslateUI
import TelegramNotices
import SolidRoundedButtonNode
private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white)
private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: .white)
@ -145,6 +146,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
private let textNode: ImmediateTextNodeWithEntities
private var spoilerTextNode: ImmediateTextNodeWithEntities?
private var dustNode: InvisibleInkDustNode?
private var buttonNode: SolidRoundedButtonNode?
private var textSelectionNode: TextSelectionNode?
@ -164,7 +166,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
private var currentMessageText: NSAttributedString?
private var currentAuthorNameText: String?
private var currentDateText: String?
private var currentMessage: Message?
private var currentWebPageAndMedia: (TelegramMediaWebpage, Media)?
private let messageContextDisposable = MetaDisposable()
@ -193,6 +195,13 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
var performAction: ((GalleryControllerInteractionTapAction) -> Void)?
var openActionOptions: ((GalleryControllerInteractionTapAction, Message) -> Void)?
private var isAd: Bool {
if self.currentMessage?.adAttribute != nil {
return true
}
return false
}
var content: ChatItemGalleryFooterContent = .info {
didSet {
if self.content != oldValue {
@ -208,8 +217,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
self.currentIsPaused = true
self.authorNameNode.isHidden = true
self.dateNode.isHidden = true
self.hasSeekControls = seekable
if status == .Local {
self.hasSeekControls = seekable && !self.isAd
if status == .Local && !self.isAd {
self.playbackControlButton.isHidden = false
self.playPauseIconNode.enqueueState(.play, animated: true)
} else {
@ -236,16 +246,20 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
self.currentIsPaused = paused
self.authorNameNode.isHidden = true
self.dateNode.isHidden = true
self.hasSeekControls = seekable
self.playbackControlButton.isHidden = false
let icon: PlayPauseIconNodeState
if let wasPlaying = self.wasPlaying {
icon = wasPlaying ? .pause : .play
if !self.isAd {
self.playbackControlButton.isHidden = false
let icon: PlayPauseIconNodeState
if let wasPlaying = self.wasPlaying {
icon = wasPlaying ? .pause : .play
} else {
icon = paused ? .play : .pause
}
self.playPauseIconNode.enqueueState(icon, animated: true)
self.hasSeekControls = seekable
} else {
icon = paused ? .play : .pause
self.hasSeekControls = false
}
self.playPauseIconNode.enqueueState(icon, animated: true)
self.statusButtonNode.isHidden = true
self.statusNode.isHidden = true
}
@ -829,15 +843,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
if Namespaces.Message.allNonRegular.contains(message.id.namespace) || message.timestamp == 0 {
displayInfo = false
}
if let _ = message.adAttribute {
displayInfo = false
}
var canFullscreen = false
var canDelete: Bool
var canShare = !message.containsSecretMedia && !Namespaces.Message.allNonRegular.contains(message.id.namespace) && message.adAttribute == nil
var canFullscreen = false
var canEdit = false
var isImage = false
var isVideo = false
@ -924,6 +933,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
canDelete = false
}
if let _ = message.adAttribute {
displayInfo = false
canFullscreen = false
}
var authorNameText: String?
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature {
authorNameText = authorSignature
@ -1044,6 +1058,22 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
self.actionButton.isHidden = !canShare
self.editButton.isHidden = !canEdit
if let adAttribute = message.adAttribute {
if self.buttonNode == nil {
let buttonNode = SolidRoundedButtonNode(title: adAttribute.buttonText, theme: SolidRoundedButtonTheme(backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.15), foregroundColor: UIColor(rgb: 0xffffff)), height: 50.0, cornerRadius: 11.0)
buttonNode.pressed = { [weak self] in
guard let self else {
return
}
self.performAction?(.ad(message.id))
}
self.contentNode.addSubnode(buttonNode)
self.buttonNode = buttonNode
}
} else if let buttonNode = self.buttonNode {
buttonNode.removeFromSupernode()
}
self.requestLayout?(.immediate)
}
}
@ -1192,6 +1222,17 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
self.scrollWrapperNode.layer.mask?.frame = self.scrollWrapperNode.bounds
self.scrollWrapperNode.layer.mask?.removeAllAnimations()
}
if let buttonNode = self.buttonNode {
let buttonHeight = buttonNode.updateLayout(width: constrainSize.width, transition: transition)
transition.updateFrame(node: buttonNode, frame: CGRect(origin: CGPoint(x: sideInset, y: scrollWrapperNodeFrame.maxY + 8.0), size: CGSize(width: constrainSize.width, height: buttonHeight)))
if let _ = self.scrubberView {
panelHeight += 68.0
} else {
panelHeight += 22.0
}
}
}
textFrame = CGRect(origin: CGPoint(x: sideInset, y: topInset + textOffset), size: textSize)
@ -1227,6 +1268,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
}
}
if let _ = self.buttonNode {
panelHeight -= 44.0
}
let scrubberFrame = CGRect(origin: CGPoint(x: leftInset, y: scrubberY), size: CGSize(width: width - leftInset - rightInset, height: 34.0))
scrubberView.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
transition.updateBounds(layer: scrubberView.layer, bounds: CGRect(origin: CGPoint(), size: scrubberFrame.size))
@ -1325,6 +1370,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
self.forwardButton.alpha = self.hasSeekControls ? 1.0 : 0.0
self.statusNode.alpha = 1.0
self.playbackControlButton.alpha = 1.0
self.buttonNode?.alpha = 1.0
self.scrollWrapperNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
}
@ -1349,6 +1395,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
self.forwardButton.alpha = 0.0
self.statusNode.alpha = 0.0
self.playbackControlButton.alpha = 0.0
self.buttonNode?.alpha = 0.0
self.scrollWrapperNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, completion: { _ in
completion()
})

View File

@ -487,6 +487,7 @@ public enum GalleryControllerInteractionTapAction {
case botCommand(String)
case hashtag(String?, String)
case timecode(Double, String)
case ad(MessageId)
}
public enum GalleryControllerItemNodeAction {
@ -962,6 +963,8 @@ public class GalleryController: ViewController, StandalonePresentableController,
strongSelf.actionInteraction?.openHashtag(peerName, hashtag)
case let .timecode(timecode, _):
strongSelf.galleryNode.pager.centralItemNode()?.processAction(.timecode(timecode))
case let .ad(messageId):
strongSelf.actionInteraction?.openAd(messageId)
}
}
}
@ -1217,6 +1220,8 @@ public class GalleryController: ViewController, StandalonePresentableController,
])
])
strongSelf.present(actionSheet, in: .window(.root))
case .ad:
break
}
}
}

View File

@ -22,6 +22,9 @@ import UndoUI
import ContextUI
import SaveToCameraRoll
import Pasteboard
import AdUI
import AdsInfoScreen
import AdsReportScreen
enum ChatMediaGalleryThumbnail: Equatable {
case image(ImageMediaReference)
@ -545,40 +548,38 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
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: { _, f in
}, iconSource: nil, action: { [weak self] _, f in
f(.dismissWithoutContent)
// controllerInteraction.navigationController()?.pushViewController(AdsInfoScreen(context: context))
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(AdsInfoScreen(context: context))
}
})))
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: { _, f in
}, 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: { result in
|> deliverOnMainQueue).start(next: { [weak self] result in
if case let .options(title, options) = result {
let _ = title
let _ = options
// controllerInteraction.navigationController()?.pushViewController(
// AdsReportScreen(
// context: context,
// peerId: message.id.peerId,
// opaqueId: adAttribute.opaqueId,
// title: title,
// options: options,
// completed: { [weak interfaceInteraction] in
// guard let interfaceInteraction else {
// return
// }
// guard let chatController = interfaceInteraction.chatController() as? ChatControllerImpl else {
// return
// }
// chatController.removeAd(opaqueId: adAttribute.opaqueId)
// }
// )
// )
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(
AdsReportScreen(
context: context,
peerId: message.id.peerId,
opaqueId: adAttribute.opaqueId,
title: title,
options: options,
forceDark: true,
completed: {
if let navigationController = self?.baseNavigationController() as? NavigationController, let chatController = navigationController.viewControllers.last as? ChatController {
chatController.removeAd(opaqueId: adAttribute.opaqueId)
}
}
)
)
}
}
})
})))
@ -587,40 +588,53 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
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: { c, _ in
}, iconSource: nil, action: { [weak self] c, _ in
c?.dismiss(completion: {
// controllerInteraction.openNoAdsDemo()
var replaceImpl: ((ViewController) -> Void)?
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: true, action: {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: true, dismissed: nil)
replaceImpl?(controller)
}, dismissed: nil)
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(controller)
}
})
})))
} 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: { _, f in
}, iconSource: nil, action: { [weak self] _, f in
f(.dismissWithoutContent)
// controllerInteraction.navigationController()?.pushViewController(AdInfoScreen(context: context))
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(AdInfoScreen(context: context, forceDark: true))
}
})))
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
if !context.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: { c, _ in
}, 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)
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: true, action: {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: true, dismissed: nil)
replaceImpl?(controller)
}, dismissed: nil)
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
// controllerInteraction.navigationController()?.pushViewController(controller)
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(controller)
}
})
})))
}
if !message.text.isEmpty {
actions.append(.separator)
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)

View File

@ -24,6 +24,9 @@ import AVKit
import TextFormat
import SliderContextItem
import Pasteboard
import AdUI
import AdsInfoScreen
import AdsReportScreen
public enum UniversalVideoGalleryItemContentInfo {
case message(Message, Int?)
@ -1477,7 +1480,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let _ = message.paidContent, message.id.namespace == Namespaces.Message.Local {
hasMoreButton = false
}
if let _ = message.adAttribute {
hasMoreButton = true
}
if hasMoreButton {
let moreMenuItem = UIBarButtonItem(customDisplayNode: self.moreBarButton)!
moreMenuItem.accessibilityLabel = self.presentationData.strings.Common_More
@ -2527,40 +2534,38 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
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: { _, f in
}, iconSource: nil, action: { [weak self] _, f in
f(.dismissWithoutContent)
// controllerInteraction.navigationController()?.pushViewController(AdsInfoScreen(context: context))
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(AdsInfoScreen(context: context, forceDark: true))
}
})))
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: { _, f in
}, 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: { result in
|> deliverOnMainQueue).start(next: { [weak self] result in
if case let .options(title, options) = result {
let _ = title
let _ = options
// controllerInteraction.navigationController()?.pushViewController(
// AdsReportScreen(
// context: context,
// peerId: message.id.peerId,
// opaqueId: adAttribute.opaqueId,
// title: title,
// options: options,
// completed: { [weak interfaceInteraction] in
// guard let interfaceInteraction else {
// return
// }
// guard let chatController = interfaceInteraction.chatController() as? ChatControllerImpl else {
// return
// }
// chatController.removeAd(opaqueId: adAttribute.opaqueId)
// }
// )
// )
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(
AdsReportScreen(
context: context,
peerId: message.id.peerId,
opaqueId: adAttribute.opaqueId,
title: title,
options: options,
forceDark: true,
completed: {
if let navigationController = self?.baseNavigationController() as? NavigationController, let chatController = navigationController.viewControllers.last as? ChatController {
chatController.removeAd(opaqueId: adAttribute.opaqueId)
}
}
)
)
}
}
})
})))
@ -2569,34 +2574,48 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
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: { c, _ in
}, iconSource: nil, action: { [weak self] c, _ in
c?.dismiss(completion: {
// controllerInteraction.openNoAdsDemo()
var replaceImpl: ((ViewController) -> Void)?
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: true, action: {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: true, dismissed: nil)
replaceImpl?(controller)
}, dismissed: nil)
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(controller)
}
})
})))
} 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: { _, f in
}, iconSource: nil, action: { [weak self] _, f in
f(.dismissWithoutContent)
// controllerInteraction.navigationController()?.pushViewController(AdInfoScreen(context: context))
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(AdInfoScreen(context: context, forceDark: true))
}
})))
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
if !context.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: { c, _ in
}, 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)
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: true, action: {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: true, dismissed: nil)
replaceImpl?(controller)
}, dismissed: nil)
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
// controllerInteraction.navigationController()?.pushViewController(controller)
if let navigationController = self?.baseNavigationController() as? NavigationController {
navigationController.pushViewController(controller)
}
})
})))
}

View File

@ -488,7 +488,8 @@ public final class AdsInfoScreen: ViewControllerComponentContainer {
private let context: AccountContext
public init(
context: AccountContext
context: AccountContext,
forceDark: Bool = false
) {
self.context = context
@ -503,7 +504,7 @@ public final class AdsInfoScreen: ViewControllerComponentContainer {
),
navigationBarAppearance: .none,
statusBarStyle: .ignore,
theme: .default
theme: forceDark ? .dark : .default
)
self.navigationPresentation = .modal

View File

@ -573,6 +573,7 @@ public final class AdsReportScreen: ViewControllerComponentContainer {
opaqueId: Data,
title: String,
options: [ReportAdMessageResult.Option],
forceDark: Bool = false,
completed: @escaping () -> Void
) {
self.context = context
@ -593,7 +594,7 @@ public final class AdsReportScreen: ViewControllerComponentContainer {
),
navigationBarAppearance: .none,
statusBarStyle: .ignore,
theme: .default
theme: forceDark ? .dark : .default
)
self.navigationPresentation = .flatModal

View File

@ -5957,7 +5957,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
override public func makeProgress() -> Promise<Bool>? {
return self.unlockButtonNode?.makeProgress()
if let unlockButtonNode = self.unlockButtonNode {
return unlockButtonNode.makeProgress()
} else {
for contentNode in self.contentNodes {
if let webpageContentNode = contentNode as? ChatMessageWebpageBubbleContentNode {
return webpageContentNode.contentNode.makeProgress()
}
}
}
return nil
}
override public func targetReactionView(value: MessageReaction.Reaction) -> UIView? {

View File

@ -5113,6 +5113,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
strongSelf.openHashtag(hashtag, peerName: peerName)
}
}, openBotCommand: { _ in
}, openAd: { _ in
}, addContact: { [weak self] phoneNumber in
if let strongSelf = self {
strongSelf.context.sharedContext.openAddContact(context: strongSelf.context, firstName: "", lastName: "", phoneNumber: phoneNumber, label: defaultContactLabel, present: { [weak self] controller, arguments in

View File

@ -2805,6 +2805,7 @@ final class StorageUsageScreenComponent: Component {
}
let _ = self
}, openBotCommand: { _ in
}, openAd: { _ in
}, addContact: { _ in
}, storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in
guard let self else {

View File

@ -294,6 +294,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let galleryHiddenMesageAndMediaDisposable = MetaDisposable()
let temporaryHiddenGalleryMediaDisposable = MetaDisposable()
let galleryPresentationContext = PresentationContext()
let chatBackgroundNode: WallpaperBackgroundNode
public private(set) var controllerInteraction: ChatControllerInteraction?
@ -1274,7 +1276,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, updatedPresentationData: strongSelf.updatedPresentationData, chatLocation: openChatLocation, chatFilterTag: chatFilterTag, chatLocationContextHolder: strongSelf.chatLocationContextHolder, message: message, mediaIndex: params.mediaIndex, standalone: standalone, reverseMessageGalleryOrder: false, mode: mode, navigationController: strongSelf.effectiveNavigationController, dismissInput: {
self?.chatDisplayNode.dismissInput()
}, present: { c, a in
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
if c is GalleryController {
c.presentationArguments = a
self?.galleryPresentationContext.present(c, on: PresentationSurfaceLevel(rawValue: 0), blockInteraction: true, completion: {})
} else {
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
}
}, transitionNode: { messageId, media, adjustRect in
var selectedNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
if let strongSelf = self {
@ -1369,6 +1376,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self {
strongSelf.controllerInteraction?.sendBotCommand(nil, command)
}
}, openAd: { [weak self] messageId in
if let strongSelf = self {
strongSelf.controllerInteraction?.activateAdAction(messageId, nil)
}
}, addContact: { [weak self] phoneNumber in
if let strongSelf = self {
strongSelf.controllerInteraction?.addContact(phoneNumber)
@ -3857,6 +3868,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let self, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId), let adAttribute = message.adAttribute else {
return
}
var progress = progress
if progress == nil {
self.chatDisplayNode.historyNode.forEachVisibleMessageItemNode { itemView in
if itemView.item?.message.id == messageId {
progress = itemView.makeProgress()
}
}
}
self.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId)
self.controllerInteraction?.openUrl(ChatControllerInteraction.OpenUrl(url: adAttribute.url, concealed: false, external: true, progress: progress))
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in
@ -7178,6 +7199,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
override public func loadDisplayNode() {
self.loadDisplayNodeImpl()
self.galleryPresentationContext.view = self.view
}
override public func viewWillAppear(_ animated: Bool) {

View File

@ -218,7 +218,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
private var didInitializeInputMediaNodeDataPromise: Bool = false
private var inputMediaNodeDataDisposable: Disposable?
private var inputMediaNodeStateContext = ChatEntityKeyboardInputNode.StateContext()
let navigateButtons: ChatHistoryNavigationButtons
private var ignoreUpdateHeight = false
@ -2058,6 +2058,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
childrenLayout.intrinsicInsets = UIEdgeInsets(top: listInsets.top, left: listInsets.left, bottom: listInsets.bottom, right: listInsets.right)
}
self.controller?.presentationContext.containerLayoutUpdated(childrenLayout, transition: transition)
self.controller?.galleryPresentationContext.containerLayoutUpdated(layout, transition: transition)
listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, scrollIndicatorInsets: listScrollIndicatorInsets, duration: duration, curve: curve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems), additionalScrollDistance, scrollToTop, { [weak self] in
if let strongSelf = self {

View File

@ -9,7 +9,7 @@ import TelegramPresentationData
import PresentationDataUtils
import ChatMessageItemView
extension ChatControllerImpl {
public extension ChatControllerImpl {
func removeAd(opaqueId: Data) {
var foundItemNode: ChatMessageItemView?
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in

View File

@ -594,7 +594,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
}, iconSource: nil, action: { _, f in
f(.dismissWithoutContent)
controllerInteraction.navigationController()?.pushViewController(AdInfoScreen(context: context))
controllerInteraction.navigationController()?.pushViewController(AdInfoScreen(context: context, forceDark: true))
})))
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })

View File

@ -2156,7 +2156,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
return controller
default:
return PremiumDemoScreen(context: context, subject: mappedSubject, action: action)
return PremiumDemoScreen(context: context, subject: mappedSubject, forceDark: forceDark, action: action)
}
}