Shared media improvements

This commit is contained in:
Ali
2021-10-25 17:00:32 +04:00
parent 66338027e7
commit 80fe21681e
6 changed files with 1637 additions and 58 deletions

View File

@@ -166,9 +166,9 @@ public final class ListMessageFileItemNode: ListMessageNode {
private let descriptionProgressNode: ImmediateTextNode
public let dateNode: TextNode
private let extensionIconNode: ASImageNode
public let extensionIconNode: ASImageNode
private let extensionIconText: TextNode
private let iconImageNode: TransformImageNode
public let iconImageNode: TransformImageNode
private let iconStatusNode: SemanticStatusNode
private let restrictionNode: ASDisplayNode

View File

@@ -26,9 +26,14 @@ public protocol SparseItemGridDisplayItem: AnyObject {
var view: SparseItemGridView? { get }
}
public protocol SparseItemGridShimmerLayer: CALayer {
func update(size: CGSize)
}
public protocol SparseItemGridBinding: AnyObject {
func createLayer() -> SparseItemGridLayer?
func createView() -> SparseItemGridView?
func createShimmerLayer() -> SparseItemGridShimmerLayer?
func bindLayers(items: [SparseItemGrid.Item], layers: [SparseItemGridDisplayItem], synchronous: Bool)
func unbindLayer(layer: SparseItemGridLayer)
func scrollerTextForTag(tag: Int32) -> String?
@@ -141,10 +146,13 @@ private final class Shimmer {
}
}
final class Layer: CALayer {
final class Layer: CALayer, SparseItemGridShimmerLayer {
override func action(forKey event: String) -> CAAction? {
return nullAction
}
func update(size: CGSize) {
}
}
}
@@ -423,7 +431,7 @@ public final class SparseItemGrid: ASDisplayNode {
var layout: Layout?
var items: Items?
var visibleItems: [AnyHashable: VisibleItem] = [:]
var visiblePlaceholders: [Shimmer.Layer] = []
var visiblePlaceholders: [SparseItemGridShimmerLayer] = []
private var scrollingArea: SparseItemGridScrollingArea?
private var currentScrollingTag: Int32?
@@ -435,9 +443,12 @@ public final class SparseItemGrid: ASDisplayNode {
private var previousScrollOffset: CGFloat = 0.0
var coveringInsetOffset: CGFloat = 0.0
init(zoomLevel: ZoomLevel, maybeLoadHoleAnchor: @escaping (HoleAnchor, HoleLocation) -> Void) {
let coveringOffsetUpdated: (Viewport, ContainedViewLayoutTransition) -> Void
init(zoomLevel: ZoomLevel, maybeLoadHoleAnchor: @escaping (HoleAnchor, HoleLocation) -> Void, coveringOffsetUpdated: @escaping (Viewport, ContainedViewLayoutTransition) -> Void) {
self.zoomLevel = zoomLevel
self.maybeLoadHoleAnchor = maybeLoadHoleAnchor
self.coveringOffsetUpdated = coveringOffsetUpdated
self.scrollView = UIScrollView()
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
@@ -476,7 +487,7 @@ public final class SparseItemGrid: ASDisplayNode {
if !self.ignoreScrolling {
self.updateVisibleItems(resetScrolling: false, synchronous: true, restoreScrollPosition: nil)
if let layout = self.layout, let items = self.items {
if let layout = self.layout, let _ = self.items {
let offset = scrollView.contentOffset.y
let delta = offset - self.previousScrollOffset
self.previousScrollOffset = offset
@@ -495,7 +506,7 @@ public final class SparseItemGrid: ASDisplayNode {
}
if coveringInsetOffset < self.coveringInsetOffset {
self.coveringInsetOffset = coveringInsetOffset
items.itemBinding.coveringInsetOffsetUpdated(transition: .immediate)
self.coveringOffsetUpdated(self, .immediate)
}
}
} else {
@@ -511,7 +522,7 @@ public final class SparseItemGrid: ASDisplayNode {
}
if coveringInsetOffset != self.coveringInsetOffset {
self.coveringInsetOffset = coveringInsetOffset
items.itemBinding.coveringInsetOffsetUpdated(transition: .immediate)
self.coveringOffsetUpdated(self, .immediate)
}
}
}
@@ -539,7 +550,7 @@ public final class SparseItemGrid: ASDisplayNode {
}
private func snapCoveringInsetOffset() {
if let layout = self.layout, let items = self.items {
if let layout = self.layout, let _ = self.items {
let offset = self.scrollView.contentOffset.y
if offset < layout.containerLayout.insets.top {
if offset <= layout.containerLayout.insets.top / 2.0 {
@@ -560,7 +571,7 @@ public final class SparseItemGrid: ASDisplayNode {
if coveringInsetOffset != self.coveringInsetOffset {
self.coveringInsetOffset = coveringInsetOffset
items.itemBinding.coveringInsetOffsetUpdated(transition: .animated(duration: 0.2, curve: .easeInOut))
self.coveringOffsetUpdated(self, .animated(duration: 0.2, curve: .easeInOut))
}
}
}
@@ -680,6 +691,10 @@ public final class SparseItemGrid: ASDisplayNode {
self.scrollView.setContentOffset(self.scrollView.contentOffset, animated: false)
}
func updateShimmerLayers() {
self.updateVisibleItems(resetScrolling: false, synchronous: false, restoreScrollPosition: nil)
}
private func updateVisibleItems(resetScrolling: Bool, synchronous: Bool, restoreScrollPosition: (y: CGFloat, index: Int)?) {
guard let layout = self.layout, let items = self.items else {
return
@@ -753,21 +768,39 @@ public final class SparseItemGrid: ASDisplayNode {
}
}
if itemLayer.needsShimmer {
let placeholderLayer: SparseItemGridShimmerLayer
if self.visiblePlaceholders.count > usedPlaceholderCount {
placeholderLayer = self.visiblePlaceholders[usedPlaceholderCount]
} else {
placeholderLayer = items.itemBinding.createShimmerLayer() ?? Shimmer.Layer()
self.scrollView.layer.insertSublayer(placeholderLayer, at: 0)
self.visiblePlaceholders.append(placeholderLayer)
}
let itemFrame = layout.frame(at: index)
placeholderLayer.frame = itemFrame
self.shimmer.update(colors: shimmerColors, layer: placeholderLayer, containerSize: layout.containerLayout.size, frame: itemFrame.offsetBy(dx: 0.0, dy: -visibleBounds.minY))
placeholderLayer.update(size: itemFrame.size)
usedPlaceholderCount += 1
}
validIds.insert(item.id)
itemLayer.frame = layout.frame(at: index)
} else if layout.containerLayout.fixedItemHeight == nil {
let placeholderLayer: Shimmer.Layer
} else {
let placeholderLayer: SparseItemGridShimmerLayer
if self.visiblePlaceholders.count > usedPlaceholderCount {
placeholderLayer = self.visiblePlaceholders[usedPlaceholderCount]
} else {
placeholderLayer = Shimmer.Layer()
placeholderLayer = items.itemBinding.createShimmerLayer() ?? Shimmer.Layer()
self.scrollView.layer.addSublayer(placeholderLayer)
self.visiblePlaceholders.append(placeholderLayer)
}
let itemFrame = layout.frame(at: index)
placeholderLayer.frame = itemFrame
self.shimmer.update(colors: shimmerColors, layer: placeholderLayer, containerSize: layout.containerLayout.size, frame: itemFrame.offsetBy(dx: 0.0, dy: -visibleBounds.minY))
placeholderLayer.update(size: itemFrame.size)
usedPlaceholderCount += 1
}
}
@@ -783,11 +816,6 @@ public final class SparseItemGrid: ASDisplayNode {
} else if let view = item.view {
view.update(size: layer.frame.size)
}
if item.needsShimmer {
let itemFrame = layer.frame
self.shimmer.update(colors: shimmerColors, layer: item.displayLayer, containerSize: layout.containerLayout.size, frame: itemFrame.offsetBy(dx: 0.0, dy: -visibleBounds.minY))
}
}
}
@@ -923,12 +951,19 @@ public final class SparseItemGrid: ASDisplayNode {
var currentProgress: CGFloat = 0.0
init(interactiveState: InteractiveState?, layout: ContainerLayout, anchorItemIndex: Int, from fromViewport: Viewport, to toViewport: Viewport) {
var coveringInsetOffset: CGFloat {
return self.fromViewport.coveringInsetOffset * (1.0 - self.currentProgress) + self.toViewport.coveringInsetOffset * self.currentProgress
}
let coveringOffsetUpdated: (ContainedViewLayoutTransition) -> Void
init(interactiveState: InteractiveState?, layout: ContainerLayout, anchorItemIndex: Int, from fromViewport: Viewport, to toViewport: Viewport, coveringOffsetUpdated: @escaping (ContainedViewLayoutTransition) -> Void) {
self.interactiveState = interactiveState
self.layout = layout
self.anchorItemIndex = anchorItemIndex
self.fromViewport = fromViewport
self.toViewport = toViewport
self.coveringOffsetUpdated = coveringOffsetUpdated
super.init()
@@ -1006,6 +1041,8 @@ public final class SparseItemGrid: ASDisplayNode {
} else {
transition.updateAlpha(node: self.fromViewport, alpha: 1.0 - fromAlphaProgress)
}
self.coveringOffsetUpdated(transition)
}
}
@@ -1033,12 +1070,17 @@ public final class SparseItemGrid: ASDisplayNode {
private let loadingHoleDisposable = MetaDisposable()
public var coveringInsetOffset: CGFloat {
if let currentViewport = self.currentViewport {
if let currentViewportTransition = self.currentViewportTransition {
return currentViewportTransition.coveringInsetOffset
} else if let currentViewport = self.currentViewport {
return currentViewport.coveringInsetOffset
} else {
return 0.0
}
return 0.0
}
public var cancelExternalContentGestures: (() -> Void)?
override public init() {
self.scrollingArea = SparseItemGridScrollingArea()
@@ -1085,7 +1127,7 @@ public final class SparseItemGrid: ASDisplayNode {
switch recognizer.state {
case .began:
break
self.cancelExternalContentGestures?()
case .changed:
let scale = recognizer.scale
if let currentViewportTransition = self.currentViewportTransition, let interactiveState = currentViewportTransition.interactiveState {
@@ -1138,6 +1180,8 @@ public final class SparseItemGrid: ASDisplayNode {
return
}
strongSelf.maybeLoadHoleAnchor(holeAnchor: holeAnchor, location: location)
}, coveringOffsetUpdated: { [weak self] viewport, transition in
self?.coveringOffsetUpdated(viewport: viewport, transition: transition)
})
nextViewport.frame = CGRect(origin: CGPoint(), size: containerLayout.size)
@@ -1146,7 +1190,9 @@ public final class SparseItemGrid: ASDisplayNode {
self.currentViewportTransition?.removeFromSupernode()
let nextInteractiveState = ViewportTransition.InteractiveState(anchorLocation: anchorLocation, initialScale: startScale, targetScale: nextScale)
let currentViewportTransition = ViewportTransition(interactiveState: nextInteractiveState, layout: containerLayout, anchorItemIndex: currentViewportTransition.anchorItemIndex, from: boundaryViewport, to: nextViewport)
let currentViewportTransition = ViewportTransition(interactiveState: nextInteractiveState, layout: containerLayout, anchorItemIndex: currentViewportTransition.anchorItemIndex, from: boundaryViewport, to: nextViewport, coveringOffsetUpdated: { [weak self] transition in
self?.transitionCoveringOffsetUpdated(transition: transition)
})
currentViewportTransition.frame = CGRect(origin: CGPoint(), size: containerLayout.size)
self.insertSubnode(currentViewportTransition, belowSubnode: self.scrollingArea)
self.currentViewportTransition = currentViewportTransition
@@ -1184,12 +1230,16 @@ public final class SparseItemGrid: ASDisplayNode {
return
}
strongSelf.maybeLoadHoleAnchor(holeAnchor: holeAnchor, location: location)
}, coveringOffsetUpdated: { [weak self] viewport, transition in
self?.coveringOffsetUpdated(viewport: viewport, transition: transition)
})
nextViewport.frame = CGRect(origin: CGPoint(), size: containerLayout.size)
nextViewport.update(containerLayout: containerLayout, items: items, restoreScrollPosition: restoreScrollPosition)
let currentViewportTransition = ViewportTransition(interactiveState: interactiveState, layout: containerLayout, anchorItemIndex: anchorItemIndex, from: previousViewport, to: nextViewport)
let currentViewportTransition = ViewportTransition(interactiveState: interactiveState, layout: containerLayout, anchorItemIndex: anchorItemIndex, from: previousViewport, to: nextViewport, coveringOffsetUpdated: { [weak self] transition in
self?.transitionCoveringOffsetUpdated(transition: transition)
})
currentViewportTransition.frame = CGRect(origin: CGPoint(), size: containerLayout.size)
self.insertSubnode(currentViewportTransition, belowSubnode: self.scrollingArea)
self.currentViewportTransition = currentViewportTransition
@@ -1249,6 +1299,8 @@ public final class SparseItemGrid: ASDisplayNode {
return
}
strongSelf.maybeLoadHoleAnchor(holeAnchor: holeAnchor, location: location)
}, coveringOffsetUpdated: { [weak self] viewport, transition in
self?.coveringOffsetUpdated(viewport: viewport, transition: transition)
})
self.currentViewport = currentViewport
self.insertSubnode(currentViewport, belowSubnode: self.scrollingArea)
@@ -1272,6 +1324,12 @@ public final class SparseItemGrid: ASDisplayNode {
return
}
/*#if DEBUG
if "".isEmpty {
return
}
#endif*/
self.isLoadingHole = true
self.loadingHoleDisposable.set((items.itemBinding.loadHole(anchor: holeAnchor, at: location)
|> deliverOnMainQueue).start(completed: { [weak self] in
@@ -1323,6 +1381,8 @@ public final class SparseItemGrid: ASDisplayNode {
return
}
strongSelf.maybeLoadHoleAnchor(holeAnchor: holeAnchor, location: location)
}, coveringOffsetUpdated: { [weak self] viewport, transition in
self?.coveringOffsetUpdated(viewport: viewport, transition: transition)
})
self.currentViewport = currentViewport
self.insertSubnode(currentViewport, belowSubnode: self.scrollingArea)
@@ -1337,7 +1397,9 @@ public final class SparseItemGrid: ASDisplayNode {
currentViewport.frame = CGRect(origin: CGPoint(), size: containerLayout.size)
currentViewport.update(containerLayout: containerLayout, items: items, restoreScrollPosition: restoreScrollPosition)
let currentViewportTransition = ViewportTransition(interactiveState: nil, layout: containerLayout, anchorItemIndex: anchorItemIndex, from: previousViewport, to: currentViewport)
let currentViewportTransition = ViewportTransition(interactiveState: nil, layout: containerLayout, anchorItemIndex: anchorItemIndex, from: previousViewport, to: currentViewport, coveringOffsetUpdated: { [weak self] transition in
self?.transitionCoveringOffsetUpdated(transition: transition)
})
currentViewportTransition.frame = CGRect(origin: CGPoint(), size: containerLayout.size)
self.insertSubnode(currentViewportTransition, belowSubnode: self.scrollingArea)
self.currentViewportTransition = currentViewportTransition
@@ -1365,6 +1427,23 @@ public final class SparseItemGrid: ASDisplayNode {
}
}
private func coveringOffsetUpdated(viewport: Viewport, transition: ContainedViewLayoutTransition) {
guard let items = self.items else {
return
}
if self.currentViewportTransition != nil {
return
}
items.itemBinding.coveringInsetOffsetUpdated(transition: transition)
}
private func transitionCoveringOffsetUpdated(transition: ContainedViewLayoutTransition) {
guard let items = self.items else {
return
}
items.itemBinding.coveringInsetOffsetUpdated(transition: transition)
}
public func forEachVisibleItem(_ f: (SparseItemGridDisplayItem) -> Void) {
guard let currentViewport = self.currentViewport else {
return
@@ -1420,4 +1499,12 @@ public final class SparseItemGrid: ASDisplayNode {
self.scrollingArea.hideScroller()
}
public func updateShimmerLayers() {
self.currentViewport?.updateShimmerLayers()
if let currentViewportTransition = self.currentViewportTransition {
currentViewportTransition.fromViewport.updateShimmerLayers()
currentViewportTransition.toViewport.updateShimmerLayers()
}
}
}

View File

@@ -907,7 +907,7 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
private func dismissLineTooltip() {
if let lineTooltip = self.lineTooltip {
self.lineTooltip = nil
lineTooltip.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak lineTooltip] _ in
lineTooltip.layer.animateAlpha(from: lineTooltip.alpha, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak lineTooltip] _ in
lineTooltip?.removeFromSuperview()
})
}
@@ -936,6 +936,10 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
transition.updateSublayerTransformOffset(layer: self.dateIndicator.layer, offset: CGPoint(x: -3.0, y: 0.0))
displayTooltip.completed()
Queue.mainQueue().after(2.0, { [weak self] in
self?.dismissLineTooltip()
})
}
private func updateLineTooltip(containerSize: CGSize) {

View File

@@ -774,15 +774,6 @@ private final class ItemLayer: CALayer, SparseItemGridLayer {
func bind(item: VisualMediaItem) {
self.item = item
self.updateShimmerLayer()
}
func updateShimmerLayer() {
if self.hasContents {
self.removeAnimation(forKey: "shimmer")
self.contentsRect = CGRect(origin: CGPoint(), size: CGSize(width: 1.0, height: 1.0))
}
}
func updateDuration(duration: Int32?) {
@@ -820,8 +811,6 @@ private final class ItemView: UIView, SparseItemGridView {
var item: VisualMediaItem?
var disposable: Disposable?
var hasContents: Bool = false
var messageItem: ListMessageItem?
var messageItemNode: ListViewItemNode?
var interaction: ListMessageItemInteraction?
@@ -925,7 +914,55 @@ private final class ItemView: UIView, SparseItemGridView {
}
}
private final class SparseItemGridBindingImpl: SparseItemGridBinding {
protocol ListShimmerLayerImageProvider: AnyObject {
func getListShimmerImage(height: CGFloat) -> UIImage
func getSeparatorColor() -> UIColor
}
private final class ListShimmerLayer: CALayer, SparseItemGridShimmerLayer {
final class OverlayLayer: CALayer {
override func action(forKey event: String) -> CAAction? {
return nullAction
}
}
let imageProvider: ListShimmerLayerImageProvider
let shimmerOverlay: OverlayLayer
let separatorLayer: OverlayLayer
private var validHeight: CGFloat?
init(imageProvider: ListShimmerLayerImageProvider) {
self.imageProvider = imageProvider
self.shimmerOverlay = OverlayLayer()
self.separatorLayer = OverlayLayer()
super.init()
self.addSublayer(self.shimmerOverlay)
self.addSublayer(self.separatorLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func action(forKey event: String) -> CAAction? {
return nullAction
}
func update(size: CGSize) {
if self.validHeight != size.height {
self.validHeight = size.height
ASDisplayNodeSetResizableContents(self.shimmerOverlay, self.imageProvider.getListShimmerImage(height: size.height))
self.separatorLayer.backgroundColor = self.imageProvider.getSeparatorColor().cgColor
}
self.shimmerOverlay.frame = CGRect(origin: CGPoint(), size: size)
self.separatorLayer.frame = CGRect(origin: CGPoint(x: 65.0, y: size.height - UIScreenPixel), size: CGSize(width: size.width - 65.0, height: UIScreenPixel))
}
}
private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimmerLayerImageProvider {
let context: AccountContext
let chatLocation: ChatLocation
let directMediaImageCache: DirectMediaImageCache
@@ -942,6 +979,9 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
var coveringInsetOffsetUpdatedImpl: ((ContainedViewLayoutTransition) -> Void)?
var onBeginFastScrollingImpl: (() -> Void)?
var getShimmerColorsImpl: (() -> SparseItemGrid.ShimmerColors)?
var updateShimmerLayersImpl: (() -> Void)?
private var shimmerImages: [CGFloat: UIImage] = [:]
init(context: AccountContext, chatLocation: ChatLocation, useListItems: Bool, listItemInteraction: ListMessageItemInteraction, chatControllerInteraction: ChatControllerInteraction, directMediaImageCache: DirectMediaImageCache) {
self.context = context
@@ -958,6 +998,95 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
self.chatPresentationData = ChatPresentationData(theme: themeData, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners, animatedEmojiScale: 1.0)
}
func getListShimmerImage(height: CGFloat) -> UIImage {
if let image = self.shimmerImages[height] {
return image
} else {
let fakeFile = TelegramMediaFile(
fileId: MediaId(namespace: 0, id: 1),
partialReference: nil,
resource: EmptyMediaResource(),
previewRepresentations: [],
videoThumbnails: [],
immediateThumbnailData: nil,
mimeType: "image/jpeg",
size: nil,
attributes: [.FileName(fileName: "file")]
)
let fakeMessage = Message(
stableId: 1,
stableVersion: 1,
id: MessageId(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(1)), namespace: 0, id: 1),
globallyUniqueId: nil,
groupingKey: nil,
groupInfo: nil,
threadId: nil,
timestamp: 1, flags: [],
tags: [],
globalTags: [],
localTags: [],
forwardInfo: nil,
author: nil,
text: "",
attributes: [],
media: [fakeFile],
peers: SimpleDictionary<PeerId, Peer>(),
associatedMessages: SimpleDictionary<MessageId, Message>(),
associatedMessageIds: []
)
let messageItem = ListMessageItem(
presentationData: self.chatPresentationData,
context: self.context,
chatLocation: self.chatLocation,
interaction: self.listItemInteraction,
message: fakeMessage,
selection: .none,
displayHeader: false
)
var itemNode: ListViewItemNode?
messageItem.nodeConfiguredForParams(async: { f in f() }, params: ListViewItemLayoutParams(width: 400.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 0.0), synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
itemNode = node
apply().1(ListViewItemApply(isOnScreen: true))
})
guard let fileItemNode = itemNode as? ListMessageFileItemNode else {
return UIImage()
}
let image = generateImage(CGSize(width: 320.0, height: height), rotatedContext: { size, context in
UIGraphicsPushContext(context)
context.setFillColor(self.chatPresentationData.theme.theme.list.plainBackgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
func fillRoundedRect(rect: CGRect, radius: CGFloat) {
UIBezierPath(roundedRect: rect, byRoundingCorners: [.topLeft, .topRight, .bottomLeft, .bottomRight], cornerRadii: CGSize(width: radius, height: radius)).fill()
}
let lineHeight: CGFloat = 8.0
let titleOrigin = CGPoint(x: fileItemNode.titleNode.frame.minX, y: fileItemNode.titleNode.frame.midY)
let dateOrigin = CGPoint(x: fileItemNode.descriptionNode.frame.minX, y: fileItemNode.descriptionNode.frame.midY)
fillRoundedRect(rect: CGRect(origin: CGPoint(x: titleOrigin.x, y: titleOrigin.y - lineHeight / 2.0), size: CGSize(width: 160.0, height: lineHeight)), radius: lineHeight / 2.0)
fillRoundedRect(rect: CGRect(origin: CGPoint(x: dateOrigin.x, y: dateOrigin.y - lineHeight / 2.0), size: CGSize(width: 220.0, height: lineHeight)), radius: lineHeight / 2.0)
fillRoundedRect(rect: fileItemNode.extensionIconNode.frame, radius: 6.0)
UIGraphicsPopContext()
})!.stretchableImage(withLeftCapWidth: 299, topCapHeight: 0)
self.shimmerImages[height] = image
return image
}
}
func getSeparatorColor() -> UIColor {
return self.chatPresentationData.theme.theme.list.itemPlainSeparatorColor
}
func createLayer() -> SparseItemGridLayer? {
if self.useListItems {
return nil
@@ -972,6 +1101,14 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
return ItemView()
}
func createShimmerLayer() -> SparseItemGridShimmerLayer? {
if self.useListItems {
let layer = ListShimmerLayer(imageProvider: self)
return layer
}
return nil
}
func bindLayers(items: [SparseItemGrid.Item], layers: [SparseItemGridDisplayItem], synchronous: Bool) {
for i in 0 ..< items.count {
guard let item = items[i] as? VisualMediaItem else {
@@ -1034,22 +1171,30 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
}
if let loadSignal = result.loadSignal {
layer.disposable = (loadSignal
|> deliverOnMainQueue).start(next: { [weak layer] image in
|> deliverOnMainQueue).start(next: { [weak self, weak layer] image in
guard let layer = layer else {
return
}
let copyLayer = ItemLayer()
copyLayer.contents = layer.contents
copyLayer.contentsRect = layer.contentsRect
copyLayer.frame = layer.bounds
layer.addSublayer(copyLayer)
copyLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak copyLayer] _ in
copyLayer?.removeFromSuperlayer()
})
if layer.hasContents {
let copyLayer = ItemLayer()
copyLayer.contents = layer.contents
copyLayer.contentsRect = layer.contentsRect
copyLayer.frame = layer.bounds
layer.addSublayer(copyLayer)
copyLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak copyLayer] _ in
copyLayer?.removeFromSuperlayer()
})
layer.contents = image?.cgImage
layer.hasContents = true
layer.updateShimmerLayer()
layer.contents = image?.cgImage
layer.hasContents = true
} else {
layer.contents = image?.cgImage
layer.hasContents = true
layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self?.updateShimmerLayersImpl?()
}
})
}
}
@@ -1293,7 +1438,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
guard let strongSelf = self else {
return
}
if count < 1 || true {
if count < 1 {
//TODO:localize
strongSelf.itemGrid.updateScrollingAreaTooltip(tooltip: SparseItemGridScrollingArea.DisplayTooltip(animation: "anim_infotip", text: "You can hold and move this bar for faster scrolling", completed: {
guard let strongSelf = self else {
@@ -1388,6 +1533,14 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
return SparseItemGrid.ShimmerColors(background: backgroundColor.argb, foreground: foregroundColor.argb)
}
self.itemGridBinding.updateShimmerLayersImpl = { [weak self] in
self?.itemGrid.updateShimmerLayers()
}
self.itemGrid.cancelExternalContentGestures = { [weak self] in
self?.contextGestureContainerNode.cancelGesture()
}
self._itemInteraction = VisualMediaItemInteraction(
openMessage: { [weak self] message in

View File

@@ -417,14 +417,8 @@ private final class PeerInfoPendingPane {
paneNode = visualPaneNode
//paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: peerId, tagMask: .music)
case .gifs:
let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .gifs)
let visualPaneNode = PeerInfoGifPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: peerId, contentType: .gifs)
paneNode = visualPaneNode
visualPaneNode.openCurrentDate = {
openMediaCalendar()
}
visualPaneNode.paneDidScroll = {
paneDidScroll()
}
case .groupsInCommon:
paneNode = PeerInfoGroupsInCommonPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, openPeerContextAction: openPeerContextAction, groupsInCommonContext: data.groupsInCommon!)
case .members:

File diff suppressed because it is too large Load Diff