mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
218 lines
12 KiB
Swift
218 lines
12 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Postbox
|
|
import SwiftSignalKit
|
|
import Display
|
|
import TelegramCore
|
|
|
|
private func historyNodeImplForMode(_ mode: PeerMediaCollectionMode, account: Account, peerId: PeerId, messageId: MessageId?, controllerInteraction: ChatControllerInteraction) -> ASDisplayNode {
|
|
switch mode {
|
|
case .photoOrVideo:
|
|
return ChatHistoryGridNode(account: account, peerId: peerId, messageId: messageId, tagMask: .PhotoOrVideo, controllerInteraction: controllerInteraction)
|
|
case .file:
|
|
let node = ChatHistoryListNode(account: account, peerId: peerId, tagMask: .File, messageId: messageId, controllerInteraction: controllerInteraction, mode: .list)
|
|
node.preloadPages = true
|
|
return node
|
|
case .music:
|
|
let node = ChatHistoryListNode(account: account, peerId: peerId, tagMask: .Music, messageId: messageId, controllerInteraction: controllerInteraction, mode: .list)
|
|
node.preloadPages = true
|
|
return node
|
|
case .webpage:
|
|
let node = ChatHistoryListNode(account: account, peerId: peerId, tagMask: .WebPage, messageId: messageId, controllerInteraction: controllerInteraction, mode: .list)
|
|
node.preloadPages = true
|
|
return node
|
|
}
|
|
}
|
|
|
|
class PeerMediaCollectionControllerNode: ASDisplayNode {
|
|
private let account: Account
|
|
private let peerId: PeerId
|
|
private let controllerInteraction: ChatControllerInteraction
|
|
|
|
private var historyNodeImpl: ASDisplayNode
|
|
var historyNode: ChatHistoryNode {
|
|
return self.historyNodeImpl as! ChatHistoryNode
|
|
}
|
|
|
|
private let candidateHistoryNodeReadyDisposable = MetaDisposable()
|
|
private var candidateHistoryNode: (ASDisplayNode, PeerMediaCollectionMode)?
|
|
|
|
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
|
|
|
var requestLayout: (ContainedViewLayoutTransition) -> Void = { _ in }
|
|
var requestUpdateMediaCollectionInterfaceState: (Bool, (PeerMediaCollectionInterfaceState) -> PeerMediaCollectionInterfaceState) -> Void = { _ in }
|
|
|
|
private var mediaCollectionInterfaceState = PeerMediaCollectionInterfaceState()
|
|
|
|
private var modeSelectionNode: PeerMediaCollectionModeSelectionNode?
|
|
private var selectionPanel: ChatMessageSelectionInputPanelNode?
|
|
|
|
init(account: Account, peerId: PeerId, messageId: MessageId?, controllerInteraction: ChatControllerInteraction) {
|
|
self.account = account
|
|
self.peerId = peerId
|
|
self.controllerInteraction = controllerInteraction
|
|
|
|
self.historyNodeImpl = historyNodeImplForMode(self.mediaCollectionInterfaceState.mode, account: account, peerId: peerId, messageId: messageId, controllerInteraction: controllerInteraction)
|
|
|
|
super.init(viewBlock: {
|
|
return UITracingLayerView()
|
|
}, didLoad: nil)
|
|
|
|
self.backgroundColor = UIColor.white
|
|
|
|
self.addSubnode(self.historyNodeImpl)
|
|
}
|
|
|
|
deinit {
|
|
self.candidateHistoryNodeReadyDisposable.dispose()
|
|
}
|
|
|
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets) -> Void) {
|
|
self.containerLayout = (layout, navigationBarHeight)
|
|
|
|
var insets = layout.insets(options: [.input])
|
|
insets.top += navigationBarHeight
|
|
|
|
if let selectionState = self.mediaCollectionInterfaceState.selectionState {
|
|
let interfaceState = ChatPresentationInterfaceState().updatedPeer({ _ in self.mediaCollectionInterfaceState.peer })
|
|
|
|
if let selectionPanel = self.selectionPanel {
|
|
selectionPanel.selectedMessageCount = selectionState.selectedIds.count
|
|
let panelHeight = selectionPanel.updateLayout(width: layout.size.width, transition: transition, interfaceState: interfaceState)
|
|
transition.updateFrame(node: selectionPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)))
|
|
} else {
|
|
let selectionPanel = ChatMessageSelectionInputPanelNode()
|
|
selectionPanel.selectedMessageCount = selectionState.selectedIds.count
|
|
selectionPanel.backgroundColor = UIColor(0xfafafa)
|
|
let panelHeight = selectionPanel.updateLayout(width: layout.size.width, transition: .immediate, interfaceState: interfaceState)
|
|
self.selectionPanel = selectionPanel
|
|
self.addSubnode(selectionPanel)
|
|
selectionPanel.frame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom), size: CGSize(width: layout.size.width, height: panelHeight))
|
|
transition.updateFrame(node: selectionPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)))
|
|
}
|
|
} else if let selectionPanel = self.selectionPanel {
|
|
self.selectionPanel = nil
|
|
transition.updateFrame(node: selectionPanel, frame: selectionPanel.frame.offsetBy(dx: 0.0, dy: selectionPanel.bounds.size.height), completion: { [weak selectionPanel] _ in
|
|
selectionPanel?.removeFromSupernode()
|
|
})
|
|
}
|
|
|
|
var duration: Double = 0.0
|
|
var curve: UInt = 0
|
|
switch transition {
|
|
case .immediate:
|
|
break
|
|
case let .animated(animationDuration, animationCurve):
|
|
duration = animationDuration
|
|
switch animationCurve {
|
|
case .easeInOut:
|
|
break
|
|
case .spring:
|
|
curve = 7
|
|
}
|
|
}
|
|
|
|
let previousBounds = self.historyNodeImpl.bounds
|
|
self.historyNodeImpl.bounds = CGRect(x: previousBounds.origin.x, y: previousBounds.origin.y, width: layout.size.width, height: layout.size.height)
|
|
self.historyNodeImpl.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
|
|
|
let listViewCurve: ListViewAnimationCurve
|
|
if curve == 7 {
|
|
listViewCurve = .Spring(duration: duration)
|
|
} else {
|
|
listViewCurve = .Default
|
|
}
|
|
|
|
var additionalBottomInset: CGFloat = 0.0
|
|
if let selectionPanel = self.selectionPanel {
|
|
additionalBottomInset = selectionPanel.bounds.size.height
|
|
}
|
|
|
|
listViewTransaction(ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: insets.top, left:
|
|
insets.right, bottom: insets.bottom + additionalBottomInset, right: insets.left), duration: duration, curve: listViewCurve))
|
|
|
|
if let (candidateHistoryNode, _) = self.candidateHistoryNode {
|
|
let previousBounds = candidateHistoryNode.bounds
|
|
candidateHistoryNode.bounds = CGRect(x: previousBounds.origin.x, y: previousBounds.origin.y, width: layout.size.width, height: layout.size.height)
|
|
candidateHistoryNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
|
|
|
(candidateHistoryNode as! ChatHistoryNode).updateLayout(transition: transition, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: insets.top, left:
|
|
insets.right, bottom: insets.bottom + additionalBottomInset, right: insets.left), duration: duration, curve: listViewCurve))
|
|
}
|
|
|
|
if self.mediaCollectionInterfaceState.selectingMode {
|
|
if let modeSelectionNode = self.modeSelectionNode {
|
|
modeSelectionNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
|
modeSelectionNode.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
|
modeSelectionNode.mediaCollectionInterfaceState = self.mediaCollectionInterfaceState
|
|
} else {
|
|
let modeSelectionNode = PeerMediaCollectionModeSelectionNode()
|
|
modeSelectionNode.selectedMode = { [weak self] mode in
|
|
if let requestUpdateMediaCollectionInterfaceState = self?.requestUpdateMediaCollectionInterfaceState {
|
|
requestUpdateMediaCollectionInterfaceState(true, { $0.withToggledSelectingMode().withMode(mode) })
|
|
}
|
|
}
|
|
modeSelectionNode.dismiss = { [weak self] in
|
|
if let requestUpdateMediaCollectionInterfaceState = self?.requestUpdateMediaCollectionInterfaceState {
|
|
requestUpdateMediaCollectionInterfaceState(true, { $0.withToggledSelectingMode() })
|
|
}
|
|
}
|
|
modeSelectionNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
|
modeSelectionNode.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
|
modeSelectionNode.mediaCollectionInterfaceState = self.mediaCollectionInterfaceState
|
|
self.insertSubnode(modeSelectionNode, aboveSubnode: self.historyNodeImpl)
|
|
modeSelectionNode.animateIn()
|
|
self.modeSelectionNode = modeSelectionNode
|
|
}
|
|
} else if let modeSelectionNode = self.modeSelectionNode {
|
|
self.modeSelectionNode = nil
|
|
modeSelectionNode.animateOut { [weak modeSelectionNode] in
|
|
modeSelectionNode?.removeFromSupernode()
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateMediaCollectionInterfaceState(_ mediaCollectionInterfaceState: PeerMediaCollectionInterfaceState, animated: Bool) {
|
|
if self.mediaCollectionInterfaceState != mediaCollectionInterfaceState {
|
|
if self.mediaCollectionInterfaceState.mode != mediaCollectionInterfaceState.mode {
|
|
if let containerLayout = self.containerLayout, self.candidateHistoryNode == nil || self.candidateHistoryNode!.1 != mediaCollectionInterfaceState.mode {
|
|
let node = historyNodeImplForMode(mediaCollectionInterfaceState.mode, account: self.account, peerId: self.peerId, messageId: nil, controllerInteraction: self.controllerInteraction)
|
|
self.candidateHistoryNode = (node, mediaCollectionInterfaceState.mode)
|
|
|
|
var insets = containerLayout.0.insets(options: [.input])
|
|
insets.top += containerLayout.1
|
|
|
|
let previousBounds = node.bounds
|
|
node.bounds = CGRect(x: previousBounds.origin.x, y: previousBounds.origin.y, width: containerLayout.0.size.width, height: containerLayout.0.size.height)
|
|
node.position = CGPoint(x: containerLayout.0.size.width / 2.0, y: containerLayout.0.size.height / 2.0)
|
|
|
|
var additionalBottomInset: CGFloat = 0.0
|
|
if let selectionPanel = self.selectionPanel {
|
|
additionalBottomInset = selectionPanel.bounds.size.height
|
|
}
|
|
|
|
(node as! ChatHistoryNode).updateLayout(transition: .immediate, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: containerLayout.0.size, insets: UIEdgeInsets(top: insets.top, left: insets.right, bottom: insets.bottom + additionalBottomInset, right: insets.left), duration: 0.0, curve: .Default))
|
|
|
|
self.candidateHistoryNodeReadyDisposable.set(((node as! ChatHistoryNode).historyReady.get()
|
|
|> deliverOnMainQueue).start(next: { [weak self, weak node] _ in
|
|
if let strongSelf = self, let strongNode = node, strongNode == strongSelf.candidateHistoryNode?.0 {
|
|
strongSelf.candidateHistoryNode = nil
|
|
strongSelf.insertSubnode(strongNode, aboveSubnode: strongSelf.historyNodeImpl)
|
|
strongSelf.historyNodeImpl.removeFromSupernode()
|
|
strongSelf.historyNodeImpl = strongNode
|
|
}
|
|
}))
|
|
}
|
|
}
|
|
|
|
self.mediaCollectionInterfaceState = mediaCollectionInterfaceState
|
|
|
|
if let modeSelectionNode = self.modeSelectionNode {
|
|
modeSelectionNode.mediaCollectionInterfaceState = mediaCollectionInterfaceState
|
|
}
|
|
|
|
self.requestLayout(animated ? .animated(duration: 0.4, curve: .spring) : .immediate)
|
|
}
|
|
}
|
|
}
|