Floating avatar bug fixes

This commit is contained in:
Ali 2021-07-22 19:56:00 +02:00
parent 6f808d95a9
commit fc778ceb5d
14 changed files with 161 additions and 17 deletions

View File

@ -171,6 +171,14 @@ public final class ChatListSearchItemHeader: ListViewItemHeader {
self.action = action
}
public func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? ChatListSearchItemHeader, other.id == self.id {
return true
} else {
return false
}
}
public func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
return ChatListSearchItemHeaderNode(type: self.type, theme: self.theme, strings: self.strings, actionTitle: self.actionTitle, action: self.action)
}

View File

@ -19,6 +19,14 @@ final class ContactListNameIndexHeader: Equatable, ListViewItemHeader {
self.id = ListViewItemNode.HeaderId(space: 0, id: Int64(letter))
}
func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? ContactListNameIndexHeader, self.id == other.id {
return true
} else {
return false
}
}
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
return ContactListNameIndexHeaderNode(theme: self.theme, letter: self.letter)
}

View File

@ -3297,7 +3297,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
var containsSameHeader = false
if let nextHeaders = nextItemNode.headers() {
nextHeaderSearch: for nextHeader in nextHeaders {
if nextHeader.id == currentId {
if nextHeader.id == currentId && nextHeader.combinesWith(other: currentHeader) {
containsSameHeader = true
break nextHeaderSearch
}
@ -3341,7 +3341,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
let flashing = self.headerItemsAreFlashing()
func addHeader(id: VisibleHeaderNodeId, upperBound: CGFloat, upperBoundEdge: CGFloat, lowerBound: CGFloat, item: ListViewItemHeader, hasValidNodes: Bool) {
func addHeader(id: VisibleHeaderNodeId, upperBound: CGFloat, upperIndex: Int, upperBoundEdge: CGFloat, lowerBound: CGFloat, lowerIndex: Int, item: ListViewItemHeader, hasValidNodes: Bool) {
let itemHeaderHeight: CGFloat = item.height
let headerFrame: CGRect
@ -3364,7 +3364,9 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
visibleHeaderNodes.insert(id)
let initialHeaderNodeAlpha = self.itemHeaderNodesAlpha
if let headerNode = self.itemHeaderNodes[id] {
let headerNode: ListViewItemHeaderNode
if let current = self.itemHeaderNodes[id] {
headerNode = current
switch transition.0 {
case .immediate:
headerNode.frame = headerFrame
@ -3410,7 +3412,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: transition.0)
} else {
let headerNode = item.node(synchronousLoad: synchronousLoad)
headerNode = item.node(synchronousLoad: synchronousLoad)
headerNode.alpha = initialHeaderNodeAlpha
if headerNode.item !== item {
item.updateNode(headerNode, previous: nil, next: nil)
@ -3432,11 +3434,52 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: .immediate)
}
var maxIntersectionHeight: (CGFloat, Int)?
for i in upperIndex ... lowerIndex {
let itemNode = self.itemNodes[i]
let itemNodeFrame = itemNode.apparentFrame
let intersectionHeight: CGFloat = itemNodeFrame.intersection(headerFrame).height
if let (currentMaxIntersectionHeight, _) = maxIntersectionHeight {
if currentMaxIntersectionHeight < intersectionHeight {
maxIntersectionHeight = (intersectionHeight, i)
}
} else {
maxIntersectionHeight = (intersectionHeight, i)
}
}
if let (_, i) = maxIntersectionHeight {
let itemNode = self.itemNodes[i]
let itemNodeFrame = itemNode.apparentFrame
if itemNodeFrame.intersects(headerFrame) {
var updated = false
if let previousItemNode = headerNode.attachedToItemNode {
if previousItemNode !== itemNode {
previousItemNode.attachedHeaderNodes.removeAll(where: { $0 === headerNode })
updated = true
}
} else {
updated = true
}
if updated {
headerNode.attachedToItemNode = itemNode
itemNode.attachedHeaderNodes.append(headerNode)
itemNode.attachedHeaderNodesUpdated()
}
}
} else {
if let previousItemNode = headerNode.attachedToItemNode {
previousItemNode.attachedHeaderNodes.removeAll(where: { $0 === headerNode })
headerNode.attachedToItemNode = nil
}
}
}
var previousHeaderBySpace: [AnyHashable: (id: VisibleHeaderNodeId, upperBound: CGFloat, upperBoundEdge: CGFloat, lowerBound: CGFloat, item: ListViewItemHeader, hasValidNodes: Bool)] = [:]
var previousHeaderBySpace: [AnyHashable: (id: VisibleHeaderNodeId, upperBound: CGFloat, upperBoundIndex: Int, upperBoundEdge: CGFloat, lowerBound: CGFloat, lowerBoundIndex: Int, item: ListViewItemHeader, hasValidNodes: Bool)] = [:]
for itemNode in self.itemNodes {
for i in 0 ..< self.itemNodes.count {
let itemNode = self.itemNodes[i]
let itemFrame = itemNode.apparentFrame
let itemTopInset = itemNode.insets.top
var validItemHeaderSpaces: [AnyHashable] = []
@ -3458,16 +3501,16 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
itemMaxY = itemFrame.maxY - (self.rotated ? itemNode.insets.top : itemNode.insets.bottom)
}
if let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeaderBySpace[itemHeader.id.space] {
if let (previousHeaderId, previousUpperBound, previousUpperIndex, previousUpperBoundEdge, previousLowerBound, previousLowerIndex, previousHeaderItem, hasValidNodes) = previousHeaderBySpace[itemHeader.id.space] {
if previousHeaderId == headerId {
previousHeaderBySpace[itemHeader.id.space] = (previousHeaderId, previousUpperBound, previousUpperBoundEdge, itemMaxY, previousHeaderItem, hasValidNodes || itemNode.index != nil)
previousHeaderBySpace[itemHeader.id.space] = (previousHeaderId, previousUpperBound, previousUpperIndex, previousUpperBoundEdge, itemMaxY, i, previousHeaderItem, hasValidNodes || itemNode.index != nil)
} else {
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes)
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperIndex: previousUpperIndex, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, lowerIndex: previousLowerIndex, item: previousHeaderItem, hasValidNodes: hasValidNodes)
previousHeaderBySpace[itemHeader.id.space] = (headerId, itemFrame.minY, itemFrame.minY + itemTopInset, itemMaxY, itemHeader, itemNode.index != nil)
previousHeaderBySpace[itemHeader.id.space] = (headerId, itemFrame.minY, i, itemFrame.minY + itemTopInset, itemMaxY, i, itemHeader, itemNode.index != nil)
}
} else {
previousHeaderBySpace[itemHeader.id.space] = (headerId, itemFrame.minY, itemFrame.minY + itemTopInset, itemMaxY, itemHeader, itemNode.index != nil)
previousHeaderBySpace[itemHeader.id.space] = (headerId, itemFrame.minY, i, itemFrame.minY + itemTopInset, itemMaxY, i, itemHeader, itemNode.index != nil)
}
}
}
@ -3477,18 +3520,18 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
continue
}
let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader
let (previousHeaderId, previousUpperBound, previousUpperIndex, previousUpperBoundEdge, previousLowerBound, previousLowerIndex, previousHeaderItem, hasValidNodes) = previousHeader
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes)
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperIndex: previousUpperIndex, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, lowerIndex: previousLowerIndex, item: previousHeaderItem, hasValidNodes: hasValidNodes)
previousHeaderBySpace.removeValue(forKey: space)
}
}
for (space, previousHeader) in previousHeaderBySpace {
let (previousHeaderId, previousUpperBound, previousUpperBoundEdge, previousLowerBound, previousHeaderItem, hasValidNodes) = previousHeader
let (previousHeaderId, previousUpperBound, previousUpperIndex, previousUpperBoundEdge, previousLowerBound, previousLowerIndex, previousHeaderItem, hasValidNodes) = previousHeader
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, item: previousHeaderItem, hasValidNodes: hasValidNodes)
addHeader(id: previousHeaderId, upperBound: previousUpperBound, upperIndex: previousUpperIndex, upperBoundEdge: previousUpperBoundEdge, lowerBound: previousLowerBound, lowerIndex: previousLowerIndex, item: previousHeaderItem, hasValidNodes: hasValidNodes)
previousHeaderBySpace.removeValue(forKey: space)
}

View File

@ -14,6 +14,8 @@ public protocol ListViewItemHeader: AnyObject {
var height: CGFloat { get }
var stickOverInsets: Bool { get }
func combinesWith(other: ListViewItemHeader) -> Bool
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode
func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?)
}
@ -25,6 +27,7 @@ open class ListViewItemHeaderNode: ASDisplayNode {
final private(set) var internalStickLocationDistanceFactor: CGFloat = 0.0
final var internalStickLocationDistance: CGFloat = 0.0
private var isFlashingOnScrolling = false
weak var attachedToItemNode: ListViewItemNode?
var item: ListViewItemHeader?

View File

@ -130,6 +130,11 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
final var tempHeaderSpaceAffinities: [ListViewItemNode.HeaderId: Int] = [:]
final var headerSpaceAffinities: [ListViewItemNode.HeaderId: Int] = [:]
public internal(set) var attachedHeaderNodes: [ListViewItemHeaderNode] = []
open func attachedHeaderNodesUpdated() {
}
final let wantsScrollDynamics: Bool
open var preferredAnimationCurve: (CGFloat) -> CGFloat {

View File

@ -1375,6 +1375,14 @@ public final class ItemListPeerItemHeader: ListViewItemHeader {
self.action = action
}
public func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? ItemListPeerItemHeader, other.id == self.id {
return true
} else {
return false
}
}
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)
}

View File

@ -68,6 +68,14 @@ final class ListMessageDateHeader: ListViewItemHeader {
let height: CGFloat = 28.0
public func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? ListMessageDateHeader, other.id == self.id {
return true
} else {
return false
}
}
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)
}

View File

@ -1498,6 +1498,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
bounds.origin.x = -translation.x
self.bounds = bounds
self.updateAttachedAvatarNodeOffset(offset: translation.x, transition: .immediate)
if let swipeToReplyNode = self.swipeToReplyNode {
swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0))
if animateReplyNodeIn {
@ -1532,6 +1534,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
bounds.origin.x = 0.0
self.bounds = bounds
self.layer.animateBounds(from: previousBounds, to: bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.updateAttachedAvatarNodeOffset(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
if let swipeToReplyNode = self.swipeToReplyNode {
self.swipeToReplyNode = nil
swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in

View File

@ -3658,6 +3658,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
shadowBounds.origin.x = -translation.x
self.shadowNode.bounds = shadowBounds
self.updateAttachedAvatarNodeOffset(offset: translation.x, transition: .immediate)
if let swipeToReplyNode = self.swipeToReplyNode {
swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0))
if animateReplyNodeIn {
@ -3696,6 +3698,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
shadowBounds.origin.x = 0.0
self.shadowNode.bounds = shadowBounds
self.layer.animateBounds(from: previousBounds, to: bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.updateAttachedAvatarNodeOffset(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
self.shadowNode.layer.animateBounds(from: previousShadowBounds, to: shadowBounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
if let swipeToReplyNode = self.swipeToReplyNode {
self.swipeToReplyNode = nil

View File

@ -43,6 +43,14 @@ final class ChatMessageDateHeader: ListViewItemHeader {
let height: CGFloat = 34.0
public func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? ChatMessageDateHeader, other.id == self.id {
return true
} else {
return false
}
}
func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
return ChatMessageDateHeaderNode(localTimestamp: self.roundedTimestamp, scheduled: self.scheduled, presentationData: self.presentationData, context: self.context, action: self.action)
}
@ -316,14 +324,22 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
let peerId: PeerId
let peer: Peer?
let messageReference: MessageReference?
let effectiveTimestamp: Int32
let presentationData: ChatPresentationData
let context: AccountContext
let controllerInteraction: ChatControllerInteraction
init(timestamp: Int32, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction) {
init(timestamp: Int32, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, message: Message, presentationData: ChatPresentationData, context: AccountContext, controllerInteraction: ChatControllerInteraction) {
self.peerId = peerId
self.peer = peer
self.messageReference = messageReference
var effectiveTimestamp = message.timestamp
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported) {
effectiveTimestamp = forwardInfo.date
}
self.effectiveTimestamp = effectiveTimestamp
self.presentationData = presentationData
self.context = context
self.controllerInteraction = controllerInteraction
@ -335,6 +351,17 @@ final class ChatMessageAvatarHeader: ListViewItemHeader {
let height: CGFloat = 38.0
public func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? ChatMessageAvatarHeader, other.id == self.id {
if abs(self.effectiveTimestamp - other.effectiveTimestamp) >= 10 * 60 {
return false
}
return true
} else {
return false
}
}
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)
}

View File

@ -914,6 +914,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
bounds.origin.x = -translation.x
self.bounds = bounds
self.updateAttachedAvatarNodeOffset(offset: translation.x, transition: .immediate)
if let swipeToReplyNode = self.swipeToReplyNode {
swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0))
if animateReplyNodeIn {
@ -948,6 +950,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
bounds.origin.x = 0.0
self.bounds = bounds
self.layer.animateBounds(from: previousBounds, to: bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.updateAttachedAvatarNodeOffset(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
if let swipeToReplyNode = self.swipeToReplyNode {
self.swipeToReplyNode = nil
swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in

View File

@ -357,7 +357,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
if !hasActionMedia && !isBroadcastChannel {
if let effectiveAuthor = effectiveAuthor {
//accessoryItem = ChatMessageAvatarAccessoryItem(context: context, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), messageTimestamp: content.index.timestamp, forwardInfo: message.forwardInfo, emptyColor: presentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper.fill, controllerInteraction: controllerInteraction)
avatarHeader = ChatMessageAvatarHeader(timestamp: content.index.timestamp, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), presentationData: presentationData, context: context, controllerInteraction: controllerInteraction)
avatarHeader = ChatMessageAvatarHeader(timestamp: content.index.timestamp, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), message: message, presentationData: presentationData, context: context, controllerInteraction: controllerInteraction)
}
}
}

View File

@ -874,4 +874,18 @@ public class ChatMessageItemView: ListViewItemNode {
func getStatusNode() -> ASDisplayNode? {
return nil
}
private var attachedAvatarNodeOffset: CGFloat = 0.0
override public func attachedHeaderNodesUpdated() {
self.updateAttachedAvatarNodeOffset(offset: self.attachedAvatarNodeOffset, transition: .immediate)
}
func updateAttachedAvatarNodeOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
for headerNode in self.attachedHeaderNodes {
if let headerNode = headerNode as? ChatMessageAvatarHeaderNode {
transition.updateSublayerTransformOffset(layer: headerNode.layer, offset: CGPoint(x: offset, y: 0.0))
}
}
}
}

View File

@ -1018,6 +1018,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
bounds.origin.x = -translation.x
self.bounds = bounds
self.updateAttachedAvatarNodeOffset(offset: translation.x, transition: .immediate)
if let swipeToReplyNode = self.swipeToReplyNode {
swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0))
if animateReplyNodeIn {
@ -1052,6 +1054,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
bounds.origin.x = 0.0
self.bounds = bounds
self.layer.animateBounds(from: previousBounds, to: bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.updateAttachedAvatarNodeOffset(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
if let swipeToReplyNode = self.swipeToReplyNode {
self.swipeToReplyNode = nil
swipeToReplyNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak swipeToReplyNode] _ in