mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Attachment menu improvements
This commit is contained in:
@@ -169,12 +169,21 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
self.extractSnapshot = extractSnapshot
|
||||
}
|
||||
}
|
||||
|
||||
final class GroupedMediaInput {
|
||||
let extractSnapshots: () -> [UIView]
|
||||
|
||||
init(extractSnapshots: @escaping () -> [UIView]) {
|
||||
self.extractSnapshots = extractSnapshots
|
||||
}
|
||||
}
|
||||
|
||||
case textInput(textInput: TextInput, replyPanel: ReplyAccessoryPanelNode?)
|
||||
case stickerMediaInput(input: StickerInput, replyPanel: ReplyAccessoryPanelNode?)
|
||||
case audioMicInput(AudioMicInput)
|
||||
case videoMessage(VideoMessage)
|
||||
case mediaInput(MediaInput)
|
||||
case groupedMediaInput(GroupedMediaInput)
|
||||
}
|
||||
|
||||
final class DecorationItemNode: ASDisplayNode {
|
||||
@@ -556,6 +565,92 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration)
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration)
|
||||
}
|
||||
} else {
|
||||
self.endAnimation()
|
||||
}
|
||||
case let .groupedMediaInput(groupedMediaInput):
|
||||
let snapshotViews = groupedMediaInput.extractSnapshots()
|
||||
if snapshotViews.isEmpty {
|
||||
self.endAnimation()
|
||||
return
|
||||
}
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
itemNode.cancelInsertionAnimations()
|
||||
|
||||
self.contextSourceNode.isExtractedToContextPreview = true
|
||||
self.contextSourceNode.isExtractedToContextPreviewUpdated?(true)
|
||||
|
||||
self.containerNode.addSubnode(self.contextSourceNode.contentNode)
|
||||
|
||||
let combinedTransition = CombinedTransition(horizontal: .animated(duration: horizontalDuration, curve: ChatMessageTransitionNode.horizontalAnimationCurve), vertical: .animated(duration: verticalDuration, curve: ChatMessageTransitionNode.verticalAnimationCurve))
|
||||
|
||||
var targetContentRects: [CGRect] = []
|
||||
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
|
||||
targetContentRects = itemNode.animateContentFromGroupedMediaInput(transition: combinedTransition)
|
||||
}
|
||||
|
||||
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: self.view)
|
||||
|
||||
func boundingRect(for views: [UIView]) -> CGRect {
|
||||
var minX: CGFloat = .greatestFiniteMagnitude
|
||||
var minY: CGFloat = .greatestFiniteMagnitude
|
||||
var maxX: CGFloat = .leastNonzeroMagnitude
|
||||
var maxY: CGFloat = .leastNonzeroMagnitude
|
||||
|
||||
for view in views {
|
||||
let rect = view.frame
|
||||
if rect.minX < minX {
|
||||
minX = rect.minX
|
||||
}
|
||||
if rect.minY < minY {
|
||||
minY = rect.minY
|
||||
}
|
||||
if rect.maxX > maxX {
|
||||
maxX = rect.maxX
|
||||
}
|
||||
if rect.maxY > maxY {
|
||||
maxY = rect.maxY
|
||||
}
|
||||
}
|
||||
return CGRect(origin: CGPoint(x: minX, y: minY), size: CGSize(width: maxX - minX, height: maxY - minY))
|
||||
}
|
||||
|
||||
let sourceBackgroundAbsoluteRect = boundingRect(for: snapshotViews)
|
||||
let sourceAbsoluteRect = CGRect(origin: CGPoint(x: sourceBackgroundAbsoluteRect.midX - self.contextSourceNode.contentRect.size.width / 2.0, y: sourceBackgroundAbsoluteRect.midY - self.contextSourceNode.contentRect.size.height / 2.0), size: self.contextSourceNode.contentRect.size)
|
||||
|
||||
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.midY - targetAbsoluteRect.midY), to: CGPoint(), duration: horizontalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.horizontalAnimationCurve.mediaTimingFunction, additive: true, force: true)
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.midX - targetAbsoluteRect.midX, y: 0.0), to: CGPoint(), duration: verticalDuration, delay: delay, mediaTimingFunction: ChatMessageTransitionNode.verticalAnimationCurve.mediaTimingFunction, additive: true, force: true, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.endAnimation()
|
||||
})
|
||||
|
||||
combinedTransition.horizontal.animateTransformScale(node: self.contextSourceNode.contentNode, from: CGPoint(x: sourceBackgroundAbsoluteRect.width / targetAbsoluteRect.width, y: sourceBackgroundAbsoluteRect.height / targetAbsoluteRect.height))
|
||||
|
||||
var index = 0
|
||||
for snapshotView in snapshotViews {
|
||||
let targetContentRect = targetContentRects[index]
|
||||
let targetAbsoluteContentRect = targetContentRect.offsetBy(dx: targetAbsoluteRect.minX, dy: targetAbsoluteRect.minY)
|
||||
|
||||
snapshotView.center = targetAbsoluteContentRect.center.offsetBy(dx: -self.containerNode.frame.minX, dy: -self.containerNode.frame.minY)
|
||||
self.containerNode.view.addSubview(snapshotView)
|
||||
|
||||
combinedTransition.horizontal.updateTransformScale(layer: snapshotView.layer, scale: CGPoint(x: 1.0 / (snapshotView.frame.width / targetContentRect.width), y: 1.0 / (snapshotView.frame.height / targetContentRect.height)))
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), ChatMessageTransitionNode.horizontalAnimationCurve, horizontalDuration)
|
||||
self.contextSourceNode.applyAbsoluteOffset?(CGPoint(x: 0.0, y: sourceAbsoluteRect.maxY - targetAbsoluteRect.maxY), ChatMessageTransitionNode.verticalAnimationCurve, verticalDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -652,14 +747,14 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
private let getContentAreaInScreenSpace: () -> CGRect
|
||||
private let onTransitionEvent: (ContainedViewLayoutTransition) -> Void
|
||||
|
||||
private var currentPendingItem: (Int64, Source, () -> Void)?
|
||||
private var currentPendingItems: [Int64: (Source, () -> Void)] = [:]
|
||||
|
||||
private var animatingItemNodes: [AnimatingItemNode] = []
|
||||
private var decorationItemNodes: [DecorationItemNode] = []
|
||||
private var messageReactionContexts: [MessageReactionContext] = []
|
||||
|
||||
var hasScheduledTransitions: Bool {
|
||||
return self.currentPendingItem != nil
|
||||
return !self.currentPendingItems.isEmpty
|
||||
}
|
||||
|
||||
var hasOngoingTransitions: Bool {
|
||||
@@ -673,21 +768,39 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.listNode.animationCorrelationMessageFound = { [weak self] itemNode, correlationId in
|
||||
guard let strongSelf = self, let (currentId, currentSource, initiated) = strongSelf.currentPendingItem else {
|
||||
self.listNode.animationCorrelationMessagesFound = { [weak self] itemNodeAndCorrelationIds in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if currentId == correlationId {
|
||||
strongSelf.currentPendingItem = nil
|
||||
strongSelf.beginAnimation(itemNode: itemNode, source: currentSource)
|
||||
initiated()
|
||||
|
||||
for (correlationId, itemNode) in itemNodeAndCorrelationIds {
|
||||
if let (currentSource, initiated) = strongSelf.currentPendingItems[correlationId] {
|
||||
strongSelf.beginAnimation(itemNode: itemNode, source: currentSource)
|
||||
initiated()
|
||||
}
|
||||
}
|
||||
|
||||
if itemNodeAndCorrelationIds.count == strongSelf.currentPendingItems.count {
|
||||
strongSelf.currentPendingItems = [:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func add(correlationId: Int64, source: Source, initiated: @escaping () -> Void) {
|
||||
self.currentPendingItem = (correlationId, source, initiated)
|
||||
self.listNode.setCurrentSendAnimationCorrelationId(correlationId)
|
||||
self.currentPendingItems = [correlationId: (source, initiated)]
|
||||
self.listNode.setCurrentSendAnimationCorrelationIds(Set([correlationId]))
|
||||
}
|
||||
|
||||
func add(grouped: [(correlationId: Int64, source: Source, initiated: () -> Void)]) {
|
||||
var currentPendingItems: [Int64: (Source, () -> Void)] = [:]
|
||||
var correlationIds = Set<Int64>()
|
||||
for (correlationId, source, initiated) in grouped {
|
||||
currentPendingItems[correlationId] = (source, initiated)
|
||||
correlationIds.insert(correlationId)
|
||||
}
|
||||
|
||||
self.currentPendingItems = currentPendingItems
|
||||
self.listNode.setCurrentSendAnimationCorrelationIds(correlationIds)
|
||||
}
|
||||
|
||||
func add(decorationView: UIView, itemNode: ChatMessageItemView) -> DecorationItemNode {
|
||||
@@ -730,7 +843,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
|
||||
|
||||
self.animatingItemNodes.append(animatingItemNode)
|
||||
switch source {
|
||||
case .audioMicInput, .videoMessage, .mediaInput:
|
||||
case .audioMicInput, .videoMessage, .mediaInput, .groupedMediaInput:
|
||||
let overlayController = OverlayTransitionContainerController()
|
||||
overlayController.displayNode.addSubnode(animatingItemNode)
|
||||
animatingItemNode.overlayController = overlayController
|
||||
|
||||
Reference in New Issue
Block a user