diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a69a17c6c1..5c5a53f100 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2700,6 +2700,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return true }), in: .current) } + }, isAnimatingMessage: { [weak self] stableId in + guard let strongSelf = self else { + return false + } + return strongSelf.chatDisplayNode.messageTransitionNode.isAnimatingMessage(stableId: stableId) }, requestMessageUpdate: { [weak self] id in if let strongSelf = self { strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id) diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index 254f60d331..d911fc4323 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -121,6 +121,7 @@ public final class ChatControllerInteraction { let editMessageMedia: (MessageId, Bool) -> Void let copyText: (String) -> Void let displayUndo: (UndoOverlayContent) -> Void + let isAnimatingMessage: (UInt32) -> Bool let requestMessageUpdate: (MessageId) -> Void let cancelInteractiveKeyboardGestures: () -> Void @@ -213,6 +214,7 @@ public final class ChatControllerInteraction { editMessageMedia: @escaping (MessageId, Bool) -> Void, copyText: @escaping (String) -> Void, displayUndo: @escaping (UndoOverlayContent) -> Void, + isAnimatingMessage: @escaping (UInt32) -> Bool, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, @@ -292,6 +294,7 @@ public final class ChatControllerInteraction { self.editMessageMedia = editMessageMedia self.copyText = copyText self.displayUndo = displayUndo + self.isAnimatingMessage = isAnimatingMessage self.requestMessageUpdate = requestMessageUpdate self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures @@ -346,6 +349,8 @@ public final class ChatControllerInteraction { }, editMessageMedia: { _, _ in }, copyText: { _ in }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 07ded9549f..a0fbcf528b 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -245,11 +245,22 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.titleAccessoryPanelContainer.clipsToBounds = true self.inputContextPanelContainer = ChatControllerTitlePanelNodeContainer() - - self.historyNode = ChatHistoryListNode(context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: nil, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get()) + + var getMessageTransitionNode: (() -> ChatMessageTransitionNode?)? + self.historyNode = ChatHistoryListNode(context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: nil, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), messageTransitionNode: { + return getMessageTransitionNode?() + }) self.historyNode.rotated = true self.historyNodeContainer = ASDisplayNode() self.historyNodeContainer.addSubnode(self.historyNode) + + var getContentAreaInScreenSpaceImpl: (() -> CGRect)? + var onTransitionEventImpl: ((ContainedViewLayoutTransition) -> Void)? + self.messageTransitionNode = ChatMessageTransitionNode(listNode: self.historyNode, getContentAreaInScreenSpace: { + return getContentAreaInScreenSpaceImpl?() ?? CGRect() + }, onTransitionEvent: { transition in + onTransitionEventImpl?(transition) + }) self.reactionContainerNode = ReactionSelectionParentNode(account: context.account, theme: chatPresentationInterfaceState.theme) @@ -271,14 +282,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme, dateTimeFormat: self.chatPresentationInterfaceState.dateTimeFormat) self.navigateButtons.accessibilityElementsHidden = true - - var getContentAreaInScreenSpaceImpl: (() -> CGRect)? - var onTransitionEventImpl: ((ContainedViewLayoutTransition) -> Void)? - self.messageTransitionNode = ChatMessageTransitionNode(listNode: self.historyNode, getContentAreaInScreenSpace: { - return getContentAreaInScreenSpaceImpl?() ?? CGRect() - }, onTransitionEvent: { transition in - onTransitionEventImpl?(transition) - }) super.init() @@ -299,6 +302,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } strongSelf.backgroundNode.animateEvent(transition: transition) } + + getMessageTransitionNode = { [weak self] in + return self?.messageTransitionNode + } self.controller?.presentationContext.topLevelSubview = { [weak self] in guard let strongSelf = self else { @@ -2300,7 +2307,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { webpage = self.chatPresentationInterfaceState.urlPreview?.1 } #if DEBUG - webpage = nil + //webpage = nil #endif messages.append(.message(text: text.string, attributes: attributes, mediaReference: webpage.flatMap(AnyMediaReference.standalone), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil)) } diff --git a/submodules/TelegramUI/Sources/ChatEmptyNode.swift b/submodules/TelegramUI/Sources/ChatEmptyNode.swift index 52a0ff000c..2f85f4623a 100644 --- a/submodules/TelegramUI/Sources/ChatEmptyNode.swift +++ b/submodules/TelegramUI/Sources/ChatEmptyNode.swift @@ -887,6 +887,6 @@ final class ChatEmptyNode: ASDisplayNode { } transition.updateFrame(node: self.backgroundNode, frame: contentFrame) - self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: 20.0, transition: transition) + self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(20.0, self.backgroundNode.bounds.height / 2.0), transition: transition) } } diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 769d6c0ea1..a49f97206c 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -480,7 +480,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { private let historyDisposable = MetaDisposable() private let readHistoryDisposable = MetaDisposable() - private let messageViewQueue = Queue(name: "ChatHistoryListNode processing") + //private let messageViewQueue = Queue(name: "ChatHistoryListNode processing") private var dequeuedInitialTransitionOnLayout = false private var enqueuedHistoryViewTransitions: [ChatHistoryListViewTransition] = [] @@ -610,7 +610,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { private let clientId: Atomic - public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, tagMask: MessageTags?, source: ChatHistoryListSource = .default, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal?, NoError>, mode: ChatHistoryListMode = .bubbles) { + public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, tagMask: MessageTags?, source: ChatHistoryListSource = .default, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal?, NoError>, mode: ChatHistoryListMode = .bubbles, messageTransitionNode: @escaping () -> ChatMessageTransitionNode? = { nil }) { var tagMask = tagMask var appendMessagesFromTheSameGroup = false if case .pinnedMessages = subject { @@ -1032,7 +1032,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } } } - let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages) + let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode()) let mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, transition: rawTransition) Queue.mainQueue().async { guard let strongSelf = self else { @@ -2159,6 +2159,56 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } } + func requestMessageUpdate(stableId: UInt32) { + if let historyView = self.historyView { + var messageItem: ChatMessageItem? + self.forEachItemNode({ itemNode in + if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item { + for (message, _) in item.content { + if message.stableId == stableId { + messageItem = item + break + } + } + } + }) + + if let messageItem = messageItem { + let associatedData = messageItem.associatedData + + loop: for i in 0 ..< historyView.filteredEntries.count { + switch historyView.filteredEntries[i] { + case let .MessageEntry(message, presentationData, read, _, selection, attributes): + if message.stableId == stableId { + let index = historyView.filteredEntries.count - 1 - i + let item: ListViewItem + switch self.mode { + case .bubbles: + item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes)) + case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch): + let displayHeader: Bool + switch displayHeaders { + case .none: + displayHeader = false + case .all: + displayHeader = true + case .allButLast: + displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != historyView.lastHeaderId + } + item = ListMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: self.controllerInteraction), message: message, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch) + } + let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil) + self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + break loop + } + default: + break + } + } + } + } + } + private func messagesAtPoint(_ point: CGPoint) -> [Message]? { var resultMessages: [Message]? self.forEachVisibleItemNode { itemNode in diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift index d679949ea3..f4a2c7d66b 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleBackdrop.swift @@ -211,7 +211,13 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode { transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset)) } if let backgroundContent = self.backgroundContent { - transition.updateFrame(node: backgroundContent, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height))) + transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height))) + if let (rect, containerSize) = self.absolutePosition { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition) + } } transition.updateFrame(node: self, frame: value, completion: { _ in completion() @@ -223,7 +229,13 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode { transition.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset)) } if let backgroundContent = self.backgroundContent { - transition.updateFrame(node: backgroundContent, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height))) + transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height))) + if let (rect, containerSize) = self.absolutePosition { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition) + } } transition.updateFrame(layer: self.layer, frame: value, completion: { _ in completion() diff --git a/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift b/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift index 27ace02de0..6dca173060 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTransitionNode.swift @@ -81,7 +81,7 @@ private final class OverlayTransitionContainerController: ViewController, Standa } } -final class ChatMessageTransitionNode: ASDisplayNode { +public final class ChatMessageTransitionNode: ASDisplayNode { static let animationDuration: Double = 0.3 static let verticalAnimationControlPoints: (Float, Float, Float, Float) = (0.19919472913616398, 0.010644531250000006, 0.27920937042459737, 0.91025390625) @@ -174,7 +174,7 @@ final class ChatMessageTransitionNode: ASDisplayNode { } private final class AnimatingItemNode: ASDisplayNode { - private let itemNode: ChatMessageItemView + let itemNode: ChatMessageItemView private let contextSourceNode: ContextExtractedContentContainingNode private let source: ChatMessageTransitionNode.Source private let getContentAreaInScreenSpace: () -> CGRect @@ -186,6 +186,7 @@ final class ChatMessageTransitionNode: ASDisplayNode { weak var overlayController: OverlayTransitionContainerController? var animationEnded: (() -> Void)? + var updateAfterCompletion: Bool = false init(itemNode: ChatMessageItemView, contextSourceNode: ContextExtractedContentContainingNode, source: ChatMessageTransitionNode.Source, getContentAreaInScreenSpace: @escaping () -> CGRect) { self.itemNode = itemNode @@ -284,6 +285,18 @@ final class ChatMessageTransitionNode: ASDisplayNode { let combinedTransition = CombinedTransition(horizontal: horizontalTransition, vertical: verticalTransition) + self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY) + self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size) + self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: verticalCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in + guard let strongSelf = self else { + return + } + strongSelf.endAnimation() + }) + self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: horizontalCurve.mediaTimingFunction, additive: true) + self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), horizontalCurve, horizontalDuration) + self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), verticalCurve, verticalDuration) + if let itemNode = self.itemNode as? ChatMessageBubbleItemNode { itemNode.animateContentFromTextInputField(textInput: textInput, transition: combinedTransition) if let sourceReplyPanel = sourceReplyPanel { @@ -300,18 +313,6 @@ final class ChatMessageTransitionNode: ASDisplayNode { itemNode.animateReplyPanel(sourceReplyPanel: sourceReplyPanel, transition: combinedTransition) } } - - self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: -self.contextSourceNode.contentRect.minY) - self.contextSourceNode.updateAbsoluteRect?(self.containerNode.frame, UIScreen.main.bounds.size) - self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: verticalCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in - guard let strongSelf = self else { - return - } - strongSelf.endAnimation() - }) - self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: horizontalCurve.mediaTimingFunction, additive: true) - self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), horizontalCurve, horizontalDuration) - self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), verticalCurve, verticalDuration) case let .stickerMediaInput(stickerMediaInput, replyPanel): self.itemNode.cancelInsertionAnimations() @@ -557,6 +558,10 @@ final class ChatMessageTransitionNode: ASDisplayNode { return self.currentPendingItem != nil } + var hasOngoingTransitions: Bool { + return !self.animatingItemNodes.isEmpty + } + init(listNode: ChatHistoryListNode, getContentAreaInScreenSpace: @escaping () -> CGRect, onTransitionEvent: @escaping (ContainedViewLayoutTransition) -> Void) { self.listNode = listNode self.getContentAreaInScreenSpace = getContentAreaInScreenSpace @@ -617,6 +622,13 @@ final class ChatMessageTransitionNode: ASDisplayNode { if let index = strongSelf.animatingItemNodes.firstIndex(where: { $0 === animatingItemNode }) { strongSelf.animatingItemNodes.remove(at: index) } + + if animatingItemNode.updateAfterCompletion, let item = animatingItemNode.itemNode.item { + for (message, _) in item.content { + strongSelf.listNode.requestMessageUpdate(stableId: message.stableId) + break + } + } } animatingItemNode.frame = self.bounds @@ -626,7 +638,7 @@ final class ChatMessageTransitionNode: ASDisplayNode { } } - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { return nil } @@ -641,4 +653,42 @@ final class ChatMessageTransitionNode: ASDisplayNode { animatingItemNode.addContentOffset(offset: offset, itemNode: itemNode) } } + + func isAnimatingMessage(stableId: UInt32) -> Bool { + for itemNode in self.animatingItemNodes { + if let item = itemNode.itemNode.item { + for (message, _) in item.content { + if message.stableId == stableId { + return true + } + } + } + } + return false + } + + func scheduleUpdateMessageAfterAnimationCompleted(stableId: UInt32) { + for itemNode in self.animatingItemNodes { + if let item = itemNode.itemNode.item { + for (message, _) in item.content { + if message.stableId == stableId { + itemNode.updateAfterCompletion = true + } + } + } + } + } + + func hasScheduledUpdateMessageAfterAnimationCompleted(stableId: UInt32) -> Bool { + for itemNode in self.animatingItemNodes { + if let item = itemNode.itemNode.item { + for (message, _) in item.content { + if message.stableId == stableId { + return itemNode.updateAfterCompletion + } + } + } + } + return false + } } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 14e507311e..4b2926dc42 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -535,6 +535,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, editMessageMedia: { _, _ in }, copyText: { _ in }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index f5068f2528..18d89f6cf8 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -152,6 +152,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, editMessageMedia: { _, _ in }, copyText: { _ in }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index dfbbb13687..a9592545cd 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -144,6 +144,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, editMessageMedia: { _, _ in }, copyText: { _ in }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: nil)) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 43e5e94578..4a30c8f9aa 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2159,6 +2159,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, editMessageMedia: { _, _ in }, copyText: { _ in }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift b/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift index 2b11046ca0..cf107d2836 100644 --- a/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift +++ b/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift @@ -7,14 +7,60 @@ import Display import MergeLists import AccountContext -func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool) -> ChatHistoryViewTransition { - let mergeResult: (deleteIndices: [Int], indicesAndItems: [(Int, ChatHistoryEntry, Int?)], updateIndices: [(Int, ChatHistoryEntry, Int)]) +func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool, messageTransitionNode: ChatMessageTransitionNode?) -> ChatHistoryViewTransition { + var mergeResult: (deleteIndices: [Int], indicesAndItems: [(Int, ChatHistoryEntry, Int?)], updateIndices: [(Int, ChatHistoryEntry, Int)]) let allUpdated = fromView?.associatedData != toView.associatedData if reverse { mergeResult = mergeListsStableWithUpdatesReversed(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries, allUpdated: allUpdated) } else { mergeResult = mergeListsStableWithUpdates(leftList: fromView?.filteredEntries ?? [], rightList: toView.filteredEntries, allUpdated: allUpdated) } + + if let messageTransitionNode = messageTransitionNode, messageTransitionNode.hasOngoingTransitions, let previousEntries = fromView?.filteredEntries { + for i in 0 ..< mergeResult.updateIndices.count { + switch mergeResult.updateIndices[i].1 { + case let .MessageEntry(message, presentationData, flag, monthLocation, messageSelection, entryAttributes): + if messageTransitionNode.isAnimatingMessage(stableId: message.stableId) { + var updatedMessage = message + mediaLoop: for media in message.media { + if let webpage = media as? TelegramMediaWebpage, case .Loaded = webpage.content { + var filterMedia = false + switch previousEntries[mergeResult.updateIndices[i].2] { + case let .MessageEntry(previousMessage, _, _, _, _, _): + if previousMessage.media.contains(where: { value in + if let value = value as? TelegramMediaWebpage, case .Loaded = value.content { + return true + } else { + return false + } + }) { + if messageTransitionNode.hasScheduledUpdateMessageAfterAnimationCompleted(stableId: message.stableId) { + filterMedia = true + } + } else { + filterMedia = true + } + default: + break + } + + if filterMedia { + updatedMessage = message.withUpdatedMedia(message.media.filter { + $0 !== media + }) + messageTransitionNode.scheduleUpdateMessageAfterAnimationCompleted(stableId: message.stableId) + } + + break mediaLoop + } + } + mergeResult.updateIndices[i].1 = .MessageEntry(updatedMessage, presentationData, flag, monthLocation, messageSelection, entryAttributes) + } + default: + break + } + } + } var adjustedDeleteIndices: [ListViewDeleteItem] = [] let previousCount: Int diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 678464b545..76df503592 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1272,6 +1272,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, editMessageMedia: { _, _ in }, copyText: { _ in }, displayUndo: { _ in + }, isAnimatingMessage: { _ in + return false }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift index ee5f9223e4..5ba23bb317 100644 --- a/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift +++ b/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift @@ -162,16 +162,36 @@ public final class WallpaperBackgroundNode: ASDisplayNode { } } - public func update(rect: CGRect, within containerSize: CGSize) { + public func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) { self.currentLayout = (rect, containerSize) let shiftedContentsRect = CGRect(origin: CGPoint(x: rect.minX / containerSize.width, y: rect.minY / containerSize.height), size: CGSize(width: rect.width / containerSize.width, height: rect.height / containerSize.height)) + transition.updateFrame(layer: self.contentNode.layer, frame: self.bounds) self.contentNode.layer.contentsRect = shiftedContentsRect if let cleanWallpaperNode = self.cleanWallpaperNode { + transition.updateFrame(layer: cleanWallpaperNode.layer, frame: self.bounds) cleanWallpaperNode.layer.contentsRect = shiftedContentsRect } if let gradientWallpaperNode = self.gradientWallpaperNode { + transition.updateFrame(layer: gradientWallpaperNode.layer, frame: self.bounds) + gradientWallpaperNode.layer.contentsRect = shiftedContentsRect + } + } + + public func update(rect: CGRect, within containerSize: CGSize, transition: CombinedTransition) { + self.currentLayout = (rect, containerSize) + + let shiftedContentsRect = CGRect(origin: CGPoint(x: rect.minX / containerSize.width, y: rect.minY / containerSize.height), size: CGSize(width: rect.width / containerSize.width, height: rect.height / containerSize.height)) + + transition.updateFrame(layer: self.contentNode.layer, frame: self.bounds) + self.contentNode.layer.contentsRect = shiftedContentsRect + if let cleanWallpaperNode = self.cleanWallpaperNode { + transition.updateFrame(layer: cleanWallpaperNode.layer, frame: self.bounds) + cleanWallpaperNode.layer.contentsRect = shiftedContentsRect + } + if let gradientWallpaperNode = self.gradientWallpaperNode { + transition.updateFrame(layer: gradientWallpaperNode.layer, frame: self.bounds) gradientWallpaperNode.layer.contentsRect = shiftedContentsRect } }