diff --git a/submodules/CallListUI/Sources/CallListCallItem.swift b/submodules/CallListUI/Sources/CallListCallItem.swift index 1394f62608..72ad5c7f11 100644 --- a/submodules/CallListUI/Sources/CallListCallItem.swift +++ b/submodules/CallListUI/Sources/CallListCallItem.swift @@ -650,9 +650,9 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.3, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let (item, _, _, _, _) = self.layoutParams { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/CallListUI/Sources/CallListGroupCallItem.swift b/submodules/CallListUI/Sources/CallListGroupCallItem.swift index 88c0d17abb..6d1af1b65d 100644 --- a/submodules/CallListUI/Sources/CallListGroupCallItem.swift +++ b/submodules/CallListUI/Sources/CallListGroupCallItem.swift @@ -467,9 +467,9 @@ class CallListGroupCallItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.3, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let (item, _, _, _, _) = self.layoutParams { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/ChatListSearchItemHeader/Sources/ChatListSearchItemHeader.swift b/submodules/ChatListSearchItemHeader/Sources/ChatListSearchItemHeader.swift index 966fd6fa88..ab2515d3ed 100644 --- a/submodules/ChatListSearchItemHeader/Sources/ChatListSearchItemHeader.swift +++ b/submodules/ChatListSearchItemHeader/Sources/ChatListSearchItemHeader.swift @@ -151,9 +151,10 @@ private enum ChatListSearchItemHeaderId: Int32 { } public final class ChatListSearchItemHeader: ListViewItemHeader { - public let id: Int64 + public let id: ListViewItemNode.HeaderId public let type: ChatListSearchItemHeaderType public let stickDirection: ListViewItemHeaderStickDirection = .top + public let stickOverInsets: Bool = true public let theme: PresentationTheme public let strings: PresentationStrings public let actionTitle: String? @@ -163,14 +164,14 @@ public final class ChatListSearchItemHeader: ListViewItemHeader { public init(type: ChatListSearchItemHeaderType, theme: PresentationTheme, strings: PresentationStrings, actionTitle: String? = nil, action: (() -> Void)? = nil) { self.type = type - self.id = Int64(self.type.id.rawValue) + self.id = ListViewItemNode.HeaderId(space: 0, id: Int64(self.type.id.rawValue)) self.theme = theme self.strings = strings self.actionTitle = actionTitle self.action = action } - public func node() -> ListViewItemHeaderNode { + public func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { return ChatListSearchItemHeaderNode(type: self.type, theme: self.theme, strings: self.strings, actionTitle: self.actionTitle, action: self.action) } diff --git a/submodules/ChatListUI/Sources/ChatListAdditionalCategoryItem.swift b/submodules/ChatListUI/Sources/ChatListAdditionalCategoryItem.swift index d8912b3ab7..c55120dd20 100644 --- a/submodules/ChatListUI/Sources/ChatListAdditionalCategoryItem.swift +++ b/submodules/ChatListUI/Sources/ChatListAdditionalCategoryItem.swift @@ -363,9 +363,9 @@ public class ChatListAdditionalCategoryItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetCategoryItem.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetCategoryItem.swift index 52751ffef9..95eafaf35f 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetCategoryItem.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetCategoryItem.swift @@ -465,7 +465,7 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL } } - override func header() -> ListViewItemHeader? { + override func headers() -> [ListViewItemHeader]? { return nil } } diff --git a/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift b/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift index 175f6f607d..aceec993d0 100644 --- a/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift +++ b/submodules/ChatListUI/Sources/ChatListRecentPeersListItem.swift @@ -154,9 +154,9 @@ class ChatListRecentPeersListItemNode: ListViewItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 01f9b4bc27..c4f36a0073 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -1893,9 +1893,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.layoutParams?.0 { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/ContactListUI/Sources/ContactAddItem.swift b/submodules/ContactListUI/Sources/ContactAddItem.swift index 7a8699cefc..f3c9093614 100644 --- a/submodules/ContactListUI/Sources/ContactAddItem.swift +++ b/submodules/ContactListUI/Sources/ContactAddItem.swift @@ -245,9 +245,9 @@ class ContactsAddItemNode: ListViewItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let (item, _, _, _, _) = self.layoutParams { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/ContactListUI/Sources/ContactListActionItem.swift b/submodules/ContactListUI/Sources/ContactListActionItem.swift index 654b65b799..f27118bdab 100644 --- a/submodules/ContactListUI/Sources/ContactListActionItem.swift +++ b/submodules/ContactListUI/Sources/ContactListActionItem.swift @@ -325,9 +325,9 @@ class ContactListActionItemNode: ListViewItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/ContactListUI/Sources/ContactListNameIndexHeader.swift b/submodules/ContactListUI/Sources/ContactListNameIndexHeader.swift index 788c81b52d..7390365843 100644 --- a/submodules/ContactListUI/Sources/ContactListNameIndexHeader.swift +++ b/submodules/ContactListUI/Sources/ContactListNameIndexHeader.swift @@ -5,20 +5,21 @@ import TelegramPresentationData import ListSectionHeaderNode final class ContactListNameIndexHeader: Equatable, ListViewItemHeader { - let id: Int64 + let id: ListViewItemNode.HeaderId let theme: PresentationTheme let letter: unichar let stickDirection: ListViewItemHeaderStickDirection = .top + public let stickOverInsets: Bool = true let height: CGFloat = 29.0 init(theme: PresentationTheme, letter: unichar) { self.theme = theme self.letter = letter - self.id = Int64(letter) + self.id = ListViewItemNode.HeaderId(space: 0, id: Int64(letter)) } - func node() -> ListViewItemHeaderNode { + func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { return ContactListNameIndexHeaderNode(theme: self.theme, letter: self.letter) } diff --git a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift index 47f6e7f593..1d5c1f259e 100644 --- a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift +++ b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift @@ -1182,9 +1182,9 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let (item, _, _, _, _, _) = self.layoutParams { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/Display/Source/ContextGesture.swift b/submodules/Display/Source/ContextGesture.swift index 79a767a1a6..542cfeba7f 100644 --- a/submodules/Display/Source/ContextGesture.swift +++ b/submodules/Display/Source/ContextGesture.swift @@ -41,6 +41,8 @@ private func cancelOtherGestures(gesture: ContextGesture, view: UIView) { for recognizer in gestureRecognizers { if let recognizer = recognizer as? ContextGesture, recognizer !== gesture { recognizer.cancel() + } else if let recognizer = recognizer as? ListViewTapGestureRecognizer { + recognizer.cancel() } } } diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index a50d1e8eef..7221fe1e86 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -6,6 +6,11 @@ import UIKitRuntimeUtils private let infiniteScrollSize: CGFloat = 10000.0 private let insertionAnimationDuration: Double = 0.4 +private struct VisibleHeaderNodeId: Hashable { + var id: ListViewItemNode.HeaderId + var affinity: Int +} + private final class ListViewBackingLayer: CALayer { override func setNeedsLayout() { } @@ -275,7 +280,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture private final var items: [ListViewItem] = [] private final var itemNodes: [ListViewItemNode] = [] - private final var itemHeaderNodes: [Int64: ListViewItemHeaderNode] = [:] + private final var itemHeaderNodes: [VisibleHeaderNodeId: ListViewItemHeaderNode] = [:] public final var itemHeaderNodesAlpha: CGFloat = 1.0 @@ -846,7 +851,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } self.updateScroller(transition: .immediate) - self.updateItemHeaders(leftInset: self.insets.left, rightInset: self.insets.right) + self.updateItemHeaders(leftInset: self.insets.left, rightInset: self.insets.right, synchronousLoad: false) for (_, headerNode) in self.itemHeaderNodes { if self.dynamicBounceEnabled && headerNode.wantsScrollDynamics { @@ -1366,13 +1371,6 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } } else if let itemHighlightOverlayBackground = self.itemHighlightOverlayBackground { self.itemHighlightOverlayBackground = nil - for (_, _) in self.itemHeaderNodes { - //self.view.bringSubview(toFront: headerNode.view) - } - //self.view.bringSubview(toFront: itemHighlightOverlayBackground.view) - for _ in self.itemNodes { - //self.view.bringSubview(toFront: itemNode.view) - } transition.updateAlpha(node: itemHighlightOverlayBackground, alpha: 0.0, completion: { [weak itemHighlightOverlayBackground] _ in itemHighlightOverlayBackground?.removeFromSupernode() }) @@ -1869,7 +1867,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture let beginReplay = { [weak self] in if let strongSelf = self { - strongSelf.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateCrossfade: options.contains(.AnimateCrossfade), synchronous: options.contains(.Synchronous), animateTopItemVerticalOrigin: options.contains(.AnimateTopItemPosition), operations: updatedOperations, requestItemInsertionAnimationsIndices: options.contains(.RequestItemInsertionAnimations) ? insertedIndexSet : Set(), scrollToItem: scrollToItem, additionalScrollDistance: additionalScrollDistance, updateSizeAndInsets: updateSizeAndInsets, stationaryItemIndex: stationaryItemIndex, updateOpaqueState: updateOpaqueState, completion: { + strongSelf.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateCrossfade: options.contains(.AnimateCrossfade), synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), animateTopItemVerticalOrigin: options.contains(.AnimateTopItemPosition), operations: updatedOperations, requestItemInsertionAnimationsIndices: options.contains(.RequestItemInsertionAnimations) ? insertedIndexSet : Set(), scrollToItem: scrollToItem, additionalScrollDistance: additionalScrollDistance, updateSizeAndInsets: updateSizeAndInsets, stationaryItemIndex: stationaryItemIndex, updateOpaqueState: updateOpaqueState, completion: { if options.contains(.PreferSynchronousDrawing) { self?.recursivelyEnsureDisplaySynchronously(true) } @@ -2318,7 +2316,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } } - private func replayOperations(animated: Bool, animateAlpha: Bool, animateCrossfade: Bool, synchronous: Bool, animateTopItemVerticalOrigin: Bool, operations: [ListViewStateOperation], requestItemInsertionAnimationsIndices: Set, scrollToItem originalScrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemIndex: Int?, updateOpaqueState: Any?, completion: () -> Void) { + private func replayOperations(animated: Bool, animateAlpha: Bool, animateCrossfade: Bool, synchronous: Bool, synchronousLoads: Bool, animateTopItemVerticalOrigin: Bool, operations: [ListViewStateOperation], requestItemInsertionAnimationsIndices: Set, scrollToItem originalScrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemIndex: Int?, updateOpaqueState: Any?, completion: () -> Void) { var scrollToItem: ListViewScrollToItem? var isExperimentalSnapToScrollToItem = false if let originalScrollToItem = originalScrollToItem { @@ -3039,7 +3037,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture previousItemHeaderNodes.append(headerNode) } - self.updateItemHeaders(leftInset: listInsets.left, rightInset: listInsets.right, transition: headerNodesTransition, animateInsertion: animated || !requestItemInsertionAnimationsIndices.isEmpty) + self.updateItemHeaders(leftInset: listInsets.left, rightInset: listInsets.right, synchronousLoad: synchronousLoads, transition: headerNodesTransition, animateInsertion: animated || !requestItemInsertionAnimationsIndices.isEmpty) if let offset = offset, !offset.isZero { //self.didScrollWithOffset?(-offset, headerNodesTransition.0, nil) @@ -3215,7 +3213,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture completion() } else { - self.updateItemHeaders(leftInset: listInsets.left, rightInset: listInsets.right, transition: headerNodesTransition, animateInsertion: animated || !requestItemInsertionAnimationsIndices.isEmpty) + self.updateItemHeaders(leftInset: listInsets.left, rightInset: listInsets.right, synchronousLoad: synchronousLoads, transition: headerNodesTransition, animateInsertion: animated || !requestItemInsertionAnimationsIndices.isEmpty) self.updateItemNodesVisibilities(onlyPositive: deferredUpdateVisible) if animated { @@ -3262,15 +3260,88 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture node.headerAccessoryItemNode?.removeFromSupernode() node.headerAccessoryItemNode = nil } + + private var nextHeaderSpaceAffinity: Int = 0 + + private func assignHeaderSpaceAffinities() { + var nextTempAffinity = 0 + + var existingAffinityIdByAffinity: [Int: Int] = [:] + + for i in 0 ..< self.itemNodes.count { + let currentItemNode = self.itemNodes[i] + + if let currentItemHeaders = currentItemNode.headers() { + currentHeadersLoop: for currentHeader in currentItemHeaders { + let currentId = currentHeader.id + if let currentAffinity = currentItemNode.tempHeaderSpaceAffinities[currentId] { + if let existingAffinity = currentItemNode.headerSpaceAffinities[currentId] { + existingAffinityIdByAffinity[currentAffinity] = existingAffinity + } + + continue currentHeadersLoop + } + + let currentAffinity = nextTempAffinity + nextTempAffinity += 1 + + currentItemNode.tempHeaderSpaceAffinities[currentId] = currentAffinity + + if let existingAffinity = currentItemNode.headerSpaceAffinities[currentId] { + existingAffinityIdByAffinity[currentAffinity] = existingAffinity + } + + groupSearch: for nextIndex in (i + 1) ..< self.itemNodes.count { + let nextItemNode = self.itemNodes[nextIndex] + + var containsSameHeader = false + if let nextHeaders = nextItemNode.headers() { + nextHeaderSearch: for nextHeader in nextHeaders { + if nextHeader.id == currentId { + containsSameHeader = true + break nextHeaderSearch + } + } + } + + if containsSameHeader { + nextItemNode.tempHeaderSpaceAffinities[currentId] = currentAffinity + } else { + break groupSearch + } + } + } + } + } + + for i in 0 ..< self.itemNodes.count { + let itemNode = self.itemNodes[i] + for (headerId, tempAffinity) in itemNode.tempHeaderSpaceAffinities { + let affinity: Int + if let existing = existingAffinityIdByAffinity[tempAffinity] { + affinity = existing + } else { + affinity = self.nextHeaderSpaceAffinity + existingAffinityIdByAffinity[tempAffinity] = affinity + self.nextHeaderSpaceAffinity += 1 + } + + itemNode.headerSpaceAffinities[headerId] = affinity + itemNode.tempHeaderSpaceAffinities = [:] + } + } + } - private func updateItemHeaders(leftInset: CGFloat, rightInset: CGFloat, transition: (ContainedViewLayoutTransition, Bool, CGFloat) = (.immediate, false, 0.0), animateInsertion: Bool = false) { + private func updateItemHeaders(leftInset: CGFloat, rightInset: CGFloat, synchronousLoad: Bool, transition: (ContainedViewLayoutTransition, Bool, CGFloat) = (.immediate, false, 0.0), animateInsertion: Bool = false) { + self.assignHeaderSpaceAffinities() + let upperDisplayBound = self.headerInsets.top let lowerDisplayBound = self.visibleSize.height - self.insets.bottom - var visibleHeaderNodes = Set() + var visibleHeaderNodes = Set() let flashing = self.headerItemsAreFlashing() - func addHeader(id: Int64, upperBound: CGFloat, upperBoundEdge: CGFloat, lowerBound: CGFloat, item: ListViewItemHeader, hasValidNodes: Bool) { + func addHeader(id: VisibleHeaderNodeId, upperBound: CGFloat, upperBoundEdge: CGFloat, lowerBound: CGFloat, item: ListViewItemHeader, hasValidNodes: Bool) { let itemHeaderHeight: CGFloat = item.height let headerFrame: CGRect @@ -3334,13 +3405,12 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } else if hasValidNodes && headerNode.alpha.isZero { headerNode.alpha = initialHeaderNodeAlpha if animateInsertion { - headerNode.layer.animateAlpha(from: 0.0, to: initialHeaderNodeAlpha, duration: 0.2) - headerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2) + headerNode.animateAdded(duration: 0.2) } } headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: transition.0) } else { - let headerNode = item.node() + let headerNode = item.node(synchronousLoad: synchronousLoad) headerNode.alpha = initialHeaderNodeAlpha if headerNode.item !== item { item.updateNode(headerNode, previous: nil, next: nil) @@ -3357,39 +3427,70 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture self.addSubnode(headerNode) } if animateInsertion { - headerNode.layer.animateAlpha(from: 0.0, to: initialHeaderNodeAlpha, duration: 0.3) - headerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.3) + headerNode.alpha = initialHeaderNodeAlpha + headerNode.animateAdded(duration: 0.2) } headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: .immediate) } } + + var previousHeaderBySpace: [AnyHashable: (id: VisibleHeaderNodeId, upperBound: CGFloat, upperBoundEdge: CGFloat, lowerBound: CGFloat, item: ListViewItemHeader, hasValidNodes: Bool)] = [:] - var previousHeader: (id: Int64, upperBound: CGFloat, upperBoundEdge: CGFloat, lowerBound: CGFloat, item: ListViewItemHeader, hasValidNodes: Bool)? for itemNode in self.itemNodes { let itemFrame = itemNode.apparentFrame let itemTopInset = itemNode.insets.top - if let itemHeader = itemNode.header() { - if let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader { - if previousHeaderId == itemHeader.id { - previousHeader = (previousHeaderId, previousUpperBound, previousUpperBoundEdge, itemFrame.maxY, previousHeaderItem, hasValidNodes || itemNode.index != nil) - } else { - addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes) - - previousHeader = (itemHeader.id, itemFrame.minY, itemFrame.minY + itemTopInset, itemFrame.maxY, itemHeader, itemNode.index != nil) + var validItemHeaderSpaces: [AnyHashable] = [] + if let itemHeaders = itemNode.headers() { + for itemHeader in itemHeaders { + guard let affinity = itemNode.headerSpaceAffinities[itemHeader.id] else { + assertionFailure() + continue + } + + let headerId = VisibleHeaderNodeId(id: itemHeader.id, affinity: affinity) + + validItemHeaderSpaces.append(itemHeader.id.space) + + let itemMaxY: CGFloat + if itemHeader.stickOverInsets { + itemMaxY = itemFrame.maxY + } else { + itemMaxY = itemFrame.maxY - (self.rotated ? itemNode.insets.top : itemNode.insets.bottom) + } + + if let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeaderBySpace[itemHeader.id.space] { + if previousHeaderId == headerId { + previousHeaderBySpace[itemHeader.id.space] = (previousHeaderId, previousUpperBound, previousUpperBoundEdge, itemMaxY, previousHeaderItem, hasValidNodes || itemNode.index != nil) + } else { + addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes) + + previousHeaderBySpace[itemHeader.id.space] = (headerId, itemFrame.minY, itemFrame.minY + itemTopInset, itemMaxY, itemHeader, itemNode.index != nil) + } + } else { + previousHeaderBySpace[itemHeader.id.space] = (headerId, itemFrame.minY, itemFrame.minY + itemTopInset, itemMaxY, itemHeader, itemNode.index != nil) } - } else { - previousHeader = (itemHeader.id, itemFrame.minY, itemFrame.minY + itemTopInset, itemFrame.maxY, itemHeader, itemNode.index != nil) } - } else { - if let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader { - addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes) + } + + for (space, previousHeader) in previousHeaderBySpace { + if validItemHeaderSpaces.contains(space) { + continue } - previousHeader = nil + + let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader + + addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes) + + previousHeaderBySpace.removeValue(forKey: space) } } - - if let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader { + + for (space, previousHeader) in previousHeaderBySpace { + let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader + addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes) + + previousHeaderBySpace.removeValue(forKey: space) } let currentIds = Set(self.itemHeaderNodes.keys) @@ -3709,10 +3810,10 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture var updatedOperations = operations updatedState.removeInvisibleNodes(&updatedOperations) if synchronous { - self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, synchronous: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion) + self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, synchronous: false, synchronousLoads: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion) } else { self.dispatchOnVSync { - self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, synchronous: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion) + self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, synchronous: false, synchronousLoads: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion) } } } diff --git a/submodules/Display/Source/ListViewItemHeader.swift b/submodules/Display/Source/ListViewItemHeader.swift index e81635ae8f..dcbbffb286 100644 --- a/submodules/Display/Source/ListViewItemHeader.swift +++ b/submodules/Display/Source/ListViewItemHeader.swift @@ -8,14 +8,13 @@ public enum ListViewItemHeaderStickDirection { case bottom } -public typealias ListViewItemHeaderId = Int64 - -public protocol ListViewItemHeader: class { - var id: ListViewItemHeaderId { get } +public protocol ListViewItemHeader: AnyObject { + var id: ListViewItemNode.HeaderId { get } var stickDirection: ListViewItemHeaderStickDirection { get } var height: CGFloat { get } + var stickOverInsets: Bool { get } - func node() -> ListViewItemHeaderNode + func node(synchronousLoad: Bool) -> ListViewItemHeaderNode func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) } @@ -114,6 +113,11 @@ open class ListViewItemHeaderNode: ASDisplayNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false) self.layer.animateScale(from: 1.0, to: 0.2, duration: duration, removeOnCompletion: false) } + + open func animateAdded(duration: Double) { + self.layer.animateAlpha(from: 0.0, to: self.alpha, duration: 0.2) + self.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2) + } private var cachedLayout: (CGSize, CGFloat, CGFloat)? diff --git a/submodules/Display/Source/ListViewItemNode.swift b/submodules/Display/Source/ListViewItemNode.swift index 873e752454..2e59bccfd9 100644 --- a/submodules/Display/Source/ListViewItemNode.swift +++ b/submodules/Display/Source/ListViewItemNode.swift @@ -84,6 +84,16 @@ public struct ListViewItemLayoutParams { } open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode { + public struct HeaderId: Hashable { + public var space: AnyHashable + public var id: AnyHashable + + public init(space: AnyHashable, id: AnyHashable) { + self.space = space + self.id = id + } + } + let rotated: Bool final var index: Int? @@ -116,6 +126,9 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode { private final var spring: ListViewItemSpring? private final var animations: [(String, ListViewAnimation)] = [] + + final var tempHeaderSpaceAffinities: [ListViewItemNode.HeaderId: Int] = [:] + final var headerSpaceAffinities: [ListViewItemNode.HeaderId: Int] = [:] final let wantsScrollDynamics: Bool @@ -533,7 +546,7 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode { return false } - open func header() -> ListViewItemHeader? { + open func headers() -> [ListViewItemHeader]? { return nil } diff --git a/submodules/Display/Source/ListViewTapGestureRecognizer.swift b/submodules/Display/Source/ListViewTapGestureRecognizer.swift index f5090f99d6..2501325652 100644 --- a/submodules/Display/Source/ListViewTapGestureRecognizer.swift +++ b/submodules/Display/Source/ListViewTapGestureRecognizer.swift @@ -2,5 +2,7 @@ import Foundation import UIKit public final class ListViewTapGestureRecognizer: UITapGestureRecognizer { - + public func cancel() { + self.state = .failed + } } diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index 510a599157..5e11e84832 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -1328,8 +1328,12 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo } } - override public func header() -> ListViewItemHeader? { - return self.layoutParams?.0.header + override public func headers() -> [ListViewItemHeader]? { + if let item = self.layoutParams?.0 { + return item.header.flatMap { [$0] } + } else { + return nil + } } override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { @@ -1350,10 +1354,11 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo } public final class ItemListPeerItemHeader: ListViewItemHeader { - public let id: Int64 + public let id: ListViewItemNode.HeaderId public let text: String public let additionalText: String public let stickDirection: ListViewItemHeaderStickDirection = .topEdge + public let stickOverInsets: Bool = true public let theme: PresentationTheme public let strings: PresentationStrings public let actionTitle: String? @@ -1364,14 +1369,14 @@ public final class ItemListPeerItemHeader: ListViewItemHeader { public init(theme: PresentationTheme, strings: PresentationStrings, text: String, additionalText: String, actionTitle: String? = nil, id: Int64, action: (() -> Void)? = nil) { self.text = text self.additionalText = additionalText - self.id = id + self.id = ListViewItemNode.HeaderId(space: 0, id: id) self.theme = theme self.strings = strings self.actionTitle = actionTitle self.action = action } - public func node() -> ListViewItemHeaderNode { + public func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { return ItemListPeerItemHeaderNode(theme: self.theme, strings: self.strings, text: self.text, additionalText: self.additionalText, actionTitle: self.actionTitle, action: self.action) } diff --git a/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift b/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift index cc5e1c9f7b..9b4765bbdd 100644 --- a/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift +++ b/submodules/ItemListVenueItem/Sources/ItemListVenueItem.swift @@ -457,7 +457,11 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode { self.item?.infoAction?() } - override public func header() -> ListViewItemHeader? { - return self.item?.header + override public func headers() -> [ListViewItemHeader]? { + if let item = self.item { + return item.header.flatMap { [$0] } + } else { + return nil + } } } diff --git a/submodules/ListMessageItem/Sources/ListMessageDateHeader.swift b/submodules/ListMessageItem/Sources/ListMessageDateHeader.swift index 9700c275bb..99e90d504e 100644 --- a/submodules/ListMessageItem/Sources/ListMessageDateHeader.swift +++ b/submodules/ListMessageItem/Sources/ListMessageDateHeader.swift @@ -42,7 +42,7 @@ final class ListMessageDateHeader: ListViewItemHeader { private let month: Int32 private let year: Int32 - let id: Int64 + let id: ListViewItemNode.HeaderId let theme: PresentationTheme let strings: PresentationStrings let fontSize: PresentationFontSize @@ -61,14 +61,15 @@ final class ListMessageDateHeader: ListViewItemHeader { self.month = timeinfo.tm_mon self.year = timeinfo.tm_year - self.id = Int64(self.roundedTimestamp) + self.id = ListViewItemNode.HeaderId(space: 0, id: Int64(self.roundedTimestamp)) } let stickDirection: ListViewItemHeaderStickDirection = .top + let stickOverInsets: Bool = true let height: CGFloat = 28.0 - func node() -> ListViewItemHeaderNode { + func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { return ListMessageDateHeaderNode(theme: self.theme, strings: self.strings, fontSize: self.fontSize, roundedTimestamp: self.roundedTimestamp, month: self.month, year: self.year) } diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index 69d9195410..846e318a9c 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -1118,8 +1118,8 @@ public final class ListMessageFileItemNode: ListMessageNode { } } - override public func header() -> ListViewItemHeader? { - return self.item?.header + override public func headers() -> [ListViewItemHeader]? { + return self.item?.header.flatMap { [$0] } } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { diff --git a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift index 5f16078450..209da15c40 100644 --- a/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageSnippetItemNode.swift @@ -759,8 +759,12 @@ public final class ListMessageSnippetItemNode: ListMessageNode { } } - override public func header() -> ListViewItemHeader? { - return self.item?.header + override public func headers() -> [ListViewItemHeader]? { + if let item = self.item { + return item.header.flatMap { [$0] } + } else { + return nil + } } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { diff --git a/submodules/MtProtoKit/Sources/MTProto.m b/submodules/MtProtoKit/Sources/MTProto.m index fa9cda74f5..fd0dc1ce8e 100644 --- a/submodules/MtProtoKit/Sources/MTProto.m +++ b/submodules/MtProtoKit/Sources/MTProto.m @@ -2055,7 +2055,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) { [self getAuthKeyForCurrentScheme:scheme createIfNeeded:false authInfoSelector:&authInfoSelector]; if (MTLogEnabled()) { - MTLog(@"[MTProto#%p@%p missing key %lld selector %d]", self, _context, _validAuthInfo.authInfo.authKeyId, authInfoSelector); + MTLog(@"[MTProto#%p@%p missing key %lld selector %d useExplicitAuthKey: %lld, canResetAuthData: %s]", self, _context, _validAuthInfo.authInfo.authKeyId, authInfoSelector, _useExplicitAuthKey.authKeyId, _canResetAuthData ? "true" : "false"); } if (_useExplicitAuthKey != nil) { diff --git a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift index 1b32ab836f..06bce910f7 100644 --- a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift +++ b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift @@ -247,7 +247,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel dateHeaderNode = currentDateHeaderNode headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) } else { - dateHeaderNode = headerItem.node() + dateHeaderNode = headerItem.node(synchronousLoad: true) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) self.messagesContainerNode.addSubnode(dateHeaderNode) self.dateHeaderNode = dateHeaderNode diff --git a/submodules/SettingsUI/Sources/Search/SettingsSearchRecentItem.swift b/submodules/SettingsUI/Sources/Search/SettingsSearchRecentItem.swift index e51d602ac6..22dfb3b3d4 100644 --- a/submodules/SettingsUI/Sources/Search/SettingsSearchRecentItem.swift +++ b/submodules/SettingsUI/Sources/Search/SettingsSearchRecentItem.swift @@ -243,9 +243,9 @@ class SettingsSearchRecentItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift index b21d5dd791..ecff3147ef 100644 --- a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift +++ b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift @@ -386,7 +386,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView dateHeaderNode = currentDateHeaderNode headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) } else { - dateHeaderNode = headerItem.node() + dateHeaderNode = headerItem.node(synchronousLoad: true) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) self.messagesContainerNode.addSubnode(dateHeaderNode) self.dateHeaderNode = dateHeaderNode diff --git a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift index 953ddbe7a4..b27204c058 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeAccentColorControllerNode.swift @@ -970,7 +970,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate dateHeaderNode = currentDateHeaderNode headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) } else { - dateHeaderNode = headerItem.node() + dateHeaderNode = headerItem.node(synchronousLoad: true) //dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) self.messagesContainerNode.addSubnode(dateHeaderNode) self.dateHeaderNode = dateHeaderNode diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift index 3b6a3d1a41..4f2c87afe8 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift @@ -249,9 +249,9 @@ class ThemeGridSearchColorsItemNode: ListViewItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.header.flatMap { [$0] } } else { return nil } diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index 3ba133d499..82d7f5f0a0 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -550,7 +550,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { dateHeaderNode = currentDateHeaderNode headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) } else { - dateHeaderNode = headerItem.node() + dateHeaderNode = headerItem.node(synchronousLoad: true) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) self.messagesContainerNode.addSubnode(dateHeaderNode) self.dateHeaderNode = dateHeaderNode diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index 081faecd24..b2ebd337a7 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -1082,7 +1082,7 @@ final class MessageStoryRenderer { dateHeaderNode = currentDateHeaderNode headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) } else { - dateHeaderNode = headerItem.node() + dateHeaderNode = headerItem.node(synchronousLoad: true) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) self.messagesContainerNode.addSubnode(dateHeaderNode) self.dateHeaderNode = dateHeaderNode diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionItem.swift index 29dea03ed1..d547845763 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionItem.swift @@ -281,7 +281,7 @@ class VoiceChatActionItemNode: ListViewItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { return nil } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatFullscreenParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatFullscreenParticipantItem.swift index 2f1c31da5d..4ba7b1c7cb 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatFullscreenParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatFullscreenParticipantItem.swift @@ -990,7 +990,7 @@ class VoiceChatFullscreenParticipantItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) } - override func header() -> ListViewItemHeader? { + override func headers() -> [ListViewItemHeader]? { return nil } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift index 785554f09a..e2bcb6bed8 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift @@ -1273,7 +1273,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) } - override func header() -> ListViewItemHeader? { + override func headers() -> [ListViewItemHeader]? { return nil } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index d68b675c11..8f5ca4753c 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -7927,6 +7927,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G itemNode.updateSelectionState(animated: animated) } } + + self.chatDisplayNode.historyNode.forEachItemHeaderNode{ itemHeaderNode in + if let avatarNode = itemHeaderNode as? ChatMessageAvatarHeaderNode { + avatarNode.updateSelectionState(animated: animated) + } + } } private func updatePollTooltipMessageState(animated: Bool) { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 46881de74d..06d835e155 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1086,6 +1086,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { strongSelf.forEachItemHeaderNode { itemHeaderNode in if let dateNode = itemHeaderNode as? ChatMessageDateHeaderNode { dateNode.updatePresentationData(chatPresentationData, context: context) + } else if let avatarNode = itemHeaderNode as? ChatMessageAvatarHeaderNode { + avatarNode.updatePresentationData(chatPresentationData, context: context) } else if let dateNode = itemHeaderNode as? ListMessageDateHeaderNode { dateNode.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings) } diff --git a/submodules/TelegramUI/Sources/ChatHoleItem.swift b/submodules/TelegramUI/Sources/ChatHoleItem.swift index b88cf37698..761ec425b4 100644 --- a/submodules/TelegramUI/Sources/ChatHoleItem.swift +++ b/submodules/TelegramUI/Sources/ChatHoleItem.swift @@ -108,14 +108,6 @@ class ChatHoleItemNode: ListViewItemNode { } } - /*override public func header() -> ListViewItemHeader? { - if let item = self.item { - return item.header - } else { - return nil - } - }*/ - override public func animateAdded(_ currentTimestamp: Double, duration: Double) { self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index dcc9ab4721..9735da77e8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -150,7 +150,7 @@ class ChatMessageShareButton: HighlightableButtonNode { textNode.removeFromSupernode() } self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) - self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: self.backgroundNode.bounds.height / 2.0, transition: .immediate) + self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: min(self.backgroundNode.bounds.width, self.backgroundNode.bounds.height) / 2.0, transition: .immediate) if let image = self.iconNode.image { self.iconNode.frame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0) + self.iconOffset.x, y: floor((size.width - image.size.width) / 2.0) - (offsetIcon ? 1.0 : 0.0) + self.iconOffset.y), size: image.size) } diff --git a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift index e04373ff50..4dec9bcd94 100644 --- a/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift +++ b/submodules/TelegramUI/Sources/ChatMessageDateHeader.swift @@ -6,6 +6,7 @@ import TelegramPresentationData import Postbox import SyncCore import AccountContext +import AvatarNode private let timezoneOffset: Int32 = { let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) @@ -22,7 +23,7 @@ final class ChatMessageDateHeader: ListViewItemHeader { private let roundedTimestamp: Int32 private let scheduled: Bool - let id: Int64 + let id: ListViewItemNode.HeaderId let presentationData: ChatPresentationData let context: AccountContext let action: ((Int32) -> Void)? @@ -33,21 +34,16 @@ final class ChatMessageDateHeader: ListViewItemHeader { self.presentationData = presentationData self.context = context self.action = action - if timestamp == scheduleWhenOnlineTimestamp { - self.roundedTimestamp = scheduleWhenOnlineTimestamp - } else if timestamp == Int32.max { - self.roundedTimestamp = timestamp / (granularity) * (granularity) - } else { - self.roundedTimestamp = ((timestamp + timezoneOffset) / (granularity)) * (granularity) - } - self.id = Int64(self.roundedTimestamp) + self.roundedTimestamp = dateHeaderTimestampId(timestamp: timestamp) + self.id = ListViewItemNode.HeaderId(space: 0, id: Int64(self.roundedTimestamp)) } let stickDirection: ListViewItemHeaderStickDirection = .bottom + let stickOverInsets: Bool = true let height: CGFloat = 34.0 - func node() -> ListViewItemHeaderNode { + func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, scheduled: self.scheduled, presentationData: self.presentationData, context: self.context, action: self.action) } @@ -90,6 +86,16 @@ private func monthAtIndex(_ index: Int, strings: PresentationStrings) -> String } } +private func dateHeaderTimestampId(timestamp: Int32) -> Int32 { + if timestamp == scheduleWhenOnlineTimestamp { + return timestamp + } else if timestamp == Int32.max { + return timestamp / (granularity) * (granularity) + } else { + return ((timestamp + timezoneOffset) / (granularity)) * (granularity) + } +} + final class ChatMessageDateHeaderNode: ListViewItemHeaderNode { let labelNode: TextNode let backgroundNode: NavigationBackgroundNode @@ -164,12 +170,11 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode { self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0) let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners) - - //self.backgroundNode.image = graphics.dateStaticBackground + self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate) self.stickBackgroundNode.image = graphics.dateFloatingBackground self.stickBackgroundNode.alpha = 0.0 - //self.backgroundNode.addSubnode(self.stickBackgroundNode) + self.addSubnode(self.backgroundNode) self.addSubnode(self.labelNode) @@ -198,8 +203,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode { self.presentationData = presentationData let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners) - - //self.backgroundNode.image = graphics.dateStaticBackground + self.backgroundNode.updateColor(color: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper), transition: .immediate) self.stickBackgroundNode.image = graphics.dateFloatingBackground @@ -220,12 +224,6 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode { func updateBackgroundColor(color: UIColor, enableBlur: Bool) { self.backgroundNode.updateColor(color: color, enableBlur: enableBlur, transition: .immediate) - /*let chatDateSize: CGFloat = 20.0 - self.backgroundNode.image = generateImage(CGSize(width: chatDateSize, height: chatDateSize), contextGenerator: { size, context -> Void in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(color.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - })!.stretchableImage(withLeftCapWidth: Int(chatDateSize) / 2, topCapHeight: Int(chatDateSize) / 2)*/ } override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) { @@ -307,3 +305,173 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode { } } } + +final class ChatMessageAvatarHeader: ListViewItemHeader { + struct Id: Hashable { + var peerId: PeerId + var timestampId: Int32 + } + + let id: ListViewItemNode.HeaderId + let peerId: PeerId + let peer: Peer? + let messageReference: MessageReference? + let presentationData: ChatPresentationData + let context: AccountContext + let controllerInteraction: ChatControllerInteraction + + init(timestamp: Int32, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction) { + self.peerId = peerId + self.peer = peer + self.messageReference = messageReference + self.presentationData = presentationData + self.context = context + self.controllerInteraction = controllerInteraction + self.id = ListViewItemNode.HeaderId(space: 1, id: Id(peerId: peerId, timestampId: dateHeaderTimestampId(timestamp: timestamp))) + } + + let stickDirection: ListViewItemHeaderStickDirection = .top + let stickOverInsets: Bool = false + + let height: CGFloat = 38.0 + + func node(synchronousLoad: Bool) -> ListViewItemHeaderNode { + return ChatMessageAvatarHeaderNode(peerId: self.peerId, peer: self.peer, messageReference: self.messageReference, presentationData: self.presentationData, context: self.context, controllerInteraction: self.controllerInteraction, synchronousLoad: synchronousLoad) + } + + func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) { + guard let node = node as? ChatMessageAvatarHeaderNode, let next = next as? ChatMessageAvatarHeader else { + return + } + node.updatePresentationData(next.presentationData, context: next.context) + } +} + +private let avatarFont = avatarPlaceholderFont(size: 16.0) + +final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode { + private let peerId: PeerId + private let messageReference: MessageReference? + private let peer: Peer? + + private let containerNode: ContextControllerSourceNode + private let avatarNode: AvatarNode + private var presentationData: ChatPresentationData + private let context: AccountContext + private let controllerInteraction: ChatControllerInteraction + + init(peerId: PeerId, peer: Peer?, messageReference: MessageReference?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction, synchronousLoad: Bool) { + self.peerId = peerId + self.peer = peer + self.messageReference = messageReference + self.presentationData = presentationData + self.context = context + self.controllerInteraction = controllerInteraction + + self.containerNode = ContextControllerSourceNode() + + self.avatarNode = AvatarNode(font: avatarFont) + + super.init(layerBacked: false, dynamicBounce: true, isRotated: true, seeThrough: false) + + self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0) + + self.addSubnode(self.containerNode) + self.containerNode.addSubnode(self.avatarNode) + + if let peer = peer { + self.setPeer(context: context, theme: presentationData.theme.theme, synchronousLoad: synchronousLoad, peer: peer, authorOfMessage: messageReference, emptyColor: .black) + } + + self.containerNode.activated = { [weak self] gesture, _ in + guard let strongSelf = self, let peer = strongSelf.peer else { + return + } + var messageId: MessageId? + if let messageReference = messageReference, case let .message(m) = messageReference.content { + messageId = m.id + } + strongSelf.controllerInteraction.openPeerContextMenu(peer, messageId, strongSelf.containerNode, strongSelf.containerNode.bounds, gesture) + } + + self.updateSelectionState(animated: false) + } + + func setCustomLetters(context: AccountContext, theme: PresentationTheme, synchronousLoad: Bool, letters: [String], emptyColor: UIColor) { + self.containerNode.isGestureEnabled = false + + self.avatarNode.setCustomLetters(letters, icon: !letters.isEmpty ? nil : .phone) + } + + func setPeer(context: AccountContext, theme: PresentationTheme, synchronousLoad: Bool, peer: Peer, authorOfMessage: MessageReference?, emptyColor: UIColor) { + self.containerNode.isGestureEnabled = peer.smallProfileImage != nil + + var overrideImage: AvatarNodeImageOverride? + if peer.isDeleted { + overrideImage = .deletedIcon + } + self.avatarNode.setPeer(context: context, theme: theme, peer: peer, authorOfMessage: authorOfMessage, overrideImage: overrideImage, emptyColor: emptyColor, synchronousLoad: synchronousLoad, displayDimensions: CGSize(width: 38.0, height: 38.0)) + } + + override func didLoad() { + super.didLoad() + + self.avatarNode.view.addGestureRecognizer(ListViewTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + func updatePresentationData(_ presentationData: ChatPresentationData, context: AccountContext) { + self.presentationData = presentationData + + self.setNeedsLayout() + } + + override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) { + self.containerNode.frame = CGRect(origin: CGPoint(x: leftInset + 3.0, y: 0.0), size: CGSize(width: 38.0, height: 38.0)) + self.avatarNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0)) + } + + override func animateRemoved(duration: Double) { + self.alpha = 0.0 + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false) + self.avatarNode.layer.animateScale(from: 1.0, to: 0.2, duration: duration, removeOnCompletion: false) + } + + override func animateAdded(duration: Double) { + self.layer.animateAlpha(from: 0.0, to: self.alpha, duration: 0.2) + self.avatarNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2) + } + + override func updateStickDistanceFactor(_ factor: CGFloat, transition: ContainedViewLayoutTransition) { + } + + override func updateFlashingOnScrolling(_ isFlashingOnScrolling: Bool, animated: Bool) { + } + + func updateSelectionState(animated: Bool) { + let offset: CGFloat = self.controllerInteraction.selectionState != nil ? 42.0 : 0.0 + + let previousSubnodeTransform = self.subnodeTransform + self.subnodeTransform = CATransform3DMakeTranslation(offset, 0.0, 0.0); + if animated { + self.layer.animate(from: NSValue(caTransform3D: previousSubnodeTransform), to: NSValue(caTransform3D: self.subnodeTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.2) + } + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.bounds.contains(point) { + return nil + } + let result = self.containerNode.view.hitTest(self.view.convert(point, to: self.containerNode.view), with: event) + return result + } + + override func touchesCancelled(_ touches: Set?, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + } + + @objc func tapGesture(_ recognizer: ListViewTapGestureRecognizer) { + if case .ended = recognizer.state { + self.controllerInteraction.openPeer(self.peerId, .info, nil) + } + } +} diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index 606da3ec2a..897e312c27 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -192,9 +192,8 @@ func chatItemsHaveCommonDateHeader(_ lhs: ListViewItem, _ rhs: ListViewItem?) - let lhsHeader: ChatMessageDateHeader? let rhsHeader: ChatMessageDateHeader? if let lhs = lhs as? ChatMessageItem { - lhsHeader = lhs.header + lhsHeader = lhs.dateHeader } else if let _ = lhs as? ChatHoleItem { - //lhsHeader = lhs.header lhsHeader = nil } else if let lhs = lhs as? ChatUnreadItem { lhsHeader = lhs.header @@ -205,7 +204,7 @@ func chatItemsHaveCommonDateHeader(_ lhs: ListViewItem, _ rhs: ListViewItem?) - } if let rhs = rhs { if let rhs = rhs as? ChatMessageItem { - rhsHeader = rhs.header + rhsHeader = rhs.dateHeader } else if let _ = rhs as? ChatHoleItem { //rhsHeader = rhs.header rhsHeader = nil @@ -257,8 +256,11 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { let effectiveAuthorId: PeerId? let additionalContent: ChatMessageItemAdditionalContent? - public let accessoryItem: ListViewAccessoryItem? - let header: ChatMessageDateHeader + //public let accessoryItem: ListViewAccessoryItem? + let dateHeader: ChatMessageDateHeader + let avatarHeader: ChatMessageAvatarHeader? + + let headers: [ListViewItemHeader] var message: Message { switch self.content { @@ -288,7 +290,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { self.disableDate = disableDate self.additionalContent = additionalContent - var accessoryItem: ListViewAccessoryItem? + var avatarHeader: ChatMessageAvatarHeader? let incoming = content.effectivelyIncoming(self.context.account.peerId) var effectiveAuthor: Peer? @@ -325,7 +327,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { isScheduledMessages = true } - self.header = ChatMessageDateHeader(timestamp: content.index.timestamp, scheduled: isScheduledMessages, presentationData: presentationData, context: context, action: { timestamp in + self.dateHeader = ChatMessageDateHeader(timestamp: content.index.timestamp, scheduled: isScheduledMessages, presentationData: presentationData, context: context, action: { timestamp in var calendar = NSCalendar.current calendar.timeZone = TimeZone(abbreviation: "UTC")! let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) @@ -355,11 +357,18 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { } if !hasActionMedia && !isBroadcastChannel { if let effectiveAuthor = effectiveAuthor { - accessoryItem = ChatMessageAvatarAccessoryItem(context: context, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), messageTimestamp: content.index.timestamp, forwardInfo: message.forwardInfo, emptyColor: presentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper.fill, controllerInteraction: controllerInteraction) + //accessoryItem = ChatMessageAvatarAccessoryItem(context: context, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), messageTimestamp: content.index.timestamp, forwardInfo: message.forwardInfo, emptyColor: presentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper.fill, controllerInteraction: controllerInteraction) + avatarHeader = ChatMessageAvatarHeader(timestamp: content.index.timestamp, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), presentationData: presentationData, context: context, controllerInteraction: controllerInteraction) } } } - self.accessoryItem = accessoryItem + self.avatarHeader = avatarHeader + + var headers: [ListViewItemHeader] = [self.dateHeader] + if let avatarHeader = self.avatarHeader { + headers.append(avatarHeader) + } + self.headers = headers } public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { @@ -467,25 +476,25 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { var mergedBottom: ChatMessageMerge = .none var dateAtBottom = false if let top = top as? ChatMessageItem { - if top.header.id != self.header.id { + if top.dateHeader.id != self.dateHeader.id { mergedBottom = .none } else { mergedBottom = messagesShouldBeMerged(accountPeerId: self.context.account.peerId, message, top.message) } } if let bottom = bottom as? ChatMessageItem { - if bottom.header.id != self.header.id { + if bottom.dateHeader.id != self.dateHeader.id { mergedTop = .none dateAtBottom = true } else { mergedTop = messagesShouldBeMerged(accountPeerId: self.context.account.peerId, bottom.message, message) } } else if let bottom = bottom as? ChatUnreadItem { - if bottom.header.id != self.header.id { + if bottom.header.id != self.dateHeader.id { dateAtBottom = true } } else if let bottom = bottom as? ChatReplyCountItem { - if bottom.header.id != self.header.id { + if bottom.header.id != self.dateHeader.id { dateAtBottom = true } } else if let _ = bottom as? ChatHoleItem { diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index a640ad2c7d..c335e2e79a 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -801,9 +801,9 @@ public class ChatMessageItemView: ListViewItemNode { return nil } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.headers } else { return nil } diff --git a/submodules/TelegramUI/Sources/ChatReplyCountItem.swift b/submodules/TelegramUI/Sources/ChatReplyCountItem.swift index 6d62a55d8f..36aee95303 100644 --- a/submodules/TelegramUI/Sources/ChatReplyCountItem.swift +++ b/submodules/TelegramUI/Sources/ChatReplyCountItem.swift @@ -211,9 +211,9 @@ class ChatReplyCountItemNode: ListViewItemNode { } } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return [item.header] } else { return nil } diff --git a/submodules/TelegramUI/Sources/ChatUnreadItem.swift b/submodules/TelegramUI/Sources/ChatUnreadItem.swift index e36c4d07fa..23a2f37304 100644 --- a/submodules/TelegramUI/Sources/ChatUnreadItem.swift +++ b/submodules/TelegramUI/Sources/ChatUnreadItem.swift @@ -147,9 +147,9 @@ class ChatUnreadItemNode: ListViewItemNode { } } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return [item.header] } else { return nil } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 9e128efd5f..d2bf44a3e6 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -347,7 +347,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { let selectionPanel: ChatMessageSelectionInputPanelNode let separatorNode: ASDisplayNode - let backgroundNode: ASDisplayNode + let backgroundNode: NavigationBackgroundNode init(context: AccountContext, peerId: PeerId, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void, reportMessages: @escaping () -> Void) { self.context = context @@ -360,11 +360,10 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { let presentationData = context.sharedContext.currentPresentationData.with { $0 } self.separatorNode = ASDisplayNode() - self.backgroundNode = ASDisplayNode() + self.backgroundNode = NavigationBackgroundNode(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor) self.selectionPanel = ChatMessageSelectionInputPanelNode(theme: presentationData.theme, strings: presentationData.strings, peerMedia: true) self.selectionPanel.context = context - self.selectionPanel.backgroundColor = presentationData.theme.chat.inputPanel.panelBackgroundColor let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in }, setupEditMessage: { _, _ in @@ -466,7 +465,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { } func update(layout: ContainerViewLayout, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { - self.backgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.blurredBackgroundColor + self.backgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(self.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil) @@ -477,6 +476,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { let panelHeightWithInset = panelHeight + layout.intrinsicInsets.bottom transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeightWithInset))) + self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition) transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel))) return panelHeightWithInset diff --git a/submodules/WebSearchUI/Sources/WebSearchRecentQueryItem.swift b/submodules/WebSearchUI/Sources/WebSearchRecentQueryItem.swift index 2ee0f99011..d7cc659b6b 100644 --- a/submodules/WebSearchUI/Sources/WebSearchRecentQueryItem.swift +++ b/submodules/WebSearchUI/Sources/WebSearchRecentQueryItem.swift @@ -200,9 +200,9 @@ class WebSearchRecentQueryItemNode: ItemListRevealOptionsItemNode { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) } - override public func header() -> ListViewItemHeader? { + override public func headers() -> [ListViewItemHeader]? { if let item = self.item { - return item.header + return item.header.flatMap { [$0] } } else { return nil }