mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Improve sticker pack display on iPad
This commit is contained in:
parent
7fcce53b2c
commit
c6ca35292b
@ -667,4 +667,5 @@ public enum FileMediaResourceMediaStatus: Equatable {
|
||||
|
||||
public protocol ChatMessageItemNodeProtocol: ListViewItemNode {
|
||||
func targetReactionView(value: MessageReaction.Reaction) -> UIView?
|
||||
func contentFrame() -> CGRect
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public final class OpenChatMessageParams {
|
||||
public let playlistLocation: PeerMessagesPlaylistLocation?
|
||||
public let gallerySource: GalleryControllerItemSource?
|
||||
public let centralItemUpdated: ((MessageId) -> Void)?
|
||||
public let getSourceRect: (() -> CGRect?)?
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
@ -72,7 +73,8 @@ public final class OpenChatMessageParams {
|
||||
actionInteraction: GalleryControllerActionInteraction? = nil,
|
||||
playlistLocation: PeerMessagesPlaylistLocation? = nil,
|
||||
gallerySource: GalleryControllerItemSource? = nil,
|
||||
centralItemUpdated: ((MessageId) -> Void)? = nil
|
||||
centralItemUpdated: ((MessageId) -> Void)? = nil,
|
||||
getSourceRect: (() -> CGRect?)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
@ -100,5 +102,6 @@ public final class OpenChatMessageParams {
|
||||
self.playlistLocation = playlistLocation
|
||||
self.gallerySource = gallerySource
|
||||
self.centralItemUpdated = centralItemUpdated
|
||||
self.getSourceRect = getSourceRect
|
||||
}
|
||||
}
|
||||
|
@ -255,9 +255,11 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
guard let strongSelf = self, !strongSelf.isDismissed else {
|
||||
return
|
||||
}
|
||||
if let (layout, _, _, _) = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
return
|
||||
}
|
||||
let contentOffset = strongSelf.gridNode.scrollView.contentOffset
|
||||
let insets = strongSelf.gridNode.scrollView.contentInset
|
||||
|
||||
if contentOffset.y <= -insets.top - 30.0 {
|
||||
strongSelf.isDismissed = true
|
||||
DispatchQueue.main.async {
|
||||
@ -1203,7 +1205,9 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|
||||
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
var insets = layout.insets(options: [.statusBar])
|
||||
if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height {
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
insets.top = 0.0
|
||||
} else if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height {
|
||||
insets.top = 0.0
|
||||
} else {
|
||||
insets.top += 10.0
|
||||
@ -1271,11 +1275,14 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
|
||||
let initialRevealedRowCount: CGFloat = 4.5
|
||||
|
||||
let topInset = max(0.0, layout.size.height - floor(initialRevealedRowCount * itemWidth) - insets.top - actionAreaHeight - titleAreaInset)
|
||||
|
||||
let topInset: CGFloat
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
topInset = 0.0
|
||||
} else {
|
||||
topInset = insets.top + max(0.0, layout.size.height - floor(initialRevealedRowCount * itemWidth) - insets.top - actionAreaHeight - titleAreaInset)
|
||||
}
|
||||
let additionalGridBottomInset = max(0.0, gridFrame.size.height - actionAreaHeight - contentHeight)
|
||||
|
||||
let gridInsets = UIEdgeInsets(top: insets.top + topInset, left: gridLeftInset, bottom: actionAreaHeight + additionalGridBottomInset, right: layout.size.width - fillingWidth - gridLeftInset)
|
||||
let gridInsets = UIEdgeInsets(top: topInset, left: gridLeftInset, bottom: actionAreaHeight + additionalGridBottomInset, right: layout.size.width - fillingWidth - gridLeftInset)
|
||||
|
||||
let firstTime = self.validLayout == nil
|
||||
self.validLayout = (layout, gridFrame, titleAreaInset, gridInsets)
|
||||
@ -1354,9 +1361,16 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
self.titleSeparatorNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: max(minBackgroundY, unclippedBackgroundY)), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
var backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: max(minBackgroundY, unclippedBackgroundY)), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
var titleContainerFrame: CGRect
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
backgroundFrame.origin.y = min(0.0, backgroundFrame.origin.y)
|
||||
titleContainerFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((backgroundFrame.width) / 2.0), y: floor((56.0) / 2.0)), size: CGSize())
|
||||
} else {
|
||||
titleContainerFrame = CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((backgroundFrame.width) / 2.0), y: backgroundFrame.minY + floor((56.0) / 2.0)), size: CGSize())
|
||||
}
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
transition.updateFrame(node: self.titleContainer, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + floor((backgroundFrame.width) / 2.0), y: backgroundFrame.minY + floor((56.0) / 2.0)), size: CGSize()))
|
||||
transition.updateFrame(node: self.titleContainer, frame: titleContainerFrame)
|
||||
transition.updateFrame(node: self.titleSeparatorNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY + 56.0 - UIScreenPixel), size: CGSize(width: backgroundFrame.width, height: UIScreenPixel)))
|
||||
transition.updateFrame(node: self.titleBackgroundnode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.width, height: 56.0)))
|
||||
self.titleBackgroundnode.update(size: CGSize(width: layout.size.width, height: 56.0), transition: .immediate)
|
||||
@ -1427,6 +1441,8 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
private let openMention: (String) -> Void
|
||||
|
||||
private let dimNode: ASDisplayNode
|
||||
private let shadowNode: ASImageNode
|
||||
private let arrowNode: ASImageNode
|
||||
private let containerContainingNode: ASDisplayNode
|
||||
|
||||
private var containers: [Int: StickerPackContainer] = [:]
|
||||
@ -1475,12 +1491,23 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||
self.dimNode.alpha = 0.0
|
||||
|
||||
self.shadowNode = ASImageNode()
|
||||
self.shadowNode.displaysAsynchronously = false
|
||||
self.shadowNode.isUserInteractionEnabled = false
|
||||
|
||||
self.arrowNode = ASImageNode()
|
||||
self.arrowNode.displaysAsynchronously = false
|
||||
self.arrowNode.isUserInteractionEnabled = false
|
||||
self.arrowNode.image = generateArrowImage(color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
|
||||
self.containerContainingNode = ASDisplayNode()
|
||||
self.containerContainingNode.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.dimNode)
|
||||
|
||||
self.addSubnode(self.shadowNode)
|
||||
self.addSubnode(self.arrowNode)
|
||||
self.addSubnode(self.containerContainingNode)
|
||||
}
|
||||
|
||||
@ -1494,6 +1521,7 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
for (_, container) in self.containers {
|
||||
container.updatePresentationData(presentationData)
|
||||
}
|
||||
self.arrowNode.image = generateArrowImage(color: presentationData.theme.actionSheet.opaqueItemBackgroundColor)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
@ -1502,10 +1530,65 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
self.validLayout = layout
|
||||
|
||||
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
transition.updateFrame(node: self.containerContainingNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
|
||||
let containerContainingFrame: CGRect
|
||||
let containerInsets: UIEdgeInsets
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.01)
|
||||
self.containerContainingNode.cornerRadius = 10.0
|
||||
|
||||
let size = CGSize(width: 390.0, height: min(620.0, layout.size.height - 60.0))
|
||||
var contentRect: CGRect
|
||||
if let sourceRect = self.controller?.getSourceRect?() {
|
||||
let sideSpacing: CGFloat = 10.0
|
||||
let margin: CGFloat = 64.0
|
||||
contentRect = CGRect(origin: CGPoint(x: sourceRect.maxX + sideSpacing, y: floor(sourceRect.midY - size.height / 2.0)), size: size)
|
||||
contentRect.origin.y = min(layout.size.height - margin - size.height - layout.intrinsicInsets.bottom, max(margin, contentRect.origin.y))
|
||||
|
||||
let arrowSize = CGSize(width: 23.0, height: 12.0)
|
||||
let arrowFrame: CGRect
|
||||
if contentRect.maxX > layout.size.width {
|
||||
contentRect.origin.x = sourceRect.minX - size.width - sideSpacing
|
||||
arrowFrame = CGRect(origin: CGPoint(x: contentRect.maxX - (arrowSize.width - arrowSize.height) / 2.0, y: floor(sourceRect.midY - arrowSize.height / 2.0)), size: arrowSize)
|
||||
self.arrowNode.transform = CATransform3DMakeRotation(-.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
} else {
|
||||
arrowFrame = CGRect(origin: CGPoint(x: contentRect.minX - arrowSize.width + (arrowSize.width - arrowSize.height) / 2.0, y: floor(sourceRect.midY - arrowSize.height / 2.0)), size: arrowSize)
|
||||
self.arrowNode.transform = CATransform3DMakeRotation(.pi / 2.0, 0.0, 0.0, 1.0)
|
||||
}
|
||||
|
||||
self.arrowNode.frame = arrowFrame
|
||||
self.arrowNode.isHidden = false
|
||||
|
||||
} else {
|
||||
let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0))
|
||||
let detailWidth = layout.size.width - masterWidth
|
||||
contentRect = CGRect(origin: CGPoint(x: masterWidth + floor((detailWidth - size.width) / 2.0), y: floor((layout.size.height - size.height) / 2.0)), size: size)
|
||||
self.arrowNode.isHidden = true
|
||||
}
|
||||
|
||||
containerContainingFrame = contentRect
|
||||
containerInsets = .zero
|
||||
|
||||
self.shadowNode.alpha = 1.0
|
||||
if self.shadowNode.image == nil {
|
||||
self.shadowNode.image = generateShadowImage()
|
||||
}
|
||||
} else {
|
||||
self.containerContainingNode.cornerRadius = 0.0
|
||||
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||
containerContainingFrame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
containerInsets = layout.intrinsicInsets
|
||||
|
||||
self.arrowNode.isHidden = true
|
||||
self.shadowNode.alpha = 0.0
|
||||
}
|
||||
transition.updateFrame(node: self.containerContainingNode, frame: containerContainingFrame)
|
||||
|
||||
let shadowFrame = containerContainingFrame.insetBy(dx: -60.0, dy: -60.0)
|
||||
transition.updateFrame(node: self.shadowNode, frame: shadowFrame)
|
||||
|
||||
let expandProgress: CGFloat = 1.0
|
||||
|
||||
let scaledInset: CGFloat = 12.0
|
||||
let scaledDistance: CGFloat = 4.0
|
||||
let minScale = (layout.size.width - scaledInset * 2.0) / layout.size.width
|
||||
@ -1593,11 +1676,15 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
self.containers[i] = container
|
||||
}
|
||||
|
||||
let containerFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * layout.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: layout.size)
|
||||
let containerFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * containerContainingFrame.size.width + self.relativeToSelectedStickerPackTransition + scaledOffset, y: containerVerticalOffset), size: containerContainingFrame.size)
|
||||
containerTransition.updateFrame(node: container, frame: containerFrame, beginWithCurrentState: true)
|
||||
containerTransition.updateSublayerTransformScaleAndOffset(node: container, scale: containerScale, offset: CGPoint(), beginWithCurrentState: true)
|
||||
var containerLayout = layout
|
||||
containerLayout.size = containerFrame.size
|
||||
containerLayout.intrinsicInsets = containerInsets
|
||||
|
||||
if container.validLayout?.0 != layout {
|
||||
container.updateLayout(layout: layout, transition: containerTransition)
|
||||
container.updateLayout(layout: containerLayout, transition: containerTransition)
|
||||
}
|
||||
|
||||
if wasAdded {
|
||||
@ -1680,23 +1767,40 @@ private final class StickerPackScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
guard let layout = self.validLayout else {
|
||||
return
|
||||
}
|
||||
self.dimNode.alpha = 1.0
|
||||
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
|
||||
} else {
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
guard let layout = self.validLayout else {
|
||||
return
|
||||
}
|
||||
self.dimNode.alpha = 0.0
|
||||
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
|
||||
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
|
||||
self.modalProgressUpdated(0.0, .animated(duration: 0.2, curve: .easeInOut))
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
self.layer.allowsGroupOpacity = true
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
} else {
|
||||
let minInset: CGFloat = (self.containers.map { (_, container) -> CGFloat in container.topContentInset }).max() ?? 0.0
|
||||
self.containerContainingNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.containerContainingNode.bounds.height - minInset), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
|
||||
self.modalProgressUpdated(0.0, .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
|
||||
func dismiss() {
|
||||
@ -1782,6 +1886,8 @@ public final class StickerPackScreenImpl: ViewController {
|
||||
public var dismissed: (() -> Void)?
|
||||
public var actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)?
|
||||
|
||||
public var getSourceRect: (() -> CGRect?)?
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
override public var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
@ -2032,8 +2138,9 @@ public func StickerPackScreen(
|
||||
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil,
|
||||
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)? = nil,
|
||||
actionPerformed: (([(StickerPackCollectionInfo, [StickerPackItem], StickerPackScreenPerformedAction)]) -> Void)? = nil,
|
||||
dismissed: (() -> Void)? = nil) -> ViewController
|
||||
{
|
||||
dismissed: (() -> Void)? = nil,
|
||||
getSourceRect: (() -> CGRect?)? = nil
|
||||
) -> ViewController {
|
||||
let controller = StickerPackScreenImpl(
|
||||
context: context,
|
||||
stickerPacks: stickerPacks,
|
||||
@ -2045,6 +2152,7 @@ public func StickerPackScreen(
|
||||
actionPerformed: actionPerformed
|
||||
)
|
||||
controller.dismissed = dismissed
|
||||
controller.getSourceRect = getSourceRect
|
||||
return controller
|
||||
}
|
||||
|
||||
@ -2062,3 +2170,34 @@ private final class StickerPackContextReferenceContentSource: ContextReferenceCo
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func generateShadowImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.saveGState()
|
||||
context.setShadow(offset: CGSize(), blur: 60.0, color: UIColor(white: 0.0, alpha: 0.4).cgColor)
|
||||
let path = UIBezierPath(roundedRect: CGRect(x: 60.0, y: 60.0, width: 20.0, height: 20.0), cornerRadius: 10.0).cgPath
|
||||
context.addPath(path)
|
||||
context.fillPath()
|
||||
|
||||
context.restoreGState()
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
context.addPath(path)
|
||||
context.fillPath()
|
||||
})?.stretchableImage(withLeftCapWidth: 70, topCapHeight: 70)
|
||||
}
|
||||
|
||||
private func generateArrowImage(color: UIColor) -> UIImage? {
|
||||
return generateImage(CGSize(width: 23.0, height: 12.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setFillColor(color.cgColor)
|
||||
|
||||
context.translateBy(x: -183.0, y: -209.0)
|
||||
|
||||
try? drawSvgPath(context, path: "M183.219,208.89 H206.781 C205.648,208.89 204.567,209.371 203.808,210.214 L197.23,217.523 C196.038,218.848 193.962,218.848 192.77,217.523 L186.192,210.214 C185.433,209.371 184.352,208.89 183.219,208.89 Z ")
|
||||
})
|
||||
}
|
||||
|
@ -996,78 +996,92 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}))
|
||||
}
|
||||
}, actionInteraction: GalleryControllerActionInteraction(openUrl: { [weak self] url, concealed in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrl(url, concealed: concealed, message: nil)
|
||||
}
|
||||
}, openUrlIn: { [weak self] url in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrlIn(url)
|
||||
}
|
||||
}, openPeerMention: { [weak self] mention in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeerMention(mention)
|
||||
}
|
||||
}, openPeer: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeer(peer, .default, nil, .default)
|
||||
}
|
||||
}, openHashtag: { [weak self] peerName, hashtag in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openHashtag(peerName, hashtag)
|
||||
}
|
||||
}, openBotCommand: { [weak self] command in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.sendBotCommand(nil, command)
|
||||
}
|
||||
}, addContact: { [weak self] phoneNumber in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.addContact(phoneNumber)
|
||||
}
|
||||
}, storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var storedState: MediaPlaybackStoredState?
|
||||
if let timestamp = timestamp {
|
||||
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate))
|
||||
}
|
||||
let _ = updateMediaPlaybackStoredStateInteractively(engine: strongSelf.context.engine, messageId: messageId, state: storedState).start()
|
||||
}, editMedia: { [weak self] messageId, snapshots, transitionCompletion in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] message in
|
||||
guard let strongSelf = self, let message = message else {
|
||||
}, actionInteraction: GalleryControllerActionInteraction(
|
||||
openUrl: { [weak self] url, concealed in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrl(url, concealed: concealed, message: nil)
|
||||
}
|
||||
}, openUrlIn: { [weak self] url in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openUrlIn(url)
|
||||
}
|
||||
}, openPeerMention: { [weak self] mention in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeerMention(mention)
|
||||
}
|
||||
}, openPeer: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeer(peer, .default, nil, .default)
|
||||
}
|
||||
}, openHashtag: { [weak self] peerName, hashtag in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openHashtag(peerName, hashtag)
|
||||
}
|
||||
}, openBotCommand: { [weak self] command in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.sendBotCommand(nil, command)
|
||||
}
|
||||
}, addContact: { [weak self] phoneNumber in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.addContact(phoneNumber)
|
||||
}
|
||||
}, storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var storedState: MediaPlaybackStoredState?
|
||||
if let timestamp = timestamp {
|
||||
storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate))
|
||||
}
|
||||
let _ = updateMediaPlaybackStoredStateInteractively(engine: strongSelf.context.engine, messageId: messageId, state: storedState).start()
|
||||
}, editMedia: { [weak self] messageId, snapshots, transitionCompletion in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var mediaReference: AnyMediaReference?
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
mediaReference = AnyMediaReference.standalone(media: image)
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
mediaReference = AnyMediaReference.standalone(media: file)
|
||||
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] message in
|
||||
guard let strongSelf = self, let message = message else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: {
|
||||
transitionCompletion()
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false)
|
||||
|
||||
var mediaReference: AnyMediaReference?
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
mediaReference = AnyMediaReference.standalone(media: image)
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
mediaReference = AnyMediaReference.standalone(media: file)
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
}
|
||||
|
||||
if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] {
|
||||
legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: {
|
||||
transitionCompletion()
|
||||
}, getCaptionPanelView: { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false)
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
}
|
||||
})
|
||||
}),
|
||||
getSourceRect: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
})))
|
||||
var rect: CGRect?
|
||||
strongSelf.chatDisplayNode.historyNode.forEachVisibleMessageItemNode({ itemNode in
|
||||
if itemNode.item?.message.id == message.id {
|
||||
rect = itemNode.view.convert(itemNode.contentFrame(), to: nil)
|
||||
}
|
||||
})
|
||||
return rect
|
||||
}
|
||||
))
|
||||
}, openPeer: { [weak self] peer, navigation, fromMessage, source in
|
||||
self?.openPeer(peer: peer, navigation: navigation, fromMessage: fromMessage, fromReactionMessageId: source == .reaction ? fromMessage?.id : nil, expandAvatar: source == .groupParticipant)
|
||||
}, openPeerMention: { [weak self] name in
|
||||
|
@ -2889,6 +2889,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
override func unreadMessageRangeUpdated() {
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.imageNode.frame
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimatedEmojiSoundsConfiguration {
|
||||
|
@ -4562,4 +4562,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.backgroundNode.frame
|
||||
}
|
||||
}
|
||||
|
@ -1399,4 +1399,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.interactiveVideoNode.frame
|
||||
}
|
||||
}
|
||||
|
@ -951,4 +951,8 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
|
||||
|
||||
func unreadMessageRangeUpdated() {
|
||||
}
|
||||
|
||||
public func contentFrame() -> CGRect {
|
||||
return self.bounds
|
||||
}
|
||||
}
|
||||
|
@ -1833,4 +1833,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func contentFrame() -> CGRect {
|
||||
return self.imageNode.frame
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
}, getSourceRect: params.getSourceRect)
|
||||
params.dismissInput()
|
||||
params.present(controller, nil)
|
||||
return true
|
||||
|
Loading…
x
Reference in New Issue
Block a user