mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Reaction updates
This commit is contained in:
parent
f47fa686e9
commit
85b5913b6a
@ -7252,3 +7252,4 @@ Sorry for the inconvenience.";
|
||||
"Group.Members.Other" = "OTHERS MEMBERS";
|
||||
|
||||
"Conversation.ReadAllReactions" = "Read All Reactions";
|
||||
"ChatList.UserReacted" = "Reacted %@ to your message";
|
||||
|
@ -983,6 +983,20 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
initialHideAuthor = true
|
||||
messageText = psaText
|
||||
}
|
||||
|
||||
switch itemPeer.peer {
|
||||
case .user:
|
||||
if let attribute = messages.first?._asMessage().reactionsAttribute {
|
||||
loop: for recentPeer in attribute.recentPeers {
|
||||
if recentPeer.isUnseen {
|
||||
messageText = item.presentationData.strings.ChatList_UserReacted(recentPeer.value).string
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers)
|
||||
hideAuthor = initialHideAuthor
|
||||
@ -1307,13 +1321,16 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
|
||||
if !isPeerGroup {
|
||||
if hasUnseenMentions || hasUnseenReactions {
|
||||
if hasUnseenMentions {
|
||||
if case .archive = item.peerGroupId {
|
||||
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveMention(item.presentationData.theme, diameter: badgeDiameter)
|
||||
} else {
|
||||
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundMention(item.presentationData.theme, diameter: badgeDiameter)
|
||||
}
|
||||
mentionBadgeContent = .mention
|
||||
} else if hasUnseenReactions {
|
||||
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundReactions(item.presentationData.theme, diameter: badgeDiameter)
|
||||
mentionBadgeContent = .mention
|
||||
} else if item.index.pinningIndex != nil && promoInfo == nil && currentBadgeBackgroundImage == nil {
|
||||
currentPinnedIconImage = PresentationResourcesChatList.badgeBackgroundPinned(item.presentationData.theme, diameter: badgeDiameter)
|
||||
}
|
||||
|
@ -2800,6 +2800,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
var frame = itemNode.frame
|
||||
frame.origin.y += offset
|
||||
itemNode.updateFrame(frame, within: self.visibleSize)
|
||||
self.didScrollWithOffset?(-offset, .immediate, itemNode)
|
||||
if let accessoryItemNode = itemNode.accessoryItemNode {
|
||||
itemNode.layoutAccessoryItemNode(accessoryItemNode, leftInset: listInsets.left, rightInset: listInsets.right)
|
||||
}
|
||||
|
@ -656,7 +656,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
context: strongSelf.context,
|
||||
theme: strongSelf.context.sharedContext.currentPresentationData.with({ $0 }).theme,
|
||||
reaction: itemNode.item,
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: nil,
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
@ -863,11 +865,11 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
self.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, reaction: ReactionContextItem, targetView: UIView, completion: @escaping () -> Void) {
|
||||
self.animateReactionSelection(context: context, theme: theme, reaction: reaction, targetView: targetView, currentItemNode: nil, completion: completion)
|
||||
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, reaction: ReactionContextItem, isLarge: Bool, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) {
|
||||
self.animateReactionSelection(context: context, theme: theme, reaction: reaction, isLarge: isLarge, targetView: targetView, addStandaloneReactionAnimation: addStandaloneReactionAnimation, currentItemNode: nil, completion: completion)
|
||||
}
|
||||
|
||||
func animateReactionSelection(context: AccountContext, theme: PresentationTheme, reaction: ReactionContextItem, targetView: UIView, currentItemNode: ReactionNode?, completion: @escaping () -> Void) {
|
||||
func animateReactionSelection(context: AccountContext, theme: PresentationTheme, reaction: ReactionContextItem, isLarge: Bool, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, currentItemNode: ReactionNode?, completion: @escaping () -> Void) {
|
||||
guard let sourceSnapshotView = targetView.snapshotContentTree() else {
|
||||
completion()
|
||||
return
|
||||
@ -883,7 +885,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
}
|
||||
self.itemNode = itemNode
|
||||
|
||||
if let targetView = targetView as? ReactionIconView {
|
||||
if let targetView = targetView as? ReactionIconView, !isLarge {
|
||||
self.itemNodeIsEmbedded = true
|
||||
targetView.addSubnode(itemNode)
|
||||
} else {
|
||||
@ -894,7 +896,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
guard let strongSelf = self, let targetView = targetView else {
|
||||
return
|
||||
}
|
||||
if let targetView = targetView as? ReactionIconView {
|
||||
if let targetView = targetView as? ReactionIconView, !isLarge {
|
||||
strongSelf.itemNodeIsEmbedded = true
|
||||
|
||||
targetView.imageView.isHidden = true
|
||||
@ -906,37 +908,54 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
itemNode.isExtracted = true
|
||||
let selfTargetRect = self.view.convert(targetView.bounds, from: targetView)
|
||||
|
||||
let expandedSize: CGSize = selfTargetRect.size
|
||||
var expandedSize: CGSize = selfTargetRect.size
|
||||
if isLarge {
|
||||
expandedSize = CGSize(width: 120.0, height: 120.0)
|
||||
}
|
||||
|
||||
let expandedFrame = CGRect(origin: CGPoint(x: selfTargetRect.midX - expandedSize.width / 2.0, y: selfTargetRect.midY - expandedSize.height / 2.0), size: expandedSize)
|
||||
|
||||
let effectFrame = expandedFrame.insetBy(dx: -60.0, dy: -60.0)
|
||||
let effectFrame: CGRect
|
||||
let incomingMessage: Bool = expandedFrame.midX < self.bounds.width / 2.0
|
||||
if isLarge {
|
||||
effectFrame = expandedFrame.insetBy(dx: -expandedFrame.width * 0.5, dy: -expandedFrame.height * 0.5).offsetBy(dx: incomingMessage ? (expandedFrame.width - 50.0) : (-expandedFrame.width + 50.0), dy: 0.0)
|
||||
} else {
|
||||
effectFrame = expandedFrame.insetBy(dx: -60.0, dy: -60.0)
|
||||
}
|
||||
|
||||
sourceSnapshotView.frame = selfTargetRect
|
||||
self.view.addSubview(sourceSnapshotView)
|
||||
sourceSnapshotView.alpha = 0.0
|
||||
sourceSnapshotView.layer.animateSpring(from: 1.0 as NSNumber, to: (expandedFrame.width / selfTargetRect.width) as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||
sourceSnapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.01, completion: { [weak sourceSnapshotView] _ in
|
||||
sourceSnapshotView?.removeFromSuperview()
|
||||
})
|
||||
if !self.itemNodeIsEmbedded {
|
||||
sourceSnapshotView.frame = selfTargetRect
|
||||
self.view.addSubview(sourceSnapshotView)
|
||||
sourceSnapshotView.alpha = 0.0
|
||||
sourceSnapshotView.layer.animateSpring(from: 1.0 as NSNumber, to: (expandedFrame.width / selfTargetRect.width) as NSNumber, keyPath: "transform.scale", duration: 0.7)
|
||||
sourceSnapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.01, completion: { [weak sourceSnapshotView] _ in
|
||||
sourceSnapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
if self.itemNodeIsEmbedded {
|
||||
itemNode.frame = targetView.bounds
|
||||
} else {
|
||||
itemNode.frame = expandedFrame
|
||||
|
||||
itemNode.layer.animateSpring(from: (selfTargetRect.width / expandedFrame.width) as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||
|
||||
if targetView.bounds.width < 25.0 {
|
||||
itemNode.layer.animateScale(from: 0.01, to: 1.0, duration: 0.15)
|
||||
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
itemNode.layer.animateSpring(from: (selfTargetRect.width / expandedFrame.width) as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.7)
|
||||
}
|
||||
|
||||
itemNode.updateLayout(size: expandedFrame.size, isExpanded: true, largeExpanded: false, isPreviewing: false, transition: .immediate)
|
||||
itemNode.updateLayout(size: expandedFrame.size, isExpanded: true, largeExpanded: isLarge, isPreviewing: false, transition: .immediate)
|
||||
|
||||
let additionalAnimationNode = AnimatedStickerNode()
|
||||
additionalAnimationNode.setup(source: AnimatedStickerResourceSource(account: itemNode.context.account, resource: itemNode.item.applicationAnimation.resource), width: Int(effectFrame.width * 2.0), height: Int(effectFrame.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: itemNode.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(itemNode.item.applicationAnimation.resource.id)))
|
||||
|
||||
let additionalAnimation: TelegramMediaFile
|
||||
if isLarge {
|
||||
additionalAnimation = itemNode.item.largeApplicationAnimation
|
||||
if incomingMessage {
|
||||
additionalAnimationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
|
||||
}
|
||||
} else {
|
||||
additionalAnimation = itemNode.item.applicationAnimation
|
||||
}
|
||||
|
||||
additionalAnimationNode.setup(source: AnimatedStickerResourceSource(account: itemNode.context.account, resource: additionalAnimation.resource), width: Int(effectFrame.width * 2.0), height: Int(effectFrame.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: itemNode.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(additionalAnimation.resource.id)))
|
||||
additionalAnimationNode.frame = effectFrame
|
||||
additionalAnimationNode.updateLayout(size: effectFrame.size)
|
||||
self.addSubnode(additionalAnimationNode)
|
||||
@ -960,28 +979,52 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
return
|
||||
}
|
||||
|
||||
if let targetView = strongSelf.targetView {
|
||||
if let targetView = targetView as? ReactionIconView {
|
||||
targetView.imageView.isHidden = false
|
||||
} else {
|
||||
targetView.alpha = 1.0
|
||||
targetView.isHidden = false
|
||||
if isLarge {
|
||||
strongSelf.animateFromItemNodeToReaction(itemNode: itemNode, targetView: targetView, hideNode: true, completion: {
|
||||
if let addStandaloneReactionAnimation = addStandaloneReactionAnimation {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
||||
|
||||
addStandaloneReactionAnimation(standaloneReactionAnimation)
|
||||
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: itemNode.context,
|
||||
theme: itemNode.context.sharedContext.currentPresentationData.with({ $0 }).theme,
|
||||
reaction: itemNode.item,
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: nil,
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
mainAnimationCompleted = true
|
||||
intermediateCompletion()
|
||||
})
|
||||
} else {
|
||||
if let targetView = strongSelf.targetView {
|
||||
if let targetView = targetView as? ReactionIconView, !isLarge {
|
||||
targetView.imageView.isHidden = false
|
||||
} else {
|
||||
targetView.alpha = 1.0
|
||||
targetView.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
if strongSelf.itemNodeIsEmbedded {
|
||||
strongSelf.itemNode?.removeFromSupernode()
|
||||
}
|
||||
|
||||
mainAnimationCompleted = true
|
||||
intermediateCompletion()
|
||||
}
|
||||
|
||||
if strongSelf.itemNodeIsEmbedded {
|
||||
strongSelf.itemNode?.removeFromSupernode()
|
||||
}
|
||||
|
||||
mainAnimationCompleted = true
|
||||
intermediateCompletion()
|
||||
}
|
||||
}
|
||||
|
||||
additionalAnimationNode.completed = { _ in
|
||||
additionalAnimationCompleted = true
|
||||
intermediateCompletion()
|
||||
|
||||
beginDismissAnimation()
|
||||
}
|
||||
|
||||
@ -992,6 +1035,58 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
})
|
||||
}
|
||||
|
||||
private func animateFromItemNodeToReaction(itemNode: ReactionNode, targetView: UIView, hideNode: Bool, completion: @escaping () -> Void) {
|
||||
guard let targetSnapshotView = targetView.snapshotContentTree(unhide: true) else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
|
||||
let sourceFrame = itemNode.view.convert(itemNode.bounds, to: self.view)
|
||||
let targetFrame = self.view.convert(targetView.convert(targetView.bounds, to: nil), from: nil)
|
||||
|
||||
targetSnapshotView.frame = targetFrame
|
||||
self.view.insertSubview(targetSnapshotView, belowSubview: itemNode.view)
|
||||
|
||||
var completedTarget = false
|
||||
var targetScaleCompleted = false
|
||||
let intermediateCompletion: () -> Void = {
|
||||
if completedTarget && targetScaleCompleted {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
let targetPosition = targetFrame.center
|
||||
let duration: Double = 0.16
|
||||
|
||||
itemNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.9, removeOnCompletion: false)
|
||||
itemNode.layer.animatePosition(from: itemNode.layer.position, to: targetPosition, duration: duration, removeOnCompletion: false)
|
||||
targetSnapshotView.alpha = 1.0
|
||||
targetSnapshotView.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration * 0.8)
|
||||
targetSnapshotView.layer.animatePosition(from: sourceFrame.center, to: targetPosition, duration: duration, removeOnCompletion: false)
|
||||
targetSnapshotView.layer.animateScale(from: itemNode.bounds.width / targetSnapshotView.bounds.width, to: 1.0, duration: duration, removeOnCompletion: false, completion: { [weak targetSnapshotView] _ in
|
||||
completedTarget = true
|
||||
intermediateCompletion()
|
||||
|
||||
targetSnapshotView?.isHidden = true
|
||||
|
||||
if hideNode {
|
||||
targetView.alpha = 1.0
|
||||
targetView.isHidden = false
|
||||
if let targetView = targetView as? ReactionIconView {
|
||||
targetView.imageView.alpha = 1.0
|
||||
}
|
||||
targetSnapshotView?.isHidden = true
|
||||
targetScaleCompleted = true
|
||||
intermediateCompletion()
|
||||
} else {
|
||||
targetScaleCompleted = true
|
||||
intermediateCompletion()
|
||||
}
|
||||
})
|
||||
|
||||
itemNode.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 1.0) / itemNode.bounds.width, duration: duration, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
public func addRelativeContentOffset(_ offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
||||
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: offset.y)
|
||||
transition.animateOffsetAdditive(node: self, offset: -offset.y)
|
||||
@ -1001,7 +1096,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
self.isCancelled = true
|
||||
|
||||
if let targetView = self.targetView {
|
||||
if let targetView = targetView as? ReactionIconView {
|
||||
if let targetView = targetView as? ReactionIconView, self.itemNodeIsEmbedded {
|
||||
targetView.imageView.isHidden = false
|
||||
} else {
|
||||
targetView.alpha = 1.0
|
||||
|
@ -130,8 +130,12 @@ final class ReactionNode: ASDisplayNode {
|
||||
self.animationNode = animationNode
|
||||
self.addSubnode(animationNode)
|
||||
|
||||
var didReportStarted = false
|
||||
animationNode.started = { [weak self] in
|
||||
self?.expandedAnimationDidBegin?()
|
||||
if !didReportStarted {
|
||||
didReportStarted = true
|
||||
self?.expandedAnimationDidBegin?()
|
||||
}
|
||||
}
|
||||
|
||||
if largeExpanded {
|
||||
|
@ -170,7 +170,9 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation
|
||||
),
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: nil,
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
|
@ -877,7 +877,13 @@ public final class AccountViewTracker {
|
||||
if !added {
|
||||
attributes.append(updatedReactions)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, 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))
|
||||
var tags = currentMessage.tags
|
||||
if updatedReactions.hasUnseen {
|
||||
tags.insert(.unseenReaction)
|
||||
} else {
|
||||
tags.remove(.unseenReaction)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
default:
|
||||
break
|
||||
@ -1167,6 +1173,23 @@ public final class AccountViewTracker {
|
||||
}
|
||||
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
|
||||
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenPersonalMessage).map({ $0.id }))
|
||||
|
||||
for id in ids {
|
||||
transaction.updateMessage(id, update: { currentMessage in
|
||||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||
var attributes = currentMessage.attributes
|
||||
for i in 0 ..< attributes.count {
|
||||
if let attribute = attributes[i] as? ConsumablePersonalMentionMessageAttribute {
|
||||
attributes[i] = ConsumablePersonalMentionMessageAttribute(consumed: true, pending: attribute.pending)
|
||||
break
|
||||
}
|
||||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenPersonalMessage)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), summary.count > 0 {
|
||||
var maxId: Int32 = summary.range.maxId
|
||||
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
@ -1179,9 +1202,7 @@ public final class AccountViewTracker {
|
||||
|
||||
return ids
|
||||
}
|
||||
|> deliverOn(self.queue)).start(next: { _ in
|
||||
//self?.updateMarkMentionsSeenForMessageIds(messageIds: messageIds)
|
||||
})
|
||||
|> deliverOn(self.queue)).start()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1235,7 +1256,24 @@ public final class AccountViewTracker {
|
||||
}
|
||||
let _ = (account.postbox.transaction { transaction -> Set<MessageId> in
|
||||
let ids = Set(transaction.getMessageIndicesWithTag(peerId: peerId, namespace: Namespaces.Message.Cloud, tag: .unseenReaction).map({ $0.id }))
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud), summary.count > 0 {
|
||||
|
||||
for id in ids {
|
||||
transaction.updateMessage(id, update: { currentMessage in
|
||||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||
var attributes = currentMessage.attributes
|
||||
for i in 0 ..< attributes.count {
|
||||
if let attribute = attributes[i] as? ReactionsMessageAttribute {
|
||||
attributes[i] = attribute.withAllSeen()
|
||||
break
|
||||
}
|
||||
}
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
}
|
||||
|
||||
if let summary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud) {
|
||||
var maxId: Int32 = summary.range.maxId
|
||||
if let index = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
|
||||
maxId = index.id.id
|
||||
|
@ -283,7 +283,33 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|
||||
guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else {
|
||||
return .complete()
|
||||
}
|
||||
let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
|
||||
let signal = network.request(Api.functions.messages.readReactions(peer: inputPeer))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.AffectedHistory?, Bool> in
|
||||
return .fail(true)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, Bool> in
|
||||
if let result = result {
|
||||
switch result {
|
||||
case let .affectedHistory(pts, ptsCount, offset):
|
||||
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
|
||||
if offset == 0 {
|
||||
return .fail(true)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .fail(true)
|
||||
}
|
||||
}
|
||||
return (signal |> restart)
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|
||||
/*let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
let limit: Int32 = 100
|
||||
let oneOperation: (Int32) -> Signal<Int32?, MTRpcError> = { maxId in
|
||||
return network.request(Api.functions.messages.getUnreadReactions(peer: inputPeer, offsetId: maxId, addOffset: maxId == 0 ? 0 : -1, limit: limit, maxId: maxId == 0 ? 0 : (maxId + 1), minId: 1))
|
||||
@ -365,7 +391,7 @@ private func synchronizeMarkAllUnseenReactions(transaction: Transaction, postbox
|
||||
return loopOperations
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func markUnseenReactionMessage(transaction: Transaction, id: MessageId, addSynchronizeAction: Bool) {
|
||||
@ -386,7 +412,9 @@ func markUnseenReactionMessage(transaction: Transaction, id: MessageId, addSynch
|
||||
break loop
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
var tags = currentMessage.tags
|
||||
tags.remove(.unseenReaction)
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if addSynchronizeAction {
|
||||
|
@ -274,6 +274,7 @@ public enum PresentationResourceParameterKey: Hashable {
|
||||
case chatListBadgeBackgroundActive(CGFloat)
|
||||
case chatListBadgeBackgroundInactive(CGFloat)
|
||||
case chatListBadgeBackgroundMention(CGFloat)
|
||||
case badgeBackgroundReactions(CGFloat)
|
||||
case chatListBadgeBackgroundInactiveMention(CGFloat)
|
||||
case chatListBadgeBackgroundPinned(CGFloat)
|
||||
|
||||
|
@ -683,7 +683,7 @@ public struct PresentationResourcesChat {
|
||||
context.setStrokeColor(theme.chat.historyNavigation.strokeColor.cgColor)
|
||||
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.25, y: 0.25), size: CGSize(width: size.width - 0.5, height: size.height - 0.5)))
|
||||
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/ScheduleIcon"), color: theme.chat.historyNavigation.foregroundColor), let cgImage = image.cgImage {
|
||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reactions"), color: theme.chat.historyNavigation.foregroundColor), let cgImage = image.cgImage {
|
||||
context.draw(cgImage, in: CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size))
|
||||
}
|
||||
})
|
||||
|
@ -189,6 +189,12 @@ public struct PresentationResourcesChatList {
|
||||
})
|
||||
}
|
||||
|
||||
public static func badgeBackgroundReactions(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
|
||||
return theme.image(PresentationResourceParameterKey.badgeBackgroundReactions(diameter), { theme in
|
||||
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/ReactionsBadgeIcon"), color: theme.chatList.unreadBadgeActiveTextColor))
|
||||
})
|
||||
}
|
||||
|
||||
public static func badgeBackgroundInactiveMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
|
||||
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactiveMention(diameter), { theme in
|
||||
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Chat List/ReactionsBadgeIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat List/ReactionsBadgeIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "reactionbadge.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
156
submodules/TelegramUI/Images.xcassets/Chat List/ReactionsBadgeIcon.imageset/reactionbadge.pdf
vendored
Normal file
156
submodules/TelegramUI/Images.xcassets/Chat List/ReactionsBadgeIcon.imageset/reactionbadge.pdf
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 3.447266 3.519043 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
4.715820 12.213867 m
|
||||
4.785645 12.213867 4.833984 12.251465 4.850098 12.326660 c
|
||||
4.989746 13.110840 4.984375 13.116211 5.784668 13.261230 c
|
||||
5.859863 13.282715 5.902832 13.325684 5.902832 13.390137 c
|
||||
5.902832 13.465332 5.859863 13.508301 5.784668 13.524414 c
|
||||
4.984375 13.685547 5.005859 13.690918 4.850098 14.458984 c
|
||||
4.833984 14.534180 4.791016 14.577148 4.715820 14.577148 c
|
||||
4.651367 14.577148 4.603027 14.528809 4.592285 14.464355 c
|
||||
4.431152 13.680176 4.452637 13.680176 3.652344 13.524414 c
|
||||
3.577148 13.508301 3.534180 13.459961 3.534180 13.390137 c
|
||||
3.534180 13.331055 3.577148 13.282715 3.652344 13.261230 c
|
||||
4.452637 13.105469 4.447266 13.110840 4.592285 12.321289 c
|
||||
4.603027 12.256836 4.651367 12.213867 4.715820 12.213867 c
|
||||
h
|
||||
8.443359 10.774414 m
|
||||
8.540039 10.774414 8.609863 10.838867 8.620605 10.940918 c
|
||||
8.770996 12.187012 8.824707 12.219238 10.097656 12.423340 c
|
||||
10.210449 12.439453 10.274902 12.498535 10.274902 12.600586 c
|
||||
10.274902 12.691895 10.210449 12.756348 10.119141 12.772461 c
|
||||
8.835449 13.019531 8.770996 13.008789 8.620605 14.254883 c
|
||||
8.609863 14.356934 8.540039 14.421387 8.443359 14.421387 c
|
||||
8.352051 14.421387 8.282227 14.356934 8.271484 14.260254 c
|
||||
8.110352 12.992676 8.072754 12.955078 6.778320 12.772461 c
|
||||
6.687012 12.761719 6.622559 12.691895 6.622559 12.600586 c
|
||||
6.622559 12.503906 6.681641 12.439453 6.772949 12.423340 c
|
||||
8.072754 12.170898 8.104980 12.176270 8.271484 10.930176 c
|
||||
8.282227 10.838867 8.352051 10.774414 8.443359 10.774414 c
|
||||
h
|
||||
4.425781 1.772461 m
|
||||
6.128418 0.069824 8.282227 0.198730 9.823730 1.734863 c
|
||||
10.989258 2.900391 11.263184 4.125000 10.833496 5.591309 c
|
||||
10.602539 6.536621 10.065430 7.589355 9.571289 8.513184 c
|
||||
9.324219 8.980469 9.028809 9.587402 8.840820 9.802246 c
|
||||
8.631348 10.038574 8.319824 10.049316 8.078125 9.839844 c
|
||||
7.804199 9.598145 7.793457 9.281250 7.970703 8.770996 c
|
||||
8.577637 7.100586 l
|
||||
8.642090 6.939453 8.631348 6.842773 8.572266 6.783691 c
|
||||
8.502441 6.713867 8.411133 6.703125 8.282227 6.832031 c
|
||||
4.270020 10.844238 l
|
||||
4.028320 11.085938 3.641602 11.085938 3.399902 10.844238 c
|
||||
3.158203 10.602539 3.158203 10.215820 3.399902 9.974121 c
|
||||
6.316406 7.057617 l
|
||||
6.182129 6.993164 6.047852 6.917969 5.908203 6.826660 c
|
||||
2.540527 10.194336 l
|
||||
2.298828 10.436035 1.912109 10.436035 1.670410 10.194336 c
|
||||
1.428711 9.952637 1.428711 9.565918 1.670410 9.324219 c
|
||||
5.000488 5.994141 l
|
||||
4.893066 5.870605 4.796387 5.747070 4.705078 5.618164 c
|
||||
1.654297 8.668945 l
|
||||
1.412598 8.910645 1.025879 8.910645 0.784180 8.668945 c
|
||||
0.537109 8.427246 0.542480 8.040527 0.784180 7.798828 c
|
||||
4.092773 4.484863 l
|
||||
4.033691 4.312988 3.990723 4.146484 3.953125 3.985352 c
|
||||
1.648926 6.289551 l
|
||||
1.401855 6.536621 1.015137 6.536621 0.773438 6.294922 c
|
||||
0.531738 6.047852 0.531738 5.661133 0.773438 5.419434 c
|
||||
4.425781 1.772461 l
|
||||
h
|
||||
7.272461 9.893555 m
|
||||
6.321777 10.844238 l
|
||||
6.074707 11.085938 5.687988 11.085938 5.451660 10.844238 c
|
||||
5.435547 10.833496 5.430176 10.822754 5.419434 10.806641 c
|
||||
7.224121 8.996582 l
|
||||
7.191895 9.318848 7.202637 9.619629 7.272461 9.893555 c
|
||||
h
|
||||
11.870117 1.734863 m
|
||||
13.035645 2.900391 13.309570 4.125000 12.879883 5.591309 c
|
||||
12.648926 6.536621 12.111816 7.583984 11.617676 8.513184 c
|
||||
11.375977 8.980469 11.075195 9.592773 10.887207 9.796875 c
|
||||
10.677734 10.038574 10.366211 10.049316 10.124512 9.839844 c
|
||||
10.022461 9.753906 9.958008 9.651855 9.925781 9.544434 c
|
||||
10.060059 9.286621 10.194336 9.028809 10.328613 8.770996 c
|
||||
10.801270 7.874023 11.365234 6.767578 11.590820 5.763184 c
|
||||
12.090332 3.990723 11.698242 2.502930 10.376953 1.187012 c
|
||||
10.140625 0.950684 9.893555 0.746582 9.641113 0.574707 c
|
||||
10.441406 0.676758 11.214844 1.079590 11.870117 1.734863 c
|
||||
h
|
||||
1.568359 0.000000 m
|
||||
1.654297 0.000000 1.708008 0.053711 1.718750 0.139648 c
|
||||
1.906738 1.192383 1.901367 1.213867 2.997070 1.417969 c
|
||||
3.088379 1.434082 3.142090 1.482422 3.142090 1.568359 c
|
||||
3.142090 1.659668 3.088379 1.708008 3.002441 1.718750 c
|
||||
1.901367 1.944336 1.922852 1.960449 1.718750 3.002441 c
|
||||
1.708008 3.088379 1.654297 3.136719 1.568359 3.136719 c
|
||||
1.487793 3.136719 1.439453 3.088379 1.417969 3.002441 c
|
||||
1.213867 1.949707 1.246094 1.933594 0.139648 1.718750 c
|
||||
0.059082 1.708008 0.000000 1.659668 0.000000 1.568359 c
|
||||
0.000000 1.482422 0.053711 1.434082 0.139648 1.417969 c
|
||||
1.246094 1.197754 1.229980 1.187012 1.417969 0.134277 c
|
||||
1.439453 0.053711 1.487793 0.000000 1.568359 0.000000 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
4420
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 20.000000 20.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000004510 00000 n
|
||||
0000004533 00000 n
|
||||
0000004706 00000 n
|
||||
0000004780 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
4839
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Chat/NavigateToReactions.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/NavigateToReactions.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "reactionbutton.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
181
submodules/TelegramUI/Images.xcassets/Chat/NavigateToReactions.imageset/reactionbutton.pdf
vendored
Normal file
181
submodules/TelegramUI/Images.xcassets/Chat/NavigateToReactions.imageset/reactionbutton.pdf
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.597168 4.368164 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
7.288086 18.900879 m
|
||||
7.387695 18.900879 7.470703 18.958984 7.495605 19.075195 c
|
||||
7.703125 20.287109 7.703125 20.295410 8.931641 20.519531 c
|
||||
9.056152 20.552734 9.122559 20.619141 9.122559 20.718750 c
|
||||
9.122559 20.834961 9.056152 20.901367 8.939941 20.926270 c
|
||||
7.703125 21.175293 7.728027 21.183594 7.495605 22.370605 c
|
||||
7.470703 22.486816 7.395996 22.553223 7.288086 22.553223 c
|
||||
7.180176 22.553223 7.105469 22.478516 7.088867 22.378906 c
|
||||
6.839844 21.166992 6.881348 21.166992 5.636230 20.926270 c
|
||||
5.520020 20.901367 5.453613 20.826660 5.453613 20.718750 c
|
||||
5.453613 20.627441 5.520020 20.552734 5.636230 20.519531 c
|
||||
6.881348 20.278809 6.864746 20.287109 7.088867 19.066895 c
|
||||
7.105469 18.967285 7.180176 18.900879 7.288086 18.900879 c
|
||||
h
|
||||
13.040527 16.676270 m
|
||||
13.198242 16.676270 13.306152 16.775879 13.314453 16.933594 c
|
||||
13.555176 18.859375 13.638184 18.909180 15.597168 19.224609 c
|
||||
15.771484 19.249512 15.871094 19.340820 15.871094 19.498535 c
|
||||
15.871094 19.639648 15.771484 19.739258 15.630371 19.764160 c
|
||||
13.654785 20.145996 13.555176 20.129395 13.314453 22.055176 c
|
||||
13.306152 22.212891 13.198242 22.312500 13.040527 22.312500 c
|
||||
12.907715 22.312500 12.799805 22.212891 12.783203 22.063477 c
|
||||
12.525879 20.104492 12.467773 20.046387 10.467285 19.764160 c
|
||||
10.326172 19.747559 10.226562 19.639648 10.226562 19.498535 c
|
||||
10.226562 19.349121 10.326172 19.249512 10.467285 19.224609 c
|
||||
12.476074 18.834473 12.525879 18.842773 12.783203 16.916992 c
|
||||
12.799805 16.775879 12.907715 16.676270 13.040527 16.676270 c
|
||||
h
|
||||
7.445801 17.456543 m
|
||||
7.312988 17.332031 7.213379 17.190918 7.155273 17.033203 c
|
||||
6.466309 17.506348 5.661133 17.423340 5.038574 16.800781 c
|
||||
4.814453 16.576660 4.681641 16.294434 4.656738 16.003906 c
|
||||
3.951172 16.485352 3.179199 16.427246 2.573242 15.829590 c
|
||||
1.992188 15.240234 1.934082 14.443359 2.390625 13.754395 c
|
||||
2.108398 13.737793 1.851074 13.613281 1.651855 13.405762 c
|
||||
0.979492 12.741699 0.996094 11.820312 1.685059 11.131348 c
|
||||
2.241211 10.575195 l
|
||||
1.950684 10.566895 1.660156 10.425781 1.436035 10.201660 c
|
||||
0.763672 9.529297 0.788574 8.566406 1.502441 7.852539 c
|
||||
6.632324 2.722656 l
|
||||
8.906738 0.456543 11.596191 0.000000 13.920410 1.253418 c
|
||||
15.314941 1.311523 16.676270 1.934082 17.863281 3.121094 c
|
||||
20.021484 5.287598 20.378418 7.960449 18.909180 11.056641 c
|
||||
17.016602 15.041016 l
|
||||
16.659668 15.812988 16.045410 16.261230 15.298340 16.252930 c
|
||||
14.891602 16.252930 14.194336 16.037109 13.903809 15.389648 c
|
||||
13.322754 15.754883 12.600586 15.705078 12.052734 15.248535 c
|
||||
9.853027 17.439941 l
|
||||
9.105957 18.187012 8.167969 18.170410 7.445801 17.456543 c
|
||||
h
|
||||
11.978027 12.260254 m
|
||||
8.068359 16.161621 l
|
||||
8.093262 16.252930 8.143066 16.335938 8.217773 16.410645 c
|
||||
8.441895 16.634766 8.765625 16.626465 9.006348 16.385742 c
|
||||
11.504883 13.887207 l
|
||||
11.521484 13.737793 11.554688 13.588379 11.621094 13.438965 c
|
||||
12.077637 12.334961 l
|
||||
12.094238 12.301758 12.094238 12.268555 12.069336 12.251953 c
|
||||
12.044434 12.218750 12.002930 12.227051 11.978027 12.260254 c
|
||||
h
|
||||
14.542969 3.453125 m
|
||||
12.442871 1.353027 9.819824 1.411133 7.470703 3.760254 c
|
||||
2.548340 8.682617 l
|
||||
2.324219 8.906738 2.315918 9.205566 2.531738 9.429688 c
|
||||
2.747559 9.645508 3.062988 9.645508 3.278809 9.421387 c
|
||||
6.300293 6.399902 l
|
||||
6.549316 6.150879 6.931152 6.175781 7.163574 6.399902 c
|
||||
7.395996 6.640625 7.420898 7.022461 7.171875 7.271484 c
|
||||
2.639648 11.803711 l
|
||||
2.415527 12.019531 2.407227 12.326660 2.623047 12.542480 c
|
||||
2.838867 12.758301 3.154297 12.758301 3.378418 12.534180 c
|
||||
7.603516 8.309082 l
|
||||
7.852539 8.060059 8.234375 8.084961 8.458496 8.317383 c
|
||||
8.690918 8.549805 8.724121 8.931641 8.475098 9.180664 c
|
||||
3.502930 14.144531 l
|
||||
3.278809 14.368652 3.270508 14.684082 3.486328 14.899902 c
|
||||
3.702148 15.115723 4.017578 15.107422 4.241699 14.883301 c
|
||||
9.139160 9.977539 l
|
||||
9.379883 9.736816 9.761719 9.753418 9.994141 9.985840 c
|
||||
10.234863 10.226562 10.251465 10.608398 10.010742 10.849121 c
|
||||
5.852051 15.007812 l
|
||||
5.627930 15.231934 5.627930 15.539062 5.843750 15.754883 c
|
||||
6.059570 15.970703 6.366699 15.970703 6.590820 15.746582 c
|
||||
12.434570 9.902832 l
|
||||
12.766602 9.562500 13.173340 9.587402 13.447266 9.861328 c
|
||||
13.679688 10.102051 13.779297 10.417480 13.604980 10.865723 c
|
||||
12.567383 13.596680 l
|
||||
12.434570 13.937012 12.559082 14.210938 12.816406 14.327148 c
|
||||
13.090332 14.451660 13.347656 14.327148 13.513672 13.970215 c
|
||||
15.431152 9.869629 l
|
||||
16.709473 7.146973 16.244629 5.154785 14.542969 3.453125 c
|
||||
h
|
||||
16.609863 10.434082 m
|
||||
14.841797 14.177734 l
|
||||
14.816895 14.252441 14.800293 14.327148 14.800293 14.410156 c
|
||||
14.800293 14.650879 14.999512 14.891602 15.323242 14.891602 c
|
||||
15.530762 14.891602 15.738281 14.750488 15.846191 14.509766 c
|
||||
17.730469 10.492188 l
|
||||
19.000488 7.777832 18.543945 5.769043 16.842285 4.083984 c
|
||||
16.792480 4.034180 16.742676 3.984375 16.692871 3.942871 c
|
||||
17.796875 5.818848 17.771973 7.993652 16.609863 10.434082 c
|
||||
h
|
||||
2.423828 0.024902 m
|
||||
2.556641 0.024902 2.631348 0.107910 2.656250 0.240723 c
|
||||
2.946777 1.867676 2.938477 1.900879 4.631836 2.216309 c
|
||||
4.772949 2.241211 4.847656 2.315918 4.847656 2.448730 c
|
||||
4.847656 2.589844 4.772949 2.664551 4.640137 2.681152 c
|
||||
2.938477 3.029785 2.971680 3.054688 2.656250 4.665039 c
|
||||
2.631348 4.797852 2.556641 4.872559 2.423828 4.872559 c
|
||||
2.291016 4.872559 2.216309 4.797852 2.191406 4.665039 c
|
||||
1.867676 3.038086 1.917480 3.013184 0.215820 2.681152 c
|
||||
0.083008 2.664551 0.000000 2.589844 0.000000 2.448730 c
|
||||
0.000000 2.315918 0.083008 2.241211 0.215820 2.216309 c
|
||||
1.917480 1.875977 1.892578 1.859375 2.191406 0.232422 c
|
||||
2.216309 0.107910 2.291016 0.024902 2.423828 0.024902 c
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
5599
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000005689 00000 n
|
||||
0000005712 00000 n
|
||||
0000005885 00000 n
|
||||
0000005959 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
6018
|
||||
%%EOF
|
@ -1294,7 +1294,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation
|
||||
),
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { standaloneReactionAnimation in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
|
||||
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
@ -5944,7 +5953,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation
|
||||
),
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { standaloneReactionAnimation in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = strongSelf.chatDisplayNode.bounds
|
||||
strongSelf.chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
@ -12505,10 +12523,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let messageId = messageLocation.messageId, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
|
||||
self.loadingMessage.set(.single(nil))
|
||||
self.messageIndexDisposable.set(nil)
|
||||
|
||||
var delayCompletion = true
|
||||
if self.chatDisplayNode.historyNode.isMessageVisible(id: messageId) {
|
||||
delayCompletion = false
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.scrollToMessage(from: scrollFromIndex, to: message.index, animated: animated, scrollPosition: scrollPosition)
|
||||
Queue.mainQueue().after(0.25, {
|
||||
completion?()
|
||||
})
|
||||
|
||||
if delayCompletion {
|
||||
Queue.mainQueue().after(0.25, {
|
||||
completion?()
|
||||
})
|
||||
} else {
|
||||
Queue.mainQueue().justDispatch({
|
||||
completion?()
|
||||
})
|
||||
}
|
||||
|
||||
if case let .id(_, maybeTimecode) = messageLocation, let timecode = maybeTimecode {
|
||||
let _ = self.controllerInteraction?.openMessage(message, .timecode(timecode))
|
||||
|
@ -1344,6 +1344,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
if strongSelf.canReadHistoryValue && !strongSelf.context.sharedContext.immediateExperimentalUISettings.skipReadHistory && !strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen.isEmpty {
|
||||
let messageIds = strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen
|
||||
|
||||
let _ = strongSelf.displayUnseenReactionAnimations(messageIds: Array(messageIds))
|
||||
|
||||
strongSelf.messageIdsWithReactionsScheduledForMarkAsSeen.removeAll()
|
||||
context?.account.viewTracker.updateMarkReactionsSeenForMessageIds(messageIds: messageIds)
|
||||
}
|
||||
@ -2381,9 +2384,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
let completion: (Bool, ListViewDisplayedItemRange) -> Void = { [weak self] wasTransformed, visibleRange in
|
||||
if let strongSelf = self {
|
||||
var newIncomingReactions: [MessageId: String] = [:]
|
||||
var newIncomingReactions: [MessageId: (value: String, isLarge: Bool)] = [:]
|
||||
if case .peer = strongSelf.chatLocation, let previousHistoryView = strongSelf.historyView {
|
||||
var updatedIncomingReactions: [MessageId: String] = [:]
|
||||
var updatedIncomingReactions: [MessageId: (value: String, isLarge: Bool)] = [:]
|
||||
for entry in transition.historyView.filteredEntries {
|
||||
switch entry {
|
||||
case let .MessageEntry(message, _, _, _, _, _):
|
||||
@ -2393,7 +2396,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
if let reactions = message.reactionsAttribute {
|
||||
for recentPeer in reactions.recentPeers {
|
||||
if recentPeer.isUnseen {
|
||||
updatedIncomingReactions[message.id] = recentPeer.value
|
||||
updatedIncomingReactions[message.id] = (recentPeer.value, recentPeer.isLarge)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2405,7 +2408,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
if let reactions = message.0.reactionsAttribute {
|
||||
for recentPeer in reactions.recentPeers {
|
||||
if recentPeer.isUnseen {
|
||||
updatedIncomingReactions[message.0.id] = recentPeer.value
|
||||
updatedIncomingReactions[message.0.id] = (recentPeer.value, recentPeer.isLarge)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2426,7 +2429,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
if previousReaction != updatedReaction {
|
||||
if previousReaction != updatedReaction.value {
|
||||
newIncomingReactions[message.id] = updatedReaction
|
||||
}
|
||||
}
|
||||
@ -2441,7 +2444,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
if previousReaction != updatedReaction {
|
||||
if previousReaction != updatedReaction.value {
|
||||
newIncomingReactions[message.0.id] = updatedReaction
|
||||
}
|
||||
}
|
||||
@ -2599,52 +2602,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
}
|
||||
|
||||
if !newIncomingReactions.isEmpty, let chatDisplayNode = strongSelf.controllerInteraction.chatControllerNode() as? ChatControllerNode {
|
||||
var visibleNewIncomingReactionMessageIds: [MessageId] = []
|
||||
strongSelf.forEachVisibleItemNode { itemNode in
|
||||
guard let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let updatedReaction = newIncomingReactions[item.content.firstMessage.id] else {
|
||||
return
|
||||
}
|
||||
visibleNewIncomingReactionMessageIds.append(item.content.firstMessage.id)
|
||||
|
||||
if let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: updatedReaction) {
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
|
||||
if reaction.value == updatedReaction {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
||||
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: strongSelf.context,
|
||||
theme: item.presentationData.theme.theme,
|
||||
reaction: ReactionContextItem(
|
||||
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
||||
appearAnimation: reaction.appearAnimation,
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
listAnimation: centerAnimation,
|
||||
largeListAnimation: reaction.activateAnimation,
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation
|
||||
),
|
||||
targetView: targetView,
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !newIncomingReactions.isEmpty {
|
||||
let messageIds = Array(newIncomingReactions.keys)
|
||||
|
||||
let visibleNewIncomingReactionMessageIds = strongSelf.displayUnseenReactionAnimations(messageIds: messageIds)
|
||||
if !visibleNewIncomingReactionMessageIds.isEmpty {
|
||||
strongSelf.unseenReactionsProcessingManager.add(visibleNewIncomingReactionMessageIds)
|
||||
}
|
||||
@ -2696,6 +2657,79 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
}
|
||||
|
||||
private func displayUnseenReactionAnimations(messageIds: [MessageId]) -> [MessageId] {
|
||||
guard let chatDisplayNode = self.controllerInteraction.chatControllerNode() as? ChatControllerNode else {
|
||||
return []
|
||||
}
|
||||
var visibleNewIncomingReactionMessageIds: [MessageId] = []
|
||||
self.forEachVisibleItemNode { itemNode in
|
||||
guard let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let reactionsAttribute = item.content.firstMessage.reactionsAttribute, messageIds.contains(item.content.firstMessage.id) else {
|
||||
return
|
||||
}
|
||||
|
||||
var selectedReaction: (String, Bool)?
|
||||
for recentPeer in reactionsAttribute.recentPeers {
|
||||
if recentPeer.isUnseen {
|
||||
selectedReaction = (recentPeer.value, recentPeer.isLarge)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
guard let (updatedReaction, updatedReactionIsLarge) = selectedReaction else {
|
||||
return
|
||||
}
|
||||
|
||||
visibleNewIncomingReactionMessageIds.append(item.content.firstMessage.id)
|
||||
|
||||
if let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: updatedReaction) {
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
|
||||
if reaction.value == updatedReaction {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
||||
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: self.context,
|
||||
theme: item.presentationData.theme.theme,
|
||||
reaction: ReactionContextItem(
|
||||
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
||||
appearAnimation: reaction.appearAnimation,
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
listAnimation: centerAnimation,
|
||||
largeListAnimation: reaction.activateAnimation,
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation
|
||||
),
|
||||
isLarge: updatedReactionIsLarge,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { [weak self] standaloneReactionAnimation in
|
||||
guard let strongSelf = self, let chatDisplayNode = strongSelf.controllerInteraction.chatControllerNode() as? ChatControllerNode else {
|
||||
return
|
||||
}
|
||||
chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = chatDisplayNode.bounds
|
||||
chatDisplayNode.addSubnode(standaloneReactionAnimation)
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return visibleNewIncomingReactionMessageIds
|
||||
}
|
||||
|
||||
public func updateLayout(transition: ContainedViewLayoutTransition, updateSizeAndInsets: ListViewUpdateSizeAndInsets) {
|
||||
self.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: 0.0, scrollToTop: false, completion: {})
|
||||
}
|
||||
@ -2964,6 +2998,29 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
return resultMessages
|
||||
}
|
||||
|
||||
func isMessageVisible(id: MessageId) -> Bool {
|
||||
var found = false
|
||||
self.forEachVisibleItemNode { itemNode in
|
||||
if !found, let itemNode = itemNode as? ListViewItemNode {
|
||||
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item {
|
||||
switch item.content {
|
||||
case let .message(message, _, _ , _, _):
|
||||
if message.id == id {
|
||||
found = true
|
||||
}
|
||||
case let .group(messages):
|
||||
for message in messages {
|
||||
if message.0.id == id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
private var selectionPanState: (selecting: Bool, initialMessageId: MessageId, toggledMessageIds: [[MessageId]])?
|
||||
private var selectionScrollActivationTimer: SwiftSignalKit.Timer?
|
||||
private var selectionScrollDisplayLink: ConstantDisplayLinkAnimator?
|
||||
|
Loading…
x
Reference in New Issue
Block a user