mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Message effects improvements
This commit is contained in:
@@ -13,11 +13,15 @@ import MosaicLayout
|
||||
import WallpaperBackgroundNode
|
||||
import AccountContext
|
||||
import ChatMessageBackground
|
||||
import ChatSendMessageActionUI
|
||||
import ComponentFlow
|
||||
import ComponentDisplayAdapters
|
||||
|
||||
private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
let asset: TGMediaEditableItem
|
||||
private let interaction: MediaPickerInteraction?
|
||||
private let enableAnimations: Bool
|
||||
private let isExternalPreview: Bool
|
||||
|
||||
private let imageNode: ImageNode
|
||||
private var checkNode: InteractiveCheckNode?
|
||||
@@ -57,10 +61,11 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
|
||||
private var videoDuration: Double?
|
||||
|
||||
init(asset: TGMediaEditableItem, interaction: MediaPickerInteraction?, enableAnimations: Bool) {
|
||||
init(asset: TGMediaEditableItem, interaction: MediaPickerInteraction?, enableAnimations: Bool, isExternalPreview: Bool) {
|
||||
self.asset = asset
|
||||
self.interaction = interaction
|
||||
self.enableAnimations = enableAnimations
|
||||
self.isExternalPreview = isExternalPreview
|
||||
|
||||
self.imageNode = ImageNode()
|
||||
self.imageNode.contentMode = .scaleAspectFill
|
||||
@@ -279,7 +284,7 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
|
||||
if let checkNode = self.checkNode {
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
transition.updateAlpha(node: checkNode, alpha: selectionState.count() < 2 ? 0.0 : 1.0)
|
||||
transition.updateAlpha(node: checkNode, alpha: (self.isExternalPreview || selectionState.count() < 2) ? 0.0 : 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,7 +387,7 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
return view
|
||||
}
|
||||
|
||||
func animateFrom(_ view: UIView) {
|
||||
func animateFrom(_ view: UIView, transition: ContainedViewLayoutTransition) {
|
||||
view.alpha = 0.0
|
||||
|
||||
let frame = view.convert(view.bounds, to: self.supernode?.view)
|
||||
@@ -392,13 +397,19 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
self.durationBackgroundNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
||||
self.updateLayout(size: frame.size, transition: .immediate)
|
||||
self.updateLayout(size: targetFrame.size, transition: .animated(duration: 0.25, curve: .spring))
|
||||
self.layer.animateFrame(from: frame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak view] _ in
|
||||
view?.alpha = 1.0
|
||||
self.updateLayout(size: targetFrame.size, transition: transition)
|
||||
transition.animateFrame(layer: self.layer, from: frame, to: targetFrame, completion: { [weak self, weak view] _ in
|
||||
guard let self else {
|
||||
view?.alpha = 1.0
|
||||
return
|
||||
}
|
||||
if !self.isExternalPreview {
|
||||
view?.alpha = 1.0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func animateTo(_ view: UIView, dustNode: ASDisplayNode?, completion: @escaping (Bool) -> Void) {
|
||||
func animateTo(_ view: UIView, dustNode: ASDisplayNode?, transition: ContainedViewLayoutTransition, completion: @escaping (Bool) -> Void) {
|
||||
view.alpha = 0.0
|
||||
|
||||
let frame = self.frame
|
||||
@@ -418,14 +429,13 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
self.addSubnode(dustNode)
|
||||
dustNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
|
||||
dustNode.layer.animatePosition(from: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0), to: dustNode.position, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
|
||||
transition.animatePositionAdditive(layer: dustNode.layer, offset: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0), to: dustNode.position)
|
||||
self.spoilerNode?.dustNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
self.corners = []
|
||||
self.updateLayout(size: targetFrame.size, transition: .animated(duration: 0.25, curve: .spring))
|
||||
self.layer.animateFrame(from: frame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak view, weak self] _ in
|
||||
self.updateLayout(size: targetFrame.size, transition: transition)
|
||||
transition.animateFrame(layer: self.layer, from: frame, to: targetFrame, removeOnCompletion: false, completion: { [weak view, weak self] _ in
|
||||
view?.alpha = 1.0
|
||||
|
||||
self?.durationTextNode?.layer.removeAllAnimations()
|
||||
@@ -471,7 +481,7 @@ private class MessageBackgroundNode: ASDisplayNode {
|
||||
|
||||
private var absoluteRect: (CGRect, CGSize)?
|
||||
|
||||
func update(size: CGSize, theme: PresentationTheme, wallpaper: TelegramWallpaper, graphics: PrincipalThemeEssentialGraphics, wallpaperBackgroundNode: WallpaperBackgroundNode, transition: ContainedViewLayoutTransition) {
|
||||
func update(size: CGSize, theme: PresentationTheme, wallpaper: TelegramWallpaper, graphics: PrincipalThemeEssentialGraphics, wallpaperBackgroundNode: WallpaperBackgroundNode?, transition: ContainedViewLayoutTransition) {
|
||||
self.backgroundNode.setType(type: .outgoing(.Extracted), highlighted: false, graphics: graphics, maskMode: false, hasWallpaper: wallpaper.hasWallpaper, transition: transition, backgroundNode: wallpaperBackgroundNode)
|
||||
self.backgroundWallpaperNode.setType(type: .outgoing(.Extracted), theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), essentialGraphics: graphics, maskMode: true, backgroundNode: wallpaperBackgroundNode)
|
||||
self.shadowNode.setType(type: .outgoing(.Extracted), hasWallpaper: wallpaper.hasWallpaper, graphics: graphics)
|
||||
@@ -496,11 +506,13 @@ private class MessageBackgroundNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDelegate {
|
||||
final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDelegate, ChatSendMessageContextScreenMediaPreview {
|
||||
private let context: AccountContext
|
||||
private let persistentItems: Bool
|
||||
private let isExternalPreview: Bool
|
||||
var globalClippingRect: CGRect?
|
||||
|
||||
fileprivate let wallpaperBackgroundNode: WallpaperBackgroundNode
|
||||
fileprivate var wallpaperBackgroundNode: WallpaperBackgroundNode?
|
||||
private let scrollNode: ASScrollNode
|
||||
private var backgroundNodes: [Int: MessageBackgroundNode] = [:]
|
||||
private var itemNodes: [String: MediaPickerSelectedItemNode] = [:]
|
||||
@@ -518,17 +530,28 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
private var didSetReady = false
|
||||
private var ready = Promise<Bool>()
|
||||
|
||||
init(context: AccountContext, persistentItems: Bool) {
|
||||
private var contentSize: CGSize = CGSize()
|
||||
|
||||
var isReady: Signal<Bool, NoError> {
|
||||
return self.ready.get()
|
||||
}
|
||||
|
||||
init(context: AccountContext, persistentItems: Bool, isExternalPreview: Bool) {
|
||||
self.context = context
|
||||
self.persistentItems = persistentItems
|
||||
self.isExternalPreview = isExternalPreview
|
||||
|
||||
self.wallpaperBackgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true, useSharedAnimationPhase: false)
|
||||
self.wallpaperBackgroundNode.backgroundColor = .black
|
||||
self.scrollNode = ASScrollNode()
|
||||
self.scrollNode.clipsToBounds = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.wallpaperBackgroundNode)
|
||||
if !self.isExternalPreview {
|
||||
let wallpaperBackgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true, useSharedAnimationPhase: false)
|
||||
wallpaperBackgroundNode.backgroundColor = .black
|
||||
self.wallpaperBackgroundNode = wallpaperBackgroundNode
|
||||
self.addSubnode(wallpaperBackgroundNode)
|
||||
}
|
||||
self.addSubnode(self.scrollNode)
|
||||
}
|
||||
|
||||
@@ -578,7 +601,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
|
||||
var getTransitionView: (String) -> (UIView, ASDisplayNode?, (Bool) -> Void)? = { _ in return nil }
|
||||
|
||||
func animateIn(initiated: @escaping () -> Void, completion: @escaping () -> Void = {}) {
|
||||
func animateIn(transition: ContainedViewLayoutTransition, initiated: @escaping () -> Void, completion: @escaping () -> Void = {}) {
|
||||
let _ = (self.ready.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
@@ -589,79 +612,105 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
strongSelf.alpha = 1.0
|
||||
initiated()
|
||||
|
||||
strongSelf.wallpaperBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { _ in
|
||||
if let wallpaperBackgroundNode = strongSelf.wallpaperBackgroundNode {
|
||||
wallpaperBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
wallpaperBackgroundNode.layer.animateScale(from: 1.2, to: 1.0, duration: 0.33, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
} else {
|
||||
completion()
|
||||
})
|
||||
strongSelf.wallpaperBackgroundNode.layer.animateScale(from: 1.2, to: 1.0, duration: 0.33, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
|
||||
for (_, backgroundNode) in strongSelf.backgroundNodes {
|
||||
backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
|
||||
if strongSelf.isExternalPreview {
|
||||
Transition.immediate.setScale(layer: backgroundNode.layer, scale: 0.001)
|
||||
transition.updateTransformScale(layer: backgroundNode.layer, scale: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
for (identifier, itemNode) in strongSelf.itemNodes {
|
||||
if let (transitionView, _, _) = strongSelf.getTransitionView(identifier) {
|
||||
itemNode.animateFrom(transitionView)
|
||||
itemNode.animateFrom(transitionView, transition: transition)
|
||||
} else {
|
||||
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
if strongSelf.isExternalPreview {
|
||||
itemNode.alpha = 0.0
|
||||
transition.animateTransformScale(node: itemNode, from: 0.001)
|
||||
transition.updateAlpha(node: itemNode, alpha: 1.0)
|
||||
} else {
|
||||
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let topNode = strongSelf.messageNodes?.first, !topNode.alpha.isZero {
|
||||
topNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
|
||||
topNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -30.0), to: CGPoint(), duration: 0.4, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
transition.animatePositionAdditive(layer: topNode.layer, offset: CGPoint(x: 0.0, y: -30.0))
|
||||
}
|
||||
|
||||
if let bottomNode = strongSelf.messageNodes?.last, !bottomNode.alpha.isZero {
|
||||
bottomNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.1)
|
||||
bottomNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 30.0), to: CGPoint(), duration: 0.4, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
transition.animatePositionAdditive(layer: bottomNode.layer, offset: CGPoint(x: 0.0, y: 30.0))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void = {}) {
|
||||
self.wallpaperBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
completion()
|
||||
|
||||
if let strongSelf = self {
|
||||
Queue.mainQueue().after(0.01) {
|
||||
for (_, backgroundNode) in strongSelf.backgroundNodes {
|
||||
backgroundNode.layer.removeAllAnimations()
|
||||
func animateOut(transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) {
|
||||
if let wallpaperBackgroundNode = self.wallpaperBackgroundNode{
|
||||
wallpaperBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
completion()
|
||||
|
||||
if let strongSelf = self {
|
||||
Queue.mainQueue().after(0.01) {
|
||||
for (_, backgroundNode) in strongSelf.backgroundNodes {
|
||||
backgroundNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
for (_, itemNode) in strongSelf.itemNodes {
|
||||
itemNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
strongSelf.messageNodes?.first?.layer.removeAllAnimations()
|
||||
strongSelf.messageNodes?.last?.layer.removeAllAnimations()
|
||||
|
||||
strongSelf.wallpaperBackgroundNode?.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
for (_, itemNode) in strongSelf.itemNodes {
|
||||
itemNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
strongSelf.messageNodes?.first?.layer.removeAllAnimations()
|
||||
strongSelf.messageNodes?.last?.layer.removeAllAnimations()
|
||||
|
||||
strongSelf.wallpaperBackgroundNode.layer.removeAllAnimations()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.wallpaperBackgroundNode.layer.animateScale(from: 1.0, to: 1.2, duration: 0.33, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
})
|
||||
|
||||
wallpaperBackgroundNode.layer.animateScale(from: 1.0, to: 1.2, duration: 0.33, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
} else {
|
||||
completion()
|
||||
}
|
||||
|
||||
for (_, backgroundNode) in self.backgroundNodes {
|
||||
backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
if self.isExternalPreview {
|
||||
transition.updateTransformScale(layer: backgroundNode.layer, scale: 0.001)
|
||||
}
|
||||
}
|
||||
|
||||
for (identifier, itemNode) in self.itemNodes {
|
||||
if let (transitionView, maybeDustNode, completion) = self.getTransitionView(identifier) {
|
||||
itemNode.animateTo(transitionView, dustNode: maybeDustNode, completion: completion)
|
||||
itemNode.animateTo(transitionView, dustNode: maybeDustNode, transition: transition, completion: completion)
|
||||
} else {
|
||||
itemNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
if self.isExternalPreview {
|
||||
transition.updateTransformScale(node: itemNode, scale: 0.001)
|
||||
transition.updateAlpha(node: itemNode, alpha: 0.0)
|
||||
} else {
|
||||
itemNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let topNode = self.messageNodes?.first {
|
||||
topNode.layer.animateAlpha(from: topNode.alpha, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
topNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -30.0), duration: 0.4, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
||||
transition.animatePositionAdditive(layer: topNode.layer, offset: CGPoint(), to: CGPoint(x: 0.0, y: -30.0), removeOnCompletion: false)
|
||||
}
|
||||
|
||||
if let bottomNode = self.messageNodes?.last {
|
||||
bottomNode.layer.animateAlpha(from: bottomNode.alpha, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
bottomNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: 30.0), duration: 0.4, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
||||
transition.animatePositionAdditive(layer: bottomNode.layer, offset: CGPoint(), to: CGPoint(x: 0.0, y: 30.0), removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,7 +831,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
if let current = self.itemNodes[identifier] {
|
||||
itemNode = current
|
||||
} else {
|
||||
itemNode = MediaPickerSelectedItemNode(asset: asset, interaction: self.interaction, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency)
|
||||
itemNode = MediaPickerSelectedItemNode(asset: asset, interaction: self.interaction, enableAnimations: self.context.sharedContext.energyUsageSettings.fullTranslucency, isExternalPreview: self.isExternalPreview)
|
||||
self.itemNodes[identifier] = itemNode
|
||||
self.scrollNode.addSubnode(itemNode)
|
||||
|
||||
@@ -852,55 +901,61 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
}
|
||||
}
|
||||
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil)
|
||||
|
||||
let previewText = groupLayouts.count > 1 ? presentationData.strings.Attachment_MessagesPreview : presentationData.strings.Attachment_MessagePreview
|
||||
|
||||
let previewMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: previewText, entities: [], additionalAttributes: nil))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
let previewItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [previewMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: true, isPreview: true, isStandalone: false)
|
||||
|
||||
let dragMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_DragToReorder, entities: [], additionalAttributes: nil))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
let dragItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [dragMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: true, isPreview: true, isStandalone: false)
|
||||
|
||||
let headerItems: [ListViewItem] = [previewItem, dragItem]
|
||||
|
||||
let params = ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< headerItems.count {
|
||||
let itemNode = messageNodes[i]
|
||||
headerItems[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: size.width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
itemNode.frame = nodeFrame
|
||||
itemNode.isUserInteractionEnabled = false
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
if !self.isExternalPreview {
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1))
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil)
|
||||
|
||||
let previewText = groupLayouts.count > 1 ? presentationData.strings.Attachment_MessagesPreview : presentationData.strings.Attachment_MessagePreview
|
||||
|
||||
let previewMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: previewText, entities: [], additionalAttributes: nil))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
let previewItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [previewMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: true, isPreview: true, isStandalone: false)
|
||||
|
||||
let dragMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_DragToReorder, entities: [], additionalAttributes: nil))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
let dragItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [dragMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: true, isPreview: true, isStandalone: false)
|
||||
|
||||
let headerItems: [ListViewItem] = [previewItem, dragItem]
|
||||
|
||||
let params = ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< headerItems.count {
|
||||
let itemNode = messageNodes[i]
|
||||
headerItems[i].updateNode(async: { $0() }, node: {
|
||||
return itemNode
|
||||
}, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in
|
||||
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: size.width, height: layout.size.height))
|
||||
|
||||
itemNode.contentSize = layout.contentSize
|
||||
itemNode.insets = layout.insets
|
||||
itemNode.frame = nodeFrame
|
||||
itemNode.isUserInteractionEnabled = false
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
var messageNodes: [ListViewItemNode] = []
|
||||
for i in 0 ..< headerItems.count {
|
||||
var itemNode: ListViewItemNode?
|
||||
headerItems[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
|
||||
itemNode = node
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
itemNode!.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
messageNodes.append(itemNode!)
|
||||
self.scrollNode.addSubnode(itemNode!)
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
} else {
|
||||
var messageNodes: [ListViewItemNode] = []
|
||||
for i in 0 ..< headerItems.count {
|
||||
var itemNode: ListViewItemNode?
|
||||
headerItems[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
|
||||
itemNode = node
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
itemNode!.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
messageNodes.append(itemNode!)
|
||||
self.scrollNode.addSubnode(itemNode!)
|
||||
}
|
||||
self.messageNodes = messageNodes
|
||||
}
|
||||
|
||||
let spacing: CGFloat = 8.0
|
||||
var contentHeight: CGFloat = 60.0
|
||||
var contentHeight: CGFloat = 0.0
|
||||
var contentWidth: CGFloat = 0.0
|
||||
if !self.isExternalPreview {
|
||||
contentHeight += 60.0
|
||||
}
|
||||
|
||||
if let previewNode = self.messageNodes?.first {
|
||||
transition.updateFrame(node: previewNode, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top + 28.0), size: previewNode.frame.size))
|
||||
@@ -915,26 +970,35 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
|
||||
var groupIndex = 0
|
||||
for (items, groupSize) in groupLayouts {
|
||||
let groupRect = CGRect(origin: CGPoint(x: insets.left + floorToScreenPixels((size.width - insets.left - insets.right - groupSize.width) / 2.0), y: insets.top + contentHeight), size: groupSize)
|
||||
|
||||
let groupBackgroundNode: MessageBackgroundNode
|
||||
if let current = self.backgroundNodes[groupIndex] {
|
||||
groupBackgroundNode = current
|
||||
} else {
|
||||
groupBackgroundNode = MessageBackgroundNode()
|
||||
groupBackgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNodes[groupIndex] = groupBackgroundNode
|
||||
self.scrollNode.insertSubnode(groupBackgroundNode, at: 0)
|
||||
var groupRect = CGRect(origin: CGPoint(x: 0.0, y: insets.top + contentHeight), size: groupSize)
|
||||
if !self.isExternalPreview {
|
||||
groupRect.origin.x = insets.left + floorToScreenPixels((size.width - insets.left - insets.right - groupSize.width) / 2.0)
|
||||
}
|
||||
|
||||
var itemTransition = transition
|
||||
if groupBackgroundNode.frame.width.isZero {
|
||||
itemTransition = .immediate
|
||||
}
|
||||
|
||||
itemTransition.updateFrame(node: groupBackgroundNode, frame: groupRect.insetBy(dx: -5.0, dy: -2.0).offsetBy(dx: 3.0, dy: 0.0))
|
||||
groupBackgroundNode.update(size: groupBackgroundNode.frame.size, theme: theme, wallpaper: wallpaper, graphics: graphics, wallpaperBackgroundNode: self.wallpaperBackgroundNode, transition: itemTransition)
|
||||
|
||||
if !self.isExternalPreview {
|
||||
let groupBackgroundNode: MessageBackgroundNode
|
||||
if let current = self.backgroundNodes[groupIndex] {
|
||||
groupBackgroundNode = current
|
||||
} else {
|
||||
groupBackgroundNode = MessageBackgroundNode()
|
||||
groupBackgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNodes[groupIndex] = groupBackgroundNode
|
||||
self.scrollNode.insertSubnode(groupBackgroundNode, at: 0)
|
||||
}
|
||||
|
||||
if groupBackgroundNode.frame.width.isZero {
|
||||
itemTransition = .immediate
|
||||
}
|
||||
|
||||
let groupBackgroundFrame = groupRect.insetBy(dx: -5.0, dy: -2.0).offsetBy(dx: 3.0, dy: 0.0)
|
||||
itemTransition.updatePosition(node: groupBackgroundNode, position: groupBackgroundFrame.center)
|
||||
itemTransition.updateBounds(node: groupBackgroundNode, bounds: CGRect(origin: CGPoint(), size: groupBackgroundFrame.size))
|
||||
groupBackgroundNode.update(size: groupBackgroundNode.frame.size, theme: theme, wallpaper: wallpaper, graphics: graphics, wallpaperBackgroundNode: self.wallpaperBackgroundNode, transition: itemTransition)
|
||||
}
|
||||
|
||||
var isFirstGroup = true
|
||||
for (item, itemRect, itemPosition) in items {
|
||||
if let identifier = item.uniqueIdentifier, let itemNode = self.itemNodes[identifier] {
|
||||
var corners: CACornerMask = []
|
||||
@@ -968,7 +1032,13 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
}
|
||||
}
|
||||
|
||||
contentHeight += groupSize.height + spacing
|
||||
if isFirstGroup {
|
||||
isFirstGroup = false
|
||||
} else {
|
||||
contentHeight += spacing
|
||||
}
|
||||
contentHeight += groupSize.height
|
||||
contentWidth = max(contentWidth, groupSize.width)
|
||||
groupIndex += 1
|
||||
}
|
||||
|
||||
@@ -1032,7 +1102,13 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
|
||||
self.updateAbsoluteRects()
|
||||
|
||||
self.scrollNode.view.contentSize = CGSize(width: size.width, height: contentHeight)
|
||||
if self.isExternalPreview {
|
||||
self.scrollNode.view.contentSize = CGSize(width: contentWidth, height: contentHeight)
|
||||
} else {
|
||||
self.scrollNode.view.contentSize = CGSize(width: size.width, height: contentHeight)
|
||||
}
|
||||
|
||||
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
|
||||
}
|
||||
|
||||
func updateSelectionState() {
|
||||
@@ -1047,6 +1123,25 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn(transition: Transition) {
|
||||
self.animateIn(transition: transition.containedViewLayoutTransition, initiated: {}, completion: {})
|
||||
}
|
||||
|
||||
func animateOut(transition: Transition) {
|
||||
self.animateOut(transition: transition.containedViewLayoutTransition, completion: {})
|
||||
}
|
||||
|
||||
func update(containerSize: CGSize, transition: Transition) -> CGSize {
|
||||
if var validLayout = self.validLayout {
|
||||
validLayout.size = containerSize
|
||||
self.validLayout = validLayout
|
||||
}
|
||||
|
||||
self.updateItems(transition: transition.containedViewLayoutTransition)
|
||||
|
||||
return self.contentSize
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, insets: UIEdgeInsets, items: [TGMediaSelectableItem], grouped: Bool, theme: PresentationTheme, wallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners, transition: ContainedViewLayoutTransition) {
|
||||
let previous = self.validLayout
|
||||
self.validLayout = (size, insets, items, grouped, theme, wallpaper, bubbleCorners)
|
||||
@@ -1068,10 +1163,12 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
}
|
||||
|
||||
let inset: CGFloat = insets.left == 70 ? insets.left : 0.0
|
||||
self.wallpaperBackgroundNode.update(wallpaper: wallpaper, animated: false)
|
||||
self.wallpaperBackgroundNode.updateBubbleTheme(bubbleTheme: theme, bubbleCorners: bubbleCorners)
|
||||
transition.updateFrame(node: self.wallpaperBackgroundNode, frame: CGRect(origin: CGPoint(x: inset, y: 0.0), size: CGSize(width: size.width - inset * 2.0, height: size.height)))
|
||||
self.wallpaperBackgroundNode.updateLayout(size: CGSize(width: size.width - inset * 2.0, height: size.height), displayMode: .aspectFill, transition: transition)
|
||||
if let wallpaperBackgroundNode = self.wallpaperBackgroundNode {
|
||||
wallpaperBackgroundNode.update(wallpaper: wallpaper, animated: false)
|
||||
wallpaperBackgroundNode.updateBubbleTheme(bubbleTheme: theme, bubbleCorners: bubbleCorners)
|
||||
transition.updateFrame(node: wallpaperBackgroundNode, frame: CGRect(origin: CGPoint(x: inset, y: 0.0), size: CGSize(width: size.width - inset * 2.0, height: size.height)))
|
||||
wallpaperBackgroundNode.updateLayout(size: CGSize(width: size.width - inset * 2.0, height: size.height), displayMode: .aspectFill, transition: transition)
|
||||
}
|
||||
|
||||
self.updateItems(transition: itemsTransition)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user