mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
Reaction improvements
This commit is contained in:
@@ -9,6 +9,7 @@ import TelegramPresentationData
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
import ReactionButtonListComponent
|
||||
import WebPBinding
|
||||
|
||||
private func maybeAddRotationAnimation(_ layer: CALayer, duration: Double) {
|
||||
if let _ = layer.animation(forKey: "clockFrameAnimation") {
|
||||
@@ -45,59 +46,91 @@ private let reactionCountFont = Font.semibold(11.0)
|
||||
private let reactionFont = Font.regular(12.0)
|
||||
|
||||
private final class StatusReactionNode: ASDisplayNode {
|
||||
let selectedImageNode: ASImageNode
|
||||
let iconView: UIImageView
|
||||
|
||||
private let iconImageDisposable = MetaDisposable()
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
private var value: String?
|
||||
private var isSelected: Bool?
|
||||
|
||||
override init() {
|
||||
self.selectedImageNode = ASImageNode()
|
||||
self.selectedImageNode.displaysAsynchronously = false
|
||||
self.iconView = UIImageView()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.selectedImageNode)
|
||||
self.view.addSubview(self.iconView)
|
||||
}
|
||||
|
||||
func update(type: ChatMessageDateAndStatusType, value: String, isSelected: Bool, count: Int, theme: PresentationTheme, wallpaper: TelegramWallpaper, animated: Bool) {
|
||||
deinit {
|
||||
self.iconImageDisposable.dispose()
|
||||
}
|
||||
|
||||
func update(context: AccountContext, type: ChatMessageDateAndStatusType, value: String, file: TelegramMediaFile?, isSelected: Bool, count: Int, theme: PresentationTheme, wallpaper: TelegramWallpaper, animated: Bool) {
|
||||
if self.value != value {
|
||||
self.value = value
|
||||
|
||||
let selectedImage: UIImage? = generateImage(CGSize(width: 14.0, height: 14.0), rotatedContext: { size, context in
|
||||
UIGraphicsPushContext(context)
|
||||
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.scaleBy(x: size.width / 20.0, y: size.width / 20.0)
|
||||
|
||||
let string = NSAttributedString(string: value, font: reactionFont, textColor: .black)
|
||||
string.draw(at: CGPoint(x: 1.0, y: 2.0))
|
||||
|
||||
UIGraphicsPopContext()
|
||||
})
|
||||
|
||||
if let selectedImage = selectedImage {
|
||||
self.selectedImageNode.image = selectedImage
|
||||
self.selectedImageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: selectedImage.size)
|
||||
let defaultImageSize = CGSize(width: 19.0, height: 19.0)
|
||||
let imageSize: CGSize
|
||||
if let file = file {
|
||||
self.iconImageDisposable.set((context.account.postbox.mediaBox.resourceData(file.resource)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] data in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if data.complete, let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||
if let image = WebP.convert(fromWebP: dataValue) {
|
||||
strongSelf.iconView.image = image
|
||||
}
|
||||
}
|
||||
}))
|
||||
imageSize = file.dimensions?.cgSize.aspectFitted(defaultImageSize) ?? defaultImageSize
|
||||
} else {
|
||||
imageSize = defaultImageSize
|
||||
}
|
||||
|
||||
self.iconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((defaultImageSize.width - imageSize.width) / 2.0), y: floorToScreenPixels((defaultImageSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
struct ReactionSettings {
|
||||
struct TrailingReactionSettings {
|
||||
var displayInline: Bool
|
||||
var preferAdditionalInset: Bool
|
||||
|
||||
init(preferAdditionalInset: Bool) {
|
||||
init(displayInline: Bool, preferAdditionalInset: Bool) {
|
||||
self.displayInline = displayInline
|
||||
self.preferAdditionalInset = preferAdditionalInset
|
||||
}
|
||||
}
|
||||
|
||||
struct StandaloneReactionSettings {
|
||||
init() {
|
||||
}
|
||||
}
|
||||
|
||||
enum LayoutInput {
|
||||
case trailingContent(contentWidth: CGFloat, reactionSettings: ReactionSettings?)
|
||||
case standalone
|
||||
case trailingContent(contentWidth: CGFloat, reactionSettings: TrailingReactionSettings?)
|
||||
case standalone(reactionSettings: StandaloneReactionSettings?)
|
||||
|
||||
var displayInlineReactions: Bool {
|
||||
switch self {
|
||||
case let .trailingContent(_, reactionSettings):
|
||||
if let reactionSettings = reactionSettings {
|
||||
return reactionSettings.displayInline
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .standalone(reactionSettings):
|
||||
if let _ = reactionSettings {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
@@ -154,7 +187,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
private var clockMinNode: ASImageNode?
|
||||
private let dateNode: TextNode
|
||||
private var impressionIcon: ASImageNode?
|
||||
private var reactionNodes: [StatusReactionNode] = []
|
||||
private var reactionNodes: [String: StatusReactionNode] = [:]
|
||||
private let reactionButtonsContainer = ReactionButtonsLayoutContainer()
|
||||
private var reactionCountNode: TextNode?
|
||||
private var reactionButtonNode: HighlightTrackingButtonNode?
|
||||
@@ -247,22 +280,24 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
switch arguments.type {
|
||||
case .BubbleIncoming, .ImageIncoming, .FreeIncoming:
|
||||
reactionColors = ReactionButtonComponent.Colors(
|
||||
background: arguments.presentationData.theme.theme.chat.message.incoming.accentControlColor.withMultipliedAlpha(0.1).argb,
|
||||
foreground: arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor.argb,
|
||||
stroke: arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor.argb
|
||||
deselectedBackground: arguments.presentationData.theme.theme.chat.message.incoming.accentControlColor.withMultipliedAlpha(0.1).argb,
|
||||
selectedBackground: arguments.presentationData.theme.theme.chat.message.incoming.accentControlColor.withMultipliedAlpha(1.0).argb,
|
||||
deselectedForeground: arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor.argb,
|
||||
selectedForeground: arguments.presentationData.theme.theme.chat.message.incoming.bubble.withWallpaper.fill.last!.argb
|
||||
)
|
||||
case .BubbleOutgoing, .ImageOutgoing, .FreeOutgoing:
|
||||
reactionColors = ReactionButtonComponent.Colors(
|
||||
background: arguments.presentationData.theme.theme.chat.message.outgoing.accentControlColor.withMultipliedAlpha(0.1).argb,
|
||||
foreground: arguments.presentationData.theme.theme.chat.message.outgoing.accentTextColor.argb,
|
||||
stroke: arguments.presentationData.theme.theme.chat.message.outgoing.accentTextColor.argb
|
||||
deselectedBackground: arguments.presentationData.theme.theme.chat.message.outgoing.accentControlColor.withMultipliedAlpha(0.1).argb,
|
||||
selectedBackground: arguments.presentationData.theme.theme.chat.message.outgoing.accentControlColor.withMultipliedAlpha(1.0).argb,
|
||||
deselectedForeground: arguments.presentationData.theme.theme.chat.message.outgoing.accentTextColor.argb,
|
||||
selectedForeground: arguments.presentationData.theme.theme.chat.message.outgoing.bubble.withWallpaper.fill.last!.argb
|
||||
)
|
||||
}
|
||||
|
||||
switch arguments.type {
|
||||
case .BubbleIncoming:
|
||||
dateColor = arguments.presentationData.theme.theme.chat.message.incoming.secondaryTextColor
|
||||
leftInset = 10.0
|
||||
leftInset = 5.0
|
||||
loadedCheckFullImage = PresentationResourcesChat.chatOutgoingFullCheck(arguments.presentationData.theme.theme, size: checkSize)
|
||||
loadedCheckPartialImage = PresentationResourcesChat.chatOutgoingPartialCheck(arguments.presentationData.theme.theme, size: checkSize)
|
||||
clockFrameImage = graphics.clockBubbleIncomingFrameImage
|
||||
@@ -278,7 +313,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
case let .BubbleOutgoing(status):
|
||||
dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor
|
||||
outgoingStatus = status
|
||||
leftInset = 10.0
|
||||
leftInset = 5.0
|
||||
loadedCheckFullImage = PresentationResourcesChat.chatOutgoingFullCheck(arguments.presentationData.theme.theme, size: checkSize)
|
||||
loadedCheckPartialImage = PresentationResourcesChat.chatOutgoingPartialCheck(arguments.presentationData.theme.theme, size: checkSize)
|
||||
clockFrameImage = graphics.clockBubbleOutgoingFrameImage
|
||||
@@ -524,13 +559,13 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
|
||||
var replyCountLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
|
||||
let reactionSize: CGFloat = 14.0
|
||||
let reactionSize: CGFloat = 19.0
|
||||
var reactionCountLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
let reactionSpacing: CGFloat = -4.0
|
||||
let reactionTrailingSpacing: CGFloat = 4.0
|
||||
let reactionSpacing: CGFloat = 2.0
|
||||
let reactionTrailingSpacing: CGFloat = 6.0
|
||||
|
||||
var reactionInset: CGFloat = 0.0
|
||||
if !"".isEmpty && !arguments.reactions.isEmpty {
|
||||
if arguments.layoutInput.displayInlineReactions, !arguments.reactions.isEmpty {
|
||||
reactionInset = -1.0 + CGFloat(arguments.reactions.count) * reactionSize + CGFloat(arguments.reactions.count - 1) * reactionSpacing + reactionTrailingSpacing
|
||||
|
||||
var count = 0
|
||||
@@ -547,9 +582,11 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
countString = "\(count)"
|
||||
}
|
||||
|
||||
let layoutAndApply = makeReactionCountLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: countString, font: dateFont, textColor: dateColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0)))
|
||||
reactionInset += max(10.0, layoutAndApply.0.size.width) + 2.0
|
||||
reactionCountLayoutAndApply = layoutAndApply
|
||||
if count > arguments.reactions.count {
|
||||
let layoutAndApply = makeReactionCountLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: countString, font: dateFont, textColor: dateColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0)))
|
||||
reactionInset += layoutAndApply.0.size.width + 4.0
|
||||
reactionCountLayoutAndApply = layoutAndApply
|
||||
}
|
||||
}
|
||||
|
||||
if arguments.replyCount > 0 {
|
||||
@@ -599,7 +636,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
transition: .immediate
|
||||
)
|
||||
case let .trailingContent(contentWidth, reactionSettings):
|
||||
if let _ = reactionSettings {
|
||||
if let reactionSettings = reactionSettings, !reactionSettings.displayInline {
|
||||
reactionButtons = reactionButtonsContainer.update(
|
||||
context: arguments.context,
|
||||
action: { value in
|
||||
@@ -686,11 +723,13 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
resultingHeight = 0.0
|
||||
}
|
||||
} else {
|
||||
var additionalVerticalInset: CGFloat = 0.0
|
||||
if let reactionSettings = reactionSettings {
|
||||
if reactionSettings.preferAdditionalInset {
|
||||
verticalReactionsInset = 5.0
|
||||
verticalReactionsInset = 8.0
|
||||
additionalVerticalInset += 1.0
|
||||
} else {
|
||||
verticalReactionsInset = 2.0
|
||||
verticalReactionsInset = 3.0
|
||||
}
|
||||
} else {
|
||||
verticalReactionsInset = 0.0
|
||||
@@ -698,12 +737,12 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
|
||||
if currentRowWidth + layoutSize.width > arguments.constrainedSize.width {
|
||||
resultingWidth = max(layoutSize.width, reactionButtonsSize.width)
|
||||
resultingHeight = verticalReactionsInset + reactionButtonsSize.height + layoutSize.height
|
||||
verticalInset = verticalReactionsInset + reactionButtonsSize.height
|
||||
resultingHeight = verticalReactionsInset + reactionButtonsSize.height + 1.0 + layoutSize.height
|
||||
verticalInset = verticalReactionsInset + reactionButtonsSize.height + 3.0
|
||||
} else {
|
||||
resultingWidth = max(layoutSize.width + currentRowWidth, reactionButtonsSize.width)
|
||||
verticalInset = verticalReactionsInset + reactionButtonsSize.height - layoutSize.height
|
||||
resultingHeight = verticalReactionsInset + reactionButtonsSize.height
|
||||
verticalInset = verticalReactionsInset + reactionButtonsSize.height - layoutSize.height + additionalVerticalInset
|
||||
resultingHeight = verticalReactionsInset + reactionButtonsSize.height + 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -717,7 +756,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
strongSelf.type = arguments.type
|
||||
strongSelf.layoutSize = layoutSize
|
||||
|
||||
var reactionButtonPosition = CGPoint(x: 0.0, y: verticalReactionsInset)
|
||||
var reactionButtonPosition = CGPoint(x: -1.0, y: verticalReactionsInset)
|
||||
for item in reactionButtons.items {
|
||||
if reactionButtonPosition.x + item.size.width > boundingWidth {
|
||||
reactionButtonPosition.x = 0.0
|
||||
@@ -773,7 +812,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
if let blurredBackgroundNode = strongSelf.blurredBackgroundNode {
|
||||
blurredBackgroundNode.updateColor(color: blurredBackgroundColor.0, enableBlur: blurredBackgroundColor.1, transition: .immediate)
|
||||
animation.animator.updateFrame(layer: blurredBackgroundNode.layer, frame: CGRect(origin: CGPoint(), size: layoutSize), completion: nil)
|
||||
blurredBackgroundNode.update(size: blurredBackgroundNode.bounds.size, cornerRadius: blurredBackgroundNode.bounds.height / 2.0, transition: animation.transition)
|
||||
blurredBackgroundNode.update(size: blurredBackgroundNode.bounds.size, cornerRadius: blurredBackgroundNode.bounds.height / 2.0, animator: animation.animator)
|
||||
} else {
|
||||
let blurredBackgroundNode = NavigationBackgroundNode(color: blurredBackgroundColor.0, enableBlur: blurredBackgroundColor.1)
|
||||
strongSelf.blurredBackgroundNode = blurredBackgroundNode
|
||||
@@ -789,6 +828,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
let _ = dateApply()
|
||||
|
||||
if let currentImpressionIcon = currentImpressionIcon {
|
||||
let impressionIconFrame = CGRect(origin: CGPoint(x: leftOffset + leftInset + backgroundInsets.left, y: backgroundInsets.top + 1.0 + offset + verticalInset + floor((date.size.height - impressionSize.height) / 2.0)), size: impressionSize)
|
||||
currentImpressionIcon.displaysAsynchronously = false
|
||||
if currentImpressionIcon.image !== impressionImage {
|
||||
currentImpressionIcon.image = impressionImage
|
||||
@@ -796,8 +836,10 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
if currentImpressionIcon.supernode == nil {
|
||||
strongSelf.impressionIcon = currentImpressionIcon
|
||||
strongSelf.addSubnode(currentImpressionIcon)
|
||||
currentImpressionIcon.frame = impressionIconFrame
|
||||
} else {
|
||||
animation.animator.updateFrame(layer: currentImpressionIcon.layer, frame: impressionIconFrame, completion: nil)
|
||||
}
|
||||
currentImpressionIcon.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset + backgroundInsets.left, y: backgroundInsets.top + 1.0 + offset + verticalInset + floor((date.size.height - impressionSize.height) / 2.0)), size: impressionSize)
|
||||
} else if let impressionIcon = strongSelf.impressionIcon {
|
||||
impressionIcon.removeFromSupernode()
|
||||
strongSelf.impressionIcon = nil
|
||||
@@ -908,38 +950,49 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var reactionOffset: CGFloat = leftOffset + leftInset - reactionInset + backgroundInsets.left
|
||||
if !"".isEmpty {
|
||||
for i in 0 ..< arguments.reactions.count {
|
||||
if arguments.layoutInput.displayInlineReactions {
|
||||
var validReactions = Set<String>()
|
||||
for reaction in arguments.reactions.sorted(by: { lhs, rhs in
|
||||
if lhs.isSelected != rhs.isSelected {
|
||||
if lhs.isSelected {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return lhs.value < rhs.value
|
||||
}
|
||||
}) {
|
||||
let node: StatusReactionNode
|
||||
var animateNode = true
|
||||
if strongSelf.reactionNodes.count > i {
|
||||
node = strongSelf.reactionNodes[i]
|
||||
if let current = strongSelf.reactionNodes[reaction.value] {
|
||||
node = current
|
||||
} else {
|
||||
animateNode = false
|
||||
node = StatusReactionNode()
|
||||
if strongSelf.reactionNodes.count > i {
|
||||
let previousNode = strongSelf.reactionNodes[i]
|
||||
if animation.isAnimated {
|
||||
previousNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousNode] _ in
|
||||
previousNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
previousNode.removeFromSupernode()
|
||||
strongSelf.reactionNodes[reaction.value] = node
|
||||
}
|
||||
validReactions.insert(reaction.value)
|
||||
|
||||
var iconFile: TelegramMediaFile?
|
||||
|
||||
if let availableReactions = arguments.availableReactions {
|
||||
for availableReaction in availableReactions.reactions {
|
||||
if availableReaction.value == reaction.value {
|
||||
iconFile = availableReaction.staticIcon
|
||||
break
|
||||
}
|
||||
strongSelf.reactionNodes[i] = node
|
||||
} else {
|
||||
strongSelf.reactionNodes.append(node)
|
||||
}
|
||||
}
|
||||
|
||||
node.update(type: arguments.type, value: arguments.reactions[i].value, isSelected: arguments.reactions[i].isSelected, count: Int(arguments.reactions[i].count), theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper, animated: false)
|
||||
node.update(context: arguments.context, type: arguments.type, value: reaction.value, file: iconFile, isSelected: reaction.isSelected, count: Int(reaction.count), theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper, animated: false)
|
||||
if node.supernode == nil {
|
||||
strongSelf.addSubnode(node)
|
||||
if animation.isAnimated {
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + offset + verticalInset + 1.0), size: CGSize(width: reactionSize, height: reactionSize))
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + offset + verticalInset - 2.0), size: CGSize(width: reactionSize, height: reactionSize))
|
||||
if animateNode {
|
||||
animation.animator.updateFrame(layer: node.layer, frame: nodeFrame, completion: nil)
|
||||
} else {
|
||||
@@ -950,18 +1003,24 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
if !arguments.reactions.isEmpty {
|
||||
reactionOffset += reactionTrailingSpacing
|
||||
}
|
||||
|
||||
for _ in arguments.reactions.count ..< strongSelf.reactionNodes.count {
|
||||
let node = strongSelf.reactionNodes.removeLast()
|
||||
if animation.isAnimated {
|
||||
node.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2, removeOnCompletion: false)
|
||||
node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak node] _ in
|
||||
node?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
node.removeFromSupernode()
|
||||
|
||||
var removeIds: [String] = []
|
||||
for (id, node) in strongSelf.reactionNodes {
|
||||
if !validReactions.contains(id) {
|
||||
removeIds.append(id)
|
||||
if animation.isAnimated {
|
||||
node.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2, removeOnCompletion: false)
|
||||
node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak node] _ in
|
||||
node?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
node.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
for id in removeIds {
|
||||
strongSelf.reactionNodes.removeValue(forKey: id)
|
||||
}
|
||||
}
|
||||
|
||||
if let (layout, apply) = reactionCountLayoutAndApply {
|
||||
@@ -974,7 +1033,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
}
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset + 1.0, y: backgroundInsets.top + 1.0 + offset + verticalInset), size: layout.size)
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset - 4.0, y: backgroundInsets.top + 1.0 + offset + verticalInset), size: layout.size)
|
||||
animation.animator.updateFrame(layer: node.layer, frame: nodeFrame, completion: nil)
|
||||
reactionOffset += 1.0 + layout.size.width + 4.0
|
||||
} else if let reactionCountNode = strongSelf.reactionCountNode {
|
||||
@@ -1068,6 +1127,11 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
func reactionView(value: String) -> UIView? {
|
||||
for (id, node) in self.reactionNodes {
|
||||
if id == value {
|
||||
return node.iconView
|
||||
}
|
||||
}
|
||||
for (_, button) in self.reactionButtonsContainer.buttons {
|
||||
if let result = button.findTaggedView(tag: ReactionButtonComponent.ViewTag(value: value)) as? ReactionButtonComponent.View {
|
||||
return result.iconView
|
||||
@@ -1092,3 +1156,10 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func shouldDisplayInlineDateReactions(message: Message) -> Bool {
|
||||
if message.id.peerId.namespace == Namespaces.Peer.CloudUser || message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user