mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
4a89668a10
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -465,7 +465,7 @@ class ChatListFilterPresetCategoryItemNode: ItemListRevealOptionsItemNode, ItemL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func header() -> ListViewItemHeader? {
|
override func headers() -> [ListViewItemHeader]? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)?
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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? {
|
||||||
|
@ -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? {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user