[WIP] Monoforums
This commit is contained in:
parent
0e119dd6f1
commit
140efd6cfd
70 changed files with 666 additions and 669 deletions
|
|
@ -1166,7 +1166,6 @@ public enum ChatCustomContentsKind: Equatable {
|
|||
case quickReplyMessageInput(shortcut: String, shortcutType: ChatQuickReplyShortcutType)
|
||||
case businessLinkSetup(link: TelegramBusinessChatLinks.Link)
|
||||
case hashTagSearch(publicPosts: Bool)
|
||||
case postSuggestions(price: StarsAmount)
|
||||
}
|
||||
|
||||
public protocol ChatCustomContentsProtocol: AnyObject {
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||
}, forceUpdateWarpContents: {
|
||||
}, playShakeAnimation: {
|
||||
}, displayQuickShare: { _, _ ,_ in
|
||||
}, updateChatLocationThread: { _ in
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ public final class ChatListSearchItemHeaderNode: ListViewItemHeaderNode {
|
|||
}
|
||||
}
|
||||
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, leftInset, rightInset)
|
||||
self.sectionHeaderNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.sectionHeaderNode.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ final class ContactListNameIndexHeaderNode: ListViewItemHeaderNode {
|
|||
self.sectionHeaderNode.updateTheme(theme: theme)
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.sectionHeaderNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.sectionHeaderNode.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -453,6 +453,14 @@ public extension CALayer {
|
|||
self.animate(from: from as NSNumber, to: to as NSNumber, keyPath: "bounds.origin.y", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: duration, mediaTimingFunction: mediaTimingFunction, additive: true)
|
||||
}
|
||||
|
||||
func animateBoundsOriginAdditive(from: CGPoint, to: CGPoint, duration: Double, mediaTimingFunction: CAMediaTimingFunction) {
|
||||
self.animate(from: NSValue(cgPoint: from), to: NSValue(cgPoint: to), keyPath: "bounds.origin", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: duration, mediaTimingFunction: mediaTimingFunction, additive: true)
|
||||
}
|
||||
|
||||
func animateBoundsOriginAdditive(from: CGPoint, to: CGPoint, duration: Double, timingFunction: String = CAMediaTimingFunctionName.easeInEaseOut.rawValue, mediaTimingFunction: CAMediaTimingFunction? = nil) {
|
||||
self.animate(from: NSValue(cgPoint: from), to: NSValue(cgPoint: to), keyPath: "bounds.origin", timingFunction: timingFunction, duration: duration, mediaTimingFunction: mediaTimingFunction, additive: true)
|
||||
}
|
||||
|
||||
func animateShapeLineWidth(from: CGFloat, to: CGFloat, duration: Double, delay: Double = 0.0, timingFunction: String = CAMediaTimingFunctionName.easeInEaseOut.rawValue, mediaTimingFunction: CAMediaTimingFunction? = nil, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||
self.animate(from: NSNumber(value: Float(from)), to: NSNumber(value: Float(to)), keyPath: "lineWidth", timingFunction: timingFunction, duration: duration, delay: delay, mediaTimingFunction: mediaTimingFunction, removeOnCompletion: removeOnCompletion, additive: additive, completion: completion)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -651,6 +651,15 @@ public extension ContainedViewLayoutTransition {
|
|||
}
|
||||
}
|
||||
|
||||
func animateOffsetAdditive(node: ASDisplayNode, offset: CGPoint) {
|
||||
switch self {
|
||||
case .immediate:
|
||||
break
|
||||
case let .animated(duration, curve):
|
||||
node.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction)
|
||||
}
|
||||
}
|
||||
|
||||
func animateHorizontalOffsetAdditive(node: ASDisplayNode, offset: CGFloat, completion: (() -> Void)? = nil) {
|
||||
switch self {
|
||||
case .immediate:
|
||||
|
|
|
|||
|
|
@ -1740,18 +1740,30 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
}
|
||||
|
||||
private func nodeForItem(synchronous: Bool, synchronousLoads: Bool, item: ListViewItem, previousNode: QueueLocalObject<ListViewItemNode>?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimationIsAnimated: Bool, updateAnimationIsCrossfade: Bool, completion: @escaping (QueueLocalObject<ListViewItemNode>, ListViewItemNodeLayout, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
private func nodeForItem(synchronous: Bool, synchronousLoads: Bool, item: ListViewItem, previousNode: QueueLocalObject<ListViewItemNode>?, index: Int, previousItem: ListViewItem?, nextItem: ListViewItem?, params: ListViewItemLayoutParams, updateAnimationIsAnimated: Bool, updateAnimationIsCrossfade: Bool, customAnimationTransition: ControlledTransition?, completion: @escaping (QueueLocalObject<ListViewItemNode>, ListViewItemNodeLayout, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
if let previousNode = previousNode {
|
||||
var controlledTransition: ControlledTransition?
|
||||
let updateAnimation: ListViewItemUpdateAnimation
|
||||
if updateAnimationIsCrossfade {
|
||||
updateAnimation = .Crossfade
|
||||
} else if updateAnimationIsAnimated {
|
||||
let transition = ControlledTransition(duration: insertionAnimationDuration * UIView.animationDurationFactor(), curve: .spring, interactive: true)
|
||||
controlledTransition = transition
|
||||
updateAnimation = .System(duration: insertionAnimationDuration * UIView.animationDurationFactor(), transition: transition)
|
||||
if let customAnimationTransition {
|
||||
controlledTransition = customAnimationTransition
|
||||
var duration: Double = insertionAnimationDuration
|
||||
switch customAnimationTransition.legacyAnimator.transition {
|
||||
case .immediate:
|
||||
duration = 0.0
|
||||
case let .animated(durationValue, _):
|
||||
duration = durationValue
|
||||
}
|
||||
updateAnimation = .System(duration: duration * UIView.animationDurationFactor(), transition: customAnimationTransition)
|
||||
} else {
|
||||
updateAnimation = .None
|
||||
if updateAnimationIsCrossfade {
|
||||
updateAnimation = .Crossfade
|
||||
} else if updateAnimationIsAnimated {
|
||||
let transition = ControlledTransition(duration: insertionAnimationDuration * UIView.animationDurationFactor(), curve: .spring, interactive: true)
|
||||
controlledTransition = transition
|
||||
updateAnimation = .System(duration: insertionAnimationDuration * UIView.animationDurationFactor(), transition: transition)
|
||||
} else {
|
||||
updateAnimation = .None
|
||||
}
|
||||
}
|
||||
|
||||
if let controlledTransition = controlledTransition {
|
||||
|
|
@ -1846,7 +1858,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
self.transactionQueue.addTransaction({ [weak self] transactionCompletion in
|
||||
if let strongSelf = self {
|
||||
strongSelf.transactionOffset = 0.0
|
||||
strongSelf.deleteAndInsertItemsTransaction(deleteIndices: deleteIndices, insertIndicesAndItems: insertIndicesAndItems, updateIndicesAndItems: updateIndicesAndItems, options: options, scrollToItem: scrollToItem, additionalScrollDistance: additionalScrollDistance, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: stationaryItemRange, updateOpaqueState: updateOpaqueState, completion: { [weak strongSelf] in
|
||||
strongSelf.deleteAndInsertItemsTransaction(deleteIndices: deleteIndices, insertIndicesAndItems: insertIndicesAndItems, updateIndicesAndItems: updateIndicesAndItems, options: options, scrollToItem: scrollToItem, additionalScrollDistance: additionalScrollDistance, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: stationaryItemRange, updateOpaqueState: updateOpaqueState, customAnimationTransition: updateSizeAndInsets?.customAnimationTransition, completion: { [weak strongSelf] in
|
||||
completion(strongSelf?.immediateDisplayedItemRange() ?? ListViewDisplayedItemRange(loadedRange: nil, visibleRange: nil))
|
||||
|
||||
transactionCompletion()
|
||||
|
|
@ -1855,7 +1867,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
})
|
||||
}
|
||||
|
||||
private func deleteAndInsertItemsTransaction(deleteIndices: [ListViewDeleteItem], insertIndicesAndItems: [ListViewInsertItem], updateIndicesAndItems: [ListViewUpdateItem], options: ListViewDeleteAndInsertOptions, scrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemRange: (Int, Int)?, updateOpaqueState: Any?, completion: @escaping () -> Void) {
|
||||
private func deleteAndInsertItemsTransaction(deleteIndices: [ListViewDeleteItem], insertIndicesAndItems: [ListViewInsertItem], updateIndicesAndItems: [ListViewUpdateItem], options: ListViewDeleteAndInsertOptions, scrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemRange: (Int, Int)?, updateOpaqueState: Any?, customAnimationTransition: ControlledTransition?, completion: @escaping () -> Void) {
|
||||
if deleteIndices.isEmpty && insertIndicesAndItems.isEmpty && updateIndicesAndItems.isEmpty && scrollToItem == nil {
|
||||
if let updateSizeAndInsets = updateSizeAndInsets, (self.items.count == 0 || (updateSizeAndInsets.size == self.visibleSize && updateSizeAndInsets.insets == self.insets && !options.contains(.ForceUpdate))) {
|
||||
self.visibleSize = updateSizeAndInsets.size
|
||||
|
|
@ -2096,7 +2108,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
print("deleteAndInsertItemsTransaction prepare \((CACurrentMediaTime() - startTime) * 1000.0) ms")
|
||||
}
|
||||
|
||||
self.fillMissingNodes(synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), animated: animated, inputAnimatedInsertIndices: animated ? insertedIndexSet : Set<Int>(), insertDirectionHints: insertDirectionHints, inputState: state, inputPreviousNodes: previousNodes, inputOperations: operations, inputCompletion: { updatedState, operations in
|
||||
self.fillMissingNodes(synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), animated: animated, customAnimationTransition: updateSizeAndInsets?.customAnimationTransition, inputAnimatedInsertIndices: animated ? insertedIndexSet : Set<Int>(), insertDirectionHints: insertDirectionHints, inputState: state, inputPreviousNodes: previousNodes, inputOperations: operations, inputCompletion: { updatedState, operations in
|
||||
|
||||
if self.debugInfo {
|
||||
print("fillMissingNodes completion \((CACurrentMediaTime() - startTime) * 1000.0) ms")
|
||||
|
|
@ -2119,8 +2131,8 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
|
||||
updateIndices.subtract(explicitelyUpdateIndices)
|
||||
|
||||
self.updateNodes(synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), crossfade: options.contains(.AnimateCrossfade), animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: updatedState, previousNodes: previousNodes, inputOperations: operations, completion: { updatedState, operations in
|
||||
self.updateAdjacent(synchronous: options.contains(.Synchronous), animated: animated, state: updatedState, updateAdjacentItemsIndices: updateIndices, operations: operations, completion: { state, operations in
|
||||
self.updateNodes(synchronous: options.contains(.Synchronous), synchronousLoads: options.contains(.PreferSynchronousResourceLoading), crossfade: options.contains(.AnimateCrossfade), customAnimationTransition: customAnimationTransition, animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: updatedState, previousNodes: previousNodes, inputOperations: operations, completion: { updatedState, operations in
|
||||
self.updateAdjacent(synchronous: options.contains(.Synchronous), animated: animated, customAnimationTransition: customAnimationTransition, state: updatedState, updateAdjacentItemsIndices: updateIndices, operations: operations, completion: { state, operations in
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
updatedState.removeInvisibleNodes(&updatedOperations)
|
||||
|
|
@ -2154,7 +2166,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
|
||||
let beginReplay = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateCrossfade: options.contains(.AnimateCrossfade), animateFullTransition: options.contains(.AnimateFullTransition), 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, forceInvertOffsetDirection: options.contains(.InvertOffsetDirection), completion: {
|
||||
strongSelf.replayOperations(animated: animated, animateAlpha: options.contains(.AnimateAlpha), animateCrossfade: options.contains(.AnimateCrossfade), animateFullTransition: options.contains(.AnimateFullTransition), customAnimationTransition: updateSizeAndInsets?.customAnimationTransition, 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, forceInvertOffsetDirection: options.contains(.InvertOffsetDirection), completion: {
|
||||
if options.contains(.PreferSynchronousDrawing) {
|
||||
self?.recursivelyEnsureDisplaySynchronously(true)
|
||||
}
|
||||
|
|
@ -2199,7 +2211,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
}
|
||||
|
||||
private func updateAdjacent(synchronous: Bool, animated: Bool, state: ListViewState, updateAdjacentItemsIndices: Set<Int>, operations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
private func updateAdjacent(synchronous: Bool, animated: Bool, customAnimationTransition: ControlledTransition?, state: ListViewState, updateAdjacentItemsIndices: Set<Int>, operations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
if updateAdjacentItemsIndices.isEmpty {
|
||||
completion(state, operations)
|
||||
} else {
|
||||
|
|
@ -2217,12 +2229,24 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
continueWithoutNode = false
|
||||
var controlledTransition: ControlledTransition?
|
||||
let updateAnimation: ListViewItemUpdateAnimation
|
||||
if animated {
|
||||
let transition = ControlledTransition(duration: insertionAnimationDuration * UIView.animationDurationFactor(), curve: .spring, interactive: true)
|
||||
controlledTransition = transition
|
||||
updateAnimation = .System(duration: insertionAnimationDuration * UIView.animationDurationFactor(), transition: transition)
|
||||
if let customAnimationTransition {
|
||||
controlledTransition = customAnimationTransition
|
||||
var duration: Double = insertionAnimationDuration
|
||||
switch customAnimationTransition.legacyAnimator.transition {
|
||||
case .immediate:
|
||||
duration = 0.0
|
||||
case let .animated(durationValue, _):
|
||||
duration = durationValue
|
||||
}
|
||||
updateAnimation = .System(duration: duration * UIView.animationDurationFactor(), transition: customAnimationTransition)
|
||||
} else {
|
||||
updateAnimation = .None
|
||||
if animated {
|
||||
let transition = ControlledTransition(duration: insertionAnimationDuration * UIView.animationDurationFactor(), curve: .spring, interactive: true)
|
||||
controlledTransition = transition
|
||||
updateAnimation = .System(duration: insertionAnimationDuration * UIView.animationDurationFactor(), transition: transition)
|
||||
} else {
|
||||
updateAnimation = .None
|
||||
}
|
||||
}
|
||||
|
||||
if let controlledTransition = controlledTransition {
|
||||
|
|
@ -2264,7 +2288,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
}
|
||||
|
||||
self.updateAdjacent(synchronous: synchronous, animated: animated, state: updatedState, updateAdjacentItemsIndices: updatedUpdateAdjacentItemsIndices, operations: updatedOperations, completion: completion)
|
||||
self.updateAdjacent(synchronous: synchronous, animated: animated, customAnimationTransition: customAnimationTransition, state: updatedState, updateAdjacentItemsIndices: updatedUpdateAdjacentItemsIndices, operations: updatedOperations, completion: completion)
|
||||
})
|
||||
}
|
||||
break
|
||||
|
|
@ -2273,12 +2297,12 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
|
||||
if continueWithoutNode {
|
||||
updateAdjacent(synchronous: synchronous, animated: animated, state: state, updateAdjacentItemsIndices: updatedUpdateAdjacentItemsIndices, operations: operations, completion: completion)
|
||||
updateAdjacent(synchronous: synchronous, animated: animated, customAnimationTransition: customAnimationTransition, state: state, updateAdjacentItemsIndices: updatedUpdateAdjacentItemsIndices, operations: operations, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fillMissingNodes(synchronous: Bool, synchronousLoads: Bool, animated: Bool, inputAnimatedInsertIndices: Set<Int>, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
private func fillMissingNodes(synchronous: Bool, synchronousLoads: Bool, animated: Bool, customAnimationTransition: ControlledTransition?, inputAnimatedInsertIndices: Set<Int>, insertDirectionHints: [Int: ListViewItemOperationDirectionHint], inputState: ListViewState, inputPreviousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], inputCompletion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
let animatedInsertIndices = inputAnimatedInsertIndices
|
||||
var state = inputState
|
||||
let previousNodes = inputPreviousNodes
|
||||
|
|
@ -2312,7 +2336,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
let index = insertionItemIndexAndDirection.0
|
||||
let threadId = pthread_self()
|
||||
var tailRecurse = false
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), updateAnimationIsAnimated: animated, updateAnimationIsCrossfade: false, completion: { (node, layout, apply) in
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), updateAnimationIsAnimated: animated, updateAnimationIsCrossfade: false, customAnimationTransition: customAnimationTransition, completion: { (node, layout, apply) in
|
||||
if pthread_equal(pthread_self(), threadId) != 0 && !tailRecurse {
|
||||
tailRecurse = true
|
||||
state.insertNode(index, node: node, layout: layout, apply: apply, offsetDirection: insertionItemIndexAndDirection.1, animated: animated && animatedInsertIndices.contains(index), operations: &operations, itemCount: self.items.count)
|
||||
|
|
@ -2320,7 +2344,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
updatedState.insertNode(index, node: node, layout: layout, apply: apply, offsetDirection: insertionItemIndexAndDirection.1, animated: animated && animatedInsertIndices.contains(index), operations: &updatedOperations, itemCount: self.items.count)
|
||||
self.fillMissingNodes(synchronous: synchronous, synchronousLoads: synchronousLoads, animated: animated, inputAnimatedInsertIndices: animatedInsertIndices, insertDirectionHints: insertDirectionHints, inputState: updatedState, inputPreviousNodes: previousNodes, inputOperations: updatedOperations, inputCompletion: completion)
|
||||
self.fillMissingNodes(synchronous: synchronous, synchronousLoads: synchronousLoads, animated: animated, customAnimationTransition: customAnimationTransition, inputAnimatedInsertIndices: animatedInsertIndices, insertDirectionHints: insertDirectionHints, inputState: updatedState, inputPreviousNodes: previousNodes, inputOperations: updatedOperations, inputCompletion: completion)
|
||||
}
|
||||
})
|
||||
if !tailRecurse {
|
||||
|
|
@ -2335,7 +2359,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
}
|
||||
|
||||
private func updateNodes(synchronous: Bool, synchronousLoads: Bool, crossfade: Bool, animated: Bool, updateIndicesAndItems: [ListViewUpdateItem], inputState: ListViewState, previousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
private func updateNodes(synchronous: Bool, synchronousLoads: Bool, crossfade: Bool, customAnimationTransition: ControlledTransition?, animated: Bool, updateIndicesAndItems: [ListViewUpdateItem], inputState: ListViewState, previousNodes: [Int: QueueLocalObject<ListViewItemNode>], inputOperations: [ListViewStateOperation], completion: @escaping (ListViewState, [ListViewStateOperation]) -> Void) {
|
||||
var state = inputState
|
||||
var operations = inputOperations
|
||||
var updateIndicesAndItems = updateIndicesAndItems
|
||||
|
|
@ -2347,11 +2371,11 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
} else {
|
||||
let updateItem = updateIndicesAndItems[0]
|
||||
if let previousNode = previousNodes[updateItem.index] {
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: updateItem.item, previousNode: previousNode, index: updateItem.index, previousItem: updateItem.index == 0 ? nil : self.items[updateItem.index - 1], nextItem: updateItem.index == (self.items.count - 1) ? nil : self.items[updateItem.index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), updateAnimationIsAnimated: animated, updateAnimationIsCrossfade: crossfade, completion: { _, layout, apply in
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: updateItem.item, previousNode: previousNode, index: updateItem.index, previousItem: updateItem.index == 0 ? nil : self.items[updateItem.index - 1], nextItem: updateItem.index == (self.items.count - 1) ? nil : self.items[updateItem.index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), updateAnimationIsAnimated: animated, updateAnimationIsCrossfade: crossfade, customAnimationTransition: customAnimationTransition, completion: { _, layout, apply in
|
||||
state.updateNodeAtItemIndex(updateItem.index, layout: layout, direction: updateItem.directionHint, isAnimated: animated, apply: apply, operations: &operations)
|
||||
|
||||
updateIndicesAndItems.remove(at: 0)
|
||||
self.updateNodes(synchronous: synchronous, synchronousLoads: synchronousLoads, crossfade: crossfade, animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: state, previousNodes: previousNodes, inputOperations: operations, completion: completion)
|
||||
self.updateNodes(synchronous: synchronous, synchronousLoads: synchronousLoads, crossfade: crossfade, customAnimationTransition: customAnimationTransition, animated: animated, updateIndicesAndItems: updateIndicesAndItems, inputState: state, previousNodes: previousNodes, inputOperations: operations, completion: completion)
|
||||
})
|
||||
break
|
||||
} else {
|
||||
|
|
@ -2621,7 +2645,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
}
|
||||
|
||||
private func replayOperations(animated: Bool, animateAlpha: Bool, animateCrossfade: Bool, animateFullTransition: Bool, synchronous: Bool, synchronousLoads: Bool, animateTopItemVerticalOrigin: Bool, operations: [ListViewStateOperation], requestItemInsertionAnimationsIndices: Set<Int>, scrollToItem originalScrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemIndex: Int?, updateOpaqueState: Any?, forceInvertOffsetDirection: Bool = false, completion: () -> Void) {
|
||||
private func replayOperations(animated: Bool, animateAlpha: Bool, animateCrossfade: Bool, animateFullTransition: Bool, customAnimationTransition: ControlledTransition?, synchronous: Bool, synchronousLoads: Bool, animateTopItemVerticalOrigin: Bool, operations: [ListViewStateOperation], requestItemInsertionAnimationsIndices: Set<Int>, scrollToItem originalScrollToItem: ListViewScrollToItem?, additionalScrollDistance: CGFloat, updateSizeAndInsets: ListViewUpdateSizeAndInsets?, stationaryItemIndex: Int?, updateOpaqueState: Any?, forceInvertOffsetDirection: Bool = false, completion: () -> Void) {
|
||||
var scrollToItem: ListViewScrollToItem?
|
||||
var isExperimentalSnapToScrollToItem = false
|
||||
if let originalScrollToItem = originalScrollToItem {
|
||||
|
|
@ -2896,7 +2920,24 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
|
||||
var offsetRanges = OffsetRanges()
|
||||
|
||||
if animated {
|
||||
if let customAnimationTransition {
|
||||
node.apparentHeight = updatedApparentHeight
|
||||
|
||||
let apparentHeightDelta = updatedApparentHeight - previousApparentHeight
|
||||
if apparentHeightDelta != 0.0 {
|
||||
var apparentFrame = node.apparentFrame
|
||||
apparentFrame.origin.y += offsetRanges.offsetForIndex(index)
|
||||
if apparentFrame.maxY < self.insets.top {
|
||||
offsetRanges.offset(IndexRange(first: 0, last: index), offset: -apparentHeightDelta)
|
||||
} else {
|
||||
offsetRanges.offset(IndexRange(first: index + 1, last: Int.max), offset: apparentHeightDelta)
|
||||
}
|
||||
}
|
||||
|
||||
if previousApparentHeight != updatedApparentHeight {
|
||||
customAnimationTransition.legacyAnimator.transition.animateOffsetAdditive(node: node, offset: previousApparentHeight - updatedApparentHeight)
|
||||
}
|
||||
} else if animated {
|
||||
if updatedInsets != previousInsets {
|
||||
node.insets = previousInsets
|
||||
node.addInsetsAnimationToValue(updatedInsets, duration: insertionAnimationDuration * UIView.animationDurationFactor(), beginAt: timestamp)
|
||||
|
|
@ -2966,7 +3007,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
if offset != 0.0 {
|
||||
var frame = itemNode.frame
|
||||
frame.origin.y += offset
|
||||
itemNode.updateFrame(frame, within: self.visibleSize)
|
||||
itemNode.updateFrame(frame, within: self.visibleSize, transition: customAnimationTransition)
|
||||
}
|
||||
|
||||
index += 1
|
||||
|
|
@ -3129,7 +3170,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
self.visibleSize = updateSizeAndInsets.size
|
||||
|
||||
for itemNode in self.itemNodes {
|
||||
itemNode.updateFrame(itemNode.frame.offsetBy(dx: 0.0, dy: offsetFix), within: self.visibleSize)
|
||||
itemNode.updateFrame(itemNode.frame.offsetBy(dx: 0.0, dy: offsetFix), within: self.visibleSize, transition: customAnimationTransition)
|
||||
}
|
||||
|
||||
let (snappedTopInset, snapToBoundsOffset) = self.snapToBounds(snapTopItem: scrollToItem != nil && scrollToItem?.directionHint != .Down, stackFromBottom: self.stackFromBottom, updateSizeAndInsets: updateSizeAndInsets, isExperimentalSnapToScrollToItem: isExperimentalSnapToScrollToItem, insetDeltaOffsetFix: insetDeltaOffsetFix)
|
||||
|
|
@ -3859,22 +3900,25 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
case let .animated(duration, curve):
|
||||
let previousFrame = headerNode.frame
|
||||
headerNode.updateFrame(headerFrame, within: self.visibleSize)
|
||||
var offset = headerFrame.minY - previousFrame.minY + transition.2
|
||||
var offsetY = headerFrame.minY - previousFrame.minY + transition.2
|
||||
var offsetX: CGFloat = 0.0
|
||||
if headerNode.isRotated {
|
||||
offset = -offset
|
||||
offsetY = -offsetY
|
||||
offsetX = headerFrame.width - previousFrame.width
|
||||
}
|
||||
let offset = CGPoint(x: offsetX, y: offsetY)
|
||||
switch curve {
|
||||
case .linear:
|
||||
headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear))
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear))
|
||||
case .spring, .customSpring:
|
||||
transition.0.animateOffsetAdditive(node: headerNode, offset: offset)
|
||||
case let .custom(p1, p2, p3, p4):
|
||||
headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: CAMediaTimingFunction(controlPoints: p1, p2, p3, p4))
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: CAMediaTimingFunction(controlPoints: p1, p2, p3, p4))
|
||||
case .easeInOut:
|
||||
if transition.1 {
|
||||
headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: ContainedViewLayoutTransitionCurve.slide.mediaTimingFunction)
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: ContainedViewLayoutTransitionCurve.slide.mediaTimingFunction)
|
||||
} else {
|
||||
headerNode.layer.animateBoundsOriginYAdditive(from: offset, to: 0.0, duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut))
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3883,7 +3927,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
item.updateNode(headerNode, previous: nil, next: nil)
|
||||
headerNode.item = item
|
||||
}
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset, transition: transition.0)
|
||||
headerNode.updateInternalStickLocationDistanceFactor(stickLocationDistanceFactor, animated: true)
|
||||
headerNode.internalStickLocationDistance = stickLocationDistance
|
||||
if !hasValidNodes && !headerNode.alpha.isZero {
|
||||
|
|
@ -3906,7 +3950,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
}
|
||||
headerNode.updateFlashingOnScrolling(flashing, animated: false)
|
||||
headerNode.frame = headerFrame
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset, transition: transition.0)
|
||||
headerNode.updateInternalStickLocationDistanceFactor(stickLocationDistanceFactor, animated: false)
|
||||
self.itemHeaderNodes[id] = headerNode
|
||||
if let verticalScrollIndicator = self.verticalScrollIndicator {
|
||||
|
|
@ -4368,15 +4412,15 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
|||
let state = self.currentState()
|
||||
|
||||
let begin: () -> Void = {
|
||||
self.fillMissingNodes(synchronous: synchronous, synchronousLoads: false, animated: false, inputAnimatedInsertIndices: [], insertDirectionHints: [:], inputState: state, inputPreviousNodes: [:], inputOperations: []) { state, operations in
|
||||
self.fillMissingNodes(synchronous: synchronous, synchronousLoads: false, animated: false, customAnimationTransition: nil, inputAnimatedInsertIndices: [], insertDirectionHints: [:], inputState: state, inputPreviousNodes: [:], inputOperations: []) { state, operations in
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
updatedState.removeInvisibleNodes(&updatedOperations)
|
||||
if synchronous {
|
||||
self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, animateFullTransition: false, synchronous: false, synchronousLoads: 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, animateFullTransition: false, customAnimationTransition: nil, synchronous: false, synchronousLoads: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion)
|
||||
} else {
|
||||
self.dispatchOnVSync {
|
||||
self.replayOperations(animated: false, animateAlpha: false, animateCrossfade: false, animateFullTransition: false, synchronous: false, synchronousLoads: 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, animateFullTransition: false, customAnimationTransition: nil, synchronous: false, synchronousLoads: false, animateTopItemVerticalOrigin: false, operations: updatedOperations, requestItemInsertionAnimationsIndices: Set(), scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemIndex: nil, updateOpaqueState: nil, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,8 +141,9 @@ public struct ListViewUpdateSizeAndInsets {
|
|||
public var duration: Double
|
||||
public var curve: ListViewAnimationCurve
|
||||
public var ensureTopInsetForOverlayHighlightedItems: CGFloat?
|
||||
public var customAnimationTransition: ControlledTransition?
|
||||
|
||||
public init(size: CGSize, insets: UIEdgeInsets, headerInsets: UIEdgeInsets? = nil, scrollIndicatorInsets: UIEdgeInsets? = nil, duration: Double, curve: ListViewAnimationCurve, ensureTopInsetForOverlayHighlightedItems: CGFloat? = nil) {
|
||||
public init(size: CGSize, insets: UIEdgeInsets, headerInsets: UIEdgeInsets? = nil, scrollIndicatorInsets: UIEdgeInsets? = nil, duration: Double, curve: ListViewAnimationCurve, ensureTopInsetForOverlayHighlightedItems: CGFloat? = nil, customAnimationTransition: ControlledTransition? = nil) {
|
||||
self.size = size
|
||||
self.insets = insets
|
||||
self.headerInsets = headerInsets
|
||||
|
|
@ -150,6 +151,7 @@ public struct ListViewUpdateSizeAndInsets {
|
|||
self.duration = duration
|
||||
self.curve = curve
|
||||
self.ensureTopInsetForOverlayHighlightedItems = ensureTopInsetForOverlayHighlightedItems
|
||||
self.customAnimationTransition = customAnimationTransition
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ open class ListViewItemHeaderNode: ASDisplayNode {
|
|||
|
||||
private var cachedLayout: (CGSize, CGFloat, CGFloat)?
|
||||
|
||||
public func updateLayoutInternal(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
public func updateLayoutInternal(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
var update = false
|
||||
if let cachedLayout = self.cachedLayout {
|
||||
if cachedLayout.0 != size || cachedLayout.1 != leftInset || cachedLayout.2 != rightInset {
|
||||
|
|
@ -139,11 +139,11 @@ open class ListViewItemHeaderNode: ASDisplayNode {
|
|||
}
|
||||
if update {
|
||||
self.cachedLayout = (size, leftInset, rightInset)
|
||||
self.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
|
||||
self.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
open func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
open func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
}
|
||||
|
||||
open func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||
|
|
|
|||
|
|
@ -629,9 +629,16 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
|
|||
(self.supernode as? ListView)?.ensureItemNodeVisible(self, animated: false, overflow: 22.0, allowIntersection: true)
|
||||
}
|
||||
|
||||
public func updateFrame(_ frame: CGRect, within containerSize: CGSize, updateFrame: Bool = true) {
|
||||
public func updateFrame(_ frame: CGRect, within containerSize: CGSize, updateFrame: Bool = true, transition: ControlledTransition? = nil) {
|
||||
if updateFrame {
|
||||
self.frame = frame
|
||||
if let transition {
|
||||
let previousFrame = self.frame
|
||||
self.frame = frame
|
||||
|
||||
transition.legacyAnimator.transition.animatePositionAdditive(layer: self.layer, offset: CGPoint(x: previousFrame.minX - frame.minX, y: previousFrame.minY - frame.minY))
|
||||
} else {
|
||||
self.frame = frame
|
||||
}
|
||||
}
|
||||
if frame.maxY < 0.0 || frame.minY > containerSize.height {
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2201,11 +2201,11 @@ public final class ItemListPeerItemHeaderNode: ListViewItemHeaderNode, ItemListH
|
|||
self.actionTextNode.attributedText = NSAttributedString(string: actionTitle ?? "", font: titleFont, textColor: action == nil ? theme.list.sectionHeaderTextColor : theme.list.itemAccentColor)
|
||||
self.actionButton.isUserInteractionEnabled = self.action != nil
|
||||
if let (size, leftInset, rightInset) = self.validLayout {
|
||||
self.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
|
||||
self.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, leftInset, rightInset)
|
||||
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.snappedBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ public final class ListMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||
self.setNeedsLayout()
|
||||
}
|
||||
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: size.height + UIScreenPixel))
|
||||
self.headerNode.frame = headerFrame
|
||||
self.headerNode.updateLayout(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, ASScrollViewDel
|
|||
}
|
||||
|
||||
transition.updateFrame(node: dateHeaderNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: CGSize(width: layout.size.width, height: headerItem.height)))
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: .immediate)
|
||||
}
|
||||
|
||||
func updatePresentationThemeSettings(_ presentationThemeSettings: PresentationThemeSettings) {
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, ASScrollView
|
|||
}
|
||||
|
||||
transition.updateFrame(node: dateHeaderNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: CGSize(width: layout.size.width, height: headerItem.height)))
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: .immediate)
|
||||
}
|
||||
|
||||
func updatePresentationThemeSettings(_ presentationThemeSettings: PresentationThemeSettings) {
|
||||
|
|
|
|||
|
|
@ -696,7 +696,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}
|
||||
|
||||
transition.updateFrame(node: dateHeaderNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: CGSize(width: layout.size.width, height: headerItem.height)))
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: .immediate)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
|
|
|||
|
|
@ -228,7 +228,6 @@ private var declaredEncodables: Void = {
|
|||
declareEncodable(DerivedDataMessageAttribute.self, f: { DerivedDataMessageAttribute(decoder: $0) })
|
||||
declareEncodable(TelegramApplicationIcons.self, f: { TelegramApplicationIcons(decoder: $0) })
|
||||
declareEncodable(OutgoingQuickReplyMessageAttribute.self, f: { OutgoingQuickReplyMessageAttribute(decoder: $0) })
|
||||
declareEncodable(OutgoingSuggestedPostMessageAttribute.self, f: { OutgoingSuggestedPostMessageAttribute(decoder: $0) })
|
||||
declareEncodable(EffectMessageAttribute.self, f: { EffectMessageAttribute(decoder: $0) })
|
||||
declareEncodable(FactCheckMessageAttribute.self, f: { FactCheckMessageAttribute(decoder: $0) })
|
||||
declareEncodable(TelegramMediaPaidContent.self, f: { TelegramMediaPaidContent(decoder: $0) })
|
||||
|
|
|
|||
|
|
@ -236,8 +236,6 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt
|
|||
return true
|
||||
case _ as OutgoingQuickReplyMessageAttribute:
|
||||
return true
|
||||
case _ as OutgoingSuggestedPostMessageAttribute:
|
||||
return true
|
||||
case _ as EmbeddedMediaStickersMessageAttribute:
|
||||
return true
|
||||
case _ as EmojiSearchQueryMessageAttribute:
|
||||
|
|
@ -277,8 +275,6 @@ private func filterMessageAttributesForForwardedMessage(_ attributes: [MessageAt
|
|||
return true
|
||||
case _ as OutgoingQuickReplyMessageAttribute:
|
||||
return true
|
||||
case _ as OutgoingSuggestedPostMessageAttribute:
|
||||
return true
|
||||
case _ as ForwardOptionsMessageAttribute:
|
||||
return true
|
||||
case _ as SendAsMessageAttribute:
|
||||
|
|
@ -737,9 +733,6 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
|||
} else if attribute is OutgoingQuickReplyMessageAttribute {
|
||||
messageNamespace = Namespaces.Message.QuickReplyLocal
|
||||
effectiveTimestamp = 0
|
||||
} else if attribute is OutgoingSuggestedPostMessageAttribute {
|
||||
messageNamespace = Namespaces.Message.SuggestedPostLocal
|
||||
effectiveTimestamp = 0
|
||||
} else if let attribute = attribute as? SendAsMessageAttribute {
|
||||
if let peer = transaction.getPeer(attribute.peerId) {
|
||||
sendAsPeer = peer
|
||||
|
|
@ -776,9 +769,6 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
|||
if messageNamespace != Namespaces.Message.QuickReplyLocal {
|
||||
attributes.removeAll(where: { $0 is OutgoingQuickReplyMessageAttribute })
|
||||
}
|
||||
if messageNamespace != Namespaces.Message.SuggestedPostLocal {
|
||||
attributes.removeAll(where: { $0 is OutgoingSuggestedPostMessageAttribute })
|
||||
}
|
||||
|
||||
if let peer = peer as? TelegramChannel {
|
||||
switch peer.info {
|
||||
|
|
@ -1013,9 +1003,6 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
|||
} else if attribute is OutgoingQuickReplyMessageAttribute {
|
||||
messageNamespace = Namespaces.Message.QuickReplyLocal
|
||||
effectiveTimestamp = 0
|
||||
} else if attribute is OutgoingSuggestedPostMessageAttribute {
|
||||
messageNamespace = Namespaces.Message.SuggestedPostLocal
|
||||
effectiveTimestamp = 0
|
||||
} else if let attribute = attribute as? ReplyMessageAttribute {
|
||||
if let threadMessageId = attribute.threadMessageId {
|
||||
threadId = Int64(threadMessageId.id)
|
||||
|
|
@ -1048,9 +1035,6 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
|
|||
if messageNamespace != Namespaces.Message.QuickReplyLocal {
|
||||
attributes.removeAll(where: { $0 is OutgoingQuickReplyMessageAttribute })
|
||||
}
|
||||
if messageNamespace != Namespaces.Message.SuggestedPostLocal {
|
||||
attributes.removeAll(where: { $0 is OutgoingSuggestedPostMessageAttribute })
|
||||
}
|
||||
|
||||
let (tags, globalTags) = tagsForStoreMessage(incoming: false, attributes: attributes, media: sourceMessage.media, textEntities: entitiesAttribute?.entities, isPinned: false)
|
||||
|
||||
|
|
|
|||
|
|
@ -179,9 +179,6 @@ private func requestEditMessageInternal(accountPeerId: PeerId, postbox: Postbox,
|
|||
if messageId.namespace == Namespaces.Message.QuickReplyCloud {
|
||||
quickReplyShortcutId = Int32(clamping: message.threadId ?? 0)
|
||||
flags |= Int32(1 << 17)
|
||||
} else if messageId.namespace == Namespaces.Message.SuggestedPostLocal {
|
||||
//TODO:release
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: text, media: inputMedia, replyMarkup: nil, entities: apiEntities, scheduleDate: effectiveScheduleTime, quickReplyShortcutId: quickReplyShortcutId))
|
||||
|
|
|
|||
|
|
@ -72,8 +72,6 @@ private func fetchWebpage(account: Account, messageId: MessageId, threadId: Int6
|
|||
targetMessageNamespace = Namespaces.Message.ScheduledCloud
|
||||
} else if Namespaces.Message.allQuickReply.contains(messageId.namespace) {
|
||||
targetMessageNamespace = Namespaces.Message.QuickReplyCloud
|
||||
} else if Namespaces.Message.allSuggestedPost.contains(messageId.namespace) {
|
||||
targetMessageNamespace = Namespaces.Message.SuggestedPostCloud
|
||||
} else {
|
||||
targetMessageNamespace = Namespaces.Message.Cloud
|
||||
}
|
||||
|
|
@ -1073,10 +1071,6 @@ public final class AccountViewTracker {
|
|||
} else {
|
||||
fetchSignal = .never()
|
||||
}
|
||||
} else if let messageId = messageIds.first, messageId.namespace == Namespaces.Message.SuggestedPostCloud {
|
||||
//TODO:release
|
||||
assertionFailure()
|
||||
fetchSignal = .never()
|
||||
} else if peerIdAndThreadId.peerId.namespace == Namespaces.Peer.CloudUser || peerIdAndThreadId.peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
fetchSignal = account.network.request(Api.functions.messages.getMessages(id: messageIds.map { Api.InputMessage.inputMessageID(id: $0.id) }))
|
||||
} else if peerIdAndThreadId.peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
|
|
@ -2126,36 +2120,6 @@ public final class AccountViewTracker {
|
|||
}
|
||||
return signal
|
||||
}
|
||||
|
||||
public func postSuggestionsViewForLocation(peerId: EnginePeer.Id, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
guard let account = self.account else {
|
||||
return .never()
|
||||
}
|
||||
let chatLocation: ChatLocationInput = .peer(peerId: peerId, threadId: nil)
|
||||
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: .upperBound, ignoreMessagesInTimestampRange: nil, ignoreMessageIds: Set(), count: 200, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .just(Namespaces.Message.allSuggestedPost), orderStatistics: [], additionalData: additionalData)
|
||||
return withState(signal, { [weak self] () -> Int32 in
|
||||
if let strongSelf = self {
|
||||
return OSAtomicIncrement32(&strongSelf.nextViewId)
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}, next: { [weak self] next, viewId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.queue.async {
|
||||
let (messageIds, localWebpages) = pendingWebpages(entries: next.0.entries)
|
||||
strongSelf.updatePendingWebpages(viewId: viewId, threadId: nil, messageIds: messageIds, localWebpages: localWebpages)
|
||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: next.0, location: chatLocation)
|
||||
}
|
||||
}
|
||||
}, disposed: { [weak self] viewId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.queue.async {
|
||||
strongSelf.updatePendingWebpages(viewId: viewId, threadId: nil, messageIds: [], localWebpages: [:])
|
||||
strongSelf.historyViewStateValidationContexts.updateView(id: viewId, view: nil, location: nil)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil, ignoreMessageIds: Set<MessageId> = Set(), count: Int, tag: HistoryViewInputTag? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = [], useRootInterfaceStateForThread: Bool = false) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
|
||||
if let account = self.account {
|
||||
|
|
|
|||
|
|
@ -198,14 +198,6 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
}
|
||||
}
|
||||
}
|
||||
if Namespaces.Message.allSuggestedPost.contains(message.id.namespace) {
|
||||
for i in 0 ..< updatedAttributes.count {
|
||||
if updatedAttributes[i] is OutgoingSuggestedPostMessageAttribute {
|
||||
updatedAttributes.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attributes = updatedAttributes
|
||||
text = currentMessage.text
|
||||
|
|
@ -228,8 +220,6 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
}
|
||||
if Namespaces.Message.allQuickReply.contains(message.id.namespace) {
|
||||
namespace = Namespaces.Message.QuickReplyCloud
|
||||
} else if Namespaces.Message.allSuggestedPost.contains(message.id.namespace) {
|
||||
namespace = Namespaces.Message.SuggestedPostCloud
|
||||
} else if let updatedTimestamp = updatedTimestamp {
|
||||
if attributes.contains(where: { $0 is PendingProcessingMessageAttribute }) {
|
||||
namespace = Namespaces.Message.ScheduledCloud
|
||||
|
|
@ -253,8 +243,6 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
|||
if let threadId {
|
||||
_internal_applySentQuickReplyMessage(transaction: transaction, shortcut: attribute.shortcut, quickReplyId: Int32(clamping: threadId))
|
||||
}
|
||||
} else if attribute is OutgoingSuggestedPostMessageAttribute {
|
||||
//TODO:release
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,8 +397,6 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage
|
|||
var namespace = Namespaces.Message.Cloud
|
||||
if Namespaces.Message.allQuickReply.contains(messages[0].id.namespace) {
|
||||
namespace = Namespaces.Message.QuickReplyCloud
|
||||
} else if Namespaces.Message.allSuggestedPost.contains(messages[0].id.namespace) {
|
||||
namespace = Namespaces.Message.SuggestedPostCloud
|
||||
} else if let message = messages.first, let apiMessage = result.messages.first {
|
||||
if message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
||||
namespace = Namespaces.Message.ScheduledCloud
|
||||
|
|
@ -488,8 +474,6 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage
|
|||
if let threadId = updatedMessage.threadId {
|
||||
_internal_applySentQuickReplyMessage(transaction: transaction, shortcut: attribute.shortcut, quickReplyId: Int32(clamping: threadId))
|
||||
}
|
||||
} else if attribute is OutgoingSuggestedPostMessageAttribute {
|
||||
//TODO:release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,25 +35,6 @@ func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId,
|
|||
} else if case .forEveryone = type {
|
||||
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: .max), threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type))
|
||||
}
|
||||
} else if type == .suggestedPostMessages {
|
||||
var messageIds: [MessageId] = []
|
||||
transaction.withAllMessages(peerId: peerId, namespace: Namespaces.Message.SuggestedPostCloud) { message -> Bool in
|
||||
messageIds.append(message.id)
|
||||
return true
|
||||
}
|
||||
cloudChatAddRemoveMessagesOperation(transaction: transaction, peerId: peerId, threadId: threadId, messageIds: messageIds, type: .forLocalPeer)
|
||||
|
||||
let topMessageId: MessageId?
|
||||
if let explicitTopMessageId = explicitTopMessageId {
|
||||
topMessageId = explicitTopMessageId
|
||||
} else {
|
||||
topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.SuggestedPostCloud)
|
||||
}
|
||||
if let topMessageId = topMessageId {
|
||||
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type))
|
||||
} else if case .forEveryone = type {
|
||||
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: .max), threadId: threadId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type))
|
||||
}
|
||||
} else {
|
||||
let topMessageId: MessageId?
|
||||
if let explicitTopMessageId = explicitTopMessageId {
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@ func managedCloudChatRemoveMessagesOperations(postbox: Postbox, network: Network
|
|||
private func removeMessages(postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatRemoveMessagesOperation) -> Signal<Void, NoError> {
|
||||
var isScheduled = false
|
||||
var isQuickReply = false
|
||||
var isSuggestedPost = false
|
||||
for id in operation.messageIds {
|
||||
if id.namespace == Namespaces.Message.ScheduledCloud {
|
||||
isScheduled = true
|
||||
|
|
@ -136,9 +135,6 @@ private func removeMessages(postbox: Postbox, network: Network, stateManager: Ac
|
|||
} else if id.namespace == Namespaces.Message.QuickReplyCloud {
|
||||
isQuickReply = true
|
||||
break
|
||||
} else if id.namespace == Namespaces.Message.SuggestedPostCloud {
|
||||
isSuggestedPost = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,10 +190,6 @@ private func removeMessages(postbox: Postbox, network: Network, stateManager: Ac
|
|||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} else if isSuggestedPost {
|
||||
//TODO:release
|
||||
assertionFailure()
|
||||
return .complete()
|
||||
} else if peer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let inputChannel = apiInputChannel(peer) {
|
||||
var signal: Signal<Void, NoError> = .complete()
|
||||
|
|
|
|||
|
|
@ -858,15 +858,11 @@ public final class PendingMessageManager {
|
|||
var videoTimestamp: Int32?
|
||||
var sendAsPeerId: PeerId?
|
||||
var quickReply: OutgoingQuickReplyMessageAttribute?
|
||||
var suggestedPost: OutgoingSuggestedPostMessageAttribute?
|
||||
var messageEffect: EffectMessageAttribute?
|
||||
var allowPaidStars: Int64?
|
||||
|
||||
var flags: Int32 = 0
|
||||
|
||||
//TODO:release
|
||||
let _ = suggestedPost
|
||||
|
||||
for attribute in messages[0].0.attributes {
|
||||
if let replyAttribute = attribute as? ReplyMessageAttribute {
|
||||
replyMessageId = replyAttribute.messageId.id
|
||||
|
|
@ -894,8 +890,6 @@ public final class PendingMessageManager {
|
|||
sendAsPeerId = attribute.peerId
|
||||
} else if let attribute = attribute as? OutgoingQuickReplyMessageAttribute {
|
||||
quickReply = attribute
|
||||
} else if let attribute = attribute as? OutgoingSuggestedPostMessageAttribute {
|
||||
suggestedPost = attribute
|
||||
} else if let attribute = attribute as? EffectMessageAttribute {
|
||||
messageEffect = attribute
|
||||
} else if let _ = attribute as? InvertMediaMessageAttribute {
|
||||
|
|
@ -1846,8 +1840,6 @@ public final class PendingMessageManager {
|
|||
targetNamespace = Namespaces.Message.ScheduledCloud
|
||||
} else if Namespaces.Message.allQuickReply.contains(message.id.namespace) {
|
||||
targetNamespace = Namespaces.Message.QuickReplyCloud
|
||||
} else if Namespaces.Message.allSuggestedPost.contains(message.id.namespace) {
|
||||
targetNamespace = Namespaces.Message.SuggestedPostCloud
|
||||
} else {
|
||||
targetNamespace = Namespaces.Message.Cloud
|
||||
}
|
||||
|
|
@ -1899,8 +1891,6 @@ public final class PendingMessageManager {
|
|||
if let message = messages.first {
|
||||
if message.id.namespace == Namespaces.Message.QuickReplyLocal {
|
||||
namespace = Namespaces.Message.QuickReplyCloud
|
||||
} else if Namespaces.Message.allSuggestedPost.contains(message.id.namespace) {
|
||||
namespace = Namespaces.Message.SuggestedPostCloud
|
||||
} else if let apiMessage = result.messages.first, message.scheduleTime != nil && message.scheduleTime == apiMessage.timestamp {
|
||||
namespace = Namespaces.Message.ScheduledCloud
|
||||
} else if let apiMessage = result.messages.first, case let .message(_, flags2, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _) = apiMessage, (flags2 & (1 << 4)) != 0 {
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
import Foundation
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
|
||||
public final class OutgoingSuggestedPostMessageAttribute: Equatable, MessageAttribute {
|
||||
public let price: StarsAmount
|
||||
public let timestamp: Int32?
|
||||
|
||||
public init(price: StarsAmount, timestamp: Int32?) {
|
||||
self.price = price
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.price = decoder.decodeCodable(StarsAmount.self, forKey: "s") ?? StarsAmount(value: 0, nanos: 0)
|
||||
self.timestamp = decoder.decodeOptionalInt32ForKey("t")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeCodable(self.price, forKey: "s")
|
||||
if let timestamp = self.timestamp {
|
||||
encoder.encodeInt32(timestamp, forKey: "t")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "t")
|
||||
}
|
||||
}
|
||||
|
||||
public static func ==(lhs: OutgoingSuggestedPostMessageAttribute, rhs: OutgoingSuggestedPostMessageAttribute) -> Bool {
|
||||
if lhs.price != rhs.price {
|
||||
return false
|
||||
}
|
||||
if lhs.timestamp != rhs.timestamp {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,6 @@ public enum CloudChatClearHistoryType: Int32 {
|
|||
case forEveryone
|
||||
case scheduledMessages
|
||||
case quickReplyMessages
|
||||
case suggestedPostMessages
|
||||
}
|
||||
|
||||
public enum InteractiveHistoryClearingType: Int32 {
|
||||
|
|
|
|||
|
|
@ -10,13 +10,10 @@ public struct Namespaces {
|
|||
public static let ScheduledLocal: Int32 = 4
|
||||
public static let QuickReplyCloud: Int32 = 5
|
||||
public static let QuickReplyLocal: Int32 = 6
|
||||
public static let SuggestedPostLocal: Int32 = 7
|
||||
public static let SuggestedPostCloud: Int32 = 8
|
||||
|
||||
public static let allScheduled: Set<Int32> = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal])
|
||||
public static let allQuickReply: Set<Int32> = Set([Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal])
|
||||
public static let allSuggestedPost: Set<Int32> = Set([Namespaces.Message.SuggestedPostCloud, Namespaces.Message.SuggestedPostLocal])
|
||||
public static let allNonRegular: Set<Int32> = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal, Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal, Namespaces.Message.SuggestedPostCloud, Namespaces.Message.SuggestedPostLocal])
|
||||
public static let allNonRegular: Set<Int32> = Set([Namespaces.Message.ScheduledCloud, Namespaces.Message.ScheduledLocal, Namespaces.Message.QuickReplyCloud, Namespaces.Message.QuickReplyLocal])
|
||||
public static let allLocal: [Int32] = [
|
||||
Namespaces.Message.Local,
|
||||
Namespaces.Message.SecretIncoming,
|
||||
|
|
|
|||
|
|
@ -701,9 +701,6 @@ func fetchRemoteMessage(accountPeerId: PeerId, postbox: Postbox, source: FetchMe
|
|||
} else {
|
||||
signal = .never()
|
||||
}
|
||||
} else if id.namespace == Namespaces.Message.SuggestedPostCloud {
|
||||
//TODO:release
|
||||
signal = .never()
|
||||
} else if id.peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let channel = peer.inputChannel {
|
||||
signal = source.request(Api.functions.channels.getMessages(channel: channel, id: [Api.InputMessage.inputMessageID(id: id.id)]))
|
||||
|
|
|
|||
|
|
@ -338,6 +338,8 @@ public enum PresentationResourceKey: Int32 {
|
|||
case expandSmallDownArrowImage
|
||||
|
||||
case callListCallIcon
|
||||
|
||||
case chatFreeNavigateToThreadButtonIcon
|
||||
}
|
||||
|
||||
public enum ChatExpiredStoryIndicatorType: Hashable {
|
||||
|
|
|
|||
|
|
@ -1105,7 +1105,24 @@ public struct PresentationResourcesChat {
|
|||
|
||||
public static func chatFreeNavigateButtonIcon(_ theme: PresentationTheme, wallpaper: TelegramWallpaper) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatFreeNavigateButtonIcon.rawValue, { _ in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/NavigateToMessageIcon"), color: bubbleVariableColor(variableColor: theme.chat.message.shareButtonForegroundColor, wallpaper: wallpaper))
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: bubbleVariableColor(variableColor: theme.chat.message.shareButtonForegroundColor, wallpaper: wallpaper))
|
||||
})
|
||||
}
|
||||
|
||||
public static func chatFreeNavigateToThreadButtonIcon(_ theme: PresentationTheme, wallpaper: TelegramWallpaper) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatFreeNavigateToThreadButtonIcon.rawValue, { _ in
|
||||
return generateImage(CGSize(width: 8.0, height: 14.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setStrokeColor(bubbleVariableColor(variableColor: theme.chat.message.shareButtonForegroundColor, wallpaper: wallpaper).cgColor)
|
||||
context.setLineWidth(1.66)
|
||||
context.setLineCap(.round)
|
||||
context.setLineJoin(.round)
|
||||
context.beginPath()
|
||||
context.move(to: CGPoint(x: 1.0, y: 1.0))
|
||||
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height / 2.0))
|
||||
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
|
||||
context.strokePath()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -781,10 +781,6 @@ private final class ChatEmptyNodeCloudChatContent: ASDisplayNode, ChatEmptyNodeC
|
|||
insets.top = -9.0
|
||||
imageSpacing = 4.0
|
||||
titleSpacing = 5.0
|
||||
case .postSuggestions:
|
||||
insets.top = 10.0
|
||||
imageSpacing = 5.0
|
||||
titleSpacing = 5.0
|
||||
case .hashTagSearch:
|
||||
break
|
||||
}
|
||||
|
|
@ -846,7 +842,7 @@ private final class ChatEmptyNodeCloudChatContent: ASDisplayNode, ChatEmptyNodeC
|
|||
}
|
||||
|
||||
self.businessLink = link
|
||||
case .hashTagSearch, .postSuggestions:
|
||||
case .hashTagSearch:
|
||||
titleString = ""
|
||||
strings = []
|
||||
}
|
||||
|
|
@ -1303,10 +1299,7 @@ public final class ChatEmptyNodePremiumRequiredChatContent: ASDisplayNode, ChatE
|
|||
let starsString = presentationStringsFormattedNumber(Int32(amount), interfaceState.dateTimeFormat.groupingSeparator)
|
||||
let rawText: String
|
||||
|
||||
if case let .customChatContents(customChatContents) = interfaceState.subject, case .postSuggestions = customChatContents.kind {
|
||||
//TODO:localize
|
||||
rawText = "\(peerTitle) charges $ \(starsString) per message suggestion."
|
||||
} else if self.isPremiumDisabled {
|
||||
if self.isPremiumDisabled {
|
||||
rawText = interfaceState.strings.Chat_EmptyStatePaidMessagingDisabled_Text(peerTitle, " $ \(starsString)").string
|
||||
} else {
|
||||
rawText = interfaceState.strings.Chat_EmptyStatePaidMessaging_Text(peerTitle, " $ \(starsString)").string
|
||||
|
|
@ -1369,14 +1362,7 @@ public final class ChatEmptyNodePremiumRequiredChatContent: ASDisplayNode, ChatE
|
|||
contentsHeight += iconTextSpacing
|
||||
|
||||
let iconComponent: AnyComponent<Empty>
|
||||
if case let .customChatContents(customChatContents) = interfaceState.subject, case .postSuggestions = customChatContents.kind {
|
||||
iconComponent = AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Chat/Empty Chat/PostSuggestions",
|
||||
tintColor: serviceColor.primaryText
|
||||
)
|
||||
)
|
||||
} else {
|
||||
do {
|
||||
iconComponent = AnyComponent(
|
||||
LottieComponent(
|
||||
content: LottieComponent.AppBundleContent(name: "PremiumRequired"),
|
||||
|
|
@ -1447,7 +1433,6 @@ private enum ChatEmptyNodeContentType: Equatable {
|
|||
case topic
|
||||
case premiumRequired
|
||||
case starsRequired(Int64)
|
||||
case postSuggestions(Int64)
|
||||
}
|
||||
|
||||
private final class EmptyAttachedDescriptionNode: HighlightTrackingButtonNode {
|
||||
|
|
@ -1816,12 +1801,8 @@ public final class ChatEmptyNode: ASDisplayNode {
|
|||
case let .emptyChat(emptyType):
|
||||
if case .customGreeting = emptyType {
|
||||
contentType = .greeting
|
||||
} else if case let .customChatContents(customChatContents) = interfaceState.subject {
|
||||
if case let .postSuggestions(postSuggestions) = customChatContents.kind {
|
||||
contentType = .postSuggestions(postSuggestions.value)
|
||||
} else {
|
||||
contentType = .cloud
|
||||
}
|
||||
} else if case .customChatContents = interfaceState.subject {
|
||||
contentType = .cloud
|
||||
} else if case .replyThread = interfaceState.chatLocation {
|
||||
if case .topic = emptyType {
|
||||
contentType = .topic
|
||||
|
|
@ -1908,8 +1889,6 @@ public final class ChatEmptyNode: ASDisplayNode {
|
|||
node = ChatEmptyNodePremiumRequiredChatContent(context: self.context, interaction: self.interaction, stars: nil)
|
||||
case let .starsRequired(stars):
|
||||
node = ChatEmptyNodePremiumRequiredChatContent(context: self.context, interaction: self.interaction, stars: stars)
|
||||
case let .postSuggestions(stars):
|
||||
node = ChatEmptyNodePremiumRequiredChatContent(context: self.context, interaction: self.interaction, stars: stars)
|
||||
}
|
||||
self.content = (contentType, node)
|
||||
self.addSubnode(node)
|
||||
|
|
@ -1921,7 +1900,7 @@ public final class ChatEmptyNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
switch contentType {
|
||||
case .peerNearby, .greeting, .premiumRequired, .starsRequired, .cloud, .postSuggestions:
|
||||
case .peerNearby, .greeting, .premiumRequired, .starsRequired, .cloud:
|
||||
self.isUserInteractionEnabled = true
|
||||
default:
|
||||
self.isUserInteractionEnabled = false
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ swift_library(
|
|||
"//submodules/TelegramAnimatedStickerNode",
|
||||
"//submodules/TelegramUI/Components/LottieMetal",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
"//submodules/AvatarNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import ChatMessageTransitionNode
|
|||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import LottieMetal
|
||||
import AvatarNode
|
||||
|
||||
private struct BubbleItemAttributes {
|
||||
var index: Int?
|
||||
|
|
@ -629,10 +630,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
|
||||
private var swipeToReplyFeedback: HapticFeedback?
|
||||
|
||||
private var nameAvatarNode: AvatarNode?
|
||||
private var nameNode: TextNode?
|
||||
private var nameButtonNode: HighlightTrackingButtonNode?
|
||||
private var nameHighlightNode: ASImageNode?
|
||||
private var viaMeasureNode: TextNode?
|
||||
private var nameNavigateButton: NameNavigateButton?
|
||||
|
||||
private var adminBadgeNode: TextNode?
|
||||
private var credibilityIconView: ComponentHostView<Empty>?
|
||||
|
|
@ -1479,6 +1482,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) {
|
||||
let isPreview = item.presentationData.isPreview
|
||||
let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: isSelected)
|
||||
let isSidePanelOpen = item.controllerInteraction.isSidePanelOpen
|
||||
|
||||
let fontSize = floor(item.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0)
|
||||
let nameFont = Font.semibold(fontSize)
|
||||
|
|
@ -1579,6 +1583,18 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
if let forwardInfo = firstMessage.forwardInfo, forwardInfo.psaType != nil {
|
||||
displayAuthorInfo = false
|
||||
}
|
||||
|
||||
var isMonoForum = false
|
||||
if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel {
|
||||
if peer.isMonoForum {
|
||||
isMonoForum = true
|
||||
}
|
||||
}
|
||||
if isMonoForum {
|
||||
if case .replyThread = item.chatLocation {
|
||||
displayAuthorInfo = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info {
|
||||
|
|
@ -1605,9 +1621,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
if !peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
|
||||
if peerId.isGroupOrChannel && effectiveAuthor != nil {
|
||||
var isBroadcastChannel = false
|
||||
if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case .broadcast = peer.info {
|
||||
isBroadcastChannel = true
|
||||
allowFullWidth = true
|
||||
var isMonoForum = false
|
||||
if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel {
|
||||
if case .broadcast = peer.info {
|
||||
isBroadcastChannel = true
|
||||
allowFullWidth = true
|
||||
} else if peer.isMonoForum {
|
||||
isMonoForum = true
|
||||
}
|
||||
}
|
||||
|
||||
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.isChannelPost, replyThreadMessage.effectiveTopId == firstMessage.id {
|
||||
|
|
@ -1621,6 +1642,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
} else if overrideEffectiveAuthor {
|
||||
hasAvatar = true
|
||||
}
|
||||
|
||||
if isMonoForum {
|
||||
if case .replyThread = item.chatLocation {
|
||||
hasAvatar = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if incoming {
|
||||
hasAvatar = true
|
||||
|
|
@ -1651,10 +1678,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
}
|
||||
|
||||
avatarInset = hasAvatar ? layoutConstants.avatarDiameter : 0.0
|
||||
if isSidePanelOpen {
|
||||
avatarInset = 0.0
|
||||
}
|
||||
|
||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||
|
||||
var needsShareButton = false
|
||||
|
||||
if incoming, case let .customChatContents(contents) = item.associatedData.subject, case .hashTagSearch = contents.kind {
|
||||
needsShareButton = true
|
||||
} else if case .pinnedMessages = item.associatedData.subject {
|
||||
|
|
@ -1676,6 +1707,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
}
|
||||
} else if item.message.id.peerId.isRepliesOrVerificationCodes {
|
||||
needsShareButton = false
|
||||
} else if let channel = item.content.firstMessage.peers[item.content.firstMessage.id.peerId] as? TelegramChannel, channel.isMonoForum, channel.adminRights != nil, case .peer = item.chatLocation {
|
||||
if incoming {
|
||||
needsShareButton = true
|
||||
}
|
||||
} else if incoming {
|
||||
if let _ = sourceReference {
|
||||
needsShareButton = true
|
||||
|
|
@ -1755,14 +1790,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
var tmpWidth: CGFloat
|
||||
if allowFullWidth {
|
||||
tmpWidth = baseWidth
|
||||
if needsShareButton || isAd {
|
||||
if (needsShareButton && !isSidePanelOpen) || isAd {
|
||||
tmpWidth -= 45.0
|
||||
} else {
|
||||
tmpWidth -= 4.0
|
||||
}
|
||||
} else {
|
||||
tmpWidth = layoutConstants.bubble.maximumWidthFill.widthFor(baseWidth)
|
||||
if (needsShareButton || isAd) && tmpWidth + 32.0 > baseWidth {
|
||||
if ((needsShareButton && !isSidePanelOpen) || isAd) && tmpWidth + 32.0 > baseWidth {
|
||||
tmpWidth = baseWidth - 32.0
|
||||
}
|
||||
}
|
||||
|
|
@ -1777,7 +1812,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
let (contentNodeMessagesAndClasses, needSeparateContainers, needReactions) = contentNodeMessagesAndClassesForItem(item)
|
||||
|
||||
var maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset * 3.0 - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset)
|
||||
if needsShareButton {
|
||||
if (needsShareButton && !isSidePanelOpen) {
|
||||
maximumContentWidth -= 10.0
|
||||
}
|
||||
|
||||
|
|
@ -2387,6 +2422,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
var unlockButtonSizeApply: (CGSize, (Bool) -> ChatMessageUnlockMediaNode?) = (CGSize(), { _ in nil })
|
||||
var mediaInfoSizeApply: (CGSize, (Bool) -> ChatMessageStarsMediaInfoNode?) = (CGSize(), { _ in nil })
|
||||
|
||||
var hasTitleAvatar = false
|
||||
|
||||
if displayHeader {
|
||||
let bubbleWidthInsets: CGFloat = mosaicRange == nil ? layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right : 0.0
|
||||
if authorNameString != nil || inlineBotNameString != nil {
|
||||
|
|
@ -2394,6 +2431,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
headerSize.height += 7.0
|
||||
}
|
||||
|
||||
if isSidePanelOpen {
|
||||
hasTitleAvatar = true
|
||||
}
|
||||
|
||||
let inlineBotNameColor = messageTheme.accentTextColor
|
||||
|
||||
let attributedString: NSAttributedString
|
||||
|
|
@ -2493,8 +2534,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
}
|
||||
|
||||
nameNodeOriginY = headerSize.height
|
||||
|
||||
var nameAvatarSpaceWidth: CGFloat = 0.0
|
||||
if hasTitleAvatar {
|
||||
headerSize.height += 12.0
|
||||
nameAvatarSpaceWidth += 26.0 + 5.0 + 4.0 + 26.0
|
||||
nameNodeOriginY += 5.0
|
||||
}
|
||||
|
||||
headerSize.width = max(headerSize.width, nameNodeSizeApply.0.width + 8.0 + adminBadgeSizeAndApply.0.size.width + credibilityIconWidth + boostBadgeWidth + closeButtonWidth + bubbleWidthInsets)
|
||||
headerSize.width = max(headerSize.width, nameAvatarSpaceWidth + nameNodeSizeApply.0.width + 8.0 + adminBadgeSizeAndApply.0.size.width + credibilityIconWidth + boostBadgeWidth + closeButtonWidth + bubbleWidthInsets)
|
||||
headerSize.height += nameNodeSizeApply.0.height
|
||||
}
|
||||
|
||||
|
|
@ -3119,13 +3167,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
}
|
||||
|
||||
var suggestedPostInfoNodeLayout: (CGSize, () -> ChatMessageSuggestedPostInfoNode)?
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? OutgoingSuggestedPostMessageAttribute {
|
||||
let _ = attribute
|
||||
let suggestedPostInfoNodeLayoutValue = makeSuggestedPostInfoNodeLayout(item, baseWidth)
|
||||
suggestedPostInfoNodeLayout = suggestedPostInfoNodeLayoutValue
|
||||
}
|
||||
}
|
||||
suggestedPostInfoNodeLayout = nil
|
||||
|
||||
if let suggestedPostInfoNodeLayout {
|
||||
additionalTopHeight += 4.0 + suggestedPostInfoNodeLayout.0.height + 8.0
|
||||
|
|
@ -3229,6 +3271,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
viaWidth: viaWidth,
|
||||
contentOrigin: contentOrigin,
|
||||
nameNodeOriginY: nameNodeOriginY + detachedContentNodesHeight + additionalTopHeight,
|
||||
hasTitleAvatar: hasTitleAvatar,
|
||||
authorNameColor: authorNameColor,
|
||||
layoutConstants: layoutConstants,
|
||||
currentCredibilityIcon: currentCredibilityIcon,
|
||||
|
|
@ -3259,7 +3302,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
hidesHeaders: hidesHeaders,
|
||||
disablesComments: disablesComments,
|
||||
suggestedPostInfoNodeLayout: suggestedPostInfoNodeLayout,
|
||||
alignment: alignment
|
||||
alignment: alignment,
|
||||
isSidePanelOpen: isSidePanelOpen
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
@ -3290,6 +3334,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
viaWidth: CGFloat,
|
||||
contentOrigin: CGPoint,
|
||||
nameNodeOriginY: CGFloat,
|
||||
hasTitleAvatar: Bool,
|
||||
authorNameColor: UIColor?,
|
||||
layoutConstants: ChatMessageItemLayoutConstants,
|
||||
currentCredibilityIcon: (EmojiStatusComponent.Content, UIColor?)?,
|
||||
|
|
@ -3320,7 +3365,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
hidesHeaders: Bool,
|
||||
disablesComments: Bool,
|
||||
suggestedPostInfoNodeLayout: (CGSize, () -> ChatMessageSuggestedPostInfoNode)?,
|
||||
alignment: ChatMessageBubbleContentAlignment
|
||||
alignment: ChatMessageBubbleContentAlignment,
|
||||
isSidePanelOpen: Bool
|
||||
) -> Void {
|
||||
guard let strongSelf = selfReference.value else {
|
||||
return
|
||||
|
|
@ -3418,9 +3464,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
suggestedPostInfoNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let avatarOffset = avatarOffset {
|
||||
if let avatarOffset {
|
||||
strongSelf.updateAttachedAvatarNodeOffset(offset: avatarOffset, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
strongSelf.updateAttachedAvatarNodeIsHidden(isHidden: isSidePanelOpen, transition: animation.transition)
|
||||
|
||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||
if isFailed {
|
||||
|
|
@ -3458,8 +3505,91 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
strongSelf.nameNode = nameNode
|
||||
nameNode.displaysAsynchronously = !item.presentationData.isPreview && !item.presentationData.theme.theme.forceSync
|
||||
|
||||
//let previousNameNodeFrame = nameNode.frame
|
||||
let nameNodeFrame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + nameNodeOriginY), size: nameNodeSizeApply.0)
|
||||
let previousNameNodeFrame = nameNode.frame
|
||||
|
||||
var nameNodeFrame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + nameNodeOriginY), size: nameNodeSizeApply.0)
|
||||
|
||||
var nameNavigateButtonOffset: CGFloat = currentCredibilityIcon == nil ? 4.0 : 28.0
|
||||
nameNavigateButtonOffset += 34.0
|
||||
|
||||
if hasTitleAvatar {
|
||||
let nameAvatarNode: AvatarNode
|
||||
var animateNameAvatar = true
|
||||
if let current = strongSelf.nameAvatarNode {
|
||||
nameAvatarNode = current
|
||||
} else {
|
||||
animateNameAvatar = false
|
||||
nameAvatarNode = AvatarNode(font: avatarPlaceholderFont(size: 8.0))
|
||||
strongSelf.nameAvatarNode = nameAvatarNode
|
||||
strongSelf.clippingNode.addSubnode(nameAvatarNode)
|
||||
}
|
||||
|
||||
let nameNavigateButton: NameNavigateButton
|
||||
if let current = strongSelf.nameNavigateButton {
|
||||
nameNavigateButton = current
|
||||
} else {
|
||||
nameNavigateButton = NameNavigateButton(frame: CGRect())
|
||||
strongSelf.nameNavigateButton = nameNavigateButton
|
||||
strongSelf.clippingNode.view.addSubview(nameNavigateButton)
|
||||
nameNavigateButton.action = { [weak strongSelf] in
|
||||
guard let strongSelf, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.updateChatLocationThread(item.content.firstMessage.threadId)
|
||||
}
|
||||
}
|
||||
|
||||
let nameAvatarFrame = CGRect(origin: CGPoint(x: nameNodeFrame.minX, y: nameNodeFrame.minY - 4.0), size: CGSize(width: 26.0, height: 26.0))
|
||||
let nameNavigateFrame = CGRect(origin: CGPoint(x: nameNodeFrame.maxX + 4.0 + nameNavigateButtonOffset, y: nameNodeFrame.minY - 4.0), size: CGSize(width: 26.0, height: 26.0))
|
||||
|
||||
if let peer = item.content.firstMessage.author, peer.smallProfileImage != nil {
|
||||
nameAvatarNode.setPeerV2(context: item.context, theme: item.presentationData.theme.theme, peer: EnginePeer(peer), displayDimensions: nameAvatarFrame.size)
|
||||
} else {
|
||||
nameAvatarNode.setPeer(context: item.context, theme: item.presentationData.theme.theme, peer: item.content.firstMessage.author.flatMap(EnginePeer.init), displayDimensions: nameAvatarFrame.size)
|
||||
}
|
||||
nameAvatarNode.updateSize(size: nameAvatarFrame.size)
|
||||
|
||||
nameNavigateButton.update(size: nameNavigateFrame.size, color: authorNameColor ?? item.presentationData.theme.theme.chat.message.incoming.accentTextColor)
|
||||
|
||||
if animateNameAvatar {
|
||||
animation.animator.updateFrame(layer: nameAvatarNode.layer, frame: nameAvatarFrame, completion: nil)
|
||||
animation.animator.updateFrame(layer: nameNavigateButton.layer, frame: nameNavigateFrame, completion: nil)
|
||||
} else {
|
||||
nameAvatarNode.frame = CGRect(origin: CGPoint(x: previousNameNodeFrame.minX - 26.0 * 0.5, y: previousNameNodeFrame.minY - 4.0), size: CGSize(width: 26.0, height: 26.0))
|
||||
animation.animator.updateFrame(layer: nameAvatarNode.layer, frame: nameAvatarFrame, completion: nil)
|
||||
if animation.isAnimated {
|
||||
animation.transition.animateTransformScale(view: nameAvatarNode.view, from: 0.001)
|
||||
nameAvatarNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
}
|
||||
|
||||
nameNavigateButton.frame = CGRect(origin: CGPoint(x: previousNameNodeFrame.maxX + nameNavigateButtonOffset - 26.0 * 0.5, y: previousNameNodeFrame.minY - 4.0), size: CGSize(width: 26.0, height: 26.0))
|
||||
animation.animator.updateFrame(layer: nameNavigateButton.layer, frame: nameNavigateFrame, completion: nil)
|
||||
if animation.isAnimated {
|
||||
animation.transition.animateTransformScale(view: nameNavigateButton, from: 0.001)
|
||||
nameNavigateButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
nameNodeFrame.origin.x += 26.0 + 5.0
|
||||
} else {
|
||||
if let nameAvatarNode = strongSelf.nameAvatarNode {
|
||||
strongSelf.nameAvatarNode = nil
|
||||
nameAvatarNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak nameAvatarNode] _ in
|
||||
nameAvatarNode?.removeFromSupernode()
|
||||
})
|
||||
animation.animator.updateFrame(layer: nameAvatarNode.layer, frame: CGRect(origin: CGPoint(x: nameNodeFrame.minX - 26.0 * 0.5, y: nameNodeFrame.minY - 4.0), size: CGSize(width: 26.0, height: 26.0)), completion: nil)
|
||||
animation.transition.updateTransformScale(node: nameAvatarNode, scale: CGPoint(x: 0.001, y: 0.001))
|
||||
}
|
||||
if let nameNavigateButton = strongSelf.nameNavigateButton {
|
||||
strongSelf.nameNavigateButton = nil
|
||||
nameNavigateButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak nameNavigateButton] _ in
|
||||
nameNavigateButton?.removeFromSuperview()
|
||||
})
|
||||
animation.animator.updateFrame(layer: nameNavigateButton.layer, frame: CGRect(origin: CGPoint(x: nameNodeFrame.maxX + nameNavigateButtonOffset - 26.0 * 0.5, y: nameNodeFrame.minY - 4.0), size: CGSize(width: 26.0, height: 26.0)), completion: nil)
|
||||
animation.transition.updateTransformScale(layer: nameNavigateButton.layer, scale: CGPoint(x: 0.001, y: 0.001))
|
||||
}
|
||||
}
|
||||
|
||||
if nameNode.supernode == nil {
|
||||
if !nameNode.isNodeLoaded {
|
||||
nameNode.isUserInteractionEnabled = false
|
||||
|
|
@ -3516,9 +3646,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
|
||||
if let (currentCredibilityIcon, currentParticleColor) = currentCredibilityIcon {
|
||||
let credibilityIconView: ComponentHostView<Empty>
|
||||
var animateCredibilityIconFrame = true
|
||||
if let current = strongSelf.credibilityIconView {
|
||||
credibilityIconView = current
|
||||
} else {
|
||||
animateCredibilityIconFrame = false
|
||||
credibilityIconView = ComponentHostView<Empty>()
|
||||
credibilityIconView.isUserInteractionEnabled = false
|
||||
strongSelf.credibilityIconView = credibilityIconView
|
||||
|
|
@ -3549,7 +3681,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
)
|
||||
|
||||
let credibilityIconFrame = CGRect(origin: CGPoint(x: nameNode.frame.maxX + 3.0, y: nameNode.frame.minY + floor((nameNode.bounds.height - credibilityIconSize.height) / 2.0)), size: credibilityIconSize)
|
||||
credibilityIconView.frame = credibilityIconFrame
|
||||
if !animateCredibilityIconFrame {
|
||||
credibilityIconView.frame = CGRect(origin: CGPoint(x: previousNameNodeFrame.maxX + 3.0, y: previousNameNodeFrame.minY + floor((previousNameNodeFrame.height - credibilityIconSize.height) / 2.0)), size: credibilityIconSize)
|
||||
}
|
||||
animation.animator.updateFrame(layer: credibilityIconView.layer, frame: credibilityIconFrame, completion: nil)
|
||||
|
||||
let credibilityButtonNode: HighlightTrackingButtonNode
|
||||
let credibilityHighlightNode: ASImageNode
|
||||
|
|
@ -3780,6 +3915,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
}
|
||||
} else {
|
||||
if animation.isAnimated {
|
||||
if let nameAvatarNode = strongSelf.nameAvatarNode {
|
||||
strongSelf.nameAvatarNode = nil
|
||||
nameAvatarNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak nameAvatarNode] _ in
|
||||
nameAvatarNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
if let nameNode = strongSelf.nameNode {
|
||||
strongSelf.nameNode = nil
|
||||
nameNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak nameNode] _ in
|
||||
|
|
@ -3811,6 +3952,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
})
|
||||
}
|
||||
} else {
|
||||
strongSelf.nameAvatarNode?.removeFromSupernode()
|
||||
strongSelf.nameAvatarNode = nil
|
||||
strongSelf.nameNavigateButton?.removeFromSuperview()
|
||||
strongSelf.nameNavigateButton = nil
|
||||
strongSelf.nameNode?.removeFromSupernode()
|
||||
strongSelf.nameNode = nil
|
||||
strongSelf.adminBadgeNode?.removeFromSupernode()
|
||||
|
|
@ -4582,9 +4727,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
buttonFrame.origin.y = buttonFrame.origin.y - (buttonSize.height - 30.0)
|
||||
}
|
||||
|
||||
animation.animator.updateFrame(layer: shareButtonNode.layer, frame: buttonFrame, completion: nil)
|
||||
animation.animator.updateAlpha(layer: shareButtonNode.layer, alpha: isCurrentlyPlayingMedia ? 0.0 : 1.0, completion: nil)
|
||||
|
||||
if isSidePanelOpen {
|
||||
buttonFrame.origin.x -= buttonFrame.width * 0.5
|
||||
buttonFrame.origin.y += buttonFrame.height * 0.5
|
||||
}
|
||||
|
||||
animation.animator.updatePosition(layer: shareButtonNode.layer, position: buttonFrame.center, completion: nil)
|
||||
animation.animator.updateBounds(layer: shareButtonNode.layer, bounds: CGRect(origin: CGPoint(), size: buttonFrame.size), completion: nil)
|
||||
animation.animator.updateAlpha(layer: shareButtonNode.layer, alpha: (isCurrentlyPlayingMedia || isSidePanelOpen) ? 0.0 : 1.0, completion: nil)
|
||||
animation.animator.updateScale(layer: shareButtonNode.layer, scale: (isCurrentlyPlayingMedia || isSidePanelOpen) ? 0.001 : 1.0, completion: nil)
|
||||
}
|
||||
} else {
|
||||
/*if let _ = strongSelf.backgroundFrameTransition {
|
||||
|
|
@ -4609,8 +4760,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
} else if !disablesComments {
|
||||
buttonFrame.origin.y = buttonFrame.origin.y - (buttonSize.height - 30.0)
|
||||
}
|
||||
shareButtonNode.frame = buttonFrame
|
||||
shareButtonNode.alpha = isCurrentlyPlayingMedia ? 0.0 : 1.0
|
||||
|
||||
if isSidePanelOpen {
|
||||
buttonFrame.origin.x -= buttonFrame.width * 0.5
|
||||
buttonFrame.origin.y += buttonFrame.height * 0.5
|
||||
}
|
||||
|
||||
animation.animator.updatePosition(layer: shareButtonNode.layer, position: buttonFrame.center, completion: nil)
|
||||
animation.animator.updateBounds(layer: shareButtonNode.layer, bounds: CGRect(origin: CGPoint(), size: buttonFrame.size), completion: nil)
|
||||
animation.animator.updateAlpha(layer: shareButtonNode.layer, alpha: (isCurrentlyPlayingMedia || isSidePanelOpen) ? 0.0 : 1.0, completion: nil)
|
||||
animation.animator.updateScale(layer: shareButtonNode.layer, scale: (isCurrentlyPlayingMedia || isSidePanelOpen) ? 0.001 : 1.0, completion: nil)
|
||||
}
|
||||
|
||||
if case .System = animation, strongSelf.mainContextSourceNode.isExtractedToContextPreview {
|
||||
|
|
@ -5826,6 +5985,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
break
|
||||
}
|
||||
}
|
||||
} else if let channel = item.message.peers[item.message.id.peerId], channel.isMonoForum, case .peer = item.chatLocation {
|
||||
item.controllerInteraction.updateChatLocationThread(item.message.threadId)
|
||||
} else {
|
||||
if !self.disablesComments {
|
||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||
|
|
@ -6482,3 +6643,54 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func generateNameNavigateButtonImage() -> UIImage {
|
||||
return generateImage(CGSize(width: 26.0, height: 26.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor(white: 1.0, alpha: 0.1).cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let arrowRect = CGSize(width: 4.0, height: 8.0).centered(in: CGRect(origin: CGPoint(), size: size)).offsetBy(dx: 1.0, dy: 0.0)
|
||||
|
||||
context.setStrokeColor(UIColor.white.cgColor)
|
||||
context.setLineWidth(1.0)
|
||||
context.setLineCap(.round)
|
||||
context.setLineJoin(.round)
|
||||
context.beginPath()
|
||||
context.move(to: arrowRect.origin)
|
||||
context.addLine(to: CGPoint(x: arrowRect.maxX, y: arrowRect.midY))
|
||||
context.addLine(to: CGPoint(x: arrowRect.minX, y: arrowRect.maxY))
|
||||
context.strokePath()
|
||||
|
||||
})!.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
|
||||
public final class NameNavigateButton: HighlightableButton {
|
||||
private static let sharedImage: UIImage = generateNameNavigateButtonImage()
|
||||
|
||||
private let backgroundView: UIImageView
|
||||
public var action: (() -> Void)?
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
self.backgroundView = UIImageView(image: NameNavigateButton.sharedImage)
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
|
||||
self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func pressed() {
|
||||
self.action?()
|
||||
}
|
||||
|
||||
public func update(size: CGSize, color: UIColor) {
|
||||
self.backgroundView.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.backgroundView.tintColor = color
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,12 +49,18 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
|
|||
|
||||
var amount: Int64 = 0
|
||||
var timestamp: Int32?
|
||||
for attribute in item.message.attributes {
|
||||
|
||||
if "".isEmpty {
|
||||
amount = 0
|
||||
timestamp = nil
|
||||
}
|
||||
|
||||
/*for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? OutgoingSuggestedPostMessageAttribute {
|
||||
amount = attribute.price.value
|
||||
timestamp = attribute.timestamp
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//TODO:localize
|
||||
let amountString: String
|
||||
|
|
|
|||
|
|
@ -95,17 +95,6 @@ public func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Mess
|
|||
dateText = " "
|
||||
}
|
||||
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? OutgoingSuggestedPostMessageAttribute {
|
||||
if let timestamp = attribute.timestamp {
|
||||
dateText = stringForMessageTimestamp(timestamp: timestamp, dateTimeFormat: dateTimeFormat)
|
||||
} else {
|
||||
//TODO:localize
|
||||
dateText = "Anytime"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if message.id.namespace == Namespaces.Message.ScheduledCloud, let _ = message.pendingProcessingAttribute {
|
||||
return "appx. \(dateText)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ public enum ChatMessageMerge: Int32 {
|
|||
|
||||
public protocol ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
||||
func updateSelectionState(animated: Bool)
|
||||
func updateAvatarIsHidden(isHidden: Bool, transition: ContainedViewLayoutTransition)
|
||||
}
|
||||
|
||||
public protocol ChatMessageItem: ListViewItem {
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ public final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||
}
|
||||
}
|
||||
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let chatDateSize: CGFloat = 20.0
|
||||
let chatDateInset: CGFloat = 6.0
|
||||
|
||||
|
|
@ -282,22 +282,26 @@ public final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
|||
let backgroundSize = CGSize(width: labelSize.width + chatDateInset * 2.0, height: chatDateSize)
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - backgroundSize.width) / 2.0), y: (34.0 - chatDateSize) / 2.0), size: backgroundSize)
|
||||
self.stickBackgroundNode.frame = CGRect(origin: CGPoint(), size: backgroundFrame.size)
|
||||
self.backgroundNode.frame = backgroundFrame
|
||||
self.backgroundNode.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.size.height / 2.0, transition: .immediate)
|
||||
self.labelNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.origin.x + chatDateInset, y: backgroundFrame.origin.y + floorToScreenPixels((backgroundSize.height - labelSize.height) / 2.0)), size: labelSize)
|
||||
transition.updateFrame(node: self.stickBackgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
self.backgroundNode.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.size.height / 2.0, transition: transition)
|
||||
let labelFrame = CGRect(origin: CGPoint(x: backgroundFrame.origin.x + chatDateInset, y: backgroundFrame.origin.y + floorToScreenPixels((backgroundSize.height - labelSize.height) / 2.0)), size: labelSize)
|
||||
|
||||
transition.updatePosition(node: self.labelNode, position: labelFrame.center)
|
||||
self.labelNode.bounds = CGRect(origin: CGPoint(), size: labelFrame.size)
|
||||
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
backgroundContent.allowsGroupOpacity = true
|
||||
self.backgroundNode.isHidden = true
|
||||
backgroundContent.frame = self.backgroundNode.frame
|
||||
|
||||
transition.updateFrame(node: backgroundContent, frame: self.backgroundNode.frame)
|
||||
backgroundContent.cornerRadius = backgroundFrame.size.height / 2.0
|
||||
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += containerSize.height - rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,6 +476,8 @@ public final class ChatMessageAvatarHeaderNodeImpl: ListViewItemHeaderNode, Chat
|
|||
|
||||
private var backgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
||||
private var isAvatarHidden: Bool = false
|
||||
|
||||
private var trackingIsInHierarchy: Bool = false {
|
||||
didSet {
|
||||
if self.trackingIsInHierarchy != oldValue {
|
||||
|
|
@ -713,15 +719,20 @@ public final class ChatMessageAvatarHeaderNodeImpl: ListViewItemHeaderNode, Chat
|
|||
}
|
||||
}
|
||||
|
||||
override public 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 public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: leftInset + 3.0, y: 0.0), size: CGSize(width: 38.0, height: 38.0)))
|
||||
let avatarFrame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0))
|
||||
self.avatarNode.position = avatarFrame.center
|
||||
self.avatarNode.bounds = CGRect(origin: CGPoint(), size: avatarFrame.size)
|
||||
self.avatarNode.updateSize(size: avatarFrame.size)
|
||||
}
|
||||
|
||||
override public 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)
|
||||
if !self.isAvatarHidden {
|
||||
self.avatarNode.layer.animateScale(from: 1.0, to: 0.2, duration: duration, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
|
||||
override public func animateAdded(duration: Double) {
|
||||
|
|
@ -748,6 +759,18 @@ public final class ChatMessageAvatarHeaderNodeImpl: ListViewItemHeaderNode, Chat
|
|||
self.layer.animate(from: NSValue(caTransform3D: previousSubnodeTransform), to: NSValue(caTransform3D: self.subnodeTransform), keyPath: "sublayerTransform", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
public func updateAvatarIsHidden(isHidden: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.isAvatarHidden = isHidden
|
||||
var avatarTransform: CATransform3D = CATransform3DIdentity
|
||||
if isHidden {
|
||||
let scale: CGFloat = isHidden ? 0.001 : 1.0
|
||||
avatarTransform = CATransform3DTranslate(avatarTransform, -38.0 * 0.5, 38.0 * 0.5, 0.0)
|
||||
avatarTransform = CATransform3DScale(avatarTransform, scale, scale, 1.0)
|
||||
}
|
||||
transition.updateTransform(node: self.avatarNode, transform: avatarTransform)
|
||||
transition.updateAlpha(node: self.avatarNode, alpha: isHidden ? 0.0 : 1.0)
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if !self.bounds.contains(point) {
|
||||
|
|
@ -786,7 +809,7 @@ public final class ChatMessageAvatarHeaderNodeImpl: ListViewItemHeaderNode, Chat
|
|||
self.avatarVideoNode?.updateVisibility(isVisible)
|
||||
|
||||
if let videoNode = self.avatarVideoNode {
|
||||
videoNode.updateLayout(size: self.avatarNode.frame.size, cornerRadius: self.avatarNode.frame.size.width / 2.0, transition: .immediate)
|
||||
videoNode.updateLayout(size: self.avatarNode.bounds.size, cornerRadius: self.avatarNode.bounds.size.width / 2.0, transition: .immediate)
|
||||
videoNode.frame = self.avatarNode.bounds
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
|
|||
let incoming = content.effectivelyIncoming(self.context.account.peerId)
|
||||
|
||||
var effectiveAuthor: Peer?
|
||||
let displayAuthorInfo: Bool
|
||||
var displayAuthorInfo: Bool
|
||||
|
||||
let messagePeerId: PeerId = chatLocation.peerId ?? content.firstMessage.id.peerId
|
||||
|
||||
|
|
@ -316,6 +316,12 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
|
|||
}
|
||||
}
|
||||
displayAuthorInfo = incoming && peerId.isGroupOrChannel && effectiveAuthor != nil
|
||||
|
||||
if let channel = content.firstMessage.peers[content.firstMessage.id.peerId] as? TelegramChannel, channel.isMonoForum {
|
||||
if case .replyThread = chatLocation {
|
||||
displayAuthorInfo = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -367,10 +373,6 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
|
|||
}
|
||||
}
|
||||
|
||||
if let subject = associatedData.subject, case let .customChatContents(contents) = subject, case .postSuggestions = contents.kind {
|
||||
hasAvatar = false
|
||||
}
|
||||
|
||||
if hasAvatar {
|
||||
if let effectiveAuthor = effectiveAuthor {
|
||||
var storyStats: PeerStoryStats?
|
||||
|
|
|
|||
|
|
@ -901,6 +901,7 @@ open class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol {
|
|||
}
|
||||
|
||||
private var attachedAvatarNodeOffset: CGFloat = 0.0
|
||||
private var attachedAvatarNodeIsHidden: Bool = false
|
||||
|
||||
override open func attachedHeaderNodesUpdated() {
|
||||
if !self.attachedAvatarNodeOffset.isZero {
|
||||
|
|
@ -912,6 +913,12 @@ open class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for headerNode in self.attachedHeaderNodes {
|
||||
if let headerNode = headerNode as? ChatMessageAvatarHeaderNode {
|
||||
headerNode.updateAvatarIsHidden(isHidden: self.attachedAvatarNodeIsHidden, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open func updateAttachedAvatarNodeOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
|
@ -923,6 +930,15 @@ open class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
open func updateAttachedAvatarNodeIsHidden(isHidden: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.attachedAvatarNodeIsHidden = isHidden
|
||||
for headerNode in self.attachedHeaderNodes {
|
||||
if let headerNode = headerNode as? ChatMessageAvatarHeaderNode {
|
||||
headerNode.updateAvatarIsHidden(isHidden: self.attachedAvatarNodeIsHidden, transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open func unreadMessageRangeUpdated() {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,14 +105,19 @@ public class ChatMessageShareButton: ASDisplayNode {
|
|||
|
||||
public func update(presentationData: ChatPresentationData, controllerInteraction: ChatControllerInteraction, chatLocation: ChatLocation, subject: ChatControllerSubject?, message: Message, account: Account, disableComments: Bool = false) -> CGSize {
|
||||
var isReplies = false
|
||||
var isNavigate = false
|
||||
var replyCount = 0
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? ReplyThreadMessageAttribute {
|
||||
replyCount = Int(attribute.count)
|
||||
isReplies = true
|
||||
break
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? ReplyThreadMessageAttribute {
|
||||
replyCount = Int(attribute.count)
|
||||
isReplies = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if channel.isMonoForum, case .peer = chatLocation {
|
||||
isNavigate = true
|
||||
}
|
||||
}
|
||||
if case let .replyThread(replyThreadMessage) = chatLocation, replyThreadMessage.effectiveTopId == message.id {
|
||||
|
|
@ -147,6 +152,9 @@ public class ChatMessageShareButton: ASDisplayNode {
|
|||
} else if case let .customChatContents(contents) = subject, case .hashTagSearch = contents.kind {
|
||||
updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0)
|
||||
} else if isNavigate {
|
||||
updatedIconImage = PresentationResourcesChat.chatFreeNavigateToThreadButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
updatedIconOffset = CGPoint(x: UIScreenPixel, y: -3.0)
|
||||
} else if case .pinnedMessages = subject {
|
||||
updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||
updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0)
|
||||
|
|
|
|||
|
|
@ -646,6 +646,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||
}, forceUpdateWarpContents: {
|
||||
}, playShakeAnimation: {
|
||||
}, displayQuickShare: { _, _ ,_ in
|
||||
}, updateChatLocationThread: { _ in
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: self.backgroundNode))
|
||||
self.controllerInteraction = controllerInteraction
|
||||
|
|
|
|||
|
|
@ -501,6 +501,7 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess
|
|||
}, forceUpdateWarpContents: {
|
||||
}, playShakeAnimation: {
|
||||
}, displayQuickShare: { _, _ ,_ in
|
||||
}, updateChatLocationThread: { _ in
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: self.context, backgroundNode: self.wallpaperBackgroundNode))
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
let iconSize = self.icon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(BundleIconComponent(
|
||||
name: "Call/PanelIcon",
|
||||
name: "Chat/Title Panels/SidebarIcon",
|
||||
tintColor: theme.rootController.navigationBar.accentTextColor,
|
||||
maxSize: nil,
|
||||
scaleFactor: 1.0
|
||||
|
|
@ -364,7 +364,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
|
||||
let topInset: CGFloat = 12.0
|
||||
let topInset: CGFloat = 10.0
|
||||
let bottomInset: CGFloat = 12.0
|
||||
|
||||
let contentSize: CGFloat = topInset + iconSize.height + bottomInset
|
||||
|
|
@ -578,7 +578,6 @@ public final class ChatSideTopicsPanel: Component {
|
|||
self.scrollView.alwaysBounceHorizontal = false
|
||||
self.scrollView.alwaysBounceVertical = false
|
||||
self.scrollView.scrollsToTop = false
|
||||
//self.scrollView.delegate = self.wrappedScrollViewDelegate
|
||||
|
||||
self.addSubview(self.scrollView)
|
||||
self.scrollView.addSubview(self.selectedLineView)
|
||||
|
|
@ -591,6 +590,12 @@ public final class ChatSideTopicsPanel: Component {
|
|||
deinit {
|
||||
self.itemsDisposable?.dispose()
|
||||
}
|
||||
|
||||
public func updateGlobalOffset(globalOffset: CGFloat, transition: ComponentTransition) {
|
||||
if let tabItemView = self.tabItemView {
|
||||
transition.setTransform(view: tabItemView, transform: CATransform3DMakeTranslation(-globalOffset, 0.0, 0.0))
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: ChatSideTopicsPanel, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
self.isUpdating = true
|
||||
|
|
@ -774,6 +779,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
}
|
||||
|
||||
contentSize.height += itemSize.height
|
||||
contentSize.height -= 20.0
|
||||
}
|
||||
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -271,7 +271,6 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||
public let sendGift: (EnginePeer.Id) -> Void
|
||||
public let openUniqueGift: (String) -> Void
|
||||
public let openMessageFeeException: () -> Void
|
||||
|
||||
public let requestMessageUpdate: (MessageId, Bool) -> Void
|
||||
public let cancelInteractiveKeyboardGestures: () -> Void
|
||||
public let dismissTextInput: () -> Void
|
||||
|
|
@ -281,6 +280,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||
public let forceUpdateWarpContents: () -> Void
|
||||
public let playShakeAnimation: () -> Void
|
||||
public let displayQuickShare: (MessageId, ASDisplayNode, ContextGesture) -> Void
|
||||
public let updateChatLocationThread: (Int64?) -> Void
|
||||
|
||||
public var canPlayMedia: Bool = false
|
||||
public var hiddenMedia: [MessageId: [Media]] = [:]
|
||||
|
|
@ -328,6 +328,8 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||
}
|
||||
}
|
||||
|
||||
public var isSidePanelOpen: Bool = false
|
||||
|
||||
public init(
|
||||
openMessage: @escaping (Message, OpenMessageParams) -> Bool,
|
||||
openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer, MessageReference?, OpenPeerSource) -> Void,
|
||||
|
|
@ -441,6 +443,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||
forceUpdateWarpContents: @escaping () -> Void,
|
||||
playShakeAnimation: @escaping () -> Void,
|
||||
displayQuickShare: @escaping (MessageId, ASDisplayNode, ContextGesture) -> Void,
|
||||
updateChatLocationThread: @escaping (Int64?) -> Void,
|
||||
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
|
||||
pollActionState: ChatInterfacePollActionState,
|
||||
stickerSettings: ChatInterfaceStickerSettings,
|
||||
|
|
@ -559,6 +562,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||
self.forceUpdateWarpContents = forceUpdateWarpContents
|
||||
self.playShakeAnimation = playShakeAnimation
|
||||
self.displayQuickShare = displayQuickShare
|
||||
self.updateChatLocationThread = updateChatLocationThread
|
||||
|
||||
self.automaticMediaDownloadSettings = automaticMediaDownloadSettings
|
||||
|
||||
|
|
|
|||
|
|
@ -1816,8 +1816,6 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
case .businessLinkSetup:
|
||||
stickerContent = nil
|
||||
gifContent = nil
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ public final class DrawingMessageRenderer {
|
|||
}
|
||||
|
||||
avatarHeaderNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 3.0), size: CGSize(width: layout.size.width, height: avatarHeaderItem.height))
|
||||
avatarHeaderNode.updateLayout(size: size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
avatarHeaderNode.updateLayout(size: size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: .immediate)
|
||||
}
|
||||
|
||||
var finalWidth: CGFloat = width
|
||||
|
|
|
|||
|
|
@ -3790,6 +3790,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
}, forceUpdateWarpContents: {
|
||||
}, playShakeAnimation: {
|
||||
}, displayQuickShare: { _, _ ,_ in
|
||||
}, updateChatLocationThread: { _ in
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil))
|
||||
self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().startStrict(next: { [weak self] ids in
|
||||
|
|
|
|||
|
|
@ -1,153 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
|
||||
public final class PostSuggestionsChatContents: ChatCustomContentsProtocol {
|
||||
private final class Impl {
|
||||
let queue: Queue
|
||||
let context: AccountContext
|
||||
|
||||
private var peerId: EnginePeer.Id
|
||||
|
||||
private(set) var mergedHistoryView: MessageHistoryView?
|
||||
private var sourceHistoryView: MessageHistoryView?
|
||||
|
||||
private var historyViewDisposable: Disposable?
|
||||
private var pendingHistoryViewDisposable: Disposable?
|
||||
let historyViewStream = ValuePipe<(MessageHistoryView, ViewUpdateType)>()
|
||||
private var nextUpdateIsHoleFill: Bool = false
|
||||
|
||||
init(queue: Queue, context: AccountContext, peerId: EnginePeer.Id) {
|
||||
self.queue = queue
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
|
||||
self.updateHistoryViewRequest(reload: false)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.historyViewDisposable?.dispose()
|
||||
self.pendingHistoryViewDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func updateHistoryViewRequest(reload: Bool) {
|
||||
self.pendingHistoryViewDisposable?.dispose()
|
||||
self.pendingHistoryViewDisposable = nil
|
||||
|
||||
if self.historyViewDisposable == nil || reload {
|
||||
self.historyViewDisposable?.dispose()
|
||||
|
||||
self.historyViewDisposable = (self.context.account.viewTracker.postSuggestionsViewForLocation(peerId: self.peerId)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] view, update, _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if update == .FillHole {
|
||||
self.nextUpdateIsHoleFill = true
|
||||
self.updateHistoryViewRequest(reload: true)
|
||||
return
|
||||
}
|
||||
|
||||
let nextUpdateIsHoleFill = self.nextUpdateIsHoleFill
|
||||
self.nextUpdateIsHoleFill = false
|
||||
|
||||
self.sourceHistoryView = view
|
||||
|
||||
self.updateHistoryView(updateType: nextUpdateIsHoleFill ? .FillHole : .Generic)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func updateHistoryView(updateType: ViewUpdateType) {
|
||||
var entries = self.sourceHistoryView?.entries ?? []
|
||||
entries.sort(by: { $0.message.index < $1.message.index })
|
||||
|
||||
let mergedHistoryView = MessageHistoryView(tag: nil, namespaces: .just(Namespaces.Message.allSuggestedPost), entries: entries, holeEarlier: false, holeLater: false, isLoading: false)
|
||||
self.mergedHistoryView = mergedHistoryView
|
||||
|
||||
self.historyViewStream.putNext((mergedHistoryView, updateType))
|
||||
}
|
||||
|
||||
func enqueueMessages(messages: [EnqueueMessage]) {
|
||||
let _ = (TelegramCore.enqueueMessages(account: self.context.account, peerId: self.peerId, messages: messages.compactMap { message -> EnqueueMessage? in
|
||||
if !message.attributes.contains(where: { $0 is OutgoingSuggestedPostMessageAttribute }) {
|
||||
return nil
|
||||
}
|
||||
return message
|
||||
})
|
||||
|> deliverOn(self.queue)).startStandalone()
|
||||
}
|
||||
|
||||
func deleteMessages(ids: [EngineMessage.Id]) {
|
||||
let _ = self.context.engine.messages.deleteMessagesInteractively(messageIds: ids, type: .forEveryone).startStandalone()
|
||||
}
|
||||
|
||||
func editMessage(id: EngineMessage.Id, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, webpagePreviewAttribute: WebpagePreviewMessageAttribute?, disableUrlPreview: Bool) {
|
||||
}
|
||||
}
|
||||
|
||||
public let peerId: EnginePeer.Id
|
||||
public var kind: ChatCustomContentsKind
|
||||
|
||||
public var historyView: Signal<(MessageHistoryView, ViewUpdateType), NoError> {
|
||||
return self.impl.signalWith({ impl, subscriber in
|
||||
if let mergedHistoryView = impl.mergedHistoryView {
|
||||
subscriber.putNext((mergedHistoryView, .Initial))
|
||||
}
|
||||
return impl.historyViewStream.signal().start(next: subscriber.putNext)
|
||||
})
|
||||
}
|
||||
|
||||
public var messageLimit: Int? {
|
||||
return 20
|
||||
}
|
||||
|
||||
private let queue: Queue
|
||||
private let impl: QueueLocalObject<Impl>
|
||||
|
||||
public init(context: AccountContext, peerId: EnginePeer.Id) {
|
||||
self.peerId = peerId
|
||||
self.kind = .postSuggestions(price: StarsAmount(value: 250, nanos: 0))
|
||||
|
||||
let queue = Queue()
|
||||
self.queue = queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return Impl(queue: queue, context: context, peerId: peerId)
|
||||
})
|
||||
}
|
||||
|
||||
public func enqueueMessages(messages: [EnqueueMessage]) {
|
||||
self.impl.with { impl in
|
||||
impl.enqueueMessages(messages: messages)
|
||||
}
|
||||
}
|
||||
|
||||
public func deleteMessages(ids: [EngineMessage.Id]) {
|
||||
self.impl.with { impl in
|
||||
impl.deleteMessages(ids: ids)
|
||||
}
|
||||
}
|
||||
|
||||
public func editMessage(id: EngineMessage.Id, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, webpagePreviewAttribute: WebpagePreviewMessageAttribute?, disableUrlPreview: Bool) {
|
||||
self.impl.with { impl in
|
||||
impl.editMessage(id: id, text: text, media: media, entities: entities, webpagePreviewAttribute: webpagePreviewAttribute, disableUrlPreview: disableUrlPreview)
|
||||
}
|
||||
}
|
||||
|
||||
public func quickReplyUpdateShortcut(value: String) {
|
||||
}
|
||||
|
||||
public func businessLinkUpdate(message: String, entities: [MessageTextEntity], title: String?) {
|
||||
}
|
||||
|
||||
public func loadMore() {
|
||||
}
|
||||
|
||||
public func hashtagSearchUpdate(query: String) {
|
||||
}
|
||||
|
||||
public var hashtagSearchResultsUpdate: ((SearchMessagesResult, SearchMessagesState)) -> Void = { _ in }
|
||||
}
|
||||
|
|
@ -211,8 +211,6 @@ final class AutomaticBusinessMessageSetupChatContents: ChatCustomContentsProtoco
|
|||
initialShortcut = ""
|
||||
case .hashTagSearch:
|
||||
initialShortcut = ""
|
||||
case .postSuggestions:
|
||||
initialShortcut = ""
|
||||
}
|
||||
|
||||
let queue = Queue()
|
||||
|
|
@ -251,8 +249,6 @@ final class AutomaticBusinessMessageSetupChatContents: ChatCustomContentsProtoco
|
|||
break
|
||||
case .hashTagSearch:
|
||||
break
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
|
|||
header.updateNode(headerNode, previous: nil, next: nil)
|
||||
headerNode.item = header
|
||||
}
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: .immediate)
|
||||
} else {
|
||||
headerNode = header.node(synchronousLoad: true)
|
||||
|
|
@ -346,7 +346,7 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
|
|||
headerNode.item = header
|
||||
}
|
||||
headerNode.frame = headerFrame
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
strongSelf.itemHeaderNodes[id] = headerNode
|
||||
|
||||
strongSelf.containerNode.addSubnode(headerNode)
|
||||
|
|
|
|||
|
|
@ -1180,7 +1180,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, ASScrollViewDelegate
|
|||
}
|
||||
|
||||
transition.updateFrame(node: dateHeaderNode, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: CGSize(width: layout.size.width, height: headerItem.height)))
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
dateHeaderNode.updateLayout(size: self.messagesContainerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: .immediate)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
|
|
|||
12
submodules/TelegramUI/Images.xcassets/Chat/Title Panels/SidebarIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Title Panels/SidebarIcon.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "list_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Chat/Title Panels/SidebarIcon.imageset/list_24.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Title Panels/SidebarIcon.imageset/list_24.pdf
vendored
Normal file
Binary file not shown.
|
|
@ -1656,7 +1656,7 @@ extension ChatControllerImpl {
|
|||
self.reportIrrelvantGeoNoticePromise.set(.single(nil))
|
||||
self.titleDisposable.set(nil)
|
||||
|
||||
var peerView: Signal<PeerView?, NoError> = .single(nil)
|
||||
let peerView: Signal<PeerView?, NoError> = .single(nil)
|
||||
|
||||
if case let .customChatContents(customChatContents) = self.subject {
|
||||
switch customChatContents.kind {
|
||||
|
|
@ -1680,13 +1680,6 @@ extension ChatControllerImpl {
|
|||
}
|
||||
|
||||
self.chatTitleView?.titleContent = .custom(link.title ?? self.presentationData.strings.Business_Links_EditLinkTitle, linkUrl, false)
|
||||
case .postSuggestions:
|
||||
if let customChatContents = customChatContents as? PostSuggestionsChatContents {
|
||||
peerView = context.account.viewTracker.peerView(customChatContents.peerId) |> map(Optional.init)
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
self.chatTitleView?.titleContent = .custom("Message Suggestions", nil, false)
|
||||
}
|
||||
} else {
|
||||
self.chatTitleView?.titleContent = .custom(" ", nil, false)
|
||||
|
|
@ -3038,46 +3031,6 @@ extension ChatControllerImpl {
|
|||
}
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .succeed(text: strongSelf.presentationData.strings.Business_Links_EditLinkToastSaved, timeout: nil, customUndoText: nil), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
case let .postSuggestions(postSuggestions):
|
||||
if let customChatContents = customChatContents as? PostSuggestionsChatContents {
|
||||
//TODO:release
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
|
||||
let _ = (ChatSendStarsScreen.initialData(context: strongSelf.context, peerId: customChatContents.peerId, suggestMessageAmount: postSuggestions, completion: { [weak strongSelf] amount, timestamp in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
guard case let .customChatContents(customChatContents) = strongSelf.subject else {
|
||||
return
|
||||
}
|
||||
if amount == 0 {
|
||||
return
|
||||
}
|
||||
let messages = messages.map { message in
|
||||
return message.withUpdatedAttributes { attributes in
|
||||
var attributes = attributes
|
||||
attributes.removeAll(where: { $0 is OutgoingSuggestedPostMessageAttribute })
|
||||
attributes.append(OutgoingSuggestedPostMessageAttribute(
|
||||
price: StarsAmount(value: amount, nanos: 0),
|
||||
timestamp: timestamp
|
||||
))
|
||||
return attributes
|
||||
}
|
||||
}
|
||||
customChatContents.enqueueMessages(messages: messages)
|
||||
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||
})
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak strongSelf] initialData in
|
||||
guard let strongSelf, let initialData else {
|
||||
return
|
||||
}
|
||||
let sendStarsScreen = ChatSendStarsScreen(
|
||||
context: strongSelf.context,
|
||||
initialData: initialData
|
||||
)
|
||||
strongSelf.push(sendStarsScreen)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
strongSelf.updateChatPresentationInterfaceState(interactive: true, { $0.updatedShowCommands(false) })
|
||||
|
|
@ -5772,22 +5725,6 @@ extension ChatControllerImpl {
|
|||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(monoforumPeer), keepStack: .always))
|
||||
})
|
||||
})
|
||||
|
||||
/*let contents = PostSuggestionsChatContents(
|
||||
context: self.context,
|
||||
peerId: peerId
|
||||
)
|
||||
let chatController = self.context.sharedContext.makeChatController(
|
||||
context: self.context,
|
||||
chatLocation: .customChatContents,
|
||||
subject: .customChatContents(contents: contents),
|
||||
botStart: nil,
|
||||
mode: .standard(.default),
|
||||
params: nil
|
||||
)
|
||||
chatController.navigationPresentation = .modal
|
||||
|
||||
self.push(chatController)*/
|
||||
}, editMessageMedia: { [weak self] messageId, draw in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.editMessageMedia(messageId, draw)
|
||||
|
|
|
|||
|
|
@ -230,8 +230,6 @@ func updateChatPresentationInterfaceStateImpl(
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
canHaveUrlPreview = false
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,8 +196,6 @@ final class ChatBusinessLinkTitlePanelNode: ChatTitleAccessoryPanelNode {
|
|||
self.link = link
|
||||
case .hashTagSearch:
|
||||
break
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
|
|
|||
|
|
@ -777,8 +777,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
}
|
||||
case .hashTagSearch:
|
||||
break
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -885,8 +883,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
|
||||
return false
|
||||
}
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4833,6 +4829,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
return
|
||||
}
|
||||
self.displayQuickShare(id: messageId, node: node, gesture: gesture)
|
||||
}, updateChatLocationThread: { [weak self] threadId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.interfaceInteraction?.updateChatLocationThread(threadId)
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(context: context, backgroundNode: self.chatBackgroundNode))
|
||||
controllerInteraction.enableFullTranslucency = context.sharedContext.energyUsageSettings.fullTranslucency
|
||||
|
||||
|
|
@ -5227,14 +5228,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)!
|
||||
self.avatarNode = avatarNode
|
||||
case .customChatContents:
|
||||
if case let .customChatContents(customChatContents) = self.subject, case .postSuggestions = customChatContents.kind {
|
||||
let avatarNode = ChatAvatarNavigationNode()
|
||||
chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)!
|
||||
chatInfoButtonItem.isEnabled = false
|
||||
self.avatarNode = avatarNode
|
||||
} else {
|
||||
chatInfoButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
||||
}
|
||||
chatInfoButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
|
||||
}
|
||||
chatInfoButtonItem.target = self
|
||||
chatInfoButtonItem.action = #selector(self.rightNavigationButtonAction)
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
private(set) var feePanelNode: ChatFeePanelNode?
|
||||
|
||||
private let titleAccessoryPanelContainer: ChatControllerTitlePanelNodeContainer
|
||||
private var titleTopicsAccessoryPanelNode: ChatTopicListTitleAccessoryPanelNode?
|
||||
private var titleAccessoryPanelNode: ChatTitleAccessoryPanelNode?
|
||||
|
||||
private var chatTranslationPanel: ChatTranslationPanelNode?
|
||||
|
|
@ -1363,13 +1364,39 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
previousInputPanelOrigin.y -= secondaryInputPanelNode.bounds.size.height
|
||||
}
|
||||
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
|
||||
|
||||
var extraTransition = transition
|
||||
|
||||
var dismissedTitleTopicsAccessoryPanelNode: ChatTopicListTitleAccessoryPanelNode?
|
||||
var immediatelyLayoutTitleTopicsAccessoryPanelNodeAndAnimateAppearance = false
|
||||
var titleTopicsAccessoryPanelHeight: CGFloat?
|
||||
var titleTopicsAccessoryPanelBackgroundHeight: CGFloat?
|
||||
var titleTopicsAccessoryPanelHitTestSlop: CGFloat?
|
||||
if let titleTopicsAccessoryPanelNode = titleTopicsPanelForChatPresentationInterfaceState(self.chatPresentationInterfaceState, context: self.context, currentPanel: self.titleTopicsAccessoryPanelNode, controllerInteraction: self.controllerInteraction, interfaceInteraction: self.interfaceInteraction, force: false) {
|
||||
if self.titleTopicsAccessoryPanelNode != titleTopicsAccessoryPanelNode {
|
||||
dismissedTitleTopicsAccessoryPanelNode = self.titleTopicsAccessoryPanelNode
|
||||
self.titleTopicsAccessoryPanelNode = titleTopicsAccessoryPanelNode
|
||||
immediatelyLayoutTitleTopicsAccessoryPanelNodeAndAnimateAppearance = true
|
||||
self.titleAccessoryPanelContainer.addSubnode(titleTopicsAccessoryPanelNode)
|
||||
|
||||
titleTopicsAccessoryPanelNode.clipsToBounds = true
|
||||
}
|
||||
|
||||
let layoutResult = titleTopicsAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleTopicsAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState)
|
||||
titleTopicsAccessoryPanelHeight = layoutResult.insetHeight
|
||||
titleTopicsAccessoryPanelBackgroundHeight = layoutResult.backgroundHeight
|
||||
titleTopicsAccessoryPanelHitTestSlop = layoutResult.hitTestSlop
|
||||
} else if let titleTopicsAccessoryPanelNode = self.titleTopicsAccessoryPanelNode {
|
||||
dismissedTitleTopicsAccessoryPanelNode = titleTopicsAccessoryPanelNode
|
||||
self.titleTopicsAccessoryPanelNode = nil
|
||||
}
|
||||
|
||||
var dismissedTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode?
|
||||
var immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = false
|
||||
var titleAccessoryPanelHeight: CGFloat?
|
||||
var titleAccessoryPanelBackgroundHeight: CGFloat?
|
||||
var titleAccessoryPanelHitTestSlop: CGFloat?
|
||||
var extraTransition = transition
|
||||
|
||||
if let titleAccessoryPanelNode = titlePanelForChatPresentationInterfaceState(self.chatPresentationInterfaceState, context: self.context, currentPanel: self.titleAccessoryPanelNode, controllerInteraction: self.controllerInteraction, interfaceInteraction: self.interfaceInteraction, force: false) {
|
||||
if self.titleAccessoryPanelNode != titleAccessoryPanelNode {
|
||||
dismissedTitleAccessoryPanelNode = self.titleAccessoryPanelNode
|
||||
|
|
@ -1575,6 +1602,8 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
self.leftPanel = nil
|
||||
}
|
||||
|
||||
self.controllerInteraction.isSidePanelOpen = self.leftPanel != nil
|
||||
|
||||
var inputPanelNodeBaseHeight: CGFloat = 0.0
|
||||
if let inputPanelNode = self.inputPanelNode {
|
||||
inputPanelNodeBaseHeight += inputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
|
||||
|
|
@ -1859,12 +1888,27 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
|
||||
var extraNavigationBarHeight: CGFloat = 0.0
|
||||
var extraNavigationBarHitTestSlop: CGFloat = 0.0
|
||||
|
||||
var titlePanelsContentOffset: CGFloat = 0.0
|
||||
|
||||
let sidePanelTopInset: CGFloat = insets.top
|
||||
|
||||
var titleTopicsAccessoryPanelFrame: CGRect?
|
||||
if let _ = self.titleTopicsAccessoryPanelNode, let panelHeight = titleTopicsAccessoryPanelHeight {
|
||||
titleTopicsAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: titlePanelsContentOffset), size: CGSize(width: layout.size.width, height: panelHeight))
|
||||
insets.top += panelHeight
|
||||
extraNavigationBarHeight += titleTopicsAccessoryPanelBackgroundHeight ?? 0.0
|
||||
extraNavigationBarHitTestSlop = titleTopicsAccessoryPanelHitTestSlop ?? 0.0
|
||||
titlePanelsContentOffset += panelHeight
|
||||
}
|
||||
|
||||
var titleAccessoryPanelFrame: CGRect?
|
||||
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
|
||||
titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: panelHeight))
|
||||
titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: titlePanelsContentOffset), size: CGSize(width: layout.size.width, height: panelHeight))
|
||||
insets.top += panelHeight
|
||||
extraNavigationBarHeight += titleAccessoryPanelBackgroundHeight ?? 0.0
|
||||
extraNavigationBarHitTestSlop = titleAccessoryPanelHitTestSlop ?? 0.0
|
||||
titlePanelsContentOffset += panelHeight
|
||||
}
|
||||
|
||||
var translationPanelFrame: CGRect?
|
||||
|
|
@ -2226,18 +2270,19 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
self.controller?.presentationContext.containerLayoutUpdated(childrenLayout, transition: transition)
|
||||
self.controller?.galleryPresentationContext.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, scrollIndicatorInsets: listScrollIndicatorInsets, duration: duration, curve: curve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems), additionalScrollDistance, scrollToTop, { [weak self] in
|
||||
var customListAnimationTransition: ControlledTransition?
|
||||
if case let .animated(duration, curve) = transition {
|
||||
if immediatelyLayoutLeftPanelNodeAndAnimateAppearance || dismissedLeftPanel != nil {
|
||||
customListAnimationTransition = ControlledTransition(duration: duration, curve: curve, interactive: false)
|
||||
}
|
||||
}
|
||||
|
||||
listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, scrollIndicatorInsets: listScrollIndicatorInsets, duration: duration, curve: curve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems, customAnimationTransition: customListAnimationTransition), additionalScrollDistance, scrollToTop, { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.notifyTransitionCompletionListeners(transition: transition)
|
||||
}
|
||||
})
|
||||
|
||||
if immediatelyLayoutLeftPanelNodeAndAnimateAppearance {
|
||||
transition.animatePositionAdditive(layer: self.historyNode.layer, offset: CGPoint(x: -defaultLeftPanelWidth, y: 0.0))
|
||||
} else if dismissedLeftPanel != nil {
|
||||
transition.animatePositionAdditive(layer: self.historyNode.layer, offset: CGPoint(x: defaultLeftPanelWidth, y: 0.0))
|
||||
}
|
||||
|
||||
if self.isScrollingLockedAtTop {
|
||||
switch self.historyNode.visibleContentOffset() {
|
||||
case let .known(value) where value <= CGFloat.ulpOfOne:
|
||||
|
|
@ -2298,7 +2343,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
component: leftPanel.component.component,
|
||||
environment: {
|
||||
ChatSidePanelEnvironment(insets: UIEdgeInsets(
|
||||
top: containerInsets.top,
|
||||
top: sidePanelTopInset,
|
||||
left: leftPanelLeftInset,
|
||||
bottom: containerInsets.bottom + contentBottomInset,
|
||||
right: 0.0
|
||||
|
|
@ -2313,8 +2358,14 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}
|
||||
if immediatelyLayoutLeftPanelNodeAndAnimateAppearance {
|
||||
leftPanelView.frame = leftPanelFrame.offsetBy(dx: -leftPanelSize.width, dy: 0.0)
|
||||
if let leftPanelView = leftPanelView as? ChatSideTopicsPanel.View {
|
||||
leftPanelView.updateGlobalOffset(globalOffset: -leftPanelSize.width, transition: ComponentTransition(transition))
|
||||
}
|
||||
}
|
||||
transition.updateFrame(view: leftPanelView, frame: leftPanelFrame)
|
||||
if let leftPanelView = leftPanelView as? ChatSideTopicsPanel.View {
|
||||
leftPanelView.updateGlobalOffset(globalOffset: 0.0, transition: ComponentTransition(transition))
|
||||
}
|
||||
}
|
||||
}
|
||||
if let dismissedLeftPanel, let dismissedLeftPanelView = dismissedLeftPanel.view.view {
|
||||
|
|
@ -2323,7 +2374,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
component: dismissedLeftPanel.component.component,
|
||||
environment: {
|
||||
ChatSidePanelEnvironment(insets: UIEdgeInsets(
|
||||
top: containerInsets.top,
|
||||
top: sidePanelTopInset,
|
||||
left: leftPanelLeftInset,
|
||||
bottom: containerInsets.bottom + contentBottomInset,
|
||||
right: 0.0
|
||||
|
|
@ -2334,6 +2385,9 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
transition.updateFrame(view: dismissedLeftPanelView, frame: CGRect(origin: CGPoint(x: -dismissedLeftPanelSize.width, y: 0.0), size: dismissedLeftPanelSize), completion: { [weak dismissedLeftPanelView] _ in
|
||||
dismissedLeftPanelView?.removeFromSuperview()
|
||||
})
|
||||
if let dismissedLeftPanelView = dismissedLeftPanelView as? ChatSideTopicsPanel.View {
|
||||
dismissedLeftPanelView.updateGlobalOffset(globalOffset: -dismissedLeftPanelSize.width, transition: ComponentTransition(transition))
|
||||
}
|
||||
}
|
||||
|
||||
if let navigationBarBackgroundContent = self.navigationBarBackgroundContent {
|
||||
|
|
@ -2382,6 +2436,23 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
transition.updateFrame(node: self.inputPanelBackgroundSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: apparentInputBackgroundFrame.origin.y), size: CGSize(width: apparentInputBackgroundFrame.size.width, height: UIScreenPixel)))
|
||||
transition.updateFrame(node: self.navigateButtons, frame: apparentNavigateButtonsFrame)
|
||||
self.navigateButtons.update(rect: apparentNavigateButtonsFrame, within: layout.size, transition: transition)
|
||||
|
||||
if let titleTopicsAccessoryPanelNode = self.titleTopicsAccessoryPanelNode, let titleTopicsAccessoryPanelFrame, (immediatelyLayoutTitleTopicsAccessoryPanelNodeAndAnimateAppearance || !titleTopicsAccessoryPanelNode.frame.equalTo(titleTopicsAccessoryPanelFrame)) {
|
||||
if immediatelyLayoutTitleTopicsAccessoryPanelNodeAndAnimateAppearance {
|
||||
titleTopicsAccessoryPanelNode.frame = titleTopicsAccessoryPanelFrame.offsetBy(dx: 0.0, dy: -titleTopicsAccessoryPanelFrame.height)
|
||||
titleTopicsAccessoryPanelNode.updateGlobalOffset(globalOffset: -titleTopicsAccessoryPanelFrame.height, transition: .immediate)
|
||||
|
||||
transition.updateFrame(node: titleTopicsAccessoryPanelNode, frame: titleTopicsAccessoryPanelFrame)
|
||||
titleTopicsAccessoryPanelNode.updateGlobalOffset(globalOffset: 0.0, transition: ComponentTransition(transition))
|
||||
} else {
|
||||
let previousFrame = titleTopicsAccessoryPanelNode.frame
|
||||
titleTopicsAccessoryPanelNode.frame = titleTopicsAccessoryPanelFrame
|
||||
if transition.isAnimated && previousFrame.width != titleTopicsAccessoryPanelFrame.width {
|
||||
} else {
|
||||
transition.animatePositionAdditive(node: titleTopicsAccessoryPanelNode, offset: CGPoint(x: 0.0, y: -titleTopicsAccessoryPanelFrame.height))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let titleAccessoryPanelNode = self.titleAccessoryPanelNode, let titleAccessoryPanelFrame, !titleAccessoryPanelNode.frame.equalTo(titleAccessoryPanelFrame) {
|
||||
let previousFrame = titleAccessoryPanelNode.frame
|
||||
|
|
@ -2504,6 +2575,15 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let dismissedTitleTopicsAccessoryPanelNode {
|
||||
var dismissedTopPanelFrame = dismissedTitleTopicsAccessoryPanelNode.frame
|
||||
dismissedTopPanelFrame.origin.y = -dismissedTopPanelFrame.size.height
|
||||
transition.updateFrame(node: dismissedTitleTopicsAccessoryPanelNode, frame: dismissedTopPanelFrame, completion: { [weak dismissedTitleTopicsAccessoryPanelNode] _ in
|
||||
dismissedTitleTopicsAccessoryPanelNode?.removeFromSupernode()
|
||||
})
|
||||
dismissedTitleTopicsAccessoryPanelNode.updateGlobalOffset(globalOffset: -dismissedTopPanelFrame.height, transition: ComponentTransition(transition))
|
||||
}
|
||||
|
||||
if let dismissedTitleAccessoryPanelNode {
|
||||
var dismissedPanelFrame = dismissedTitleAccessoryPanelNode.frame
|
||||
|
|
@ -4375,7 +4455,6 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}
|
||||
|
||||
var postEmptyMessages = false
|
||||
var isPostSuggestions = false
|
||||
if case let .customChatContents(customChatContents) = self.chatPresentationInterfaceState.subject {
|
||||
switch customChatContents.kind {
|
||||
case .hashTagSearch:
|
||||
|
|
@ -4384,11 +4463,8 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
postEmptyMessages = true
|
||||
case .postSuggestions:
|
||||
isPostSuggestions = true
|
||||
}
|
||||
}
|
||||
let _ = isPostSuggestions
|
||||
|
||||
if !messages.isEmpty, let messageEffect {
|
||||
messages[0] = messages[0].withUpdatedAttributes { attributes in
|
||||
|
|
|
|||
|
|
@ -985,7 +985,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
|
||||
self.preloadPages = false
|
||||
|
||||
self.beginChatHistoryTransitions(resetScrolling: false)
|
||||
self.beginChatHistoryTransitions(resetScrolling: false, switchedToAnotherSource: false)
|
||||
|
||||
self.beginReadHistoryManagement()
|
||||
|
||||
|
|
@ -1230,7 +1230,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
}
|
||||
self.tag = tag
|
||||
|
||||
self.beginChatHistoryTransitions(resetScrolling: true)
|
||||
self.beginChatHistoryTransitions(resetScrolling: true, switchedToAnotherSource: false)
|
||||
}
|
||||
|
||||
public func updateChatLocation(chatLocation: ChatLocation) {
|
||||
|
|
@ -1238,7 +1238,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
return
|
||||
}
|
||||
self.chatLocation = chatLocation
|
||||
self.beginChatHistoryTransitions(resetScrolling: false)
|
||||
self.beginChatHistoryTransitions(resetScrolling: false, switchedToAnotherSource: true)
|
||||
}
|
||||
|
||||
private func beginAdMessageManagement(adMessages: Signal<(interPostInterval: Int32?, messages: [Message]), NoError>) {
|
||||
|
|
@ -1293,7 +1293,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
private let previousView = Atomic<(ChatHistoryView, Int, Set<MessageId>?, Int)?>(value: nil)
|
||||
private let previousHistoryAppearsCleared = Atomic<Bool?>(value: nil)
|
||||
|
||||
private func beginChatHistoryTransitions(resetScrolling: Bool) {
|
||||
private func beginChatHistoryTransitions(resetScrolling: Bool, switchedToAnotherSource: Bool) {
|
||||
self.historyDisposable.set(nil)
|
||||
self._isReady.set(false)
|
||||
|
||||
|
|
@ -2085,6 +2085,10 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
var disableAnimations = false
|
||||
var forceSynchronous = false
|
||||
|
||||
if switchedToAnotherSource {
|
||||
disableAnimations = true
|
||||
}
|
||||
|
||||
if let previousValueAndVersion = previousValueAndVersion, allAdMessages.version != previousValueAndVersion.3 {
|
||||
reason = ChatHistoryViewTransitionReason.Reload
|
||||
disableAnimations = true
|
||||
|
|
@ -2243,7 +2247,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
mappedTransition.options.remove(.AnimateTopItemPosition)
|
||||
mappedTransition.options.remove(.RequestItemInsertionAnimations)
|
||||
}
|
||||
if forceSynchronous || resetScrolling {
|
||||
if forceSynchronous || resetScrolling || switchedToAnotherSource {
|
||||
mappedTransition.options.insert(.Synchronous)
|
||||
}
|
||||
if resetScrolling {
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ func inputContextQueriesForChatPresentationIntefaceState(_ chatPresentationInter
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
return []
|
||||
case .postSuggestions:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,8 +241,6 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
stickersEnabled = false
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2108,39 +2108,6 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||
}
|
||||
case .businessLinkSetup:
|
||||
actions.removeAll()
|
||||
case .postSuggestions:
|
||||
//TODO:release
|
||||
actions.removeAll()
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_MessageDialogEdit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, f in
|
||||
interfaceInteraction.setupEditMessage(messages[0].id, { transition in
|
||||
f(.custom(transition))
|
||||
})
|
||||
})))
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.ScheduledMessages_EditTime, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Schedule"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
controllerInteraction.editScheduledMessagesTime(messages.map { $0.id })
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
actions.append(.action(ContextMenuActionItem(text: "Edit Price", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Tag"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
actions.append(.action(ContextMenuActionItem(text: "Delete", textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { controller, f in
|
||||
interfaceInteraction.deleteMessages(messages, controller, f)
|
||||
})))
|
||||
actions.append(.separator)
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let action: ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)? = nil
|
||||
actions.append(.action(ContextMenuActionItem(text: "Deleting suggested post will auto-refund your order.", textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: action)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,7 @@ import ChatChannelSubscriberInputPanelNode
|
|||
import ChatMessageSelectionInputPanelNode
|
||||
|
||||
func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatInputPanelNode?, currentSecondaryPanel: ChatInputPanelNode?, textInputPanelNode: ChatTextInputPanelNode?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> (primary: ChatInputPanelNode?, secondary: ChatInputPanelNode?) {
|
||||
var isPostSuggestions = false
|
||||
if case let .customChatContents(customChatContents) = chatPresentationInterfaceState.subject, case .postSuggestions = customChatContents.kind {
|
||||
isPostSuggestions = true
|
||||
}
|
||||
|
||||
if isPostSuggestions {
|
||||
} else if let renderedPeer = chatPresentationInterfaceState.renderedPeer, renderedPeer.peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) != nil {
|
||||
if let renderedPeer = chatPresentationInterfaceState.renderedPeer, renderedPeer.peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) != nil {
|
||||
return (nil, nil)
|
||||
}
|
||||
if chatPresentationInterfaceState.isNotAccessible {
|
||||
|
|
@ -138,8 +132,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||
}
|
||||
}
|
||||
|
||||
if isPostSuggestions {
|
||||
} else if chatPresentationInterfaceState.peerIsBlocked, let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo == nil {
|
||||
if chatPresentationInterfaceState.peerIsBlocked, let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo == nil {
|
||||
if let currentPanel = (currentPanel as? ChatUnblockInputPanelNode) ?? (currentSecondaryPanel as? ChatUnblockInputPanelNode) {
|
||||
currentPanel.interfaceInteraction = interfaceInteraction
|
||||
currentPanel.updateThemeAndStrings(theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings)
|
||||
|
|
@ -154,9 +147,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||
|
||||
var displayInputTextPanel = false
|
||||
|
||||
if isPostSuggestions {
|
||||
displayInputTextPanel = true
|
||||
} else if let peer = chatPresentationInterfaceState.renderedPeer?.peer {
|
||||
if let peer = chatPresentationInterfaceState.renderedPeer?.peer {
|
||||
if peer.id.isRepliesOrVerificationCodes {
|
||||
if let currentPanel = (currentPanel as? ChatChannelSubscriberInputPanelNode) ?? (currentSecondaryPanel as? ChatChannelSubscriberInputPanelNode) {
|
||||
return (currentPanel, nil)
|
||||
|
|
@ -239,7 +230,20 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||
}
|
||||
|
||||
if channel.flags.contains(.isMonoforum) {
|
||||
displayInputTextPanel = true
|
||||
if channel.adminRights != nil, case .peer = chatPresentationInterfaceState.chatLocation {
|
||||
displayInputTextPanel = false
|
||||
|
||||
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
|
||||
return (currentPanel, nil)
|
||||
} else {
|
||||
let panel = ChatRestrictedInputPanelNode()
|
||||
panel.context = context
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return (panel, nil)
|
||||
}
|
||||
} else {
|
||||
displayInputTextPanel = true
|
||||
}
|
||||
} else if channel.flags.contains(.isForum) && isMember {
|
||||
var canManage = false
|
||||
if channel.flags.contains(.isCreator) {
|
||||
|
|
@ -418,8 +422,6 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||
displayInputTextPanel = false
|
||||
case .quickReplyMessageInput, .businessLinkSetup:
|
||||
displayInputTextPanel = true
|
||||
case .postSuggestions:
|
||||
displayInputTextPanel = true
|
||||
}
|
||||
|
||||
if let chatHistoryState = chatPresentationInterfaceState.chatHistoryState, case .loaded(_, true) = chatHistoryState {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
|||
switch customChatContents.kind {
|
||||
case .hashTagSearch:
|
||||
break
|
||||
case .quickReplyMessageInput, .businessLinkSetup, .postSuggestions:
|
||||
case .quickReplyMessageInput, .businessLinkSetup:
|
||||
if let currentButton = currentButton, currentButton.action == .dismiss {
|
||||
return currentButton
|
||||
} else {
|
||||
|
|
@ -149,8 +149,6 @@ func rightNavigationButtonForChatInterfaceState(context: AccountContext, present
|
|||
buttonItem.accessibilityLabel = strings.Common_Done
|
||||
return ChatNavigationButton(action: .edit, buttonItem: buttonItem)
|
||||
}
|
||||
case .postSuggestions:
|
||||
return chatInfoNavigationButton
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,8 +68,6 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
|||
panel.interfaceInteraction = interfaceInteraction
|
||||
return panel
|
||||
}
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
|
@ -167,19 +165,6 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
|||
}
|
||||
}
|
||||
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isForumOrMonoForum {
|
||||
let topicListDisplayMode = chatPresentationInterfaceState.topicListDisplayMode ?? .top
|
||||
if case .top = topicListDisplayMode, let peerId = chatPresentationInterfaceState.chatLocation.peerId {
|
||||
if let currentPanel = currentPanel as? ChatTopicListTitleAccessoryPanelNode {
|
||||
return currentPanel
|
||||
} else {
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId)
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return panel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedContext == nil || selectedContext! <= .pinnedMessage) {
|
||||
if displayActionsPanel {
|
||||
if let currentPanel = currentPanel as? ChatReportPeerTitlePanelNode {
|
||||
|
|
@ -246,13 +231,30 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
|||
return nil
|
||||
}
|
||||
|
||||
func titleTopicsPanelForChatPresentationInterfaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatTitleAccessoryPanelNode?, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, force: Bool) -> ChatTopicListTitleAccessoryPanelNode? {
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isForumOrMonoForum, channel.adminRights != nil {
|
||||
let topicListDisplayMode = chatPresentationInterfaceState.topicListDisplayMode ?? .top
|
||||
if case .top = topicListDisplayMode, let peerId = chatPresentationInterfaceState.chatLocation.peerId {
|
||||
if let currentPanel = currentPanel as? ChatTopicListTitleAccessoryPanelNode {
|
||||
return currentPanel
|
||||
} else {
|
||||
let panel = ChatTopicListTitleAccessoryPanelNode(context: context, peerId: peerId)
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return panel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sidePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: AnyComponentWithIdentity<ChatSidePanelEnvironment>?, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, force: Bool) -> AnyComponentWithIdentity<ChatSidePanelEnvironment>? {
|
||||
guard let peerId = chatPresentationInterfaceState.chatLocation.peerId else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isForumOrMonoForum {
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isForumOrMonoForum, channel.adminRights != nil {
|
||||
let topicListDisplayMode = chatPresentationInterfaceState.topicListDisplayMode ?? .top
|
||||
if case .side = topicListDisplayMode {
|
||||
return AnyComponentWithIdentity(
|
||||
|
|
|
|||
|
|
@ -89,7 +89,10 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
|
|||
if let context = self.context {
|
||||
accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
}
|
||||
if let _ = accountFreezeConfiguration?.freezeUntilDate {
|
||||
if let channel = interfaceState.renderedPeer?.chatMainPeer as? TelegramChannel, channel.isMonoForum {
|
||||
//TODO:localize
|
||||
self.textNode.attributedText = NSAttributedString(string: "Choose a thread to reply", font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
|
||||
} else if let _ = accountFreezeConfiguration?.freezeUntilDate {
|
||||
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelFrozenAccount_Title, font: Font.semibold(15.0), textColor: interfaceState.theme.list.itemDestructiveColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_PanelFrozenAccount_Text, font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
|
||||
isUserInteractionEnabled = true
|
||||
|
|
@ -128,8 +131,6 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode {
|
|||
displayCount = customChatContents.messageLimit ?? 20
|
||||
case .businessLinkSetup:
|
||||
displayCount = 0
|
||||
case .postSuggestions:
|
||||
displayCount = 0
|
||||
}
|
||||
self.textNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_QuickReplyMessageLimitReachedText(Int32(displayCount)), font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -290,13 +290,6 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessageAction
|
|||
}
|
||||
}
|
||||
starsAmount = amount
|
||||
} else if case let .customChatContents(customChatContents) = interfaceState.subject {
|
||||
switch customChatContents.kind {
|
||||
case let .postSuggestions(postSuggestions):
|
||||
starsAmount = postSuggestions.value
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let amount = starsAmount {
|
||||
|
|
|
|||
|
|
@ -1567,8 +1567,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
displayMediaButton = false
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1955,10 +1953,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
}
|
||||
case .businessLinkSetup:
|
||||
placeholder = interfaceState.strings.Chat_Placeholder_BusinessLinkPreset
|
||||
case let .postSuggestions(postSuggestions):
|
||||
//TODO:localize
|
||||
placeholder = "Suggest for # \(postSuggestions)"
|
||||
placeholderHasStar = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1986,8 +1980,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
sendButtonHasApplyIcon = true
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2515,8 +2507,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
showTitle = true
|
||||
} else if case let .customChatContents(customChatContents) = interfaceState.subject {
|
||||
switch customChatContents.kind {
|
||||
case .postSuggestions:
|
||||
showTitle = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
@ -3794,8 +3784,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
keepSendButtonEnabled = true
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3916,8 +3904,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
hideMicButton = true
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4023,8 +4009,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||
break
|
||||
case .businessLinkSetup:
|
||||
sendButtonHasApplyIcon = true
|
||||
case .postSuggestions:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||
let iconSize = self.icon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(BundleIconComponent(
|
||||
name: "Call/PanelIcon",
|
||||
name: "Chat/Title Panels/SidebarIcon",
|
||||
tintColor: theme.rootController.navigationBar.secondaryTextColor,
|
||||
maxSize: nil,
|
||||
scaleFactor: 1.0
|
||||
|
|
@ -658,7 +658,7 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||
let itemSpacing: CGFloat = 24.0
|
||||
|
||||
var contentSize = CGSize(width: 0.0, height: panelHeight)
|
||||
contentSize.width += containerInsets.left
|
||||
contentSize.width += containerInsets.left + 8.0
|
||||
|
||||
var validIds: [Item.Id] = []
|
||||
var isFirst = true
|
||||
|
|
@ -862,4 +862,10 @@ final class ChatTopicListTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, C
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateGlobalOffset(globalOffset: CGFloat, transition: ComponentTransition) {
|
||||
if let tabItemView = self.tabItemView {
|
||||
transition.setTransform(view: tabItemView, transform: CATransform3DMakeTranslation(0.0, -globalOffset, 0.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
}, forceUpdateWarpContents: {
|
||||
}, playShakeAnimation: {
|
||||
}, displayQuickShare: { _, _ ,_ in
|
||||
}, updateChatLocationThread: { _ in
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil))
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
|
|
|
|||
|
|
@ -2388,6 +2388,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
}, forceUpdateWarpContents: {
|
||||
}, playShakeAnimation: {
|
||||
}, displayQuickShare: { _, _ ,_ in
|
||||
}, updateChatLocationThread: { _ in
|
||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: backgroundNode as? WallpaperBackgroundNode))
|
||||
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
|
|||
header.updateNode(headerNode, previous: nil, next: nil)
|
||||
headerNode.item = header
|
||||
}
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, transition: .immediate)
|
||||
} else {
|
||||
headerNode = header.node(synchronousLoad: true)
|
||||
|
|
@ -305,7 +305,7 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
|
|||
headerNode.item = header
|
||||
}
|
||||
headerNode.frame = headerFrame
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset)
|
||||
headerNode.updateLayoutInternal(size: headerFrame.size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
strongSelf.itemHeaderNodes[id] = headerNode
|
||||
|
||||
strongSelf.containerNode.addSubnode(headerNode)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue