mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Shared media updates
This commit is contained in:
parent
c982717eec
commit
af7b97d835
@ -15,6 +15,7 @@ swift_library(
|
|||||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
"//submodules/ComponentFlow:ComponentFlow",
|
"//submodules/ComponentFlow:ComponentFlow",
|
||||||
"//submodules/AnimationUI:AnimationUI",
|
"//submodules/AnimationUI:AnimationUI",
|
||||||
|
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -3,6 +3,7 @@ import UIKit
|
|||||||
import Display
|
import Display
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
private final class NullActionClass: NSObject, CAAction {
|
private final class NullActionClass: NSObject, CAAction {
|
||||||
@objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
|
@objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
|
||||||
@ -129,8 +130,7 @@ private final class Shimmer {
|
|||||||
if let image = self.image {
|
if let image = self.image {
|
||||||
layer.contents = image.cgImage
|
layer.contents = image.cgImage
|
||||||
|
|
||||||
let shiftedContentsRect = CGRect(origin: CGPoint(x: frame.minX / containerSize.width, y: frame.minY / containerSize.height), size: CGSize(width: frame.width / containerSize.width, height: frame.height / containerSize.height))
|
let shiftedContentsRect = CGRect(origin: CGPoint(x: 0.0, y: frame.minY / containerSize.height), size: CGSize(width: 1.0, height: frame.height / containerSize.height))
|
||||||
let _ = shiftedContentsRect
|
|
||||||
layer.contentsRect = shiftedContentsRect
|
layer.contentsRect = shiftedContentsRect
|
||||||
|
|
||||||
if layer.animation(forKey: "shimmer") == nil {
|
if layer.animation(forKey: "shimmer") == nil {
|
||||||
@ -140,7 +140,7 @@ private final class Shimmer {
|
|||||||
animation.isAdditive = true
|
animation.isAdditive = true
|
||||||
animation.repeatCount = .infinity
|
animation.repeatCount = .infinity
|
||||||
animation.duration = 0.8
|
animation.duration = 0.8
|
||||||
animation.beginTime = 1.0
|
animation.beginTime = layer.convertTime(1.0, from: nil)
|
||||||
layer.add(animation, forKey: "shimmer")
|
layer.add(animation, forKey: "shimmer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,6 +429,8 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
private let scrollView: UIScrollView
|
private let scrollView: UIScrollView
|
||||||
private let shimmer: Shimmer
|
private let shimmer: Shimmer
|
||||||
|
|
||||||
|
var theme: PresentationTheme
|
||||||
|
|
||||||
var layout: Layout?
|
var layout: Layout?
|
||||||
var items: Items?
|
var items: Items?
|
||||||
var visibleItems: [AnyHashable: VisibleItem] = [:]
|
var visibleItems: [AnyHashable: VisibleItem] = [:]
|
||||||
@ -446,7 +448,8 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
|
|
||||||
let coveringOffsetUpdated: (Viewport, ContainedViewLayoutTransition) -> Void
|
let coveringOffsetUpdated: (Viewport, ContainedViewLayoutTransition) -> Void
|
||||||
|
|
||||||
init(zoomLevel: ZoomLevel, maybeLoadHoleAnchor: @escaping (HoleAnchor, HoleLocation) -> Void, coveringOffsetUpdated: @escaping (Viewport, ContainedViewLayoutTransition) -> Void) {
|
init(theme: PresentationTheme, zoomLevel: ZoomLevel, maybeLoadHoleAnchor: @escaping (HoleAnchor, HoleLocation) -> Void, coveringOffsetUpdated: @escaping (Viewport, ContainedViewLayoutTransition) -> Void) {
|
||||||
|
self.theme = theme
|
||||||
self.zoomLevel = zoomLevel
|
self.zoomLevel = zoomLevel
|
||||||
self.maybeLoadHoleAnchor = maybeLoadHoleAnchor
|
self.maybeLoadHoleAnchor = maybeLoadHoleAnchor
|
||||||
self.coveringOffsetUpdated = coveringOffsetUpdated
|
self.coveringOffsetUpdated = coveringOffsetUpdated
|
||||||
@ -766,6 +769,8 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
let visibleRange = layout.visibleItemRange(for: visibleBounds, count: items.count)
|
let visibleRange = layout.visibleItemRange(for: visibleBounds, count: items.count)
|
||||||
for index in visibleRange.minIndex ... visibleRange.maxIndex {
|
for index in visibleRange.minIndex ... visibleRange.maxIndex {
|
||||||
if let item = items.item(at: index) {
|
if let item = items.item(at: index) {
|
||||||
|
let itemFrame = layout.frame(at: index)
|
||||||
|
|
||||||
let itemLayer: VisibleItem
|
let itemLayer: VisibleItem
|
||||||
if let current = self.visibleItems[item.id] {
|
if let current = self.visibleItems[item.id] {
|
||||||
itemLayer = current
|
itemLayer = current
|
||||||
@ -794,7 +799,6 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
itemLayer.shimmerLayer = placeholderLayer
|
itemLayer.shimmerLayer = placeholderLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemFrame = layout.frame(at: index)
|
|
||||||
placeholderLayer.frame = itemFrame
|
placeholderLayer.frame = itemFrame
|
||||||
self.shimmer.update(colors: shimmerColors, layer: placeholderLayer, containerSize: layout.containerLayout.size, frame: itemFrame.offsetBy(dx: 0.0, dy: -visibleBounds.minY))
|
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)
|
placeholderLayer.update(size: itemFrame.size)
|
||||||
@ -805,7 +809,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
|
|
||||||
validIds.insert(item.id)
|
validIds.insert(item.id)
|
||||||
|
|
||||||
itemLayer.frame = layout.frame(at: index)
|
itemLayer.frame = itemFrame
|
||||||
} else {
|
} else {
|
||||||
let placeholderLayer: SparseItemGridShimmerLayer
|
let placeholderLayer: SparseItemGridShimmerLayer
|
||||||
if self.visiblePlaceholders.count > usedPlaceholderCount {
|
if self.visiblePlaceholders.count > usedPlaceholderCount {
|
||||||
@ -851,6 +855,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
} else if let view = item.view {
|
} else if let view = item.view {
|
||||||
view.removeFromSuperview()
|
view.removeFromSuperview()
|
||||||
}
|
}
|
||||||
|
item.shimmerLayer?.removeFromSuperlayer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -948,6 +953,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
contentOffset: self.scrollView.bounds.minY,
|
contentOffset: self.scrollView.bounds.minY,
|
||||||
isScrolling: self.scrollView.isDragging || self.scrollView.isDecelerating,
|
isScrolling: self.scrollView.isDragging || self.scrollView.isDecelerating,
|
||||||
dateString: dateString ?? "",
|
dateString: dateString ?? "",
|
||||||
|
theme: self.theme,
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1075,6 +1081,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
private var tapRecognizer: UITapGestureRecognizer?
|
private var tapRecognizer: UITapGestureRecognizer?
|
||||||
private var pinchRecognizer: UIPinchGestureRecognizer?
|
private var pinchRecognizer: UIPinchGestureRecognizer?
|
||||||
|
|
||||||
|
private var theme: PresentationTheme
|
||||||
private var containerLayout: ContainerLayout?
|
private var containerLayout: ContainerLayout?
|
||||||
private var items: Items?
|
private var items: Items?
|
||||||
|
|
||||||
@ -1099,7 +1106,9 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
|
|
||||||
public var cancelExternalContentGestures: (() -> Void)?
|
public var cancelExternalContentGestures: (() -> Void)?
|
||||||
|
|
||||||
override public init() {
|
public init(theme: PresentationTheme) {
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
self.scrollingArea = SparseItemGridScrollingArea()
|
self.scrollingArea = SparseItemGridScrollingArea()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
@ -1152,7 +1161,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
|
|
||||||
let progress = (scale - interactiveState.initialScale) / (interactiveState.targetScale - interactiveState.initialScale)
|
let progress = (scale - interactiveState.initialScale) / (interactiveState.targetScale - interactiveState.initialScale)
|
||||||
var replacedTransition = false
|
var replacedTransition = false
|
||||||
//print("progress: \(progress), scale: \(scale), initial: \(interactiveState.initialScale), target: \(interactiveState.targetScale)")
|
|
||||||
if progress < 0.0 || progress > 1.0 {
|
if progress < 0.0 || progress > 1.0 {
|
||||||
let boundaryViewport = progress > 1.0 ? currentViewportTransition.toViewport : currentViewportTransition.fromViewport
|
let boundaryViewport = progress > 1.0 ? currentViewportTransition.toViewport : currentViewportTransition.fromViewport
|
||||||
let zoomLevels = self.availableZoomLevels(width: containerLayout.size.width, startingAt: boundaryViewport.zoomLevel)
|
let zoomLevels = self.availableZoomLevels(width: containerLayout.size.width, startingAt: boundaryViewport.zoomLevel)
|
||||||
@ -1193,7 +1202,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
|
|
||||||
let restoreScrollPosition: (y: CGFloat, index: Int)? = (anchorItemFrame.minY, nextAnchorItemIndex)
|
let restoreScrollPosition: (y: CGFloat, index: Int)? = (anchorItemFrame.minY, nextAnchorItemIndex)
|
||||||
|
|
||||||
let nextViewport = Viewport(zoomLevel: nextZoomLevel, maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
let nextViewport = Viewport(theme: self.theme, zoomLevel: nextZoomLevel, maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1243,7 +1252,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
let restoreScrollPosition: (y: CGFloat, index: Int)? = (anchorItemFrame.minY, anchorItem.index)
|
let restoreScrollPosition: (y: CGFloat, index: Int)? = (anchorItemFrame.minY, anchorItem.index)
|
||||||
let anchorItemIndex = anchorItem.index
|
let anchorItemIndex = anchorItem.index
|
||||||
|
|
||||||
let nextViewport = Viewport(zoomLevel: nextZoomLevel, maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
let nextViewport = Viewport(theme: self.theme, zoomLevel: nextZoomLevel, maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1302,7 +1311,8 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(size: CGSize, insets: UIEdgeInsets, scrollIndicatorInsets: UIEdgeInsets, lockScrollingAtTop: Bool, fixedItemHeight: CGFloat?, items: Items, synchronous: Bool) {
|
public func update(size: CGSize, insets: UIEdgeInsets, scrollIndicatorInsets: UIEdgeInsets, lockScrollingAtTop: Bool, fixedItemHeight: CGFloat?, items: Items, theme: PresentationTheme, synchronous: Bool) {
|
||||||
|
self.theme = theme
|
||||||
let containerLayout = ContainerLayout(size: size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, lockScrollingAtTop: lockScrollingAtTop, fixedItemHeight: fixedItemHeight)
|
let containerLayout = ContainerLayout(size: size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, lockScrollingAtTop: lockScrollingAtTop, fixedItemHeight: fixedItemHeight)
|
||||||
self.containerLayout = containerLayout
|
self.containerLayout = containerLayout
|
||||||
self.items = items
|
self.items = items
|
||||||
@ -1312,7 +1322,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
self.pinchRecognizer?.isEnabled = fixedItemHeight == nil && !lockScrollingAtTop
|
self.pinchRecognizer?.isEnabled = fixedItemHeight == nil && !lockScrollingAtTop
|
||||||
|
|
||||||
if self.currentViewport == nil {
|
if self.currentViewport == nil {
|
||||||
let currentViewport = Viewport(zoomLevel: self.initialZoomLevel ?? ZoomLevel(rawValue: 3), maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
let currentViewport = Viewport(theme: self.theme, zoomLevel: self.initialZoomLevel ?? ZoomLevel(rawValue: 3), maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1394,7 +1404,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
|||||||
self.currentViewport = nil
|
self.currentViewport = nil
|
||||||
previousViewport.removeFromSupernode()
|
previousViewport.removeFromSupernode()
|
||||||
|
|
||||||
let currentViewport = Viewport(zoomLevel: level, maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
let currentViewport = Viewport(theme: self.theme, zoomLevel: level, maybeLoadHoleAnchor: { [weak self] holeAnchor, location in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import AsyncDisplayKit
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import AnimationUI
|
import AnimationUI
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
public final class MultilineText: Component {
|
public final class MultilineText: Component {
|
||||||
public let text: String
|
public let text: String
|
||||||
@ -474,7 +475,7 @@ private final class SparseItemGridScrollingIndicatorComponent: CombinedComponent
|
|||||||
component: Text(
|
component: Text(
|
||||||
text: context.component.dateString,
|
text: context.component.dateString,
|
||||||
font: Font.medium(13.0),
|
font: Font.medium(13.0),
|
||||||
color: .black
|
color: context.component.foregroundColor
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: 200.0, height: 100.0),
|
availableSize: CGSize(width: 200.0, height: 100.0),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
@ -482,7 +483,7 @@ private final class SparseItemGridScrollingIndicatorComponent: CombinedComponent
|
|||||||
|
|
||||||
let rect = rect.update(
|
let rect = rect.update(
|
||||||
component: ShadowRoundedRectangle(
|
component: ShadowRoundedRectangle(
|
||||||
color: .white
|
color: context.component.backgroundColor
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: text.size.width + 26.0, height: 32.0),
|
availableSize: CGSize(width: text.size.width + 26.0, height: 32.0),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
@ -646,6 +647,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
|||||||
|
|
||||||
public var displayTooltip: DisplayTooltip?
|
public var displayTooltip: DisplayTooltip?
|
||||||
|
|
||||||
|
private var theme: PresentationTheme?
|
||||||
|
|
||||||
override public init() {
|
override public init() {
|
||||||
self.dateIndicator = ComponentHostView<Empty>()
|
self.dateIndicator = ComponentHostView<Empty>()
|
||||||
self.lineIndicator = ComponentHostView<Empty>()
|
self.lineIndicator = ComponentHostView<Empty>()
|
||||||
@ -781,9 +784,11 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
|||||||
contentOffset: CGFloat,
|
contentOffset: CGFloat,
|
||||||
isScrolling: Bool,
|
isScrolling: Bool,
|
||||||
dateString: String,
|
dateString: String,
|
||||||
|
theme: PresentationTheme,
|
||||||
transition: ContainedViewLayoutTransition
|
transition: ContainedViewLayoutTransition
|
||||||
) {
|
) {
|
||||||
self.containerSize = containerSize
|
self.containerSize = containerSize
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
if self.dateIndicator.alpha.isZero {
|
if self.dateIndicator.alpha.isZero {
|
||||||
let transition: ContainedViewLayoutTransition = .immediate
|
let transition: ContainedViewLayoutTransition = .immediate
|
||||||
@ -797,9 +802,9 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
|||||||
let indicatorSize = self.dateIndicator.update(
|
let indicatorSize = self.dateIndicator.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(SparseItemGridScrollingIndicatorComponent(
|
component: AnyComponent(SparseItemGridScrollingIndicatorComponent(
|
||||||
backgroundColor: .white,
|
backgroundColor: theme.list.itemHighlightedBackgroundColor,
|
||||||
shadowColor: .black,
|
shadowColor: .black,
|
||||||
foregroundColor: .black,
|
foregroundColor: theme.list.itemPrimaryTextColor,
|
||||||
dateString: dateString
|
dateString: dateString
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -858,7 +863,7 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateLineIndicator(transition: ContainedViewLayoutTransition) {
|
private func updateLineIndicator(transition: ContainedViewLayoutTransition) {
|
||||||
guard let indicatorPosition = self.indicatorPosition, let scrollIndicatorHeight = self.scrollIndicatorHeight else {
|
guard let indicatorPosition = self.indicatorPosition, let scrollIndicatorHeight = self.scrollIndicatorHeight, let theme = self.theme else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,7 +878,7 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
|||||||
let _ = self.lineIndicator.update(
|
let _ = self.lineIndicator.update(
|
||||||
transition: mappedTransition,
|
transition: mappedTransition,
|
||||||
component: AnyComponent(RoundedRectangle(
|
component: AnyComponent(RoundedRectangle(
|
||||||
color: UIColor(white: 0.0, alpha: 0.3)
|
color: theme.list.scrollIndicatorColor
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: lineIndicatorSize
|
containerSize: lineIndicatorSize
|
||||||
|
@ -1384,7 +1384,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
self.stateTag = tagMaskForType(contentType)
|
self.stateTag = tagMaskForType(contentType)
|
||||||
|
|
||||||
self.contextGestureContainerNode = ContextControllerSourceNode()
|
self.contextGestureContainerNode = ContextControllerSourceNode()
|
||||||
self.itemGrid = SparseItemGrid()
|
self.itemGrid = SparseItemGrid(theme: self.context.sharedContext.currentPresentationData.with({ $0 }).theme)
|
||||||
self.directMediaImageCache = DirectMediaImageCache(account: context.account)
|
self.directMediaImageCache = DirectMediaImageCache(account: context.account)
|
||||||
|
|
||||||
let useListItems: Bool
|
let useListItems: Bool
|
||||||
@ -2160,7 +2160,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
fixedItemHeight = nil
|
fixedItemHeight = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.itemGrid.update(size: size, insets: UIEdgeInsets(top: topInset, left: sideInset, bottom: bottomInset, right: sideInset), scrollIndicatorInsets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: bottomInset, right: sideInset), lockScrollingAtTop: isScrollingLockedAtTop, fixedItemHeight: fixedItemHeight, items: items, synchronous: wasFirstTime)
|
self.itemGrid.update(size: size, insets: UIEdgeInsets(top: topInset, left: sideInset, bottom: bottomInset, right: sideInset), scrollIndicatorInsets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: bottomInset, right: sideInset), lockScrollingAtTop: isScrollingLockedAtTop, fixedItemHeight: fixedItemHeight, items: items, theme: self.itemGridBinding.chatPresentationData.theme.theme, synchronous: wasFirstTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user