Merge branch 'reactions'

This commit is contained in:
Ali 2019-11-30 00:36:54 +04:00
commit e097329c54
74 changed files with 474 additions and 103 deletions

View file

@ -3,7 +3,7 @@
@implementation Serialization
- (NSUInteger)currentLayer {
return 107;
return 108;
}
- (id _Nullable)parseMessage:(NSData * _Nullable)data {

View file

@ -920,7 +920,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
}
func animateOutToReaction(value: String, into targetNode: ASImageNode, hideNode: Bool, completion: @escaping () -> Void) {
func animateOutToReaction(value: String, into targetNode: ASDisplayNode, hideNode: Bool, completion: @escaping () -> Void) {
guard let reactionContextNode = self.reactionContextNode else {
self.animateOut(result: .default, completion: completion)
return
@ -1481,7 +1481,7 @@ public final class ContextController: ViewController, StandalonePresentableContr
self.dismiss(result: .default, completion: completion)
}
public func dismissWithReaction(value: String, into targetNode: ASImageNode, hideNode: Bool, completion: (() -> Void)?) {
public func dismissWithReaction(value: String, into targetNode: ASDisplayNode, hideNode: Bool, completion: (() -> Void)?) {
if !self.wasDismissed {
self.wasDismissed = true
self.controllerNode.animateOutToReaction(value: value, into: targetNode, hideNode: hideNode, completion: { [weak self] in

View file

@ -71,7 +71,7 @@ public extension CALayer {
animation.isAdditive = additive
if !delay.isZero {
animation.beginTime = CACurrentMediaTime() + delay
animation.beginTime = CACurrentMediaTime() + delay * UIView.animationDurationFactor()
animation.fillMode = .both
}
@ -101,7 +101,7 @@ public extension CALayer {
}
if !delay.isZero {
animation.beginTime = CACurrentMediaTime() + delay
animation.beginTime = CACurrentMediaTime() + delay * UIView.animationDurationFactor()
animation.fillMode = .both
}
@ -178,7 +178,7 @@ public extension CALayer {
}
if !delay.isZero {
animation.beginTime = CACurrentMediaTime() + delay
animation.beginTime = CACurrentMediaTime() + delay * UIView.animationDurationFactor()
animation.fillMode = .both
}

View file

@ -377,14 +377,12 @@ public final class ReactionContextNode: ASDisplayNode {
}
}
public func animateOutToReaction(value: String, targetNode: ASImageNode, hideNode: Bool, completion: @escaping () -> Void) {
public func animateOutToReaction(value: String, targetNode: ASDisplayNode, hideNode: Bool, completion: @escaping () -> Void) {
for itemNode in self.itemNodes {
switch itemNode.reaction {
case let .reaction(itemValue, _, _):
if itemValue == value {
if let snapshotView = itemNode.view.snapshotContentTree(keepTransform: true) {
let targetSnapshotView = UIImageView()
targetSnapshotView.image = targetNode.image
if let snapshotView = itemNode.view.snapshotContentTree(keepTransform: true), let targetSnapshotView = targetNode.view.snapshotContentTree() {
targetSnapshotView.frame = self.view.convert(targetNode.bounds, from: targetNode.view)
itemNode.isHidden = true
self.view.addSubview(targetSnapshotView)

View file

@ -255,7 +255,11 @@ final class ReactionSelectionNode: ASDisplayNode {
let backgroundHeight: CGFloat = floor(self.minimizedReactionSize * 1.8)
var backgroundFrame = CGRect(origin: CGPoint(x: -shadowBlur, y: -shadowBlur), size: CGSize(width: contentWidth + shadowBlur * 2.0, height: backgroundHeight + shadowBlur * 2.0))
backgroundFrame = backgroundFrame.offsetBy(dx: floor((constrainedSize.width - contentWidth) / 2.0), dy: startingPoint.y - backgroundHeight - 12.0)
if constrainedSize.width > 500.0 {
backgroundFrame = backgroundFrame.offsetBy(dx: constrainedSize.width - contentWidth - 44.0, dy: startingPoint.y - backgroundHeight - 12.0)
} else {
backgroundFrame = backgroundFrame.offsetBy(dx: floor((constrainedSize.width - contentWidth) / 2.0), dy: startingPoint.y - backgroundHeight - 12.0)
}
backgroundFrame.origin.x = max(0.0, backgroundFrame.minX)
backgroundFrame.origin.x = min(constrainedSize.width - backgroundFrame.width, backgroundFrame.minX)
@ -383,9 +387,9 @@ final class ReactionSelectionNode: ASDisplayNode {
let backgroundOffset: CGPoint
if self.isRightAligned {
backgroundOffset = CGPoint(x: (self.backgroundNode.frame.width - shadowBlur) / 2.0 - 42.0, y: (self.backgroundNode.frame.height - shadowBlur) / 2.0)
backgroundOffset = CGPoint(x: (self.backgroundNode.frame.width - shadowBlur) / 2.0 - 42.0, y: 10.0)
} else {
backgroundOffset = CGPoint(x: -(self.backgroundNode.frame.width - shadowBlur) / 2.0 + 42.0, y: (self.backgroundNode.frame.height - shadowBlur) / 2.0)
backgroundOffset = CGPoint(x: -(self.backgroundNode.frame.width - shadowBlur) / 2.0 + 42.0, y: 10.0)
}
let damping: CGFloat = 100.0
@ -393,14 +397,15 @@ final class ReactionSelectionNode: ASDisplayNode {
let animationOffset: Double = 1.0 - Double(i) / Double(self.reactionNodes.count - 1)
var nodeOffset: CGPoint
if self.isRightAligned {
nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.maxX - shadowBlur) / 2.0 - 42.0, y: self.reactionNodes[i].frame.minY - self.backgroundNode.frame.maxY - shadowBlur)
nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.maxX - shadowBlur) / 2.0 - 42.0, y: 10.0)
} else {
nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.minX + shadowBlur) / 2.0 - 42.0, y: self.reactionNodes[i].frame.minY - self.backgroundNode.frame.maxY - shadowBlur)
nodeOffset = CGPoint(x: self.reactionNodes[i].frame.minX - (self.backgroundNode.frame.minX + shadowBlur) / 2.0 - 42.0, y: 10.0)
}
nodeOffset.x = -nodeOffset.x
nodeOffset.x = 0.0
nodeOffset.y = 30.0
self.reactionNodes[i].layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5 + animationOffset * 0.28, initialVelocity: 0.0, damping: damping)
self.reactionNodes[i].layer.animateSpring(from: NSValue(cgPoint: nodeOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true)
self.reactionNodes[i].layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.04, delay: animationOffset * 0.1)
self.reactionNodes[i].layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, delay: animationOffset * 0.1, initialVelocity: 0.0, damping: damping)
//self.reactionNodes[i].layer.animateSpring(from: NSValue(cgPoint: nodeOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, delay: animationOffset * 0.1, initialVelocity: 0.0, damping: damping, additive: true)
}
self.backgroundNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, damping: damping)
@ -409,7 +414,7 @@ final class ReactionSelectionNode: ASDisplayNode {
self.backgroundShadowNode.layer.animateSpring(from: NSValue(cgPoint: backgroundOffset), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.5, initialVelocity: 0.0, damping: damping, additive: true)
}
func animateOut(into targetNode: ASImageNode?, hideTarget: Bool, completion: @escaping () -> Void) {
func animateOut(into targetNode: ASDisplayNode?, hideTarget: Bool, completion: @escaping () -> Void) {
self.hapticFeedback.prepareTap()
var completedContainer = false
@ -424,9 +429,8 @@ final class ReactionSelectionNode: ASDisplayNode {
if let targetNode = targetNode {
for i in 0 ..< self.reactionNodes.count {
if let isMaximized = self.reactionNodes[i].isMaximized, isMaximized {
if let snapshotView = self.reactionNodes[i].view.snapshotContentTree() {
let targetSnapshotView = UIImageView()
targetSnapshotView.image = targetNode.image
targetNode.recursivelyEnsureDisplaySynchronously(true)
if let snapshotView = self.reactionNodes[i].view.snapshotContentTree(), let targetSnapshotView = targetNode.view.snapshotContentTree() {
targetSnapshotView.frame = self.view.convert(targetNode.bounds, from: targetNode.view)
self.reactionNodes[i].isHidden = true
self.view.addSubview(targetSnapshotView)
@ -485,7 +489,7 @@ final class ReactionSelectionNode: ASDisplayNode {
}
}
self.backgroundNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
//self.backgroundNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.backgroundShadowNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.backgroundShadowNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in

View file

@ -47,7 +47,7 @@ public final class ReactionSelectionParentNode: ASDisplayNode {
return nil
}
func dismissReactions(into targetNode: ASImageNode?, hideTarget: Bool) {
func dismissReactions(into targetNode: ASDisplayNode?, hideTarget: Bool) {
if let currentNode = self.currentNode {
currentNode.animateOut(into: targetNode, hideTarget: hideTarget, completion: { [weak currentNode] in
currentNode?.removeFromSupernode()

View file

@ -102,7 +102,7 @@ public final class ReactionSwipeGestureRecognizer: UIPanGestureRecognizer {
}
let elevate = self.shouldElevateAnchorPoint?() ?? false
let activationTimer = Timer(timeInterval: elevate ? 0.1 : 0.01, target: TimerTarget { [weak self] in
let activationTimer = Timer(timeInterval: elevate ? 0.15 : 0.01, target: TimerTarget { [weak self] in
guard let strongSelf = self else {
return
}
@ -178,7 +178,7 @@ public final class ReactionSwipeGestureRecognizer: UIPanGestureRecognizer {
}
}
public func complete(into targetNode: ASImageNode?, hideTarget: Bool) {
public func complete(into targetNode: ASDisplayNode?, hideTarget: Bool) {
if self.isAwaitingCompletion {
self.currentContainer?.dismissReactions(into: targetNode, hideTarget: hideTarget)
self.state = .ended

View file

@ -5,6 +5,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[570911930] = { return $0.readInt64() }
dict[571523412] = { return $0.readDouble() }
dict[-1255641564] = { return parseString($0) }
dict[-475111160] = { return Api.MessageReactionsList.parse_messageReactionsList($0) }
dict[-1240849242] = { return Api.messages.StickerSet.parse_stickerSet($0) }
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
dict[-206066487] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
@ -243,6 +244,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[967122427] = { return Api.Update.parse_updateNewScheduledMessage($0) }
dict[-1870238482] = { return Api.Update.parse_updateDeleteScheduledMessages($0) }
dict[-2112423005] = { return Api.Update.parse_updateTheme($0) }
dict[357013699] = { return Api.Update.parse_updateMessageReactions($0) }
dict[-2027964103] = { return Api.Update.parse_updateGeoLiveViewed($0) }
dict[1448076945] = { return Api.Update.parse_updateLoginToken($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
@ -286,6 +288,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1012306921] = { return Api.InputTheme.parse_inputTheme($0) }
dict[-175567375] = { return Api.InputTheme.parse_inputThemeSlug($0) }
dict[1158290442] = { return Api.messages.FoundGifs.parse_foundGifs($0) }
dict[-1199954735] = { return Api.MessageReactions.parse_messageReactions($0) }
dict[-1132476723] = { return Api.FileLocation.parse_fileLocationToBeDeprecated($0) }
dict[-716006138] = { return Api.Poll.parse_poll($0) }
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
@ -564,7 +567,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1820043071] = { return Api.User.parse_user($0) }
dict[-2082087340] = { return Api.Message.parse_messageEmpty($0) }
dict[-1642487306] = { return Api.Message.parse_messageService($0) }
dict[1160515173] = { return Api.Message.parse_message($0) }
dict[-1752573244] = { return Api.Message.parse_message($0) }
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) }
dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) }
dict[-182231723] = { return Api.InputFileLocation.parse_inputEncryptedFileLocation($0) }
@ -619,6 +622,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) }
dict[-332168592] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) }
dict[398898678] = { return Api.help.Support.parse_support($0) }
dict[1873957073] = { return Api.ReactionCount.parse_reactionCount($0) }
dict[1474492012] = { return Api.MessagesFilter.parse_inputMessagesFilterEmpty($0) }
dict[-1777752804] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotos($0) }
dict[-1614803355] = { return Api.MessagesFilter.parse_inputMessagesFilterVideo($0) }
@ -646,6 +650,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1449145777] = { return Api.upload.CdnFile.parse_cdnFile($0) }
dict[1984136919] = { return Api.wallet.LiteResponse.parse_liteResponse($0) }
dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) }
dict[-764945220] = { return Api.MessageUserReaction.parse_messageUserReaction($0) }
dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) }
dict[982505656] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
@ -845,6 +850,8 @@ public struct Api {
public static func serializeObject(_ object: Any, buffer: Buffer, boxed: Swift.Bool) {
switch object {
case let _1 as Api.MessageReactionsList:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.StickerSet:
_1.serialize(buffer, boxed)
case let _1 as Api.InputGeoPoint:
@ -979,6 +986,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.messages.FoundGifs:
_1.serialize(buffer, boxed)
case let _1 as Api.MessageReactions:
_1.serialize(buffer, boxed)
case let _1 as Api.FileLocation:
_1.serialize(buffer, boxed)
case let _1 as Api.Poll:
@ -1271,6 +1280,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.help.Support:
_1.serialize(buffer, boxed)
case let _1 as Api.ReactionCount:
_1.serialize(buffer, boxed)
case let _1 as Api.MessagesFilter:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.Dialogs:
@ -1283,6 +1294,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.help.InviteText:
_1.serialize(buffer, boxed)
case let _1 as Api.MessageUserReaction:
_1.serialize(buffer, boxed)
case let _1 as Api.BotInlineMessage:
_1.serialize(buffer, boxed)
case let _1 as Api.InputPeerNotifySettings:

View file

@ -1,4 +1,66 @@
public extension Api {
public enum MessageReactionsList: TypeConstructorDescription {
case messageReactionsList(flags: Int32, count: Int32, reactions: [Api.MessageUserReaction], users: [Api.User], nextOffset: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageReactionsList(let flags, let count, let reactions, let users, let nextOffset):
if boxed {
buffer.appendInt32(-475111160)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(reactions.count))
for item in reactions {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageReactionsList(let flags, let count, let reactions, let users, let nextOffset):
return ("messageReactionsList", [("flags", flags), ("count", count), ("reactions", reactions), ("users", users), ("nextOffset", nextOffset)])
}
}
public static func parse_messageReactionsList(_ reader: BufferReader) -> MessageReactionsList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.MessageUserReaction]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserReaction.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.MessageReactionsList.messageReactionsList(flags: _1!, count: _2!, reactions: _3!, users: _4!, nextOffset: _5)
}
else {
return nil
}
}
}
public enum InputGeoPoint: TypeConstructorDescription {
case inputGeoPointEmpty
case inputGeoPoint(lat: Double, long: Double)
@ -4082,6 +4144,7 @@ public extension Api {
case updateNewScheduledMessage(message: Api.Message)
case updateDeleteScheduledMessages(peer: Api.Peer, messages: [Int32])
case updateTheme(theme: Api.Theme)
case updateMessageReactions(peer: Api.Peer, msgId: Int32, reactions: Api.MessageReactions)
case updateGeoLiveViewed(peer: Api.Peer, msgId: Int32)
case updateLoginToken
@ -4708,6 +4771,14 @@ public extension Api {
}
theme.serialize(buffer, true)
break
case .updateMessageReactions(let peer, let msgId, let reactions):
if boxed {
buffer.appendInt32(357013699)
}
peer.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
reactions.serialize(buffer, true)
break
case .updateGeoLiveViewed(let peer, let msgId):
if boxed {
buffer.appendInt32(-2027964103)
@ -4874,6 +4945,8 @@ public extension Api {
return ("updateDeleteScheduledMessages", [("peer", peer), ("messages", messages)])
case .updateTheme(let theme):
return ("updateTheme", [("theme", theme)])
case .updateMessageReactions(let peer, let msgId, let reactions):
return ("updateMessageReactions", [("peer", peer), ("msgId", msgId), ("reactions", reactions)])
case .updateGeoLiveViewed(let peer, let msgId):
return ("updateGeoLiveViewed", [("peer", peer), ("msgId", msgId)])
case .updateLoginToken:
@ -6136,6 +6209,27 @@ public extension Api {
return nil
}
}
public static func parse_updateMessageReactions(_ reader: BufferReader) -> Update? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.MessageReactions?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.MessageReactions
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.Update.updateMessageReactions(peer: _1!, msgId: _2!, reactions: _3!)
}
else {
return nil
}
}
public static func parse_updateGeoLiveViewed(_ reader: BufferReader) -> Update? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
@ -7110,6 +7204,50 @@ public extension Api {
}
}
}
public enum MessageReactions: TypeConstructorDescription {
case messageReactions(flags: Int32, results: [Api.ReactionCount])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageReactions(let flags, let results):
if boxed {
buffer.appendInt32(-1199954735)
}
serializeInt32(flags, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(results.count))
for item in results {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageReactions(let flags, let results):
return ("messageReactions", [("flags", flags), ("results", results)])
}
}
public static func parse_messageReactions(_ reader: BufferReader) -> MessageReactions? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Api.ReactionCount]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ReactionCount.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageReactions.messageReactions(flags: _1!, results: _2!)
}
else {
return nil
}
}
}
public enum FileLocation: TypeConstructorDescription {
case fileLocationToBeDeprecated(volumeId: Int64, localId: Int32)
@ -14222,7 +14360,7 @@ public extension Api {
public enum Message: TypeConstructorDescription {
case messageEmpty(id: Int32)
case messageService(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, replyToMsgId: Int32?, date: Int32, action: Api.MessageAction)
case message(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, restrictionReason: [Api.RestrictionReason]?)
case message(flags: Int32, id: Int32, fromId: Int32?, toId: Api.Peer, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int32?, replyToMsgId: Int32?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -14244,9 +14382,9 @@ public extension Api {
serializeInt32(date, buffer: buffer, boxed: false)
action.serialize(buffer, true)
break
case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId, let restrictionReason):
case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason):
if boxed {
buffer.appendInt32(1160515173)
buffer.appendInt32(-1752573244)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(id, buffer: buffer, boxed: false)
@ -14268,6 +14406,7 @@ public extension Api {
if Int(flags) & Int(1 << 15) != 0 {serializeInt32(editDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 16) != 0 {serializeString(postAuthor!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 17) != 0 {serializeInt64(groupedId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 20) != 0 {reactions!.serialize(buffer, true)}
if Int(flags) & Int(1 << 22) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(restrictionReason!.count))
for item in restrictionReason! {
@ -14283,8 +14422,8 @@ public extension Api {
return ("messageEmpty", [("id", id)])
case .messageService(let flags, let id, let fromId, let toId, let replyToMsgId, let date, let action):
return ("messageService", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("replyToMsgId", replyToMsgId), ("date", date), ("action", action)])
case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId, let restrictionReason):
return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId), ("restrictionReason", restrictionReason)])
case .message(let flags, let id, let fromId, let toId, let fwdFrom, let viaBotId, let replyToMsgId, let date, let message, let media, let replyMarkup, let entities, let views, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason):
return ("message", [("flags", flags), ("id", id), ("fromId", fromId), ("toId", toId), ("fwdFrom", fwdFrom), ("viaBotId", viaBotId), ("replyToMsgId", replyToMsgId), ("date", date), ("message", message), ("media", media), ("replyMarkup", replyMarkup), ("entities", entities), ("views", views), ("editDate", editDate), ("postAuthor", postAuthor), ("groupedId", groupedId), ("reactions", reactions), ("restrictionReason", restrictionReason)])
}
}
@ -14375,9 +14514,13 @@ public extension Api {
if Int(_1!) & Int(1 << 16) != 0 {_15 = parseString(reader) }
var _16: Int64?
if Int(_1!) & Int(1 << 17) != 0 {_16 = reader.readInt64() }
var _17: [Api.RestrictionReason]?
var _17: Api.MessageReactions?
if Int(_1!) & Int(1 << 20) != 0 {if let signature = reader.readInt32() {
_17 = Api.parse(reader, signature: signature) as? Api.MessageReactions
} }
var _18: [Api.RestrictionReason]?
if Int(_1!) & Int(1 << 22) != 0 {if let _ = reader.readInt32() {
_17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
_18 = Api.parseVector(reader, elementSignature: 0, elementType: Api.RestrictionReason.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
@ -14395,9 +14538,10 @@ public extension Api {
let _c14 = (Int(_1!) & Int(1 << 15) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 16) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 17) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 22) == 0) || _17 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 {
return Api.Message.message(flags: _1!, id: _2!, fromId: _3, toId: _4!, fwdFrom: _5, viaBotId: _6, replyToMsgId: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, editDate: _14, postAuthor: _15, groupedId: _16, restrictionReason: _17)
let _c17 = (Int(_1!) & Int(1 << 20) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 22) == 0) || _18 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 {
return Api.Message.message(flags: _1!, id: _2!, fromId: _3, toId: _4!, fwdFrom: _5, viaBotId: _6, replyToMsgId: _7, date: _8!, message: _9!, media: _10, replyMarkup: _11, entities: _12, views: _13, editDate: _14, postAuthor: _15, groupedId: _16, reactions: _17, restrictionReason: _18)
}
else {
return nil
@ -15890,6 +16034,48 @@ public extension Api {
}
}
}
public enum ReactionCount: TypeConstructorDescription {
case reactionCount(flags: Int32, reaction: String, count: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .reactionCount(let flags, let reaction, let count):
if boxed {
buffer.appendInt32(1873957073)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(reaction, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .reactionCount(let flags, let reaction, let count):
return ("reactionCount", [("flags", flags), ("reaction", reaction), ("count", count)])
}
}
public static func parse_reactionCount(_ reader: BufferReader) -> ReactionCount? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.ReactionCount.reactionCount(flags: _1!, reaction: _2!, count: _3!)
}
else {
return nil
}
}
}
public enum MessagesFilter: TypeConstructorDescription {
case inputMessagesFilterEmpty
@ -16202,6 +16388,44 @@ public extension Api {
}
}
}
public enum MessageUserReaction: TypeConstructorDescription {
case messageUserReaction(userId: Int32, reaction: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageUserReaction(let userId, let reaction):
if boxed {
buffer.appendInt32(-764945220)
}
serializeInt32(userId, buffer: buffer, boxed: false)
serializeString(reaction, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageUserReaction(let userId, let reaction):
return ("messageUserReaction", [("userId", userId), ("reaction", reaction)])
}
}
public static func parse_messageUserReaction(_ reader: BufferReader) -> MessageUserReaction? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageUserReaction.messageUserReaction(userId: _1!, reaction: _2!)
}
else {
return nil
}
}
}
public enum BotInlineMessage: TypeConstructorDescription {
case botInlineMessageText(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?)

View file

@ -3161,6 +3161,61 @@ public extension Api {
return result
})
}
public static func sendReaction(flags: Int32, peer: Api.InputPeer, msgId: Int32, reaction: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(627641572)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeString(reaction!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "messages.sendReaction", parameters: [("flags", flags), ("peer", peer), ("msgId", msgId), ("reaction", reaction)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
public static func getMessagesReactions(peer: Api.InputPeer, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(-1950707482)
peer.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(id.count))
for item in id {
serializeInt32(item, buffer: buffer, boxed: false)
}
return (FunctionDescription(name: "messages.getMessagesReactions", parameters: [("peer", peer), ("id", id)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
public static func getMessageReactionsList(flags: Int32, peer: Api.InputPeer, id: Int32, reaction: String?, offset: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.MessageReactionsList>) {
let buffer = Buffer()
buffer.appendInt32(363935594)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeString(reaction!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(offset!, buffer: buffer, boxed: false)}
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.getMessageReactionsList", parameters: [("flags", flags), ("peer", peer), ("id", id), ("reaction", reaction), ("offset", offset), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.MessageReactionsList? in
let reader = BufferReader(buffer)
var result: Api.MessageReactionsList?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.MessageReactionsList
}
return result
})
}
}
public struct channels {
public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {

View file

@ -62,7 +62,7 @@ enum AccountStateMutationOperation {
case DeleteMessages([MessageId])
case EditMessage(MessageId, StoreMessage)
case UpdateMessagePoll(MediaId, Api.Poll?, Api.PollResults)
//case UpdateMessageReactions(MessageId, Api.MessageReactions)
case UpdateMessageReactions(MessageId, Api.MessageReactions)
case UpdateMedia(MediaId, Media?)
case ReadInbox(MessageId)
case ReadOutbox(MessageId, Int32?)
@ -217,9 +217,9 @@ struct AccountMutableState {
self.addOperation(.UpdateMessagePoll(id, poll, results))
}
/*mutating func updateMessageReactions(_ messageId: MessageId, reactions: Api.MessageReactions) {
mutating func updateMessageReactions(_ messageId: MessageId, reactions: Api.MessageReactions) {
self.addOperation(.UpdateMessageReactions(messageId, reactions))
}*/
}
mutating func updateMedia(_ id: MediaId, media: Media?) {
self.addOperation(.UpdateMedia(id, media))
@ -404,7 +404,7 @@ struct AccountMutableState {
mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, /*.UpdateMessageReactions,*/ .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme:
break
case let .AddMessages(messages, location):
for message in messages {

View file

@ -1280,8 +1280,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
updatedState.updateLangPack(langCode: langCode, difference: difference)
case let .updateMessagePoll(_, pollId, poll, results):
updatedState.updateMessagePoll(MediaId(namespace: Namespaces.Media.CloudPoll, id: pollId), poll: poll, results: results)
/*case let .updateMessageReactions(peer, msgId, reactions):
updatedState.updateMessageReactions(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: msgId), reactions: reactions)*/
case let .updateMessageReactions(peer, msgId, reactions):
updatedState.updateMessageReactions(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: msgId), reactions: reactions)
case let .updateFolderPeers(folderPeers, _, _):
for folderPeer in folderPeers {
switch folderPeer {
@ -2025,7 +2025,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddScheduledMessages: OptimizeAddMessagesState?
for operation in operations {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, /*.UpdateMessageReactions,*/ .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
}
@ -2347,7 +2347,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
updatedPoll = updatedPoll.withUpdatedResults(TelegramMediaPollResults(apiResults: results), min: resultsMin)
updateMessageMedia(transaction: transaction, id: pollId, media: updatedPoll)
}
/*case let .UpdateMessageReactions(messageId, reactions):
case let .UpdateMessageReactions(messageId, reactions):
transaction.updateMessage(messageId, update: { currentMessage in
var storeForwardInfo: StoreMessageForwardInfo?
if let forwardInfo = currentMessage.forwardInfo {
@ -2366,7 +2366,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
attributes.append(ReactionsMessageAttribute(apiReactions: reactions))
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})*/
})
case let .UpdateMedia(id, media):
if let media = media as? TelegramMediaWebpage {
updatedWebpages[id] = media

View file

@ -33,9 +33,7 @@ private enum RequestUpdateMessageReactionError {
}
private func requestUpdateMessageReaction(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId) -> Signal<Never, RequestUpdateMessageReactionError> {
return .complete()
/*return postbox.transaction { transaction -> (Peer, String?)? in
return postbox.transaction { transaction -> (Peer, String?)? in
guard let peer = transaction.getPeer(messageId.peerId) else {
return nil
}
@ -91,7 +89,7 @@ private func requestUpdateMessageReaction(postbox: Postbox, network: Network, st
|> castError(RequestUpdateMessageReactionError.self)
|> ignoreValues
}
}*/
}
}
private final class ManagedApplyPendingMessageReactionsActionsHelper {

View file

@ -4,7 +4,7 @@ import TelegramApi
import SyncCore
/*extension ReactionsMessageAttribute {
extension ReactionsMessageAttribute {
func withUpdatedResults(_ reactions: Api.MessageReactions) -> ReactionsMessageAttribute {
switch reactions {
case let .messageReactions(flags, results):
@ -34,7 +34,7 @@ import SyncCore
return ReactionsMessageAttribute(reactions: reactions)
}
}
}*/
}
public func mergedMessageReactions(attributes: [MessageAttribute]) -> ReactionsMessageAttribute? {
var current: ReactionsMessageAttribute?
@ -86,7 +86,7 @@ public func mergedMessageReactions(attributes: [MessageAttribute]) -> ReactionsM
}
}
/*extension ReactionsMessageAttribute {
extension ReactionsMessageAttribute {
convenience init(apiReactions: Api.MessageReactions) {
switch apiReactions {
case let .messageReactions(_, results):
@ -99,4 +99,3 @@ public func mergedMessageReactions(attributes: [MessageAttribute]) -> ReactionsM
}
}
}
*/

View file

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 107
return 108
}
public func parseMessage(_ data: Data!) -> Any! {

View file

@ -136,7 +136,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
switch message {
case let .message(flags, _, fromId, toId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _):
case let .message(flags, _, fromId, toId, fwdHeader, viaBotId, _, _, _, media, _, entities, _, _, _, _, _, _):
let peerId: PeerId
switch toId {
case let .peerUser(userId):
@ -240,7 +240,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? {
switch message {
case let .message(flags, _, fromId, toId, _, _, replyToMsgId, _, _, _, _, _, _, _, _, _, _):
case let .message(flags, _, fromId, toId, _, _, replyToMsgId, _, _, _, _, _, _, _, _, _, _, _):
if let replyToMsgId = replyToMsgId {
let peerId: PeerId
switch toId {
@ -382,7 +382,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
extension StoreMessage {
convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
switch apiMessage {
case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, editDate, postAuthor, groupingId, restrictionReason):
case let .message(flags, id, fromId, toId, fwdFrom, viaBotId, replyToMsgId, date, message, media, replyMarkup, entities, views, editDate, postAuthor, groupingId, reactions, restrictionReason):
let peerId: PeerId
var authorId: PeerId?
switch toId {
@ -537,9 +537,9 @@ extension StoreMessage {
attributes.append(ContentRequiresValidationMessageAttribute())
}
/*if let reactions = reactions {
if let reactions = reactions {
attributes.append(ReactionsMessageAttribute(apiReactions: reactions))
}*/
}
if let restrictionReason = restrictionReason {
attributes.append(RestrictedContentMessageAttribute(rules: restrictionReason.map(RestrictionRule.init(apiReason:))))

View file

@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
self.putNext(groups)
}
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyToMsgId, entities):
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: fromId, toId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil/*, reactions: nil*/, restrictionReason: nil)
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: fromId, toId: Api.Peer.peerChat(chatId: chatId), fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {
@ -75,7 +75,7 @@ class UpdateMessageService: NSObject, MTMessageService {
generatedToId = Api.Peer.peerUser(userId: self.peerId.id)
}
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, toId: generatedToId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil/*, reactions: nil*/, restrictionReason: nil)
let generatedMessage = Api.Message.message(flags: flags, id: id, fromId: generatedFromId, toId: generatedToId, fwdFrom: fwdFrom, viaBotId: viaBotId, replyToMsgId: replyToMsgId, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil)
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
if groups.count != 0 {

View file

@ -98,7 +98,7 @@ public final class ChatControllerInteraction {
let sendScheduledMessagesNow: ([MessageId]) -> Void
let editScheduledMessagesTime: ([MessageId]) -> Void
let performTextSelectionAction: (UInt32, String, TextSelectionAction) -> Void
let updateMessageReaction: (MessageId, String) -> Void
let updateMessageReaction: (MessageId, String?) -> Void
let openMessageReactions: (MessageId) -> Void
let displaySwipeToReplyHint: () -> Void
@ -115,7 +115,7 @@ public final class ChatControllerInteraction {
var searchTextHighightState: (String, [MessageIndex])?
var seenOneTimeAnimatedMedia = Set<MessageId>()
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
self.openMessage = openMessage
self.openPeer = openPeer
self.openPeerMention = openPeerMention

View file

@ -1051,7 +1051,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
return self.contentImageNode?.playMediaWithSound()
}
func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}

View file

@ -177,7 +177,7 @@ class ChatMessageBubbleContentNode: ASDisplayNode {
func updateIsExtractedToContextPreview(_ value: Bool) {
}
func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
return nil
}
}

View file

@ -522,8 +522,14 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
if let item = strongSelf.item, let reaction = reaction {
switch reaction {
case let .reaction(value, _, _):
strongSelf.awaitingAppliedReaction = (value, {})
item.controllerInteraction.updateMessageReaction(item.message.id, value)
var resolvedValue: String?
if let reactionsAttribute = mergedMessageReactions(attributes: item.message.attributes), reactionsAttribute.reactions.contains(where: { $0.value == value }) {
resolvedValue = nil
} else {
resolvedValue = value
}
strongSelf.awaitingAppliedReaction = (resolvedValue, {})
item.controllerInteraction.updateMessageReaction(item.message.id, resolvedValue)
case .reply:
strongSelf.reactionRecognizer?.complete(into: nil, hideTarget: false)
var bounds = strongSelf.bounds
@ -1994,13 +2000,15 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
}
strongSelf.awaitingAppliedReaction = nil
var targetNode: ASImageNode?
var targetNode: ASDisplayNode?
var hideTarget = false
for contentNode in strongSelf.contentNodes {
if let (reactionNode, count) = contentNode.reactionTargetNode(value: awaitingAppliedReaction) {
targetNode = reactionNode
hideTarget = count == 1
break
if let awaitingAppliedReaction = awaitingAppliedReaction {
for contentNode in strongSelf.contentNodes {
if let (reactionNode, count) = contentNode.reactionTargetNode(value: awaitingAppliedReaction) {
targetNode = reactionNode
hideTarget = count == 1
break
}
}
}
strongSelf.reactionRecognizer?.complete(into: targetNode, hideTarget: hideTarget)
@ -2852,7 +2860,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
self.contextSourceNode.contentNode.addSubnode(accessoryItemNode)
}
override func targetReactionNode(value: String) -> (ASImageNode, Int)? {
override func targetReactionNode(value: String) -> (ASDisplayNode, Int)? {
for contentNode in self.contentNodes {
if let (reactionNode, count) = contentNode.reactionTargetNode(value: value) {
return (reactionNode, count)

View file

@ -346,7 +346,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}

View file

@ -8,6 +8,7 @@ import Display
import SwiftSignalKit
import TelegramPresentationData
import AccountContext
import AppBundle
private let reactionCountFont = Font.semibold(11.0)
@ -42,26 +43,90 @@ enum ChatMessageDateAndStatusType: Equatable {
case FreeOutgoing(ChatMessageDateAndStatusOutgoingType)
}
private let reactionSize: CGFloat = 19.0
private let reactionSize: CGFloat = 20.0
private let reactionFont = Font.regular(12.0)
private final class StatusReactionNode: ASImageNode {
private final class StatusReactionNodeParameters: NSObject {
let value: String
let previousValue: String?
init(value: String, previousValue: String?) {
self.value = value
self.previousValue = previousValue
}
}
private func drawReaction(context: CGContext, value: String, in rect: CGRect) {
var fileId: Int?
switch value {
case "😔":
fileId = 8
case "😳":
fileId = 19
case "😂":
fileId = 17
case "👍":
fileId = 6
case "":
fileId = 13
default:
break
}
if let fileId = fileId, let path = getAppBundle().path(forResource: "simplereaction_\(fileId)@2x", ofType: "png"), let image = UIImage(contentsOfFile: path) {
context.saveGState()
context.translateBy(x: rect.midX, y: rect.midY)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: -rect.midX, y: -rect.midY)
context.draw(image.cgImage!, in: rect)
context.restoreGState()
} else {
let string = NSAttributedString(string: value, font: reactionFont, textColor: .black)
string.draw(at: CGPoint(x: rect.minX + 1.0, y: rect.minY + 3.0))
}
}
private final class StatusReactionNode: ASDisplayNode {
let value: String
var count: Int
var previousValue: String? {
didSet {
self.setNeedsDisplay()
}
}
init(value: String, count: Int) {
init(value: String, count: Int, previousValue: String?) {
self.value = value
self.count = count
self.previousValue = previousValue
super.init()
self.image = generateImage(CGSize(width: reactionSize, height: reactionSize), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
UIGraphicsPushContext(context)
let string = NSAttributedString(string: value, font: reactionFont, textColor: .black)
string.draw(at: CGPoint(x: 1.0, y: 3.0))
UIGraphicsPopContext()
})
self.isOpaque = false
self.backgroundColor = nil
}
override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
return StatusReactionNodeParameters(value: self.value, previousValue: self.previousValue)
}
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
let context = UIGraphicsGetCurrentContext()!
if !isRasterizing {
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
context.fill(bounds)
}
guard let parameters = parameters as? StatusReactionNodeParameters else {
return
}
drawReaction(context: context, value: parameters.value, in: bounds)
if let previousValue = parameters.previousValue {
let previousRect = bounds.offsetBy(dx: -14.0, dy: 0)
context.setBlendMode(.destinationOut)
drawReaction(context: context, value: previousValue, in: previousRect)
}
}
}
@ -346,9 +411,11 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
var reactionCountLayoutAndApply: (TextNodeLayout, () -> TextNode)?
let reactionSpacing: CGFloat = -4.0
let reactionTrailingSpacing: CGFloat = 4.0
var reactionInset: CGFloat = 0.0
if !reactions.isEmpty {
reactionInset = 5.0 + CGFloat(reactions.count) * reactionSize
reactionInset = 5.0 + CGFloat(reactions.count) * reactionSize + CGFloat(reactions.count - 1) * reactionSpacing + reactionTrailingSpacing
var count = 0
for reaction in reactions {
@ -499,8 +566,9 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
if strongSelf.reactionNodes.count > i, strongSelf.reactionNodes[i].value == reactions[i].value {
node = strongSelf.reactionNodes[i]
node.count = Int(reactions[i].count)
node.previousValue = i == 0 ? nil : reactions[i - 1].value
} else {
node = StatusReactionNode(value: reactions[i].value, count: Int(reactions[i].count))
node = StatusReactionNode(value: reactions[i].value, count: Int(reactions[i].count), previousValue: i == 0 ? nil : reactions[i - 1].value)
if strongSelf.reactionNodes.count > i {
let previousNode = strongSelf.reactionNodes[i]
if animated {
@ -522,11 +590,15 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
}
}
node.frame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + offset - 3.0), size: CGSize(width: reactionSize, height: reactionSize))
reactionOffset += reactionSize
reactionOffset += reactionSize + reactionSpacing
}
if !reactions.isEmpty {
reactionOffset += reactionTrailingSpacing
}
for _ in reactions.count ..< strongSelf.reactionNodes.count {
let node = strongSelf.reactionNodes.removeLast()
if animated {
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()
})
@ -558,7 +630,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
}
}
if !strongSelf.reactionNodes.isEmpty {
if false, !strongSelf.reactionNodes.isEmpty {
if strongSelf.reactionButtonNode == nil {
let reactionButtonNode = HighlightTrackingButtonNode()
strongSelf.reactionButtonNode = reactionButtonNode
@ -610,7 +682,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
}
}
func reactionNode(value: String) -> (ASImageNode, Int)? {
func reactionNode(value: String) -> (ASDisplayNode, Int)? {
for node in self.reactionNodes {
if node.value == value {
return (node, node.count)

View file

@ -119,7 +119,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
self.interactiveFileNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
return self.interactiveFileNode.reactionTargetNode(value: value)
}
}

View file

@ -134,7 +134,7 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode {
return self.contentNode.transitionNode(media: media)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
return self.contentNode.reactionTargetNode(value: value)
}
}

View file

@ -947,7 +947,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
self.playerUpdateTimer = nil
}
func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}

View file

@ -137,7 +137,7 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode {
return self.contentNode.transitionNode(media: media)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
return self.contentNode.reactionTargetNode(value: value)
}
}

View file

@ -634,7 +634,7 @@ public class ChatMessageItemView: ListViewItemNode {
var item: ChatMessageItem?
var accessibilityData: ChatMessageAccessibilityData?
var awaitingAppliedReaction: (String, () -> Void)?
var awaitingAppliedReaction: (String?, () -> Void)?
public required convenience init() {
self.init(layerBacked: false)
@ -814,7 +814,7 @@ public class ChatMessageItemView: ListViewItemNode {
}
}
func targetReactionNode(value: String) -> (ASImageNode, Int)? {
func targetReactionNode(value: String) -> (ASDisplayNode, Int)? {
return nil
}
}

View file

@ -469,7 +469,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}

View file

@ -386,7 +386,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
return false
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.dateAndStatusNode.isHidden {
return self.dateAndStatusNode.reactionNode(value: value)
}

View file

@ -955,7 +955,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}

View file

@ -245,7 +245,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
self.statusNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}

View file

@ -579,7 +579,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
}
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
if !self.statusNode.isHidden {
return self.statusNode.reactionNode(value: value)
}

View file

@ -511,7 +511,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
self.contentNode.updateTouchesAtPoint(point.flatMap { $0.offsetBy(dx: -contentNodeFrame.minX, dy: -contentNodeFrame.minY) })
}
override func reactionTargetNode(value: String) -> (ASImageNode, Int)? {
override func reactionTargetNode(value: String) -> (ASDisplayNode, Int)? {
return self.contentNode.reactionTargetNode(value: value)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB