mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 13:35:19 +00:00
Various improvements
This commit is contained in:
parent
8fdcb91bbc
commit
d0156faede
@ -1045,6 +1045,8 @@ public protocol ChatController: ViewController {
|
||||
func updateIsScrollingLockedAtTop(isScrollingLockedAtTop: Bool)
|
||||
|
||||
func playShakeAnimation()
|
||||
|
||||
func removeAd(opaqueId: Data)
|
||||
}
|
||||
|
||||
public protocol ChatMessagePreviewItemNode: AnyObject {
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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 })
|
||||
|
@ -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",
|
||||
|
@ -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()
|
||||
})
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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? {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 })
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user