mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add safe insets support in sparse grid view
This commit is contained in:
parent
8deda328d0
commit
faf14ace53
@ -18,7 +18,7 @@ public protocol SparseItemGridLayer: CALayer {
|
||||
}
|
||||
|
||||
public protocol SparseItemGridView: UIView {
|
||||
func update(size: CGSize)
|
||||
func update(size: CGSize, insets: UIEdgeInsets)
|
||||
func needsShimmer() -> Bool
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ public protocol SparseItemGridBinding: AnyObject {
|
||||
func createLayer() -> SparseItemGridLayer?
|
||||
func createView() -> SparseItemGridView?
|
||||
func createShimmerLayer() -> SparseItemGridShimmerLayer?
|
||||
func bindLayers(items: [SparseItemGrid.Item], layers: [SparseItemGridDisplayItem], synchronous: SparseItemGrid.Synchronous)
|
||||
func bindLayers(items: [SparseItemGrid.Item], layers: [SparseItemGridDisplayItem], size: CGSize, insets: UIEdgeInsets, synchronous: SparseItemGrid.Synchronous)
|
||||
func unbindLayer(layer: SparseItemGridLayer)
|
||||
func scrollerTextForTag(tag: Int32) -> String?
|
||||
func loadHole(anchor: SparseItemGrid.HoleAnchor, at location: SparseItemGrid.HoleLocation) -> Signal<Never, NoError>
|
||||
@ -392,15 +392,20 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
|
||||
init(containerLayout: ContainerLayout, zoomLevel: ZoomLevel) {
|
||||
self.containerLayout = containerLayout
|
||||
let width: CGFloat
|
||||
if containerLayout.useSideInsets {
|
||||
width = containerLayout.size.width - containerLayout.insets.left - containerLayout.insets.right
|
||||
} else {
|
||||
width = containerLayout.size.width
|
||||
}
|
||||
if let fixedItemHeight = containerLayout.fixedItemHeight {
|
||||
self.itemsPerRow = 1
|
||||
self.itemSize = CGSize(width: containerLayout.size.width, height: fixedItemHeight)
|
||||
self.lastItemSize = containerLayout.size.width
|
||||
self.itemSize = CGSize(width: width, height: fixedItemHeight)
|
||||
self.lastItemSize = width
|
||||
self.itemSpacing = 0.0
|
||||
} else {
|
||||
self.itemSpacing = 1.0
|
||||
|
||||
let width = containerLayout.size.width
|
||||
let itemsPerRow = CGFloat(zoomLevel.rawValue)
|
||||
self.itemsPerRow = Int(itemsPerRow)
|
||||
let itemSize = floorToScreenPixels((width - (self.itemSpacing * CGFloat(self.itemsPerRow - 1))) / itemsPerRow)
|
||||
@ -414,7 +419,8 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
let row = index / self.itemsPerRow
|
||||
let column = index % self.itemsPerRow
|
||||
|
||||
return CGRect(origin: CGPoint(x: CGFloat(column) * (self.itemSize.width + self.itemSpacing), y: self.containerLayout.insets.top + CGFloat(row) * (self.itemSize.height + self.itemSpacing)), size: CGSize(width: column == (self.itemsPerRow - 1) ? self.lastItemSize : itemSize.width, height: itemSize.height))
|
||||
|
||||
return CGRect(origin: CGPoint(x: (self.containerLayout.useSideInsets ? self.containerLayout.insets.left : 0.0) + CGFloat(column) * (self.itemSize.width + self.itemSpacing), y: self.containerLayout.insets.top + CGFloat(row) * (self.itemSize.height + self.itemSpacing)), size: CGSize(width: column == (self.itemsPerRow - 1) ? self.lastItemSize : itemSize.width, height: itemSize.height))
|
||||
}
|
||||
|
||||
func contentHeight(count: Int) -> CGFloat {
|
||||
@ -954,7 +960,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
}
|
||||
|
||||
if !bindItems.isEmpty {
|
||||
items.itemBinding.bindLayers(items: bindItems, layers: bindLayers, synchronous: synchronous)
|
||||
items.itemBinding.bindLayers(items: bindItems, layers: bindLayers, size: layout.containerLayout.size, insets: layout.containerLayout.insets, synchronous: synchronous)
|
||||
}
|
||||
|
||||
for item in updateLayers {
|
||||
@ -962,7 +968,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
if let layer = item.layer {
|
||||
layer.update(size: layer.frame.size)
|
||||
} else if let view = item.view {
|
||||
view.update(size: layer.frame.size)
|
||||
view.update(size: layer.frame.size, insets: layout.containerLayout.insets)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1257,6 +1263,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
private struct ContainerLayout: Equatable {
|
||||
var size: CGSize
|
||||
var insets: UIEdgeInsets
|
||||
var useSideInsets: Bool
|
||||
var scrollIndicatorInsets: UIEdgeInsets
|
||||
var lockScrollingAtTop: Bool
|
||||
var fixedItemHeight: CGFloat?
|
||||
@ -1504,9 +1511,9 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func update(size: CGSize, insets: UIEdgeInsets, scrollIndicatorInsets: UIEdgeInsets, lockScrollingAtTop: Bool, fixedItemHeight: CGFloat?, items: Items, theme: PresentationTheme, synchronous: SparseItemGrid.Synchronous) {
|
||||
public func update(size: CGSize, insets: UIEdgeInsets, useSideInsets: Bool, scrollIndicatorInsets: UIEdgeInsets, lockScrollingAtTop: Bool, fixedItemHeight: CGFloat?, items: Items, theme: PresentationTheme, synchronous: SparseItemGrid.Synchronous) {
|
||||
self.theme = theme
|
||||
let containerLayout = ContainerLayout(size: size, insets: insets, scrollIndicatorInsets: scrollIndicatorInsets, lockScrollingAtTop: lockScrollingAtTop, fixedItemHeight: fixedItemHeight)
|
||||
let containerLayout = ContainerLayout(size: size, insets: insets, useSideInsets: useSideInsets, scrollIndicatorInsets: scrollIndicatorInsets, lockScrollingAtTop: lockScrollingAtTop, fixedItemHeight: fixedItemHeight)
|
||||
self.containerLayout = containerLayout
|
||||
self.items = items
|
||||
self.scrollingArea.isHidden = lockScrollingAtTop
|
||||
|
@ -919,7 +919,8 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||
chatLocation: ChatLocation,
|
||||
interaction: ListMessageItemInteraction,
|
||||
isSelected: Bool?,
|
||||
size: CGSize
|
||||
size: CGSize,
|
||||
insets: UIEdgeInsets
|
||||
) {
|
||||
self.item = item
|
||||
self.interaction = interaction
|
||||
@ -940,7 +941,7 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||
let messageItemNode: ListViewItemNode
|
||||
if let current = self.messageItemNode {
|
||||
messageItemNode = current
|
||||
messageItem.updateNode(async: { f in f() }, node: { return current }, params: ListViewItemLayoutParams(width: size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 0.0), previousItem: nil, nextItem: nil, animation: .System(duration: 0.2), completion: { layout, apply in
|
||||
messageItem.updateNode(async: { f in f() }, node: { return current }, params: ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: 0.0), previousItem: nil, nextItem: nil, animation: .System(duration: 0.2), completion: { layout, apply in
|
||||
current.contentSize = layout.contentSize
|
||||
current.insets = layout.insets
|
||||
|
||||
@ -948,7 +949,7 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||
})
|
||||
} else {
|
||||
var itemNode: ListViewItemNode?
|
||||
messageItem.nodeConfiguredForParams(async: { f in f() }, params: ListViewItemLayoutParams(width: size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 0.0), synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
|
||||
messageItem.nodeConfiguredForParams(async: { f in f() }, params: ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: 0.0), synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in
|
||||
itemNode = node
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
@ -960,6 +961,7 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||
messageItemNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
}
|
||||
|
||||
func unbind() {
|
||||
self.item = nil
|
||||
}
|
||||
@ -968,7 +970,18 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||
return false
|
||||
}
|
||||
|
||||
func update(size: CGSize) {
|
||||
func update(size: CGSize, insets: UIEdgeInsets) {
|
||||
if let messageItem = self.messageItem, let messageItemNode = self.messageItemNode {
|
||||
messageItem.updateNode(async: { f in f() }, node: { return messageItemNode }, params: ListViewItemLayoutParams(width: size.width, leftInset: insets.left, rightInset: insets.right, availableHeight: 0.0), previousItem: nil, nextItem: nil, animation: .System(duration: 0.2), completion: { layout, apply in
|
||||
messageItemNode.contentSize = layout.contentSize
|
||||
messageItemNode.insets = layout.insets
|
||||
|
||||
apply(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
|
||||
messageItemNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1189,7 +1202,7 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
|
||||
return (list.map(\.0), list.map(\.1))
|
||||
}()
|
||||
|
||||
func bindLayers(items: [SparseItemGrid.Item], layers: [SparseItemGridDisplayItem], synchronous: SparseItemGrid.Synchronous) {
|
||||
func bindLayers(items: [SparseItemGrid.Item], layers: [SparseItemGridDisplayItem], size: CGSize, insets: UIEdgeInsets, synchronous: SparseItemGrid.Synchronous) {
|
||||
for i in 0 ..< items.count {
|
||||
guard let item = items[i] as? VisualMediaItem else {
|
||||
continue
|
||||
@ -1208,7 +1221,8 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
|
||||
chatLocation: self.chatLocation,
|
||||
interaction: self.listItemInteraction,
|
||||
isSelected: self.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id),
|
||||
size: view.bounds.size
|
||||
size: CGSize(width: size.width, height: view.bounds.height),
|
||||
insets: insets
|
||||
)
|
||||
} else {
|
||||
guard let layer = displayItem.layer as? ItemLayer else {
|
||||
@ -1972,7 +1986,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
|
||||
self.presentationDataDisposable = (self.context.sharedContext.presentationData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
guard let strongSelf = self else {
|
||||
guard let strongSelf = self, let (size, topInset, sideInset, bottomInset, _, _, _, _) = strongSelf.currentParams else {
|
||||
return
|
||||
}
|
||||
strongSelf.itemGridBinding.updatePresentationData(presentationData: presentationData)
|
||||
@ -1980,7 +1994,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
strongSelf.itemGrid.updatePresentationData(theme: presentationData.theme)
|
||||
|
||||
strongSelf.itemGrid.forEachVisibleItem { item in
|
||||
guard let itemView = item.view as? ItemView else {
|
||||
guard let strongSelf = self, let itemView = item.view as? ItemView else {
|
||||
return
|
||||
}
|
||||
if let item = itemView.item {
|
||||
@ -1991,7 +2005,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
chatLocation: strongSelf.itemGridBinding.chatLocation,
|
||||
interaction: strongSelf.itemGridBinding.listItemInteraction,
|
||||
isSelected: strongSelf.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id),
|
||||
size: itemView.bounds.size
|
||||
size: CGSize(width: size.width, height: itemView.bounds.height),
|
||||
insets: UIEdgeInsets(top: topInset, left: sideInset, bottom: bottomInset, right: sideInset)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -2221,7 +2236,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
switch self.contentType {
|
||||
case .files, .music, .voiceAndVideoMessages:
|
||||
self.itemGrid.forEachVisibleItem { item in
|
||||
guard let itemView = item.view as? ItemView else {
|
||||
guard let itemView = item.view as? ItemView, let (size, topInset, sideInset, bottomInset, _, _, _, _) = self.currentParams else {
|
||||
return
|
||||
}
|
||||
if let item = itemView.item {
|
||||
@ -2232,7 +2247,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
chatLocation: self.itemGridBinding.chatLocation,
|
||||
interaction: self.itemGridBinding.listItemInteraction,
|
||||
isSelected: self.chatControllerInteraction.selectionState?.selectedIds.contains(item.message.id),
|
||||
size: itemView.bounds.size
|
||||
size: CGSize(width: size.width, height: itemView.bounds.height),
|
||||
insets: UIEdgeInsets(top: topInset, left: sideInset, bottom: bottomInset, right: sideInset)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -2258,6 +2274,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
let wasFirstTime = !self.didUpdateItemsOnce
|
||||
self.didUpdateItemsOnce = true
|
||||
let fixedItemHeight: CGFloat?
|
||||
var isList = false
|
||||
switch self.contentType {
|
||||
case .files, .music, .voiceAndVideoMessages:
|
||||
let fakeFile = TelegramMediaFile(
|
||||
@ -2313,11 +2330,12 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
} else {
|
||||
preconditionFailure()
|
||||
}
|
||||
isList = true
|
||||
default:
|
||||
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, theme: self.itemGridBinding.chatPresentationData.theme.theme, synchronous: wasFirstTime ? .full : .none)
|
||||
|
||||
self.itemGrid.update(size: size, insets: UIEdgeInsets(top: topInset, left: sideInset, bottom: bottomInset, right: sideInset), useSideInsets: !isList, 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 ? .full : .none)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user