Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-07-14 01:07:17 +03:00
commit 4a89668a10
43 changed files with 467 additions and 152 deletions

View File

@ -650,9 +650,9 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.3, removeOnCompletion: false) 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 { if let (item, _, _, _, _) = self.layoutParams {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -467,9 +467,9 @@ class CallListGroupCallItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.3, removeOnCompletion: false) 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 { if let (item, _, _, _, _) = self.layoutParams {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -151,9 +151,10 @@ private enum ChatListSearchItemHeaderId: Int32 {
} }
public final class ChatListSearchItemHeader: ListViewItemHeader { public final class ChatListSearchItemHeader: ListViewItemHeader {
public let id: Int64 public let id: ListViewItemNode.HeaderId
public let type: ChatListSearchItemHeaderType public let type: ChatListSearchItemHeaderType
public let stickDirection: ListViewItemHeaderStickDirection = .top public let stickDirection: ListViewItemHeaderStickDirection = .top
public let stickOverInsets: Bool = true
public let theme: PresentationTheme public let theme: PresentationTheme
public let strings: PresentationStrings public let strings: PresentationStrings
public let actionTitle: String? 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) { public init(type: ChatListSearchItemHeaderType, theme: PresentationTheme, strings: PresentationStrings, actionTitle: String? = nil, action: (() -> Void)? = nil) {
self.type = type 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.theme = theme
self.strings = strings self.strings = strings
self.actionTitle = actionTitle self.actionTitle = actionTitle
self.action = action 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) return ChatListSearchItemHeaderNode(type: self.type, theme: self.theme, strings: self.strings, actionTitle: self.actionTitle, action: self.action)
} }

View File

@ -363,9 +363,9 @@ public class ChatListAdditionalCategoryItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let item = self.item {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -465,7 +465,7 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL
} }
} }
override func header() -> ListViewItemHeader? { override func headers() -> [ListViewItemHeader]? {
return nil return nil
} }
} }

View File

@ -154,9 +154,9 @@ class ChatListRecentPeersListItemNode: ListViewItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let item = self.item {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -1893,9 +1893,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} }
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
if let item = self.layoutParams?.0 { if let item = self.layoutParams?.0 {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -245,9 +245,9 @@ class ContactsAddItemNode: ListViewItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let (item, _, _, _, _) = self.layoutParams {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -325,9 +325,9 @@ class ContactListActionItemNode: ListViewItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) 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 { if let item = self.item {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -5,20 +5,21 @@ import TelegramPresentationData
import ListSectionHeaderNode import ListSectionHeaderNode
final class ContactListNameIndexHeader: Equatable, ListViewItemHeader { final class ContactListNameIndexHeader: Equatable, ListViewItemHeader {
let id: Int64 let id: ListViewItemNode.HeaderId
let theme: PresentationTheme let theme: PresentationTheme
let letter: unichar let letter: unichar
let stickDirection: ListViewItemHeaderStickDirection = .top let stickDirection: ListViewItemHeaderStickDirection = .top
public let stickOverInsets: Bool = true
let height: CGFloat = 29.0 let height: CGFloat = 29.0
init(theme: PresentationTheme, letter: unichar) { init(theme: PresentationTheme, letter: unichar) {
self.theme = theme self.theme = theme
self.letter = letter 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) return ContactListNameIndexHeaderNode(theme: self.theme, letter: self.letter)
} }

View File

@ -1182,9 +1182,9 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let (item, _, _, _, _, _) = self.layoutParams {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -41,6 +41,8 @@ private func cancelOtherGestures(gesture: ContextGesture, view: UIView) {
for recognizer in gestureRecognizers { for recognizer in gestureRecognizers {
if let recognizer = recognizer as? ContextGesture, recognizer !== gesture { if let recognizer = recognizer as? ContextGesture, recognizer !== gesture {
recognizer.cancel() recognizer.cancel()
} else if let recognizer = recognizer as? ListViewTapGestureRecognizer {
recognizer.cancel()
} }
} }
} }

View File

@ -6,6 +6,11 @@ import UIKitRuntimeUtils
private let infiniteScrollSize: CGFloat = 10000.0 private let infiniteScrollSize: CGFloat = 10000.0
private let insertionAnimationDuration: Double = 0.4 private let insertionAnimationDuration: Double = 0.4
private struct VisibleHeaderNodeId: Hashable {
var id: ListViewItemNode.HeaderId
var affinity: Int
}
private final class ListViewBackingLayer: CALayer { private final class ListViewBackingLayer: CALayer {
override func setNeedsLayout() { override func setNeedsLayout() {
} }
@ -275,7 +280,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
private final var items: [ListViewItem] = [] private final var items: [ListViewItem] = []
private final var itemNodes: [ListViewItemNode] = [] private final var itemNodes: [ListViewItemNode] = []
private final var itemHeaderNodes: [Int64: ListViewItemHeaderNode] = [:] private final var itemHeaderNodes: [VisibleHeaderNodeId: ListViewItemHeaderNode] = [:]
public final var itemHeaderNodesAlpha: CGFloat = 1.0 public final var itemHeaderNodesAlpha: CGFloat = 1.0
@ -846,7 +851,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} }
self.updateScroller(transition: .immediate) 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 { for (_, headerNode) in self.itemHeaderNodes {
if self.dynamicBounceEnabled && headerNode.wantsScrollDynamics { if self.dynamicBounceEnabled && headerNode.wantsScrollDynamics {
@ -1366,13 +1371,6 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} }
} else if let itemHighlightOverlayBackground = self.itemHighlightOverlayBackground { } else if let itemHighlightOverlayBackground = self.itemHighlightOverlayBackground {
self.itemHighlightOverlayBackground = nil 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 transition.updateAlpha(node: itemHighlightOverlayBackground, alpha: 0.0, completion: { [weak itemHighlightOverlayBackground] _ in
itemHighlightOverlayBackground?.removeFromSupernode() itemHighlightOverlayBackground?.removeFromSupernode()
}) })
@ -1869,7 +1867,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
let beginReplay = { [weak self] in let beginReplay = { [weak self] in
if let strongSelf = self { 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) { if options.contains(.PreferSynchronousDrawing) {
self?.recursivelyEnsureDisplaySynchronously(true) 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<Int>, 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<Int>, scrollToItem originalScrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemIndex: Int?, updateOpaqueState: Any?, completion: () -> Void) {
var scrollToItem: ListViewScrollToItem? var scrollToItem: ListViewScrollToItem?
var isExperimentalSnapToScrollToItem = false var isExperimentalSnapToScrollToItem = false
if let originalScrollToItem = originalScrollToItem { if let originalScrollToItem = originalScrollToItem {
@ -3039,7 +3037,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
previousItemHeaderNodes.append(headerNode) 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 { if let offset = offset, !offset.isZero {
//self.didScrollWithOffset?(-offset, headerNodesTransition.0, nil) //self.didScrollWithOffset?(-offset, headerNodesTransition.0, nil)
@ -3215,7 +3213,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
completion() completion()
} else { } 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) self.updateItemNodesVisibilities(onlyPositive: deferredUpdateVisible)
if animated { if animated {
@ -3262,15 +3260,88 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
node.headerAccessoryItemNode?.removeFromSupernode() node.headerAccessoryItemNode?.removeFromSupernode()
node.headerAccessoryItemNode = nil 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 upperDisplayBound = self.headerInsets.top
let lowerDisplayBound = self.visibleSize.height - self.insets.bottom let lowerDisplayBound = self.visibleSize.height - self.insets.bottom
var visibleHeaderNodes = Set<Int64>() var visibleHeaderNodes = Set<VisibleHeaderNodeId>()
let flashing = self.headerItemsAreFlashing() 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 itemHeaderHeight: CGFloat = item.height
let headerFrame: CGRect let headerFrame: CGRect
@ -3334,13 +3405,12 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} else if hasValidNodes && headerNode.alpha.isZero { } else if hasValidNodes && headerNode.alpha.isZero {
headerNode.alpha = initialHeaderNodeAlpha headerNode.alpha = initialHeaderNodeAlpha
if animateInsertion { if animateInsertion {
headerNode.layer.animateAlpha(from: 0.0, to: initialHeaderNodeAlpha, duration: 0.2) headerNode.animateAdded(duration: 0.2)
headerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2)
} }
} }
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: transition.0) headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: transition.0)
} else { } else {
let headerNode = item.node() let headerNode = item.node(synchronousLoad: synchronousLoad)
headerNode.alpha = initialHeaderNodeAlpha headerNode.alpha = initialHeaderNodeAlpha
if headerNode.item !== item { if headerNode.item !== item {
item.updateNode(headerNode, previous: nil, next: nil) item.updateNode(headerNode, previous: nil, next: nil)
@ -3357,39 +3427,70 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
self.addSubnode(headerNode) self.addSubnode(headerNode)
} }
if animateInsertion { if animateInsertion {
headerNode.layer.animateAlpha(from: 0.0, to: initialHeaderNodeAlpha, duration: 0.3) headerNode.alpha = initialHeaderNodeAlpha
headerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.3) headerNode.animateAdded(duration: 0.2)
} }
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: .immediate) 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 { for itemNode in self.itemNodes {
let itemFrame = itemNode.apparentFrame let itemFrame = itemNode.apparentFrame
let itemTopInset = itemNode.insets.top let itemTopInset = itemNode.insets.top
if let itemHeader = itemNode.header() { var validItemHeaderSpaces: [AnyHashable] = []
if let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader { if let itemHeaders = itemNode.headers() {
if previousHeaderId == itemHeader.id { for itemHeader in itemHeaders {
previousHeader = (previousHeaderId, previousUpperBound, previousUpperBoundEdge, itemFrame.maxY, previousHeaderItem, hasValidNodes || itemNode.index != nil) guard let affinity = itemNode.headerSpaceAffinities[itemHeader.id] else {
} else { assertionFailure()
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes) continue
}
previousHeader = (itemHeader.id, itemFrame.minY, itemFrame.minY + itemTopInset, itemFrame.maxY, itemHeader, itemNode.index != nil)
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) addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes)
previousHeaderBySpace.removeValue(forKey: space)
} }
let currentIds = Set(self.itemHeaderNodes.keys) let currentIds = Set(self.itemHeaderNodes.keys)
@ -3709,10 +3810,10 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
var updatedOperations = operations var updatedOperations = operations
updatedState.removeInvisibleNodes(&updatedOperations) updatedState.removeInvisibleNodes(&updatedOperations)
if synchronous { 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 { } else {
self.dispatchOnVSync { 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)
} }
} }
} }

View File

@ -8,14 +8,13 @@ public enum ListViewItemHeaderStickDirection {
case bottom case bottom
} }
public typealias ListViewItemHeaderId = Int64 public protocol ListViewItemHeader: AnyObject {
var id: ListViewItemNode.HeaderId { get }
public protocol ListViewItemHeader: class {
var id: ListViewItemHeaderId { get }
var stickDirection: ListViewItemHeaderStickDirection { get } var stickDirection: ListViewItemHeaderStickDirection { get }
var height: CGFloat { 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?) 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.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false)
self.layer.animateScale(from: 1.0, to: 0.2, 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)? private var cachedLayout: (CGSize, CGFloat, CGFloat)?

View File

@ -84,6 +84,16 @@ public struct ListViewItemLayoutParams {
} }
open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode { 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 let rotated: Bool
final var index: Int? final var index: Int?
@ -116,6 +126,9 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
private final var spring: ListViewItemSpring? private final var spring: ListViewItemSpring?
private final var animations: [(String, ListViewAnimation)] = [] private final var animations: [(String, ListViewAnimation)] = []
final var tempHeaderSpaceAffinities: [ListViewItemNode.HeaderId: Int] = [:]
final var headerSpaceAffinities: [ListViewItemNode.HeaderId: Int] = [:]
final let wantsScrollDynamics: Bool final let wantsScrollDynamics: Bool
@ -533,7 +546,7 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
return false return false
} }
open func header() -> ListViewItemHeader? { open func headers() -> [ListViewItemHeader]? {
return nil return nil
} }

View File

@ -2,5 +2,7 @@ import Foundation
import UIKit import UIKit
public final class ListViewTapGestureRecognizer: UITapGestureRecognizer { public final class ListViewTapGestureRecognizer: UITapGestureRecognizer {
public func cancel() {
self.state = .failed
}
} }

View File

@ -1328,8 +1328,12 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
} }
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
return self.layoutParams?.0.header if let item = self.layoutParams?.0 {
return item.header.flatMap { [$0] }
} else {
return nil
}
} }
override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { override public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
@ -1350,10 +1354,11 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
} }
public final class ItemListPeerItemHeader: ListViewItemHeader { public final class ItemListPeerItemHeader: ListViewItemHeader {
public let id: Int64 public let id: ListViewItemNode.HeaderId
public let text: String public let text: String
public let additionalText: String public let additionalText: String
public let stickDirection: ListViewItemHeaderStickDirection = .topEdge public let stickDirection: ListViewItemHeaderStickDirection = .topEdge
public let stickOverInsets: Bool = true
public let theme: PresentationTheme public let theme: PresentationTheme
public let strings: PresentationStrings public let strings: PresentationStrings
public let actionTitle: String? 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) { public init(theme: PresentationTheme, strings: PresentationStrings, text: String, additionalText: String, actionTitle: String? = nil, id: Int64, action: (() -> Void)? = nil) {
self.text = text self.text = text
self.additionalText = additionalText self.additionalText = additionalText
self.id = id self.id = ListViewItemNode.HeaderId(space: 0, id: id)
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.actionTitle = actionTitle self.actionTitle = actionTitle
self.action = action 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) return ItemListPeerItemHeaderNode(theme: self.theme, strings: self.strings, text: self.text, additionalText: self.additionalText, actionTitle: self.actionTitle, action: self.action)
} }

View File

@ -457,7 +457,11 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
self.item?.infoAction?() self.item?.infoAction?()
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
return self.item?.header if let item = self.item {
return item.header.flatMap { [$0] }
} else {
return nil
}
} }
} }

View File

@ -42,7 +42,7 @@ final class ListMessageDateHeader: ListViewItemHeader {
private let month: Int32 private let month: Int32
private let year: Int32 private let year: Int32
let id: Int64 let id: ListViewItemNode.HeaderId
let theme: PresentationTheme let theme: PresentationTheme
let strings: PresentationStrings let strings: PresentationStrings
let fontSize: PresentationFontSize let fontSize: PresentationFontSize
@ -61,14 +61,15 @@ final class ListMessageDateHeader: ListViewItemHeader {
self.month = timeinfo.tm_mon self.month = timeinfo.tm_mon
self.year = timeinfo.tm_year 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 stickDirection: ListViewItemHeaderStickDirection = .top
let stickOverInsets: Bool = true
let height: CGFloat = 28.0 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) return ListMessageDateHeaderNode(theme: self.theme, strings: self.strings, fontSize: self.fontSize, roundedTimestamp: self.roundedTimestamp, month: self.month, year: self.year)
} }

View File

@ -1118,8 +1118,8 @@ public final class ListMessageFileItemNode: ListMessageNode {
} }
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
return self.item?.header return self.item?.header.flatMap { [$0] }
} }
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -759,8 +759,12 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
} }
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
return self.item?.header if let item = self.item {
return item.header.flatMap { [$0] }
} else {
return nil
}
} }
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -2055,7 +2055,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
[self getAuthKeyForCurrentScheme:scheme createIfNeeded:false authInfoSelector:&authInfoSelector]; [self getAuthKeyForCurrentScheme:scheme createIfNeeded:false authInfoSelector:&authInfoSelector];
if (MTLogEnabled()) { 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) { if (_useExplicitAuthKey != nil) {

View File

@ -247,7 +247,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
dateHeaderNode = currentDateHeaderNode dateHeaderNode = currentDateHeaderNode
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
} else { } else {
dateHeaderNode = headerItem.node() dateHeaderNode = headerItem.node(synchronousLoad: true)
dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.messagesContainerNode.addSubnode(dateHeaderNode) self.messagesContainerNode.addSubnode(dateHeaderNode)
self.dateHeaderNode = dateHeaderNode self.dateHeaderNode = dateHeaderNode

View File

@ -243,9 +243,9 @@ class SettingsSearchRecentItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let item = self.item {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -386,7 +386,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
dateHeaderNode = currentDateHeaderNode dateHeaderNode = currentDateHeaderNode
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
} else { } else {
dateHeaderNode = headerItem.node() dateHeaderNode = headerItem.node(synchronousLoad: true)
dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.messagesContainerNode.addSubnode(dateHeaderNode) self.messagesContainerNode.addSubnode(dateHeaderNode)
self.dateHeaderNode = dateHeaderNode self.dateHeaderNode = dateHeaderNode

View File

@ -970,7 +970,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
dateHeaderNode = currentDateHeaderNode dateHeaderNode = currentDateHeaderNode
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
} else { } else {
dateHeaderNode = headerItem.node() dateHeaderNode = headerItem.node(synchronousLoad: true)
//dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) //dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.messagesContainerNode.addSubnode(dateHeaderNode) self.messagesContainerNode.addSubnode(dateHeaderNode)
self.dateHeaderNode = dateHeaderNode self.dateHeaderNode = dateHeaderNode

View File

@ -249,9 +249,9 @@ class ThemeGridSearchColorsItemNode: ListViewItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let item = self.item {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }

View File

@ -550,7 +550,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
dateHeaderNode = currentDateHeaderNode dateHeaderNode = currentDateHeaderNode
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
} else { } else {
dateHeaderNode = headerItem.node() dateHeaderNode = headerItem.node(synchronousLoad: true)
dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.messagesContainerNode.addSubnode(dateHeaderNode) self.messagesContainerNode.addSubnode(dateHeaderNode)
self.dateHeaderNode = dateHeaderNode self.dateHeaderNode = dateHeaderNode

View File

@ -1082,7 +1082,7 @@ final class MessageStoryRenderer {
dateHeaderNode = currentDateHeaderNode dateHeaderNode = currentDateHeaderNode
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem) headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
} else { } else {
dateHeaderNode = headerItem.node() dateHeaderNode = headerItem.node(synchronousLoad: true)
dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0) dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.messagesContainerNode.addSubnode(dateHeaderNode) self.messagesContainerNode.addSubnode(dateHeaderNode)
self.dateHeaderNode = dateHeaderNode self.dateHeaderNode = dateHeaderNode

View File

@ -281,7 +281,7 @@ class VoiceChatActionItemNode: ListViewItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) 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 return nil
} }
} }

View File

@ -990,7 +990,7 @@ class VoiceChatFullscreenParticipantItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
} }
override func header() -> ListViewItemHeader? { override func headers() -> [ListViewItemHeader]? {
return nil return nil
} }

View File

@ -1273,7 +1273,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
} }
override func header() -> ListViewItemHeader? { override func headers() -> [ListViewItemHeader]? {
return nil return nil
} }

View File

@ -7927,6 +7927,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
itemNode.updateSelectionState(animated: animated) 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) { private func updatePollTooltipMessageState(animated: Bool) {

View File

@ -1086,6 +1086,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
strongSelf.forEachItemHeaderNode { itemHeaderNode in strongSelf.forEachItemHeaderNode { itemHeaderNode in
if let dateNode = itemHeaderNode as? ChatMessageDateHeaderNode { if let dateNode = itemHeaderNode as? ChatMessageDateHeaderNode {
dateNode.updatePresentationData(chatPresentationData, context: context) dateNode.updatePresentationData(chatPresentationData, context: context)
} else if let avatarNode = itemHeaderNode as? ChatMessageAvatarHeaderNode {
avatarNode.updatePresentationData(chatPresentationData, context: context)
} else if let dateNode = itemHeaderNode as? ListMessageDateHeaderNode { } else if let dateNode = itemHeaderNode as? ListMessageDateHeaderNode {
dateNode.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings) dateNode.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings)
} }

View File

@ -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) { override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
} }

View File

@ -150,7 +150,7 @@ class ChatMessageShareButton: HighlightableButtonNode {
textNode.removeFromSupernode() textNode.removeFromSupernode()
} }
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) 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 { 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) 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)
} }

View File

@ -6,6 +6,7 @@ import TelegramPresentationData
import Postbox import Postbox
import SyncCore import SyncCore
import AccountContext import AccountContext
import AvatarNode
private let timezoneOffset: Int32 = { private let timezoneOffset: Int32 = {
let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) let nowTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
@ -22,7 +23,7 @@ final class ChatMessageDateHeader: ListViewItemHeader {
private let roundedTimestamp: Int32 private let roundedTimestamp: Int32
private let scheduled: Bool private let scheduled: Bool
let id: Int64 let id: ListViewItemNode.HeaderId
let presentationData: ChatPresentationData let presentationData: ChatPresentationData
let context: AccountContext let context: AccountContext
let action: ((Int32) -> Void)? let action: ((Int32) -> Void)?
@ -33,21 +34,16 @@ final class ChatMessageDateHeader: ListViewItemHeader {
self.presentationData = presentationData self.presentationData = presentationData
self.context = context self.context = context
self.action = action self.action = action
if timestamp == scheduleWhenOnlineTimestamp { self.roundedTimestamp = dateHeaderTimestampId(timestamp: timestamp)
self.roundedTimestamp = scheduleWhenOnlineTimestamp self.id = ListViewItemNode.HeaderId(space: 0, id: Int64(self.roundedTimestamp))
} else if timestamp == Int32.max {
self.roundedTimestamp = timestamp / (granularity) * (granularity)
} else {
self.roundedTimestamp = ((timestamp + timezoneOffset) / (granularity)) * (granularity)
}
self.id = Int64(self.roundedTimestamp)
} }
let stickDirection: ListViewItemHeaderStickDirection = .bottom let stickDirection: ListViewItemHeaderStickDirection = .bottom
let stickOverInsets: Bool = true
let height: CGFloat = 34.0 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) 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 { final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
let labelNode: TextNode let labelNode: TextNode
let backgroundNode: NavigationBackgroundNode let backgroundNode: NavigationBackgroundNode
@ -164,12 +170,11 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0) 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) 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.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.image = graphics.dateFloatingBackground
self.stickBackgroundNode.alpha = 0.0 self.stickBackgroundNode.alpha = 0.0
//self.backgroundNode.addSubnode(self.stickBackgroundNode)
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
self.addSubnode(self.labelNode) self.addSubnode(self.labelNode)
@ -198,8 +203,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
self.presentationData = presentationData self.presentationData = presentationData
let graphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners) 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.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.image = graphics.dateFloatingBackground
@ -220,12 +224,6 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
func updateBackgroundColor(color: UIColor, enableBlur: Bool) { func updateBackgroundColor(color: UIColor, enableBlur: Bool) {
self.backgroundNode.updateColor(color: color, enableBlur: enableBlur, transition: .immediate) 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) { 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<UITouch>?, 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)
}
}
}

View File

@ -192,9 +192,8 @@ func chatItemsHaveCommonDateHeader(_ lhs: ListViewItem, _ rhs: ListViewItem?) -
let lhsHeader: ChatMessageDateHeader? let lhsHeader: ChatMessageDateHeader?
let rhsHeader: ChatMessageDateHeader? let rhsHeader: ChatMessageDateHeader?
if let lhs = lhs as? ChatMessageItem { if let lhs = lhs as? ChatMessageItem {
lhsHeader = lhs.header lhsHeader = lhs.dateHeader
} else if let _ = lhs as? ChatHoleItem { } else if let _ = lhs as? ChatHoleItem {
//lhsHeader = lhs.header
lhsHeader = nil lhsHeader = nil
} else if let lhs = lhs as? ChatUnreadItem { } else if let lhs = lhs as? ChatUnreadItem {
lhsHeader = lhs.header lhsHeader = lhs.header
@ -205,7 +204,7 @@ func chatItemsHaveCommonDateHeader(_ lhs: ListViewItem, _ rhs: ListViewItem?) -
} }
if let rhs = rhs { if let rhs = rhs {
if let rhs = rhs as? ChatMessageItem { if let rhs = rhs as? ChatMessageItem {
rhsHeader = rhs.header rhsHeader = rhs.dateHeader
} else if let _ = rhs as? ChatHoleItem { } else if let _ = rhs as? ChatHoleItem {
//rhsHeader = rhs.header //rhsHeader = rhs.header
rhsHeader = nil rhsHeader = nil
@ -257,8 +256,11 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
let effectiveAuthorId: PeerId? let effectiveAuthorId: PeerId?
let additionalContent: ChatMessageItemAdditionalContent? let additionalContent: ChatMessageItemAdditionalContent?
public let accessoryItem: ListViewAccessoryItem? //public let accessoryItem: ListViewAccessoryItem?
let header: ChatMessageDateHeader let dateHeader: ChatMessageDateHeader
let avatarHeader: ChatMessageAvatarHeader?
let headers: [ListViewItemHeader]
var message: Message { var message: Message {
switch self.content { switch self.content {
@ -288,7 +290,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
self.disableDate = disableDate self.disableDate = disableDate
self.additionalContent = additionalContent self.additionalContent = additionalContent
var accessoryItem: ListViewAccessoryItem? var avatarHeader: ChatMessageAvatarHeader?
let incoming = content.effectivelyIncoming(self.context.account.peerId) let incoming = content.effectivelyIncoming(self.context.account.peerId)
var effectiveAuthor: Peer? var effectiveAuthor: Peer?
@ -325,7 +327,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
isScheduledMessages = true 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 var calendar = NSCalendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")! calendar.timeZone = TimeZone(abbreviation: "UTC")!
let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
@ -355,11 +357,18 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
} }
if !hasActionMedia && !isBroadcastChannel { if !hasActionMedia && !isBroadcastChannel {
if let effectiveAuthor = effectiveAuthor { 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<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -467,25 +476,25 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
var mergedBottom: ChatMessageMerge = .none var mergedBottom: ChatMessageMerge = .none
var dateAtBottom = false var dateAtBottom = false
if let top = top as? ChatMessageItem { if let top = top as? ChatMessageItem {
if top.header.id != self.header.id { if top.dateHeader.id != self.dateHeader.id {
mergedBottom = .none mergedBottom = .none
} else { } else {
mergedBottom = messagesShouldBeMerged(accountPeerId: self.context.account.peerId, message, top.message) mergedBottom = messagesShouldBeMerged(accountPeerId: self.context.account.peerId, message, top.message)
} }
} }
if let bottom = bottom as? ChatMessageItem { if let bottom = bottom as? ChatMessageItem {
if bottom.header.id != self.header.id { if bottom.dateHeader.id != self.dateHeader.id {
mergedTop = .none mergedTop = .none
dateAtBottom = true dateAtBottom = true
} else { } else {
mergedTop = messagesShouldBeMerged(accountPeerId: self.context.account.peerId, bottom.message, message) mergedTop = messagesShouldBeMerged(accountPeerId: self.context.account.peerId, bottom.message, message)
} }
} else if let bottom = bottom as? ChatUnreadItem { } else if let bottom = bottom as? ChatUnreadItem {
if bottom.header.id != self.header.id { if bottom.header.id != self.dateHeader.id {
dateAtBottom = true dateAtBottom = true
} }
} else if let bottom = bottom as? ChatReplyCountItem { } else if let bottom = bottom as? ChatReplyCountItem {
if bottom.header.id != self.header.id { if bottom.header.id != self.dateHeader.id {
dateAtBottom = true dateAtBottom = true
} }
} else if let _ = bottom as? ChatHoleItem { } else if let _ = bottom as? ChatHoleItem {

View File

@ -801,9 +801,9 @@ public class ChatMessageItemView: ListViewItemNode {
return nil return nil
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
if let item = self.item { if let item = self.item {
return item.header return item.headers
} else { } else {
return nil return nil
} }

View File

@ -211,9 +211,9 @@ class ChatReplyCountItemNode: ListViewItemNode {
} }
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
if let item = self.item { if let item = self.item {
return item.header return [item.header]
} else { } else {
return nil return nil
} }

View File

@ -147,9 +147,9 @@ class ChatUnreadItemNode: ListViewItemNode {
} }
} }
override public func header() -> ListViewItemHeader? { override public func headers() -> [ListViewItemHeader]? {
if let item = self.item { if let item = self.item {
return item.header return [item.header]
} else { } else {
return nil return nil
} }

View File

@ -347,7 +347,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
let selectionPanel: ChatMessageSelectionInputPanelNode let selectionPanel: ChatMessageSelectionInputPanelNode
let separatorNode: ASDisplayNode 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) { init(context: AccountContext, peerId: PeerId, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void, reportMessages: @escaping () -> Void) {
self.context = context self.context = context
@ -360,11 +360,10 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.separatorNode = ASDisplayNode() 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 = ChatMessageSelectionInputPanelNode(theme: presentationData.theme, strings: presentationData.strings, peerMedia: true)
self.selectionPanel.context = context self.selectionPanel.context = context
self.selectionPanel.backgroundColor = presentationData.theme.chat.inputPanel.panelBackgroundColor
let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in
}, setupEditMessage: { _, _ in }, setupEditMessage: { _, _ in
@ -466,7 +465,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
} }
func update(layout: ContainerViewLayout, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { 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 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) 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 let panelHeightWithInset = panelHeight + layout.intrinsicInsets.bottom
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeightWithInset))) 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))) transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
return panelHeightWithInset return panelHeightWithInset

View File

@ -200,9 +200,9 @@ class WebSearchRecentQueryItemNode: ItemListRevealOptionsItemNode {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration * 0.5, removeOnCompletion: false) 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 { if let item = self.item {
return item.header return item.header.flatMap { [$0] }
} else { } else {
return nil return nil
} }