mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
no message
This commit is contained in:
147
TelegramUI/GalleryThumbnailContainerNode.swift
Normal file
147
TelegramUI/GalleryThumbnailContainerNode.swift
Normal file
@@ -0,0 +1,147 @@
|
||||
import Foundation
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
|
||||
protocol GalleryThumbnailItem {
|
||||
func isEqual(to: GalleryThumbnailItem) -> Bool
|
||||
var image: (Signal<(TransformImageArguments) -> DrawingContext?, NoError>, CGSize) { get }
|
||||
}
|
||||
|
||||
private final class GalleryThumbnailItemNode: ASDisplayNode {
|
||||
private let imageNode: TransformImageNode
|
||||
private let imageContainerNode: ASDisplayNode
|
||||
|
||||
private let imageSize: CGSize
|
||||
|
||||
init(item: GalleryThumbnailItem) {
|
||||
self.imageNode = TransformImageNode()
|
||||
self.imageContainerNode = ASDisplayNode()
|
||||
self.imageContainerNode.clipsToBounds = true
|
||||
self.imageContainerNode.cornerRadius = 4.0
|
||||
let (signal, imageSize) = item.image
|
||||
self.imageSize = imageSize
|
||||
|
||||
super.init()
|
||||
|
||||
self.imageContainerNode.addSubnode(self.imageNode)
|
||||
self.addSubnode(self.imageContainerNode)
|
||||
self.imageNode.setSignal(signal)
|
||||
}
|
||||
|
||||
func updateLayout(height: CGFloat, progress: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let baseWidth: CGFloat = 20.0
|
||||
let boundingSize = self.imageSize.aspectFilled(CGSize(width: 1.0, height: height))
|
||||
let width = baseWidth * (1.0 - progress) + boundingSize.width * progress
|
||||
let arguments = TransformImageArguments(corners: ImageCorners(radius: 0), imageSize: boundingSize, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets())
|
||||
let makeLayout = self.imageNode.asyncLayout()
|
||||
let apply = makeLayout(arguments)
|
||||
apply()
|
||||
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: (width - boundingSize.width) / 2.0, y: 0.0), size: boundingSize))
|
||||
transition.updateFrame(node: self.imageContainerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: height)))
|
||||
|
||||
return width
|
||||
}
|
||||
}
|
||||
|
||||
final class GalleryThumbnailContainerNode: ASDisplayNode {
|
||||
let groupId: Int64
|
||||
private let contentNode: ASDisplayNode
|
||||
|
||||
private var items: [GalleryThumbnailItem] = []
|
||||
private var itemNodes: [GalleryThumbnailItemNode] = []
|
||||
private var centralIndexAndProgress: (Int, CGFloat)?
|
||||
private var currentLayout: CGSize?
|
||||
|
||||
init(groupId: Int64) {
|
||||
self.groupId = groupId
|
||||
self.contentNode = ASDisplayNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.contentNode)
|
||||
}
|
||||
|
||||
func updateItems(_ items: [GalleryThumbnailItem], centralIndex: Int, progress: CGFloat) {
|
||||
var updated = false
|
||||
if self.items.count == items.count {
|
||||
for i in 0 ..< self.items.count {
|
||||
if !self.items[i].isEqual(to: items[i]) {
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updated = true
|
||||
}
|
||||
if updated {
|
||||
var itemNodes: [GalleryThumbnailItemNode] = []
|
||||
for item in items {
|
||||
if let index = self.items.index(where: { $0.isEqual(to: item) }) {
|
||||
itemNodes.append(self.itemNodes[index])
|
||||
} else {
|
||||
itemNodes.append(GalleryThumbnailItemNode(item: item))
|
||||
}
|
||||
}
|
||||
|
||||
for itemNode in itemNodes {
|
||||
if itemNode.supernode == nil {
|
||||
self.contentNode.addSubnode(itemNode)
|
||||
}
|
||||
}
|
||||
for itemNode in self.itemNodes {
|
||||
if !itemNodes.contains(where: { $0 === itemNode }) {
|
||||
itemNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
self.items = items
|
||||
self.itemNodes = itemNodes
|
||||
}
|
||||
self.centralIndexAndProgress = (centralIndex, progress)
|
||||
if let size = self.currentLayout {
|
||||
self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.currentLayout = size
|
||||
if let (centralIndex, progress) = self.centralIndexAndProgress {
|
||||
self.updateLayout(size: size, centralIndex: centralIndex, progress: progress, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, centralIndex: Int, progress: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.currentLayout = size
|
||||
self.contentNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
let spacing: CGFloat = 2.0
|
||||
let centralSpacing: CGFloat = 6.0
|
||||
let itemHeight: CGFloat = 30.0
|
||||
let centralProgress: CGFloat = 1.0 - abs(progress * 2.0)
|
||||
let leftProgress: CGFloat = max(0.0, -progress * 2.0)
|
||||
let rightProgress: CGFloat = max(0.0, progress * 2.0)
|
||||
|
||||
let centralWidth = self.itemNodes[centralIndex].updateLayout(height: itemHeight, progress: centralProgress, transition: transition)
|
||||
var centralFrame = CGRect(origin: CGPoint(x: ((size.width - centralWidth) / 2.0), y: 0.0), size: CGSize(width: centralWidth, height: itemHeight))
|
||||
centralFrame.origin.x += -progress * 2.0 * centralFrame.width
|
||||
let currentCentralSpacing: CGFloat = centralProgress * centralSpacing + (1.0 - centralProgress) * spacing
|
||||
var leftOffset = centralFrame.minX - currentCentralSpacing
|
||||
var rightOffset = centralFrame.maxX + currentCentralSpacing
|
||||
transition.updateFrame(node: self.itemNodes[centralIndex], frame: centralFrame)
|
||||
|
||||
for i in (0 ..< centralIndex).reversed() {
|
||||
let progress: CGFloat = i == centralIndex - 1 ? leftProgress : 0.0
|
||||
let itemSpacing: CGFloat = progress * centralSpacing + (1.0 - progress) * spacing
|
||||
let itemWidth = self.itemNodes[i].updateLayout(height: itemHeight, progress: progress, transition: transition)
|
||||
transition.updateFrame(node: self.itemNodes[i], frame: CGRect(origin: CGPoint(x: leftOffset - itemWidth, y: 0.0), size: CGSize(width: itemWidth, height: itemHeight)))
|
||||
leftOffset -= itemSpacing + itemWidth
|
||||
}
|
||||
|
||||
for i in (centralIndex + 1) ..< self.itemNodes.count {
|
||||
let progress = i == centralIndex + 1 ? rightProgress : 0.0
|
||||
let itemSpacing: CGFloat = progress * centralSpacing + (1.0 - progress) * spacing
|
||||
let itemWidth = self.itemNodes[i].updateLayout(height: itemHeight, progress: progress, transition: transition)
|
||||
transition.updateFrame(node: self.itemNodes[i], frame: CGRect(origin: CGPoint(x: rightOffset, y: 0.0), size: CGSize(width: itemWidth, height: itemHeight)))
|
||||
rightOffset += itemSpacing + itemWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user