mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Implement reaction preview
This commit is contained in:
parent
7021252dc6
commit
ee7873b8f2
@ -551,3 +551,7 @@ public enum FileMediaResourceMediaStatus: Equatable {
|
||||
case fetchStatus(MediaResourceStatus)
|
||||
case playbackStatus(FileMediaResourcePlaybackStatus)
|
||||
}
|
||||
|
||||
public protocol ChatMessageItemNodeProtocol: ListViewItemNode {
|
||||
func targetReactionView(value: String) -> UIView?
|
||||
}
|
||||
|
@ -206,6 +206,14 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
|
||||
}
|
||||
}
|
||||
|
||||
public var didScrollWithOffset: ((CGFloat, ContainedViewLayoutTransition, ListViewItemNode?) -> Void)? {
|
||||
didSet {
|
||||
if self.isNodeLoaded {
|
||||
(self.displayNode as! ItemListControllerNode).listNode.didScrollWithOffset = self.didScrollWithOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var willScrollToTop: (() -> Void)?
|
||||
|
||||
public func setReorderEntry<T: ItemListNodeEntry>(_ f: @escaping (Int, Int, [T]) -> Signal<Bool, NoError>) {
|
||||
@ -471,6 +479,7 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
|
||||
displayNode.reorderEntry = self.reorderEntry
|
||||
displayNode.reorderCompleted = self.reorderCompleted
|
||||
displayNode.listNode.experimentalSnapScrollToItem = self.experimentalSnapScrollToItem
|
||||
displayNode.listNode.didScrollWithOffset = self.didScrollWithOffset
|
||||
displayNode.requestLayout = { [weak self] transition in
|
||||
self?.requestLayout(transition: transition)
|
||||
}
|
||||
|
@ -326,6 +326,18 @@ public func quickReactionSetupController(
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
|
||||
controller.didScrollWithOffset = { [weak controller] offset, transition, _ in
|
||||
guard let controller = controller else {
|
||||
return
|
||||
}
|
||||
controller.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ReactionChatPreviewItemNode {
|
||||
itemNode.standaloneReactionAnimation?.addRelativeContentOffset(CGPoint(x: 0.0, y: offset), transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dismissImpl = { [weak controller] in
|
||||
guard let controller = controller else {
|
||||
return
|
||||
|
@ -12,6 +12,7 @@ import PresentationDataUtils
|
||||
import AccountContext
|
||||
import WallpaperBackgroundNode
|
||||
import AvatarNode
|
||||
import ReactionSelectionNode
|
||||
|
||||
class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
||||
let context: AccountContext
|
||||
@ -86,6 +87,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
private var messageNode: ListViewItemNode?
|
||||
|
||||
private var item: ReactionChatPreviewItem?
|
||||
private(set) weak var standaloneReactionAnimation: StandaloneReactionAnimation?
|
||||
|
||||
init() {
|
||||
self.topStripeNode = ASDisplayNode()
|
||||
@ -109,6 +111,63 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
self.addSubnode(self.containerNode)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||
recognizer.tapActionAtPoint = { _ in
|
||||
return .waitForDoubleTap
|
||||
}
|
||||
self.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
||||
switch gesture {
|
||||
case .doubleTap:
|
||||
if let item = self.item, let updatedReaction = item.reaction, let availableReactions = item.availableReactions, let messageNode = self.messageNode as? ChatMessageItemNodeProtocol {
|
||||
if let targetView = messageNode.targetReactionView(value: updatedReaction) {
|
||||
for reaction in availableReactions.reactions {
|
||||
if reaction.value == updatedReaction {
|
||||
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
|
||||
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
})
|
||||
self.standaloneReactionAnimation = nil
|
||||
}
|
||||
|
||||
if let supernode = self.supernode {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(context: item.context, theme: item.theme, reaction: ReactionContextItem(
|
||||
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
listAnimation: reaction.activateAnimation,
|
||||
applicationAnimation: reaction.effectAnimation
|
||||
))
|
||||
self.standaloneReactionAnimation = standaloneReactionAnimation
|
||||
|
||||
supernode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = supernode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(targetView: targetView, hideNode: true, completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ item: ReactionChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
let currentNode = self.messageNode
|
||||
|
||||
@ -161,6 +220,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
node = messageNode
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
node?.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
var contentSize = CGSize(width: params.width, height: 8.0 + 8.0)
|
||||
@ -174,6 +234,15 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
return (layout, { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let previousItem = strongSelf.item, previousItem.reaction != item.reaction {
|
||||
if let standaloneReactionAnimation = strongSelf.standaloneReactionAnimation {
|
||||
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
})
|
||||
strongSelf.standaloneReactionAnimation = nil
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.item = item
|
||||
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
|
||||
|
@ -675,7 +675,7 @@ final class ChatMessageAccessibilityData {
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatMessageItemView: ListViewItemNode {
|
||||
public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol {
|
||||
let layoutConstants = (ChatMessageItemLayoutConstants.compact, ChatMessageItemLayoutConstants.regular)
|
||||
|
||||
var item: ChatMessageItem?
|
||||
@ -872,7 +872,7 @@ public class ChatMessageItemView: ListViewItemNode {
|
||||
func openMessageContextMenu() {
|
||||
}
|
||||
|
||||
func targetReactionView(value: String) -> UIView? {
|
||||
public func targetReactionView(value: String) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user