mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-19 17:51:29 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
e7772bb581
@ -1763,7 +1763,7 @@ private final class NotificationServiceHandler {
|
||||
|> mapToSignal { content, _ -> Signal<(NotificationContent, Media?), NoError> in
|
||||
return stateManager.postbox.transaction { transaction -> (NotificationContent, Media?) in
|
||||
var parsedMedia: Media?
|
||||
if let messageId, let message = transaction.getMessage(messageId), !message.containsSecretMedia {
|
||||
if let messageId, let message = transaction.getMessage(messageId), !message.containsSecretMedia, !message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) {
|
||||
if let media = message.media.first {
|
||||
parsedMedia = media
|
||||
}
|
||||
|
@ -1105,7 +1105,7 @@ public struct PresentationResourcesChat {
|
||||
|
||||
public static func chatFreeNavigateButtonIcon(_ theme: PresentationTheme, wallpaper: TelegramWallpaper) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.chatFreeNavigateButtonIcon.rawValue, { _ in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: bubbleVariableColor(variableColor: theme.chat.message.shareButtonForegroundColor, wallpaper: wallpaper))
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/NavigateToMessageIcon"), color: bubbleVariableColor(variableColor: theme.chat.message.shareButtonForegroundColor, wallpaper: wallpaper))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1926,7 +1926,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
inlineBotNameString = attribute.title
|
||||
}
|
||||
} else if let attribute = attribute as? ReplyMessageAttribute {
|
||||
if case let .replyThread(replyThreadMessage) = item.chatLocation, Int32(clamping: replyThreadMessage.threadId) == attribute.messageId.id {
|
||||
if let threadId = firstMessage.threadId, Int32(clamping: threadId) == attribute.messageId.id {
|
||||
} else {
|
||||
replyMessage = firstMessage.associatedMessages[attribute.messageId]
|
||||
}
|
||||
|
@ -531,7 +531,11 @@ public class ChatMessageForwardInfoNode: ASDisplayNode {
|
||||
avatarNode.frame = CGRect(origin: CGPoint(x: leftOffset, y: titleLayout.size.height + titleAuthorSpacing), size: avatarSize)
|
||||
avatarNode.updateSize(size: avatarSize)
|
||||
if let peer {
|
||||
avatarNode.setPeer(context: context, theme: presentationData.theme.theme, peer: EnginePeer(peer), displayDimensions: avatarSize)
|
||||
if peer.smallProfileImage != nil {
|
||||
avatarNode.setPeerV2(context: context, theme: presentationData.theme.theme, peer: EnginePeer(peer), displayDimensions: avatarSize)
|
||||
} else {
|
||||
avatarNode.setPeer(context: context, theme: presentationData.theme.theme, peer: EnginePeer(peer), displayDimensions: avatarSize)
|
||||
}
|
||||
} else if let authorName, !authorName.isEmpty {
|
||||
avatarNode.setCustomLetters([String(authorName[authorName.startIndex])])
|
||||
} else {
|
||||
|
@ -322,7 +322,9 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
|
||||
|
||||
if let channel = content.firstMessage.peers[content.firstMessage.id.peerId] as? TelegramChannel, channel.isForumOrMonoForum {
|
||||
if case .replyThread = chatLocation {
|
||||
displayAuthorInfo = false
|
||||
if channel.isMonoForum && chatLocation.threadId != context.account.peerId.toInt64() {
|
||||
displayAuthorInfo = false
|
||||
}
|
||||
} else {
|
||||
if channel.isMonoForum {
|
||||
if let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = content.firstMessage.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.adminRights != nil {
|
||||
|
@ -38,7 +38,7 @@ public class ChatUnreadItem: ListViewItem {
|
||||
Queue.mainQueue().async {
|
||||
completion(node, {
|
||||
return (nil, { _ in
|
||||
apply()
|
||||
apply(.None)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -56,7 +56,7 @@ public class ChatUnreadItem: ListViewItem {
|
||||
let (layout, apply) = nodeLayout(self, params, dateAtBottom)
|
||||
Queue.mainQueue().async {
|
||||
completion(layout, { _ in
|
||||
apply()
|
||||
apply(animation)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -122,18 +122,18 @@ public class ChatUnreadItemNode: ListViewItemNode {
|
||||
if let item = item as? ChatUnreadItem {
|
||||
let dateAtBottom = !chatItemsHaveCommonDateHeader(item, nextItem)
|
||||
let (layout, apply) = self.asyncLayout()(item, params, dateAtBottom)
|
||||
apply()
|
||||
apply(.None)
|
||||
self.contentSize = layout.contentSize
|
||||
self.insets = layout.insets
|
||||
}
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ item: ChatUnreadItem, _ params: ListViewItemLayoutParams, _ dateAtBottom: Bool) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
public func asyncLayout() -> (_ item: ChatUnreadItem, _ params: ListViewItemLayoutParams, _ dateAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
|
||||
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
||||
let layoutConstants = self.layoutConstants
|
||||
let currentTheme = self.theme
|
||||
|
||||
return { item, params, dateAtBottom in
|
||||
return { [weak self] item, params, dateAtBottom in
|
||||
var updatedBackgroundImage: UIImage?
|
||||
if currentTheme != item.presentationData.theme {
|
||||
updatedBackgroundImage = PresentationResourcesChat.chatUnreadBarBackgroundImage(item.presentationData.theme.theme)
|
||||
@ -144,7 +144,7 @@ public class ChatUnreadItemNode: ListViewItemNode {
|
||||
|
||||
let backgroundSize = CGSize(width: params.width, height: 25.0)
|
||||
|
||||
return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: 25.0), insets: UIEdgeInsets(top: 6.0 + (dateAtBottom ? layoutConstants.timestampHeaderHeight : 0.0), left: 0.0, bottom: 5.0, right: 0.0)), { [weak self] in
|
||||
return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: 25.0), insets: UIEdgeInsets(top: 6.0 + (dateAtBottom ? layoutConstants.timestampHeaderHeight : 0.0), left: 0.0, bottom: 5.0, right: 0.0)), { animation in
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = item
|
||||
strongSelf.theme = item.presentationData.theme
|
||||
@ -159,7 +159,10 @@ public class ChatUnreadItemNode: ListViewItemNode {
|
||||
strongSelf.activateArea.accessibilityLabel = string
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: backgroundSize)
|
||||
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - size.size.width) / 2.0), y: floorToScreenPixels((backgroundSize.height - size.size.height) / 2.0)), size: size.size)
|
||||
|
||||
let labelFrame = CGRect(origin: CGPoint(x: params.leftInset + floorToScreenPixels((backgroundSize.width - params.leftInset - params.rightInset - size.size.width) / 2.0), y: floorToScreenPixels((backgroundSize.height - size.size.height) / 2.0)), size: size.size)
|
||||
animation.animator.updatePosition(layer: strongSelf.labelNode.layer, position: labelFrame.center, completion: nil)
|
||||
strongSelf.labelNode.bounds = CGRect(origin: CGPoint(), size: labelFrame.size)
|
||||
|
||||
if item.controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true {
|
||||
if strongSelf.backgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
|
@ -1148,7 +1148,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
self.superview?.insertSubview(snapshotState.snapshotView, belowSubview: self)
|
||||
|
||||
let snapshotView = snapshotState.snapshotView
|
||||
snapshotState.snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotState.snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.14, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -offset.x, y: -offset.y), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
|
||||
|
@ -127,7 +127,7 @@ import PostSuggestionsSettingsScreen
|
||||
import ChatSendStarsScreen
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func reloadChatLocation(chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, historyNode: ChatHistoryListNodeImpl, isReady: Promise<Bool>?) {
|
||||
func reloadChatLocation(chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, historyNode: ChatHistoryListNodeImpl, apply: @escaping ((Bool) -> Void) -> Void) {
|
||||
self.contentDataReady.set(false)
|
||||
|
||||
self.contentDataDisposable?.dispose()
|
||||
@ -159,29 +159,42 @@ extension ChatControllerImpl {
|
||||
self.contentDataDisposable = (contentData.isReady.get()
|
||||
|> filter { $0 }
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self, weak contentData] _ in
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self, weak contentData, weak historyNode] _ in
|
||||
guard let self, let contentData, self.pendingContentData?.contentData === contentData else {
|
||||
return
|
||||
}
|
||||
self.contentData = contentData
|
||||
self.pendingContentData = nil
|
||||
self.contentDataUpdated(synchronous: true, previousState: contentData.state)
|
||||
|
||||
self.chatThemeEmoticonPromise.set(contentData.chatThemeEmoticonPromise.get())
|
||||
self.chatWallpaperPromise.set(contentData.chatWallpaperPromise.get())
|
||||
|
||||
self.contentDataReady.set(true)
|
||||
|
||||
contentData.onUpdated = { [weak self, weak contentData] previousState in
|
||||
guard let self, let contentData, self.contentData === contentData else {
|
||||
apply({ [weak self, weak contentData] forceAnimation in
|
||||
guard let self, let contentData, self.pendingContentData?.contentData === contentData else {
|
||||
return
|
||||
}
|
||||
self.contentDataUpdated(synchronous: false, previousState: previousState)
|
||||
}
|
||||
|
||||
self.contentData = contentData
|
||||
self.pendingContentData = nil
|
||||
self.contentDataUpdated(synchronous: true, forceAnimation: forceAnimation, previousState: contentData.state)
|
||||
|
||||
self.chatThemeEmoticonPromise.set(contentData.chatThemeEmoticonPromise.get())
|
||||
self.chatWallpaperPromise.set(contentData.chatWallpaperPromise.get())
|
||||
|
||||
if let historyNode {
|
||||
self.setupChatHistoryNode(historyNode: historyNode)
|
||||
|
||||
historyNode.contentPositionChanged(historyNode.visibleContentOffset())
|
||||
}
|
||||
|
||||
self.contentDataReady.set(true)
|
||||
|
||||
contentData.onUpdated = { [weak self, weak contentData] previousState in
|
||||
guard let self, let contentData, self.contentData === contentData else {
|
||||
return
|
||||
}
|
||||
self.contentDataUpdated(synchronous: false, forceAnimation: false, previousState: previousState)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func contentDataUpdated(synchronous: Bool, previousState: ContentData.State) {
|
||||
func contentDataUpdated(synchronous: Bool, forceAnimation: Bool, previousState: ContentData.State) {
|
||||
guard let contentData = self.contentData else {
|
||||
return
|
||||
}
|
||||
@ -293,19 +306,23 @@ extension ChatControllerImpl {
|
||||
if self.presentationInterfaceState.search != nil && contentData.state.hasSearchTags {
|
||||
displayActionsPanel = true
|
||||
}
|
||||
|
||||
if displayActionsPanel != didDisplayActionsPanel {
|
||||
animated = true
|
||||
}
|
||||
|
||||
if previousState.pinnedMessage != contentData.state.pinnedMessage {
|
||||
animated = true
|
||||
}
|
||||
if forceAnimation {
|
||||
animated = true
|
||||
}
|
||||
|
||||
self.updateChatPresentationInterfaceState(animated: animated && self.willAppear, interactive: false, { presentationInterfaceState in
|
||||
var presentationInterfaceState = presentationInterfaceState
|
||||
presentationInterfaceState = presentationInterfaceState.updatedPeer({ _ in
|
||||
return contentData.state.renderedPeer
|
||||
})
|
||||
presentationInterfaceState = presentationInterfaceState.updatedChatLocation(contentData.chatLocation)
|
||||
presentationInterfaceState = presentationInterfaceState.updatedIsNotAccessible(contentData.state.isNotAccessible)
|
||||
presentationInterfaceState = presentationInterfaceState.updatedContactStatus(contentData.state.contactStatus)
|
||||
presentationInterfaceState = presentationInterfaceState.updatedHasBots(contentData.state.hasBots)
|
||||
@ -749,7 +766,7 @@ extension ChatControllerImpl {
|
||||
})).startStandalone()
|
||||
}
|
||||
|
||||
self.setupChatHistoryNode()
|
||||
self.setupChatHistoryNode(historyNode: self.chatDisplayNode.historyNode)
|
||||
|
||||
self.chatDisplayNode.requestLayout = { [weak self] transition in
|
||||
self?.requestLayout(transition: transition)
|
||||
@ -1206,7 +1223,7 @@ extension ChatControllerImpl {
|
||||
self.scrollToEndOfHistory()
|
||||
}
|
||||
} else {
|
||||
if let messageId = self.historyNavigationStack.removeLast() {
|
||||
if let messageId = self.contentData?.historyNavigationStack.removeLast() {
|
||||
self.navigateToMessage(from: nil, to: .id(messageId.id, NavigateToMessageParams(timestamp: nil, quote: nil)), rememberInStack: false)
|
||||
} else {
|
||||
if case .known = self.chatDisplayNode.historyNode.visibleContentOffset() {
|
||||
@ -4295,7 +4312,7 @@ extension ChatControllerImpl {
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
func setupChatHistoryNode() {
|
||||
func setupChatHistoryNode(historyNode: ChatHistoryListNodeImpl) {
|
||||
do {
|
||||
let peerId = self.chatLocation.peerId
|
||||
if let subject = self.subject, case .scheduledMessages = subject {
|
||||
@ -4582,8 +4599,10 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.contentPositionChanged = { [weak self] offset in
|
||||
guard let strongSelf = self else { return }
|
||||
historyNode.contentPositionChanged = { [weak self, weak historyNode] offset in
|
||||
guard let strongSelf = self, let historyNode, strongSelf.chatDisplayNode.historyNode === historyNode else {
|
||||
return
|
||||
}
|
||||
|
||||
var minOffsetForNavigation: CGFloat = 40.0
|
||||
strongSelf.chatDisplayNode.historyNode.enumerateItemNodes { itemNode in
|
||||
@ -4632,7 +4651,7 @@ extension ChatControllerImpl {
|
||||
strongSelf.chatDisplayNode.updatePlainInputSeparatorAlpha(plainInputSeparatorAlpha, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.scrolledToIndex = { [weak self] toSubject, initial in
|
||||
historyNode.scrolledToIndex = { [weak self] toSubject, initial in
|
||||
if let strongSelf = self, case let .message(index) = toSubject.index {
|
||||
if case let .message(messageSubject, _, _, _) = strongSelf.subject, initial, case let .id(messageId) = messageSubject, messageId != index.id {
|
||||
if messageId.peerId == index.id.peerId {
|
||||
@ -4693,16 +4712,16 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.scrolledToSomeIndex = { [weak self] in
|
||||
historyNode.scrolledToSomeIndex = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.contentData?.scrolledToMessageIdValue = nil
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.maxVisibleMessageIndexUpdated = { [weak self] index in
|
||||
if let strongSelf = self, !strongSelf.historyNavigationStack.isEmpty {
|
||||
strongSelf.historyNavigationStack.filterOutIndicesLessThan(index)
|
||||
historyNode.maxVisibleMessageIndexUpdated = { [weak self] index in
|
||||
if let strongSelf = self, let contentData = strongSelf.contentData, !contentData.historyNavigationStack.isEmpty {
|
||||
contentData.historyNavigationStack.filterOutIndicesLessThan(index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4723,7 +4742,7 @@ extension ChatControllerImpl {
|
||||
hasActiveCalls = .single(false)
|
||||
}
|
||||
|
||||
let shouldBeActive = combineLatest(self.context.sharedContext.mediaManager.audioSession.isPlaybackActive() |> deliverOnMainQueue, self.chatDisplayNode.historyNode.hasVisiblePlayableItemNodes, hasActiveCalls)
|
||||
let shouldBeActive = combineLatest(self.context.sharedContext.mediaManager.audioSession.isPlaybackActive() |> deliverOnMainQueue, historyNode.hasVisiblePlayableItemNodes, hasActiveCalls)
|
||||
|> mapToSignal { [weak self] isPlaybackActive, hasVisiblePlayableItemNodes, hasActiveCalls -> Signal<Bool, NoError> in
|
||||
if hasVisiblePlayableItemNodes && !isPlaybackActive && !hasActiveCalls {
|
||||
return Signal<Bool, NoError> { [weak self] subscriber in
|
||||
@ -4776,7 +4795,7 @@ extension ChatControllerImpl {
|
||||
downPressed: buttonAction
|
||||
)
|
||||
|
||||
self.chatDisplayNode.historyNode.openNextChannelToRead = { [weak self] peer, threadData, location in
|
||||
historyNode.openNextChannelToRead = { [weak self] peer, threadData, location in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -4831,7 +4850,7 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.beganDragging = { [weak self] in
|
||||
historyNode.beganDragging = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -4846,7 +4865,7 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.didScrollWithOffset = { [weak self] offset, transition, itemNode, isTracking in
|
||||
historyNode.didScrollWithOffset = { [weak self] offset, transition, itemNode, isTracking in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -4876,23 +4895,22 @@ extension ChatControllerImpl {
|
||||
strongSelf.chatDisplayNode.loadingPlaceholderNode?.addContentOffset(offset: offset, transition: transition)
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.addExternalOffset(offset: offset, transition: transition, itemNode: itemNode, isRotated: strongSelf.chatDisplayNode.historyNode.rotated)
|
||||
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.hasAtLeast3MessagesUpdated = { [weak self] hasAtLeast3Messages in
|
||||
historyNode.hasAtLeast3MessagesUpdated = { [weak self] hasAtLeast3Messages in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(interactive: false, { $0.updatedHasAtLeast3Messages(hasAtLeast3Messages) })
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.hasPlentyOfMessagesUpdated = { [weak self] hasPlentyOfMessages in
|
||||
historyNode.hasPlentyOfMessagesUpdated = { [weak self] hasPlentyOfMessages in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(interactive: false, { $0.updatedHasPlentyOfMessages(hasPlentyOfMessages) })
|
||||
}
|
||||
}
|
||||
|
||||
if self.didAppear {
|
||||
self.chatDisplayNode.historyNode.canReadHistory.set(self.computedCanReadHistoryPromise.get())
|
||||
historyNode.canReadHistory.set(self.computedCanReadHistoryPromise.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ extension ChatControllerImpl {
|
||||
})
|
||||
} else if forceInCurrentChat {
|
||||
if let _ = fromId, let fromIndex = fromIndex, rememberInStack {
|
||||
self.historyNavigationStack.add(fromIndex)
|
||||
self.contentData?.historyNavigationStack.add(fromIndex)
|
||||
}
|
||||
|
||||
let scrollFromIndex: MessageIndex?
|
||||
@ -505,7 +505,7 @@ extension ChatControllerImpl {
|
||||
return
|
||||
}
|
||||
if let _ = fromId, rememberInStack {
|
||||
self.historyNavigationStack.add(fromIndex)
|
||||
self.contentData?.historyNavigationStack.add(fromIndex)
|
||||
}
|
||||
self.loadingMessage.set(.single(statusSubject) |> delay(0.1, queue: .mainQueue()))
|
||||
|
||||
|
@ -23,8 +23,6 @@ func updateChatPresentationInterfaceStateImpl(
|
||||
_ f: (ChatPresentationInterfaceState) -> ChatPresentationInterfaceState,
|
||||
completion externalCompletion: @escaping (ContainedViewLayoutTransition) -> Void
|
||||
) {
|
||||
let previousChatLocation = selfController.chatDisplayNode.historyNode.chatLocation
|
||||
|
||||
var completion = externalCompletion
|
||||
var temporaryChatPresentationInterfaceState = f(selfController.presentationInterfaceState)
|
||||
|
||||
@ -436,13 +434,13 @@ func updateChatPresentationInterfaceStateImpl(
|
||||
|
||||
selfController.presentationInterfaceState = updatedChatPresentationInterfaceState
|
||||
|
||||
if selfController.chatDisplayNode.chatLocation != selfController.presentationInterfaceState.chatLocation {
|
||||
/*if selfController.chatDisplayNode.chatLocation != selfController.presentationInterfaceState.chatLocation {
|
||||
let defaultDirection: ChatControllerAnimateInnerChatSwitchDirection? = selfController.chatDisplayNode.chatLocationTabSwitchDirection(from: selfController.chatLocation.threadId, to: selfController.presentationInterfaceState.chatLocation.threadId).flatMap { direction -> ChatControllerAnimateInnerChatSwitchDirection in
|
||||
return direction ? .right : .left
|
||||
}
|
||||
let tabSwitchDirection = selfController.currentChatSwitchDirection ?? defaultDirection
|
||||
selfController.chatDisplayNode.updateChatLocation(chatLocation: selfController.presentationInterfaceState.chatLocation, transition: transition, tabSwitchDirection: tabSwitchDirection)
|
||||
}
|
||||
}*/
|
||||
|
||||
selfController.updateSlowmodeStatus()
|
||||
|
||||
@ -603,12 +601,6 @@ func updateChatPresentationInterfaceStateImpl(
|
||||
}
|
||||
}
|
||||
|
||||
if previousChatLocation != selfController.presentationInterfaceState.chatLocation {
|
||||
selfController.chatLocation = selfController.presentationInterfaceState.chatLocation
|
||||
selfController.reloadCachedData()
|
||||
selfController.setupChatHistoryNode()
|
||||
}
|
||||
|
||||
selfController.updateDownButtonVisibility()
|
||||
|
||||
if selfController.presentationInterfaceState.hasBirthdayToday {
|
||||
|
@ -389,8 +389,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
var searchDisposable: MetaDisposable?
|
||||
|
||||
var historyNavigationStack = ChatHistoryNavigationStack()
|
||||
|
||||
public let canReadHistory = ValuePromise<Bool>(true, ignoreRepeated: true)
|
||||
public let hasBrowserOrAppInFront = Promise<Bool>(false)
|
||||
|
||||
@ -5230,7 +5228,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
|
||||
self.reloadChatLocation(chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, historyNode: self.chatDisplayNode.historyNode, isReady: nil)
|
||||
self.reloadChatLocation(chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, historyNode: self.chatDisplayNode.historyNode, apply: { $0(false) })
|
||||
|
||||
self.botCallbackAlertMessageDisposable = (self.botCallbackAlertMessage.get()
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] message in
|
||||
@ -9711,10 +9709,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var currentChatSwitchDirection: ChatControllerAnimateInnerChatSwitchDirection?
|
||||
|
||||
public func updateChatLocationThread(threadId: Int64?, animationDirection: ChatControllerAnimateInnerChatSwitchDirection? = nil) {
|
||||
/*if self.isUpdatingChatLocationThread {
|
||||
if self.isUpdatingChatLocationThread {
|
||||
return
|
||||
}
|
||||
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
@ -9725,16 +9722,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
let navigationSnapshot = self.chatTitleView?.prepareSnapshotState()
|
||||
|
||||
//let historyNode = self.chatDisplayNode.createHistoryNodeForChatLocation(chatLocation: self.chatLocation, chatLocationContextHolder: )
|
||||
|
||||
let rightBarButtonItemSnapshots: [(UIView, CGRect)] = (self.navigationItem.rightBarButtonItems ?? []).compactMap { item -> (UIView, CGRect)? in
|
||||
guard let view = item.customDisplayNode?.view, let snapshotView = view.snapshotView(afterScreenUpdates: false) else {
|
||||
return nil
|
||||
}
|
||||
return (snapshotView, view.convert(view.bounds, to: self.view))
|
||||
}
|
||||
self.saveInterfaceState()
|
||||
|
||||
let updatedChatLocation: ChatLocation
|
||||
if let threadId {
|
||||
@ -9762,6 +9750,77 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
updatedChatLocation = .peer(id: peerId)
|
||||
}
|
||||
|
||||
let navigationSnapshot = self.chatTitleView?.prepareSnapshotState()
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
let historyNode = self.chatDisplayNode.createHistoryNodeForChatLocation(chatLocation: updatedChatLocation, chatLocationContextHolder: chatLocationContextHolder)
|
||||
self.isUpdatingChatLocationThread = true
|
||||
self.reloadChatLocation(chatLocation: updatedChatLocation, chatLocationContextHolder: chatLocationContextHolder, historyNode: historyNode, apply: { [weak self, weak historyNode] apply in
|
||||
guard let self, let historyNode else {
|
||||
return
|
||||
}
|
||||
|
||||
self.currentChatSwitchDirection = animationDirection
|
||||
self.chatLocation = updatedChatLocation
|
||||
self.chatDisplayNode.prepareSwitchToChatLocation(historyNode: historyNode, animationDirection: animationDirection)
|
||||
|
||||
apply(true)
|
||||
|
||||
if let navigationSnapshot, let animationDirection {
|
||||
let mappedAnimationDirection: ChatTitleView.AnimateFromSnapshotDirection
|
||||
switch animationDirection {
|
||||
case .up:
|
||||
mappedAnimationDirection = .up
|
||||
case .down:
|
||||
mappedAnimationDirection = .down
|
||||
case .left:
|
||||
mappedAnimationDirection = .left
|
||||
case .right:
|
||||
mappedAnimationDirection = .right
|
||||
}
|
||||
|
||||
self.chatTitleView?.animateFromSnapshot(navigationSnapshot, direction: mappedAnimationDirection)
|
||||
/*if let rightBarButtonItems = self.navigationItem.rightBarButtonItems {
|
||||
for i in 0 ..< rightBarButtonItems.count {
|
||||
let item = rightBarButtonItems[i]
|
||||
if let customDisplayNode = item.customDisplayNode {
|
||||
customDisplayNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
//customDisplayNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
|
||||
let _ = rightBarButtonItemSnapshots
|
||||
/*if i < rightBarButtonItemSnapshots.count {
|
||||
let (snapshotItem, snapshotFrame) = rightBarButtonItemSnapshots[i]
|
||||
if let targetSuperview = customDisplayNode.view.superview {
|
||||
snapshotItem.frame = targetSuperview.convert(snapshotFrame, from: self.view)
|
||||
targetSuperview.addSubview(snapshotItem)
|
||||
|
||||
snapshotItem.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, completion: { [weak snapshotItem] _ in
|
||||
snapshotItem?.removeFromSuperview()
|
||||
})
|
||||
snapshotItem.layer.animateScale(from: 1.0, to: 0.1, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
self.currentChatSwitchDirection = nil
|
||||
|
||||
self.isUpdatingChatLocationThread = false
|
||||
})
|
||||
|
||||
/*
|
||||
|
||||
//
|
||||
|
||||
let rightBarButtonItemSnapshots: [(UIView, CGRect)] = (self.navigationItem.rightBarButtonItems ?? []).compactMap { item -> (UIView, CGRect)? in
|
||||
guard let view = item.customDisplayNode?.view, let snapshotView = view.snapshotView(afterScreenUpdates: false) else {
|
||||
return nil
|
||||
}
|
||||
return (snapshotView, view.convert(view.bounds, to: self.view))
|
||||
}
|
||||
|
||||
let isReady = Promise<Bool>()
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
self.reloadChatLocation(chatLocation: updatedChatLocation, chatLocationContextHolder: chatLocationContextHolder, historyNode: historyNode, isReady: isReady)
|
||||
|
@ -144,6 +144,7 @@ extension ChatControllerImpl {
|
||||
private let isChatLocationInfoReady = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
private let isCachedDataReady = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
|
||||
let chatLocation: ChatLocation
|
||||
let chatLocationInfoData: ChatLocationInfoData
|
||||
|
||||
private(set) var state: State = State()
|
||||
@ -172,6 +173,8 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
var historyNavigationStack = ChatHistoryNavigationStack()
|
||||
|
||||
let chatThemeEmoticonPromise = Promise<String?>()
|
||||
let chatWallpaperPromise = Promise<TelegramWallpaper?>()
|
||||
|
||||
@ -191,6 +194,7 @@ extension ChatControllerImpl {
|
||||
presentationData: PresentationData,
|
||||
historyNode: ChatHistoryListNodeImpl
|
||||
) {
|
||||
self.chatLocation = chatLocation
|
||||
self.presentationData = presentationData
|
||||
let strings = self.presentationData.strings
|
||||
|
||||
|
@ -133,6 +133,19 @@ class HistoryNodeContainer: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private final class PendingSwitchToChatLocation {
|
||||
let historyNode: ChatHistoryListNodeImpl
|
||||
let animationDirection: ChatControllerAnimateInnerChatSwitchDirection?
|
||||
|
||||
init(
|
||||
historyNode: ChatHistoryListNodeImpl,
|
||||
animationDirection: ChatControllerAnimateInnerChatSwitchDirection?
|
||||
) {
|
||||
self.historyNode = historyNode
|
||||
self.animationDirection = animationDirection
|
||||
}
|
||||
}
|
||||
|
||||
class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
let context: AccountContext
|
||||
private(set) var chatLocation: ChatLocation
|
||||
@ -162,7 +175,10 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
var historyNode: ChatHistoryListNodeImpl
|
||||
var blurredHistoryNode: ASImageNode?
|
||||
let historyNodeContainer: HistoryNodeContainer
|
||||
let loadingNode: ChatLoadingNode
|
||||
private(set) var loadingNode: ChatLoadingNode
|
||||
|
||||
private var isLoadingValue: Bool = false
|
||||
private var isLoadingEarlier: Bool = false
|
||||
private(set) var loadingPlaceholderNode: ChatLoadingPlaceholderNode?
|
||||
|
||||
var alwaysShowSearchResultsAsList: Bool = false
|
||||
@ -316,8 +332,8 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
let adMessagesContext: AdMessagesHistoryContext?
|
||||
|
||||
private var isLoadingValue: Bool = false
|
||||
private var isLoadingEarlier: Bool = false
|
||||
private var pendingSwitchToChatLocation: PendingSwitchToChatLocation?
|
||||
|
||||
private func updateIsLoading(isLoading: Bool, earlier: Bool, animated: Bool) {
|
||||
var useLoadingPlaceholder = self.chatLocation.peerId?.namespace != Namespaces.Peer.CloudUser && self.chatLocation.peerId?.namespace != Namespaces.Peer.SecretChat
|
||||
if case let .replyThread(message) = self.chatLocation, message.peerId == self.context.account.peerId {
|
||||
@ -351,10 +367,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
loadingPlaceholderNode.setup(self.historyNode, updating: false)
|
||||
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: .immediate, listViewTransaction: { _, _, _, _ in
|
||||
}, updateExtraNavigationBarBackgroundHeight: { _, _, _, _ in
|
||||
})
|
||||
let contentBounds = self.loadingNode.frame
|
||||
loadingPlaceholderNode.frame = contentBounds
|
||||
if let loadingPlaceholderNode = self.loadingPlaceholderNode, let validLayout = self.validLayout {
|
||||
loadingPlaceholderNode.updateLayout(size: contentBounds.size, insets: self.visibleAreaInset, metrics: validLayout.0.metrics, transition: .immediate)
|
||||
loadingPlaceholderNode.update(rect: contentBounds, within: contentBounds.size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
loadingPlaceholderNode.alpha = 1.0
|
||||
@ -371,12 +388,17 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
} else {
|
||||
if useLoadingPlaceholder {
|
||||
if let loadingPlaceholderNode = self.loadingPlaceholderNode {
|
||||
loadingPlaceholderNode.animateOut(self.historyNode, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingPlaceholderNode?.removeFromSupernode()
|
||||
strongSelf.loadingPlaceholderNode = nil
|
||||
}
|
||||
})
|
||||
if animated {
|
||||
loadingPlaceholderNode.animateOut(self.historyNode, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingPlaceholderNode?.removeFromSupernode()
|
||||
strongSelf.loadingPlaceholderNode = nil
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.loadingPlaceholderNode = nil
|
||||
loadingPlaceholderNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.loadingNode.alpha = 0.0
|
||||
@ -1295,8 +1317,6 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}
|
||||
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
|
||||
|
||||
var extraTransition = transition
|
||||
|
||||
var dismissedTitleTopicsAccessoryPanelNode: ChatTopicListTitleAccessoryPanelNode?
|
||||
var immediatelyLayoutTitleTopicsAccessoryPanelNodeAndAnimateAppearance = false
|
||||
var titleTopicsAccessoryPanelHeight: CGFloat?
|
||||
@ -1357,9 +1377,6 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
self.titleAccessoryPanelContainer.addSubnode(titleAccessoryPanelNode)
|
||||
|
||||
titleAccessoryPanelNode.clipsToBounds = true
|
||||
if transition.isAnimated {
|
||||
extraTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
}
|
||||
}
|
||||
|
||||
let layoutResult = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: leftPanelSize?.width ?? layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState)
|
||||
@ -1367,9 +1384,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
titleAccessoryPanelBackgroundHeight = layoutResult.backgroundHeight
|
||||
titleAccessoryPanelHitTestSlop = layoutResult.hitTestSlop
|
||||
if immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance {
|
||||
titleAccessoryPanelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
if transition.isAnimated {
|
||||
titleAccessoryPanelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
titleAccessoryPanelNode.subnodeTransform = CATransform3DMakeTranslation(0.0, -layoutResult.backgroundHeight, 0.0)
|
||||
extraTransition.updateSublayerTransformOffset(layer: titleAccessoryPanelNode.layer, offset: CGPoint())
|
||||
transition.updateSublayerTransformOffset(layer: titleAccessoryPanelNode.layer, offset: CGPoint())
|
||||
}
|
||||
} else if let titleAccessoryPanelNode = self.titleAccessoryPanelNode {
|
||||
dismissedTitleAccessoryPanelNode = titleAccessoryPanelNode
|
||||
@ -1412,9 +1431,6 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
self.titleAccessoryPanelContainer.addSubnode(translationPanelNode)
|
||||
|
||||
translationPanelNode.clipsToBounds = true
|
||||
if transition.isAnimated {
|
||||
extraTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
}
|
||||
}
|
||||
|
||||
let height = translationPanelNode.updateLayout(width: layout.size.width, leftInset: leftPanelSize?.width ?? layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState)
|
||||
@ -1422,7 +1438,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
if immediatelyLayoutTranslationPanelNodeAndAnimateAppearance {
|
||||
translationPanelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
translationPanelNode.subnodeTransform = CATransform3DMakeTranslation(0.0, -height, 0.0)
|
||||
extraTransition.updateSublayerTransformOffset(layer: translationPanelNode.layer, offset: CGPoint())
|
||||
transition.updateSublayerTransformOffset(layer: translationPanelNode.layer, offset: CGPoint())
|
||||
}
|
||||
} else if let chatTranslationPanel = self.chatTranslationPanel {
|
||||
dismissedTranslationPanelNode = chatTranslationPanel
|
||||
@ -1803,18 +1819,6 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
wrappingInsets.top += statusBarHeight
|
||||
}
|
||||
}
|
||||
|
||||
var isSelectionEnabled = true
|
||||
if previewing {
|
||||
isSelectionEnabled = false
|
||||
} else if case .pinnedMessages = self.chatPresentationInterfaceState.subject {
|
||||
isSelectionEnabled = false
|
||||
} else if self.chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState != nil {
|
||||
isSelectionEnabled = false
|
||||
} else if case .customChatContents = self.chatLocation {
|
||||
isSelectionEnabled = false
|
||||
}
|
||||
self.historyNode.isSelectionGestureEnabled = isSelectionEnabled
|
||||
|
||||
transition.updateFrame(node: self.titleAccessoryPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: 200.0)))
|
||||
self.titleAccessoryPanelContainer.hitTestExcludeInsets = UIEdgeInsets(top: 0.0, left: leftPanelSize?.width ?? 0.0, bottom: 0.0, right: 0.0)
|
||||
@ -1839,6 +1843,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}
|
||||
|
||||
var titleAccessoryPanelFrame: CGRect?
|
||||
let titleAccessoryPanelBaseY = titlePanelsContentOffset
|
||||
if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight {
|
||||
titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: titlePanelsContentOffset), size: CGSize(width: layout.size.width, height: panelHeight))
|
||||
insets.top += panelHeight
|
||||
@ -1881,7 +1886,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
extraNavigationBarLeftCutout = CGSize(width: 0.0, height: navigationBarHeight)
|
||||
}
|
||||
|
||||
updateExtraNavigationBarBackgroundHeight(extraNavigationBarHeight, extraNavigationBarHitTestSlop, extraNavigationBarLeftCutout, extraTransition)
|
||||
updateExtraNavigationBarBackgroundHeight(extraNavigationBarHeight, extraNavigationBarHitTestSlop, extraNavigationBarLeftCutout, transition)
|
||||
|
||||
let contentBounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width - wrappingInsets.left - wrappingInsets.right, height: layout.size.height - wrappingInsets.top - wrappingInsets.bottom)
|
||||
|
||||
@ -1908,13 +1913,154 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
transition.updateBounds(node: self.historyNodeContainer, bounds: contentBounds)
|
||||
transition.updatePosition(node: self.historyNodeContainer, position: contentBounds.center)
|
||||
|
||||
transition.updateBounds(node: self.historyNode, bounds: CGRect(origin: CGPoint(), size: contentBounds.size))
|
||||
transition.updatePosition(node: self.historyNode, position: CGPoint(x: contentBounds.size.width / 2.0, y: contentBounds.size.height / 2.0))
|
||||
if let pendingSwitchToChatLocation = self.pendingSwitchToChatLocation {
|
||||
self.pendingSwitchToChatLocation = nil
|
||||
|
||||
let previousHistoryNode = self.historyNode
|
||||
self.historyNode = pendingSwitchToChatLocation.historyNode
|
||||
|
||||
self.historyNode.position = previousHistoryNode.position
|
||||
self.historyNode.bounds = previousHistoryNode.bounds
|
||||
self.historyNode.transform = previousHistoryNode.transform
|
||||
|
||||
self.historyNode.messageTransitionNode = { [weak self] in
|
||||
guard let self else {
|
||||
return nil
|
||||
}
|
||||
return self.messageTransitionNode
|
||||
}
|
||||
|
||||
transition.updateBounds(node: self.historyNode, bounds: CGRect(origin: CGPoint(), size: contentBounds.size))
|
||||
transition.updatePosition(node: self.historyNode, position: CGPoint(x: contentBounds.size.width / 2.0, y: contentBounds.size.height / 2.0))
|
||||
|
||||
previousHistoryNode.supernode?.insertSubnode(self.historyNode, aboveSubnode: previousHistoryNode)
|
||||
|
||||
let messageTransitionNode = ChatMessageTransitionNodeImpl(listNode: self.historyNode, getContentAreaInScreenSpace: { [weak self] in
|
||||
guard let self else {
|
||||
return CGRect()
|
||||
}
|
||||
return self.view.convert(self.frameForVisibleArea(), to: nil)
|
||||
}, onTransitionEvent: { [weak self] transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if (self.context.sharedContext.currentPresentationData.with({ $0 })).reduceMotion {
|
||||
return
|
||||
}
|
||||
if self.context.sharedContext.energyUsageSettings.fullTranslucency {
|
||||
self.backgroundNode.animateEvent(transition: transition, extendAnimation: false)
|
||||
}
|
||||
})
|
||||
|
||||
let previousMessageTransitionNode = self.messageTransitionNode
|
||||
self.messageTransitionNode = messageTransitionNode
|
||||
|
||||
messageTransitionNode.position = previousMessageTransitionNode.position
|
||||
messageTransitionNode.bounds = previousMessageTransitionNode.bounds
|
||||
messageTransitionNode.transform = previousMessageTransitionNode.transform
|
||||
|
||||
self.wrappingNode.contentNode.insertSubnode(self.messageTransitionNode, aboveSubnode: previousMessageTransitionNode)
|
||||
|
||||
self.emptyType = nil
|
||||
self.isLoadingValue = false
|
||||
self.isLoadingEarlier = false
|
||||
|
||||
let previousLoadingNode = self.loadingNode
|
||||
self.loadingNode = ChatLoadingNode(context: self.context, theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners)
|
||||
self.loadingNode.frame = previousLoadingNode.frame
|
||||
self.loadingNode.isHidden = previousLoadingNode.isHidden
|
||||
self.loadingNode.alpha = previousLoadingNode.alpha
|
||||
previousLoadingNode.supernode?.insertSubnode(self.loadingNode, aboveSubnode: previousLoadingNode)
|
||||
|
||||
let previousLoadingPlaceholderNode = self.loadingPlaceholderNode
|
||||
self.loadingPlaceholderNode = nil
|
||||
|
||||
let previousEmptyNode = self.emptyNode
|
||||
self.emptyNode = nil
|
||||
|
||||
self.setupHistoryNode()
|
||||
self.historyNode.loadStateUpdated?(self.historyNode.loadState ?? .messages, false)
|
||||
|
||||
if let animationDirection = pendingSwitchToChatLocation.animationDirection {
|
||||
var offsetMultiplier = CGPoint()
|
||||
switch animationDirection {
|
||||
case .up:
|
||||
offsetMultiplier.y = -1.0
|
||||
case .down:
|
||||
offsetMultiplier.y = 1.0
|
||||
case .left:
|
||||
offsetMultiplier.x = -1.0
|
||||
case .right:
|
||||
offsetMultiplier.x = 1.0
|
||||
}
|
||||
|
||||
previousHistoryNode.clipsToBounds = true
|
||||
self.historyNode.clipsToBounds = true
|
||||
|
||||
transition.animatePosition(layer: self.historyNode.layer, from: CGPoint(x: offsetMultiplier.x * layout.size.width, y: offsetMultiplier.y * layout.size.height), to: CGPoint(), removeOnCompletion: true, additive: true, completion: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.historyNode.clipsToBounds = false
|
||||
})
|
||||
transition.animatePosition(layer: previousHistoryNode.layer, from: CGPoint(), to: CGPoint(x: -offsetMultiplier.x * layout.size.width, y: -offsetMultiplier.y * layout.size.height), removeOnCompletion: false, additive: true, completion: { [weak previousHistoryNode] _ in
|
||||
previousHistoryNode?.removeFromSupernode()
|
||||
})
|
||||
|
||||
transition.animatePosition(layer: self.messageTransitionNode.layer, from: CGPoint(x: offsetMultiplier.x * layout.size.width, y: offsetMultiplier.y * layout.size.height), to: CGPoint(), removeOnCompletion: true, additive: true)
|
||||
transition.animatePosition(layer: previousMessageTransitionNode.layer, from: CGPoint(), to: CGPoint(x: -offsetMultiplier.x * layout.size.width, y: -offsetMultiplier.y * layout.size.height), removeOnCompletion: false, additive: true, completion: { [weak previousMessageTransitionNode] _ in
|
||||
previousMessageTransitionNode?.removeFromSupernode()
|
||||
})
|
||||
|
||||
transition.animatePosition(layer: self.loadingNode.layer, from: CGPoint(x: offsetMultiplier.x * layout.size.width, y: offsetMultiplier.y * layout.size.height), to: CGPoint(), removeOnCompletion: true, additive: true)
|
||||
transition.animatePosition(layer: previousLoadingNode.layer, from: CGPoint(), to: CGPoint(x: -offsetMultiplier.x * layout.size.width, y: -offsetMultiplier.y * layout.size.height), removeOnCompletion: false, additive: true, completion: { [weak previousLoadingNode] _ in
|
||||
previousLoadingNode?.removeFromSupernode()
|
||||
})
|
||||
|
||||
if let loadingPlaceholderNode = self.loadingPlaceholderNode {
|
||||
transition.animatePosition(layer: loadingPlaceholderNode.layer, from: CGPoint(x: offsetMultiplier.x * layout.size.width, y: offsetMultiplier.y * layout.size.height), to: CGPoint(), removeOnCompletion: true, additive: true)
|
||||
}
|
||||
if let previousLoadingPlaceholderNode {
|
||||
transition.animatePosition(layer: previousLoadingPlaceholderNode.layer, from: CGPoint(), to: CGPoint(x: -offsetMultiplier.x * layout.size.width, y: -offsetMultiplier.y * layout.size.height), removeOnCompletion: false, additive: true, completion: { [weak previousLoadingPlaceholderNode] _ in
|
||||
previousLoadingPlaceholderNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
if let emptyNode = self.emptyNode {
|
||||
transition.animatePosition(layer: emptyNode.layer, from: CGPoint(x: offsetMultiplier.x * layout.size.width, y: offsetMultiplier.y * layout.size.height), to: CGPoint(), removeOnCompletion: true, additive: true)
|
||||
}
|
||||
if let previousEmptyNode {
|
||||
transition.animatePosition(layer: previousEmptyNode.layer, from: CGPoint(), to: CGPoint(x: -offsetMultiplier.x * layout.size.width, y: -offsetMultiplier.y * layout.size.height), removeOnCompletion: false, additive: true, completion: { [weak previousEmptyNode] _ in
|
||||
previousEmptyNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
previousHistoryNode.removeFromSupernode()
|
||||
previousMessageTransitionNode.removeFromSupernode()
|
||||
previousLoadingNode.removeFromSupernode()
|
||||
previousLoadingPlaceholderNode?.removeFromSupernode()
|
||||
previousEmptyNode?.removeFromSupernode()
|
||||
}
|
||||
} else {
|
||||
transition.updateBounds(node: self.historyNode, bounds: CGRect(origin: CGPoint(), size: contentBounds.size))
|
||||
transition.updatePosition(node: self.historyNode, position: CGPoint(x: contentBounds.size.width / 2.0, y: contentBounds.size.height / 2.0))
|
||||
}
|
||||
|
||||
if let blurredHistoryNode = self.blurredHistoryNode {
|
||||
transition.updateFrame(node: blurredHistoryNode, frame: contentBounds)
|
||||
}
|
||||
|
||||
//transition.updateFrame(node: self.historyScrollingArea, frame: contentBounds)
|
||||
|
||||
var isSelectionEnabled = true
|
||||
if previewing {
|
||||
isSelectionEnabled = false
|
||||
} else if case .pinnedMessages = self.chatPresentationInterfaceState.subject {
|
||||
isSelectionEnabled = false
|
||||
} else if self.chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState != nil {
|
||||
isSelectionEnabled = false
|
||||
} else if case .customChatContents = self.chatLocation {
|
||||
isSelectionEnabled = false
|
||||
}
|
||||
self.historyNode.isSelectionGestureEnabled = isSelectionEnabled
|
||||
|
||||
transition.updateFrame(node: self.loadingNode, frame: contentBounds)
|
||||
if let loadingPlaceholderNode = self.loadingPlaceholderNode {
|
||||
@ -2552,7 +2698,13 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
if let dismissedTitleAccessoryPanelNode {
|
||||
var dismissedPanelFrame = dismissedTitleAccessoryPanelNode.frame
|
||||
dismissedPanelFrame.origin.y = -dismissedPanelFrame.size.height
|
||||
transition.updateSublayerTransformOffset(layer: dismissedTitleAccessoryPanelNode.layer, offset: CGPoint(x: 0.0, y: -dismissedPanelFrame.height))
|
||||
dismissedPanelFrame.origin.y = titleAccessoryPanelBaseY
|
||||
dismissedTitleAccessoryPanelNode.clipsToBounds = true
|
||||
dismissedPanelFrame.size.height = 0.0
|
||||
if transition.isAnimated {
|
||||
dismissedTitleAccessoryPanelNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
transition.updateFrame(node: dismissedTitleAccessoryPanelNode, frame: dismissedPanelFrame, completion: { [weak dismissedTitleAccessoryPanelNode] _ in
|
||||
dismissedTitleAccessoryPanelNode?.removeFromSupernode()
|
||||
})
|
||||
@ -5078,9 +5230,27 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
historyNode.position = self.historyNode.position
|
||||
historyNode.bounds = self.historyNode.bounds
|
||||
historyNode.transform = self.historyNode.transform
|
||||
|
||||
if let currentListViewLayout = self.currentListViewLayout {
|
||||
let updateSizeAndInsets = ListViewUpdateSizeAndInsets(size: currentListViewLayout.size, insets: currentListViewLayout.insets, scrollIndicatorInsets: currentListViewLayout.scrollIndicatorInsets, duration: 0.0, curve: .Default(duration: nil), ensureTopInsetForOverlayHighlightedItems: nil, customAnimationTransition: nil)
|
||||
historyNode.updateLayout(transition: .immediate, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: 0.0, scrollToTop: false, completion: {})
|
||||
}
|
||||
|
||||
return historyNode
|
||||
}
|
||||
|
||||
func prepareSwitchToChatLocation(historyNode: ChatHistoryListNodeImpl, animationDirection: ChatControllerAnimateInnerChatSwitchDirection?) {
|
||||
self.chatLocation = historyNode.chatLocation
|
||||
self.pendingSwitchToChatLocation = PendingSwitchToChatLocation(
|
||||
historyNode: historyNode,
|
||||
animationDirection: animationDirection
|
||||
)
|
||||
}
|
||||
|
||||
func updateChatLocation(chatLocation: ChatLocation, transition: ContainedViewLayoutTransition, tabSwitchDirection: ChatControllerAnimateInnerChatSwitchDirection?) {
|
||||
if chatLocation == self.chatLocation {
|
||||
return
|
||||
|
@ -667,7 +667,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
public var contentPositionChanged: (ListViewVisibleContentOffset) -> Void = { _ in }
|
||||
|
||||
public private(set) var loadState: ChatHistoryNodeLoadState?
|
||||
private var loadStateUpdated: ((ChatHistoryNodeLoadState, Bool) -> Void)?
|
||||
public private(set) var loadStateUpdated: ((ChatHistoryNodeLoadState, Bool) -> Void)?
|
||||
private var additionalLoadStateUpdated: [(ChatHistoryNodeLoadState, Bool) -> Void] = []
|
||||
|
||||
public private(set) var hasAtLeast3Messages: Bool = false
|
||||
@ -1830,11 +1830,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
let initialData: ChatHistoryCombinedInitialData?
|
||||
switch update.0 {
|
||||
case let .Loading(combinedInitialData, type):
|
||||
if case .Generic(.FillHole) = type {
|
||||
applyHole()
|
||||
return
|
||||
}
|
||||
|
||||
initialData = combinedInitialData
|
||||
|
||||
if resetScrolling, let previousViewValue = previousView.with({ $0 })?.0 {
|
||||
@ -1891,13 +1886,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
if !strongSelf.didSetInitialData {
|
||||
strongSelf.didSetInitialData = true
|
||||
var combinedInitialData = combinedInitialData
|
||||
combinedInitialData?.cachedData = nil
|
||||
strongSelf._initialData.set(.single(combinedInitialData))
|
||||
}
|
||||
|
||||
let cachedData = initialData?.cachedData
|
||||
let cachedDataMessages = initialData?.cachedDataMessages
|
||||
|
||||
@ -1917,8 +1905,30 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
strongSelf.currentHistoryState = historyState
|
||||
strongSelf.historyState.set(historyState)
|
||||
}
|
||||
|
||||
if !strongSelf.didSetInitialData {
|
||||
strongSelf.didSetInitialData = true
|
||||
var combinedInitialData = combinedInitialData
|
||||
combinedInitialData?.cachedData = nil
|
||||
strongSelf._initialData.set(.single(combinedInitialData))
|
||||
}
|
||||
|
||||
strongSelf._isReady.set(true)
|
||||
if !strongSelf.didSetReady {
|
||||
strongSelf.didSetReady = true
|
||||
#if DEBUG
|
||||
let deltaTime = (CFAbsoluteTimeGetCurrent() - strongSelf.initTimestamp) * 1000.0
|
||||
print("Chat init to dequeue time: \(deltaTime) ms")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if case .Generic(.FillHole) = type {
|
||||
applyHole()
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
case let .HistoryView(view, type, scrollPosition, flashIndicators, originalScrollPosition, data, id):
|
||||
if case .Generic(.FillHole) = type {
|
||||
|
@ -230,10 +230,6 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
||||
}
|
||||
|
||||
func titleTopicsPanelForChatPresentationInterfaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatTitleAccessoryPanelNode?, controllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?, force: Bool) -> ChatTopicListTitleAccessoryPanelNode? {
|
||||
//TODO:release
|
||||
if "".isEmpty {
|
||||
return nil
|
||||
}
|
||||
if let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isForumOrMonoForum, let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = chatPresentationInterfaceState.renderedPeer?.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.adminRights != nil, chatPresentationInterfaceState.search == nil {
|
||||
let topicListDisplayMode = chatPresentationInterfaceState.topicListDisplayMode ?? .top
|
||||
if case .top = topicListDisplayMode, let peerId = chatPresentationInterfaceState.chatLocation.peerId {
|
||||
|
Loading…
x
Reference in New Issue
Block a user