mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Bot ad improvements
This commit is contained in:
parent
11d7bb1ab8
commit
ec9d5fde63
@ -149,6 +149,7 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
@ -634,6 +634,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
|
|
||||||
override public func searchTextUpdated(text: String) {
|
override public func searchTextUpdated(text: String) {
|
||||||
let searchQuery: String? = !text.isEmpty ? text : nil
|
let searchQuery: String? = !text.isEmpty ? text : nil
|
||||||
|
|
||||||
|
if !text.hasPrefix("#") && self.paneContainerNode.currentPaneKey == .publicPosts {
|
||||||
|
self.paneContainerNode.requestSelectPane(.chats)
|
||||||
|
}
|
||||||
|
|
||||||
self.searchQuery.set(.single(searchQuery))
|
self.searchQuery.set(.single(searchQuery))
|
||||||
self.searchQueryValue = searchQuery
|
self.searchQueryValue = searchQuery
|
||||||
|
|
||||||
|
@ -1340,6 +1340,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
private var searchQueryValue: String?
|
private var searchQueryValue: String?
|
||||||
private var searchOptionsValue: ChatListSearchOptions?
|
private var searchOptionsValue: ChatListSearchOptions?
|
||||||
|
|
||||||
|
var isCurrent: Bool = false
|
||||||
|
|
||||||
private let _isSearching = ValuePromise<Bool>(false, ignoreRepeated: true)
|
private let _isSearching = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
public var isSearching: Signal<Bool, NoError> {
|
public var isSearching: Signal<Bool, NoError> {
|
||||||
return self._isSearching.get()
|
return self._isSearching.get()
|
||||||
@ -2188,12 +2190,53 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
|
|
||||||
let foundPublicMessages: Signal<([FoundRemoteMessages], Bool), NoError>
|
let foundPublicMessages: Signal<([FoundRemoteMessages], Bool), NoError>
|
||||||
if key == .chats || key == .publicPosts, let query, query.hasPrefix("#") {
|
if key == .chats || key == .publicPosts, let query, query.hasPrefix("#") {
|
||||||
let searchSignal = context.engine.messages.searchHashtagPosts(hashtag: finalQuery, state: nil, limit: 50)
|
let searchSignal = context.engine.messages.searchHashtagPosts(hashtag: finalQuery, state: nil, limit: 10)
|
||||||
|
|
||||||
|
let loadMore: Signal<([FoundRemoteMessages], Bool), NoError>
|
||||||
|
if key == .publicPosts {
|
||||||
|
loadMore = searchContexts.get()
|
||||||
|
|> mapToSignal { searchContexts -> Signal<([FoundRemoteMessages], Bool), NoError> in
|
||||||
|
let i = 0
|
||||||
|
if let searchContext = searchContexts[i], searchContext.result.hasMore {
|
||||||
|
if let _ = searchContext.loadMoreIndex {
|
||||||
|
return context.engine.messages.searchHashtagPosts(hashtag: finalQuery, state: searchContext.result.state, limit: 80)
|
||||||
|
|> map { result, updatedState -> ChatListSearchMessagesResult in
|
||||||
|
return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.map({ EngineMessage($0) }).sorted(by: { $0.index > $1.index }), readStates: result.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadInfo: result.threadInfo, hasMore: !result.completed, totalCount: result.totalCount, state: updatedState)
|
||||||
|
}
|
||||||
|
|> mapToSignal { foundMessages -> Signal<([FoundRemoteMessages], Bool), NoError> in
|
||||||
|
updateSearchContexts { previous in
|
||||||
|
let updated = ChatListSearchMessagesContext(result: foundMessages, loadMoreIndex: nil)
|
||||||
|
var previous = previous
|
||||||
|
previous[i] = updated
|
||||||
|
return (previous, true)
|
||||||
|
}
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var currentResults: [FoundRemoteMessages] = []
|
||||||
|
if let currentContext = searchContexts[i] {
|
||||||
|
currentResults.append(FoundRemoteMessages(messages: currentContext.result.messages, readCounters: currentContext.result.readStates, threadsData: currentContext.result.threadInfo, totalCount: currentContext.result.totalCount))
|
||||||
|
}
|
||||||
|
return .single((currentResults, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadMore = .complete()
|
||||||
|
}
|
||||||
|
|
||||||
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], true))
|
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], true))
|
||||||
|> then(
|
|> then(
|
||||||
searchSignal
|
searchSignal
|
||||||
|> map { result -> ([FoundRemoteMessages], Bool) in
|
|> map { result -> ([FoundRemoteMessages], Bool) in
|
||||||
|
updateSearchContexts { _ in
|
||||||
|
var resultContexts: [Int: ChatListSearchMessagesContext] = [:]
|
||||||
|
resultContexts[0] = ChatListSearchMessagesContext(result: ChatListSearchMessagesResult(query: finalQuery, messages: result.0.messages.map({ EngineMessage($0) }).sorted(by: { $0.index > $1.index }), readStates: result.0.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadInfo: result.0.threadInfo, hasMore: !result.0.completed, totalCount: result.0.totalCount, state: result.1), loadMoreIndex: nil)
|
||||||
|
return (resultContexts, true)
|
||||||
|
}
|
||||||
|
|
||||||
let foundMessages = result.0
|
let foundMessages = result.0
|
||||||
let messages: [EngineMessage]
|
let messages: [EngineMessage]
|
||||||
if key == .chats {
|
if key == .chats {
|
||||||
@ -2204,6 +2247,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
return ([FoundRemoteMessages(messages: messages, readCounters: foundMessages.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadsData: foundMessages.threadInfo, totalCount: foundMessages.totalCount)], false)
|
return ([FoundRemoteMessages(messages: messages, readCounters: foundMessages.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadsData: foundMessages.threadInfo, totalCount: foundMessages.totalCount)], false)
|
||||||
}
|
}
|
||||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
||||||
|
|> then(loadMore)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], false))
|
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], false))
|
||||||
@ -2380,7 +2424,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
foundThreads
|
foundThreads
|
||||||
)
|
)
|
||||||
|> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, foundPublicMessages, presentationData, searchState, selectionState, resolvedMessage, recentPeers, allAndFoundThreads -> ([ChatListSearchEntry], Bool)? in
|
|> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, foundPublicMessages, presentationData, searchState, selectionState, resolvedMessage, recentPeers, allAndFoundThreads -> ([ChatListSearchEntry], Bool)? in
|
||||||
let isSearching = foundRemotePeers.2 || foundRemoteMessages.1
|
let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 || foundPublicMessages.1
|
||||||
var entries: [ChatListSearchEntry] = []
|
var entries: [ChatListSearchEntry] = []
|
||||||
var index = 0
|
var index = 0
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import MultiAnimationRenderer
|
|||||||
|
|
||||||
protocol ChatListSearchPaneNode: ASDisplayNode {
|
protocol ChatListSearchPaneNode: ASDisplayNode {
|
||||||
var isReady: Signal<Bool, NoError> { get }
|
var isReady: Signal<Bool, NoError> { get }
|
||||||
|
var isCurrent: Bool { get set }
|
||||||
|
|
||||||
func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition)
|
func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition)
|
||||||
func scrollToTop() -> Bool
|
func scrollToTop() -> Bool
|
||||||
@ -568,6 +569,7 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, ASGestureRecognizerD
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
pane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition)
|
pane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition)
|
||||||
|
pane.node.isCurrent = key == self.currentPaneKey
|
||||||
if paneWasAdded && key == self.currentPaneKey {
|
if paneWasAdded && key == self.currentPaneKey {
|
||||||
pane.node.didBecomeFocused()
|
pane.node.didBecomeFocused()
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,6 @@ private final class ContainerComponent: CombinedComponent {
|
|||||||
var bottomContentOffset: CGFloat?
|
var bottomContentOffset: CGFloat?
|
||||||
|
|
||||||
var cachedMoreImage: (UIImage, PresentationTheme)?
|
var cachedMoreImage: (UIImage, PresentationTheme)?
|
||||||
var cachedCloseImage: (UIImage, PresentationTheme)?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeState() -> State {
|
func makeState() -> State {
|
||||||
@ -393,9 +392,7 @@ private final class ContainerComponent: CombinedComponent {
|
|||||||
let scroll = Child(ScrollComponent<ViewControllerComponentContainer.Environment>.self)
|
let scroll = Child(ScrollComponent<ViewControllerComponentContainer.Environment>.self)
|
||||||
let scrollExternalState = ScrollComponent<EnvironmentType>.ExternalState()
|
let scrollExternalState = ScrollComponent<EnvironmentType>.ExternalState()
|
||||||
|
|
||||||
let buttonsBackground = Child(RoundedRectangle.self)
|
|
||||||
let moreButton = Child(Button.self)
|
let moreButton = Child(Button.self)
|
||||||
let closeButton = Child(Button.self)
|
|
||||||
|
|
||||||
return { context in
|
return { context in
|
||||||
let environment = context.environment[EnvironmentType.self]
|
let environment = context.environment[EnvironmentType.self]
|
||||||
@ -447,20 +444,11 @@ private final class ContainerComponent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if case .bot = context.component.mode {
|
if case .bot = context.component.mode {
|
||||||
let buttonsBackground = buttonsBackground.update(
|
|
||||||
component: RoundedRectangle(color: UIColor(rgb: 0x808084, alpha: 0.1), cornerRadius: 15.0),
|
|
||||||
availableSize: CGSize(width: 73.0, height: 30.0),
|
|
||||||
transition: .immediate
|
|
||||||
)
|
|
||||||
context.add(buttonsBackground
|
|
||||||
.position(CGPoint(x: context.availableSize.width - 16.0 - buttonsBackground.size.width / 2.0, y: 13.0 + buttonsBackground.size.height / 2.0))
|
|
||||||
)
|
|
||||||
|
|
||||||
let moreImage: UIImage
|
let moreImage: UIImage
|
||||||
if let (image, theme) = state.cachedMoreImage, theme === environment.theme {
|
if let (image, theme) = state.cachedMoreImage, theme === environment.theme {
|
||||||
moreImage = image
|
moreImage = image
|
||||||
} else {
|
} else {
|
||||||
moreImage = generateMoreButtonImage(color: environment.theme.actionSheet.inputClearButtonColor)!
|
moreImage = generateMoreButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: environment.theme.actionSheet.inputClearButtonColor)!
|
||||||
state.cachedMoreImage = (moreImage, environment.theme)
|
state.cachedMoreImage = (moreImage, environment.theme)
|
||||||
}
|
}
|
||||||
let moreButton = moreButton.update(
|
let moreButton = moreButton.update(
|
||||||
@ -474,28 +462,7 @@ private final class ContainerComponent: CombinedComponent {
|
|||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
context.add(moreButton
|
context.add(moreButton
|
||||||
.position(CGPoint(x: context.availableSize.width - 16.0 - buttonsBackground.size.width + moreButton.size.width / 2.0 + 3.0, y: 13.0 + buttonsBackground.size.height / 2.0))
|
.position(CGPoint(x: context.availableSize.width - 16.0 - moreButton.size.width / 2.0, y: 13.0 + moreButton.size.height / 2.0))
|
||||||
)
|
|
||||||
|
|
||||||
let closeImage: UIImage
|
|
||||||
if let (image, theme) = state.cachedCloseImage, theme === environment.theme {
|
|
||||||
closeImage = image
|
|
||||||
} else {
|
|
||||||
closeImage = generateCloseButtonImage(color: environment.theme.actionSheet.inputClearButtonColor)!
|
|
||||||
state.cachedCloseImage = (closeImage, environment.theme)
|
|
||||||
}
|
|
||||||
let closeButton = closeButton.update(
|
|
||||||
component: Button(
|
|
||||||
content: AnyComponent(Image(image: closeImage)),
|
|
||||||
action: {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
availableSize: CGSize(width: 30.0, height: 30.0),
|
|
||||||
transition: .immediate
|
|
||||||
)
|
|
||||||
context.add(closeButton
|
|
||||||
.position(CGPoint(x: context.availableSize.width - 16.0 - closeButton.size.width / 2.0, y: 13.0 + buttonsBackground.size.height / 2.0))
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1549,11 +1516,14 @@ private final class FooterComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func generateMoreButtonImage(color: UIColor) -> UIImage? {
|
private func generateMoreButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? {
|
||||||
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
context.setFillColor(color.cgColor)
|
context.setFillColor(backgroundColor.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
context.setFillColor(foregroundColor.cgColor)
|
||||||
|
|
||||||
let circleSize = CGSize(width: 4.0, height: 4.0)
|
let circleSize = CGSize(width: 4.0, height: 4.0)
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: floorToScreenPixels((size.height - circleSize.width) / 2.0), y: floorToScreenPixels((size.height - circleSize.height) / 2.0)), size: circleSize))
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: floorToScreenPixels((size.height - circleSize.width) / 2.0), y: floorToScreenPixels((size.height - circleSize.height) / 2.0)), size: circleSize))
|
||||||
@ -1564,24 +1534,6 @@ private func generateMoreButtonImage(color: UIColor) -> UIImage? {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func generateCloseButtonImage(color: UIColor) -> UIImage? {
|
|
||||||
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
|
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
||||||
|
|
||||||
context.setLineWidth(2.0)
|
|
||||||
context.setLineCap(.round)
|
|
||||||
context.setStrokeColor(color.cgColor)
|
|
||||||
|
|
||||||
context.move(to: CGPoint(x: 10.0, y: 10.0))
|
|
||||||
context.addLine(to: CGPoint(x: 20.0, y: 20.0))
|
|
||||||
context.strokePath()
|
|
||||||
|
|
||||||
context.move(to: CGPoint(x: 20.0, y: 10.0))
|
|
||||||
context.addLine(to: CGPoint(x: 10.0, y: 20.0))
|
|
||||||
context.strokePath()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class AdsInfoContextReferenceContentSource: ContextReferenceContentSource {
|
private final class AdsInfoContextReferenceContentSource: ContextReferenceContentSource {
|
||||||
let controller: ViewController
|
let controller: ViewController
|
||||||
let sourceView: UIView
|
let sourceView: UIView
|
||||||
|
@ -618,6 +618,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
@ -475,6 +475,7 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
@ -254,6 +254,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||||||
public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void
|
public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void
|
||||||
public let activateAdAction: (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void
|
public let activateAdAction: (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void
|
||||||
public let adContextAction: (Message, ASDisplayNode, ContextGesture?) -> Void
|
public let adContextAction: (Message, ASDisplayNode, ContextGesture?) -> Void
|
||||||
|
public let removeAd: (Data) -> Void
|
||||||
public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void
|
public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void
|
||||||
public let saveMediaToFiles: (EngineMessage.Id) -> Void
|
public let saveMediaToFiles: (EngineMessage.Id) -> Void
|
||||||
public let openNoAdsDemo: () -> Void
|
public let openNoAdsDemo: () -> Void
|
||||||
@ -386,6 +387,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||||||
openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void,
|
openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void,
|
||||||
activateAdAction: @escaping (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void,
|
activateAdAction: @escaping (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void,
|
||||||
adContextAction: @escaping (Message, ASDisplayNode, ContextGesture?) -> Void,
|
adContextAction: @escaping (Message, ASDisplayNode, ContextGesture?) -> Void,
|
||||||
|
removeAd: @escaping (Data) -> Void,
|
||||||
openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void,
|
openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void,
|
||||||
saveMediaToFiles: @escaping (EngineMessage.Id) -> Void,
|
saveMediaToFiles: @escaping (EngineMessage.Id) -> Void,
|
||||||
openNoAdsDemo: @escaping () -> Void,
|
openNoAdsDemo: @escaping () -> Void,
|
||||||
@ -497,6 +499,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||||||
self.openWebView = openWebView
|
self.openWebView = openWebView
|
||||||
self.activateAdAction = activateAdAction
|
self.activateAdAction = activateAdAction
|
||||||
self.adContextAction = adContextAction
|
self.adContextAction = adContextAction
|
||||||
|
self.removeAd = removeAd
|
||||||
self.openRequestedPeerSelection = openRequestedPeerSelection
|
self.openRequestedPeerSelection = openRequestedPeerSelection
|
||||||
self.saveMediaToFiles = saveMediaToFiles
|
self.saveMediaToFiles = saveMediaToFiles
|
||||||
self.openNoAdsDemo = openNoAdsDemo
|
self.openNoAdsDemo = openNoAdsDemo
|
||||||
|
@ -3499,6 +3499,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
@ -48,6 +48,8 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
private let removeBackgroundNode: ASImageNode
|
private let removeBackgroundNode: ASImageNode
|
||||||
private let removeTextNode: ImmediateTextNode
|
private let removeTextNode: ImmediateTextNode
|
||||||
|
|
||||||
|
private let closeButton: HighlightableButtonNode
|
||||||
|
|
||||||
private let imageNode: TransformImageNode
|
private let imageNode: TransformImageNode
|
||||||
private let imageNodeContainer: ASDisplayNode
|
private let imageNodeContainer: ASDisplayNode
|
||||||
|
|
||||||
@ -104,6 +106,10 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.imageNodeContainer = ASDisplayNode()
|
self.imageNodeContainer = ASDisplayNode()
|
||||||
|
|
||||||
|
self.closeButton = HighlightableButtonNode()
|
||||||
|
self.closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||||
|
self.closeButton.displaysAsynchronously = false
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.contextContainer)
|
self.addSubnode(self.contextContainer)
|
||||||
@ -183,6 +189,9 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.controllerInteraction?.adContextAction(message, self.contextContainer, gesture)
|
self.controllerInteraction?.adContextAction(message, self.contextContainer, gesture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside])
|
||||||
|
self.addSubnode(self.closeButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -191,6 +200,14 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var theme: PresentationTheme?
|
private var theme: PresentationTheme?
|
||||||
|
|
||||||
|
@objc private func closePressed() {
|
||||||
|
if self.context.isPremium, let adAttribute = self.message?.adAttribute {
|
||||||
|
self.controllerInteraction?.removeAd(adAttribute.opaqueId)
|
||||||
|
} else {
|
||||||
|
self.controllerInteraction?.openNoAdsDemo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
|
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
|
||||||
self.message = interfaceState.adMessage
|
self.message = interfaceState.adMessage
|
||||||
|
|
||||||
@ -199,13 +216,16 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
|
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.removeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 15.0, color: interfaceState.theme.chat.inputPanel.panelControlAccentColor.withMultipliedAlpha(0.1))
|
||||||
self.removeTextNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_BotAd_WhatIsThis, 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.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(interfaceState.theme), for: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
self.contextContainer.isGestureEnabled = false
|
self.contextContainer.isGestureEnabled = false
|
||||||
|
|
||||||
let panelHeight: CGFloat
|
let panelHeight: CGFloat
|
||||||
|
var hasCloseButton = true
|
||||||
if let message = interfaceState.adMessage {
|
if let message = interfaceState.adMessage {
|
||||||
panelHeight = self.enqueueTransition(width: width, leftInset: leftInset, rightInset: rightInset, transition: .immediate, animation: nil, message: message, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: false, isReplyThread: false, translateToLanguage: nil)
|
panelHeight = self.enqueueTransition(width: width, leftInset: leftInset, rightInset: rightInset, transition: .immediate, animation: nil, message: message, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: false, isReplyThread: false, translateToLanguage: nil)
|
||||||
|
hasCloseButton = message.media.isEmpty
|
||||||
} else {
|
} else {
|
||||||
panelHeight = 50.0
|
panelHeight = 50.0
|
||||||
}
|
}
|
||||||
@ -218,6 +238,12 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
||||||
self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
||||||
|
|
||||||
|
let contentRightInset: CGFloat = 14.0 + rightInset
|
||||||
|
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
|
||||||
|
self.closeButton.frame = CGRect(origin: CGPoint(x: width - contentRightInset - closeButtonSize.width, y: floorToScreenPixels((panelHeight - closeButtonSize.height) / 2.0)), size: closeButtonSize)
|
||||||
|
|
||||||
|
self.closeButton.isHidden = !hasCloseButton
|
||||||
|
|
||||||
self.currentLayout = (width, leftInset, rightInset)
|
self.currentLayout = (width, leftInset, rightInset)
|
||||||
|
|
||||||
return panelHeight
|
return panelHeight
|
||||||
|
@ -3982,6 +3982,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self?.removeAd(opaqueId: opaqueId)
|
self?.removeAd(opaqueId: opaqueId)
|
||||||
}
|
}
|
||||||
self.effectiveNavigationController?.pushViewController(controller)
|
self.effectiveNavigationController?.pushViewController(controller)
|
||||||
|
}, removeAd: { [weak self] opaqueId in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.removeAd(opaqueId: opaqueId)
|
||||||
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in
|
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
@ -167,6 +167,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
@ -1782,6 +1782,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user