mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
8bef96fbe0
@ -398,9 +398,14 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent
|
||||
if !self.listState.canLoadMore {
|
||||
return self.mergedItems.count
|
||||
} else {
|
||||
var value = self.listState.totalCount
|
||||
let reactionCount = self.listState.totalCount
|
||||
var value = reactionCount
|
||||
if let readStats = self.readStats {
|
||||
value = max(value, readStats.peers.count)
|
||||
if reactionCount < readStats.peers.count && self.listState.hasOutgoingReaction {
|
||||
value = readStats.peers.count + 1
|
||||
} else {
|
||||
value = max(reactionCount, readStats.peers.count)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
@ -174,29 +174,37 @@ final class ReactionContextBackgroundNode: ASDisplayNode {
|
||||
|
||||
self.largeCircleLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.01, delay: largeCircleDelay)
|
||||
self.largeCircleLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: largeCircleDuration, delay: largeCircleDelay)
|
||||
self.largeCircleShadowLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: largeCircleDuration, delay: largeCircleDelay)
|
||||
//self.largeCircleLayer.animate(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: largeCircleDuration)
|
||||
|
||||
self.backgroundLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.01, delay: mainCircleDelay)
|
||||
self.backgroundLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: mainCircleDuration, delay: mainCircleDelay)
|
||||
self.backgroundShadowLayer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: mainCircleDuration, delay: mainCircleDelay)
|
||||
}
|
||||
|
||||
func animateInFromAnchorRect(size: CGSize, sourceBackgroundFrame: CGRect) {
|
||||
let springDuration: Double = 0.2
|
||||
let springDamping: CGFloat = 104.0
|
||||
let springDelay: Double = 0.25
|
||||
let shadowInset: CGFloat = 15.0
|
||||
|
||||
self.backgroundLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.backgroundLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||
self.backgroundShadowLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.backgroundShadowLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||
let contentBounds = self.backgroundNode.frame
|
||||
|
||||
let visualSourceBackgroundFrame = sourceBackgroundFrame.offsetBy(dx: -contentBounds.minX, dy: -contentBounds.minY)
|
||||
let sourceShadowFrame = visualSourceBackgroundFrame.insetBy(dx: -shadowInset, dy: -shadowInset)
|
||||
|
||||
self.backgroundLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: visualSourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.backgroundLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualSourceBackgroundFrame.size)), to: NSValue(cgRect: self.backgroundLayer.bounds), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||
self.backgroundShadowLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceShadowFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true)
|
||||
self.backgroundShadowLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceShadowFrame.size)), to: NSValue(cgRect: self.backgroundShadowLayer.bounds), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping)
|
||||
}
|
||||
|
||||
func animateOut() {
|
||||
self.backgroundLayer.animateAlpha(from: CGFloat(self.backgroundLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.backgroundShadowLayer.animateAlpha(from: CGFloat(self.backgroundShadowLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.backgroundShadowLayer.animateAlpha(from: CGFloat(self.backgroundShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
self.largeCircleLayer.animateAlpha(from: CGFloat(self.largeCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.largeCircleShadowLayer.animateAlpha(from: CGFloat(self.largeCircleShadowLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.largeCircleShadowLayer.animateAlpha(from: CGFloat(self.largeCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
self.smallCircleLayer.animateAlpha(from: CGFloat(self.smallCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.smallCircleShadowLayer.animateAlpha(from: CGFloat(self.smallCircleShadowLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.smallCircleShadowLayer.animateAlpha(from: CGFloat(self.smallCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,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, Int32?)
|
||||
case UpdateMedia(MediaId, Media?)
|
||||
case ReadInbox(MessageId)
|
||||
case ReadOutbox(MessageId, Int32?)
|
||||
@ -258,8 +258,8 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdateMessagePoll(id, poll, results))
|
||||
}
|
||||
|
||||
mutating func updateMessageReactions(_ messageId: MessageId, reactions: Api.MessageReactions) {
|
||||
self.addOperation(.UpdateMessageReactions(messageId, reactions))
|
||||
mutating func updateMessageReactions(_ messageId: MessageId, reactions: Api.MessageReactions, eventTimestamp: Int32?) {
|
||||
self.addOperation(.UpdateMessageReactions(messageId, reactions, eventTimestamp))
|
||||
}
|
||||
|
||||
mutating func updateMedia(_ id: MediaId, media: Media?) {
|
||||
@ -610,6 +610,7 @@ struct AccountFinalState {
|
||||
struct AccountReplayedFinalState {
|
||||
let state: AccountFinalState
|
||||
let addedIncomingMessageIds: [MessageId]
|
||||
let addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)]
|
||||
let wasScheduledMessageIds: [MessageId]
|
||||
let addedSecretMessageIds: [MessageId]
|
||||
let deletedMessageIds: [DeletedMessageId]
|
||||
@ -627,6 +628,7 @@ struct AccountReplayedFinalState {
|
||||
|
||||
struct AccountFinalStateEvents {
|
||||
let addedIncomingMessageIds: [MessageId]
|
||||
let addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)]
|
||||
let wasScheduledMessageIds:[MessageId]
|
||||
let deletedMessageIds: [DeletedMessageId]
|
||||
let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]]
|
||||
@ -646,11 +648,12 @@ struct AccountFinalStateEvents {
|
||||
let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id]
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
||||
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
||||
}
|
||||
|
||||
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||
self.addedReactionEvents = addedReactionEvents
|
||||
self.wasScheduledMessageIds = wasScheduledMessageIds
|
||||
self.deletedMessageIds = deletedMessageIds
|
||||
self.updatedTypingActivities = updatedTypingActivities
|
||||
@ -672,6 +675,7 @@ struct AccountFinalStateEvents {
|
||||
|
||||
init(state: AccountReplayedFinalState) {
|
||||
self.addedIncomingMessageIds = state.addedIncomingMessageIds
|
||||
self.addedReactionEvents = state.addedReactionEvents
|
||||
self.wasScheduledMessageIds = state.wasScheduledMessageIds
|
||||
self.deletedMessageIds = state.deletedMessageIds
|
||||
self.updatedTypingActivities = state.updatedTypingActivities
|
||||
@ -714,6 +718,6 @@ struct AccountFinalStateEvents {
|
||||
let externallyUpdatedPeerId = self.externallyUpdatedPeerId.union(other.externallyUpdatedPeerId)
|
||||
let authorizationListUpdated = self.authorizationListUpdated || other.authorizationListUpdated
|
||||
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }))
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }))
|
||||
}
|
||||
}
|
||||
|
@ -1474,7 +1474,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
}
|
||||
})
|
||||
case let .updateMessageReactions(peer, msgId, reactions):
|
||||
updatedState.updateMessageReactions(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: msgId), reactions: reactions)
|
||||
updatedState.updateMessageReactions(MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: msgId), reactions: reactions, eventTimestamp: updatesDate)
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -2430,6 +2430,7 @@ func replayFinalState(
|
||||
}
|
||||
var wasScheduledMessageIds:[MessageId] = []
|
||||
var addedIncomingMessageIds: [MessageId] = []
|
||||
var addedReactionEvents: [(reactionAuthor: Peer, message: Message, timestamp: Int32)] = []
|
||||
|
||||
if !wasOperationScheduledMessageIds.isEmpty {
|
||||
let existingIds = transaction.filterStoredMessageIds(Set(wasOperationScheduledMessageIds))
|
||||
@ -3228,16 +3229,19 @@ func replayFinalState(
|
||||
return state
|
||||
})
|
||||
}
|
||||
case let .UpdateMessageReactions(messageId, reactions):
|
||||
case let .UpdateMessageReactions(messageId, reactions, eventTimestamp):
|
||||
var generatedEvent: (reactionAuthor: Peer, message: Message, timestamp: Int32)?
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
var updatedReactions = ReactionsMessageAttribute(apiReactions: reactions)
|
||||
|
||||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||
var attributes = currentMessage.attributes
|
||||
var previousReactions: ReactionsMessageAttribute?
|
||||
var added = false
|
||||
loop: for j in 0 ..< attributes.count {
|
||||
if let attribute = attributes[j] as? ReactionsMessageAttribute {
|
||||
added = true
|
||||
previousReactions = attribute
|
||||
updatedReactions = attribute.withUpdatedResults(reactions)
|
||||
|
||||
if updatedReactions == attribute {
|
||||
@ -3251,8 +3255,44 @@ func replayFinalState(
|
||||
attributes.append(updatedReactions)
|
||||
}
|
||||
|
||||
if let eventTimestamp = eventTimestamp, !currentMessage.flags.contains(.Incoming), let chatPeer = currentMessage.peers[currentMessage.id.peerId] {
|
||||
let _ = chatPeer
|
||||
|
||||
var previousCount = 0
|
||||
if let previousReactions = previousReactions {
|
||||
for reaction in previousReactions.reactions {
|
||||
previousCount += Int(reaction.count)
|
||||
}
|
||||
}
|
||||
|
||||
var updatedCount = 0
|
||||
for reaction in updatedReactions.reactions {
|
||||
updatedCount += Int(reaction.count)
|
||||
}
|
||||
|
||||
if updatedCount > previousCount {
|
||||
if let topPeer = updatedReactions.recentPeers.last {
|
||||
var wasPresentBefore = false
|
||||
if let previousReactions = previousReactions {
|
||||
for recentPeer in previousReactions.recentPeers {
|
||||
if recentPeer.peerId == topPeer.peerId {
|
||||
wasPresentBefore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !wasPresentBefore, let reactionAuthor = transaction.getPeer(topPeer.peerId), transaction.isPeerContact(peerId: topPeer.peerId) {
|
||||
generatedEvent = (reactionAuthor: reactionAuthor, message: currentMessage.withUpdatedAttributes(attributes), timestamp: eventTimestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
})
|
||||
if let generatedEvent = generatedEvent {
|
||||
addedReactionEvents.append(generatedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3624,5 +3664,5 @@ func replayFinalState(
|
||||
requestChatListFiltersSync(transaction: transaction)
|
||||
}
|
||||
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates)
|
||||
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, addedReactionEvents: addedReactionEvents, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedGroupCallParticipants: updatedGroupCallParticipants, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates)
|
||||
}
|
||||
|
@ -105,6 +105,11 @@ public final class AccountStateManager {
|
||||
return self.notificationMessagesPipe.signal()
|
||||
}
|
||||
|
||||
private let reactionNotificationsPipe = ValuePipe<[(reactionAuthor: Peer, message: Message)]>()
|
||||
public var reactionNotifications: Signal<[(reactionAuthor: Peer, message: Message)], NoError> {
|
||||
return self.reactionNotificationsPipe.signal()
|
||||
}
|
||||
|
||||
private let displayAlertsPipe = ValuePipe<[(text: String, isDropAuth: Bool)]>()
|
||||
public var displayAlerts: Signal<[(text: String, isDropAuth: Bool)], NoError> {
|
||||
return self.displayAlertsPipe.signal()
|
||||
@ -739,6 +744,19 @@ public final class AccountStateManager {
|
||||
completed()
|
||||
})
|
||||
|
||||
let timestamp = Int32(Date().timeIntervalSince1970)
|
||||
let minReactionTimestamp = timestamp - 20
|
||||
let reactionEvents = events.addedReactionEvents.compactMap { event -> (reactionAuthor: Peer, message: Message)? in
|
||||
if event.timestamp >= minReactionTimestamp {
|
||||
return (event.reactionAuthor, event.message)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if !reactionEvents.isEmpty {
|
||||
self.reactionNotificationsPipe.putNext(reactionEvents)
|
||||
}
|
||||
|
||||
if !events.displayAlerts.isEmpty {
|
||||
self.displayAlertsPipe.putNext(events.displayAlerts)
|
||||
}
|
||||
|
@ -231,15 +231,20 @@ private func synchronizeMessageReactions(transaction: Transaction, postbox: Post
|
||||
|
||||
public extension EngineMessageReactionListContext.State {
|
||||
init(message: EngineMessage, reaction: String?) {
|
||||
var totalCount: Int = 0
|
||||
var totalCount = 0
|
||||
var hasOutgoingReaction = false
|
||||
if let reactionsAttribute = message._asMessage().reactionsAttribute {
|
||||
for messageReaction in reactionsAttribute.reactions {
|
||||
if reaction == nil || messageReaction.value == reaction {
|
||||
if messageReaction.isSelected {
|
||||
hasOutgoingReaction = true
|
||||
}
|
||||
totalCount += Int(messageReaction.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.init(
|
||||
hasOutgoingReaction: hasOutgoingReaction,
|
||||
totalCount: totalCount,
|
||||
items: [],
|
||||
canLoadMore: totalCount != 0
|
||||
@ -272,15 +277,18 @@ public final class EngineMessageReactionListContext {
|
||||
}
|
||||
|
||||
public struct State: Equatable {
|
||||
public var hasOutgoingReaction: Bool
|
||||
public var totalCount: Int
|
||||
public var items: [Item]
|
||||
public var canLoadMore: Bool
|
||||
|
||||
public init(
|
||||
hasOutgoingReaction: Bool,
|
||||
totalCount: Int,
|
||||
items: [Item],
|
||||
canLoadMore: Bool
|
||||
) {
|
||||
self.hasOutgoingReaction = hasOutgoingReaction
|
||||
self.totalCount = totalCount
|
||||
self.items = items
|
||||
self.canLoadMore = canLoadMore
|
||||
@ -289,6 +297,7 @@ public final class EngineMessageReactionListContext {
|
||||
|
||||
private final class Impl {
|
||||
struct InternalState: Equatable {
|
||||
var hasOutgoingReaction: Bool
|
||||
var totalCount: Int
|
||||
var items: [Item]
|
||||
var canLoadMore: Bool
|
||||
@ -315,7 +324,7 @@ public final class EngineMessageReactionListContext {
|
||||
self.reaction = reaction
|
||||
|
||||
let initialState = EngineMessageReactionListContext.State(message: message, reaction: reaction)
|
||||
self.state = InternalState(totalCount: initialState.totalCount, items: initialState.items, canLoadMore: true, nextOffset: nil)
|
||||
self.state = InternalState(hasOutgoingReaction: initialState.hasOutgoingReaction, totalCount: initialState.totalCount, items: initialState.items, canLoadMore: true, nextOffset: nil)
|
||||
|
||||
if initialState.canLoadMore {
|
||||
self.loadMore()
|
||||
@ -344,10 +353,10 @@ public final class EngineMessageReactionListContext {
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<InternalState, NoError> in
|
||||
if message.id.namespace != Namespaces.Message.Cloud {
|
||||
return .single(InternalState(totalCount: 0, items: [], canLoadMore: false, nextOffset: nil))
|
||||
return .single(InternalState(hasOutgoingReaction: false, totalCount: 0, items: [], canLoadMore: false, nextOffset: nil))
|
||||
}
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .single(InternalState(totalCount: 0, items: [], canLoadMore: false, nextOffset: nil))
|
||||
return .single(InternalState(hasOutgoingReaction: false, totalCount: 0, items: [], canLoadMore: false, nextOffset: nil))
|
||||
}
|
||||
var flags: Int32 = 0
|
||||
if reaction != nil {
|
||||
@ -391,9 +400,9 @@ public final class EngineMessageReactionListContext {
|
||||
}
|
||||
}
|
||||
|
||||
return InternalState(totalCount: Int(count), items: items, canLoadMore: nextOffset != nil, nextOffset: nextOffset)
|
||||
return InternalState(hasOutgoingReaction: false, totalCount: Int(count), items: items, canLoadMore: nextOffset != nil, nextOffset: nextOffset)
|
||||
case .none:
|
||||
return InternalState(totalCount: 0, items: [], canLoadMore: false, nextOffset: nil)
|
||||
return InternalState(hasOutgoingReaction: false, totalCount: 0, items: [], canLoadMore: false, nextOffset: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,6 +447,7 @@ public final class EngineMessageReactionListContext {
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.statePromise.get().start(next: { state in
|
||||
subscriber.putNext(State(
|
||||
hasOutgoingReaction: state.hasOutgoingReaction,
|
||||
totalCount: state.totalCount,
|
||||
items: state.items,
|
||||
canLoadMore: state.canLoadMore
|
||||
|
Loading…
x
Reference in New Issue
Block a user