diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 17586f6241..18f70dc88d 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -523,6 +523,23 @@ private final class CachedChatListSearchResult { } } +private final class CachedCustomTextEntities { + let text: String + let textEntities: [MessageTextEntity] + + init(text: String, textEntities: [MessageTextEntity]) { + self.text = text + self.textEntities = textEntities + } + + func matches(text: String) -> Bool { + if self.text != text { + return false + } + return true + } +} + private let playIconImage = UIImage(bundleImageName: "Chat List/MiniThumbnailPlay")?.precomposed() private final class ChatListMediaPreviewNode: ASDisplayNode { @@ -611,7 +628,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode { } } -private let loginCodeRegex = try? NSRegularExpression(pattern: "[\\d\\-]{5,7}", options: []) +private let loginCodeRegex = try? NSRegularExpression(pattern: "[0-9]{5,6}", options: []) class ChatListItemNode: ItemListRevealOptionsItemNode { final class TopicItemNode: ASDisplayNode { @@ -926,6 +943,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { private var cachedChatListText: (String, String)? private var cachedChatListSearchResult: CachedChatListSearchResult? + private var cachedCustomTextEntities: CachedCustomTextEntities? var layoutParams: (ChatListItem, first: Bool, last: Bool, firstWithHeader: Bool, nextIsPinned: Bool, ListViewItemLayoutParams, countersSize: CGFloat)? @@ -1494,6 +1512,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { let currentItem = self.layoutParams?.0 let currentChatListText = self.cachedChatListText let currentChatListSearchResult = self.cachedChatListSearchResult + let currentCustomTextEntities = self.cachedCustomTextEntities return { item, params, first, last, firstWithHeader, nextIsPinned in let titleFont = Font.medium(floor(item.presentationData.fontSize.itemListBaseFontSize * 16.0 / 17.0)) @@ -1771,6 +1790,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var chatListText: (String, String)? var chatListSearchResult: CachedChatListSearchResult? + var customTextEntities: CachedCustomTextEntities? let contentImageSide: CGFloat = max(10.0, min(20.0, floor(item.presentationData.fontSize.baseDisplaySize * 18.0 / 17.0))) let contentImageSize = CGSize(width: contentImageSide, height: contentImageSide) @@ -1853,18 +1873,23 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { return false } } - if message.author?.id.id == PeerId.Id._internalFromInt64Value(777000) { - if let loginCodeRegex { - let results = loginCodeRegex.matches(in: message.text, range: NSRange(message.text.startIndex..., in: message.text)) - for result in results { - let spoilerRange: Range = result.range.location ..< (result.range.location + result.range.length) - if !entities.contains(where: { $0.range.overlaps(spoilerRange) }) { - entities.append(MessageTextEntity(range: spoilerRange, type: .Spoiler)) - } + + if message.id.peerId.namespace == Namespaces.Peer.CloudUser && message.id.peerId.id._internalGetInt64Value() == 777000 { + if let cached = currentCustomTextEntities, cached.matches(text: message.text) { + customTextEntities = cached + } else if let matches = loginCodeRegex?.matches(in: message.text, options: [], range: NSMakeRange(0, (message.text as NSString).length)) { + var entities: [MessageTextEntity] = [] + if let first = matches.first { + entities.append(MessageTextEntity(range: first.range.location ..< first.range.location + first.range.length, type: .Spoiler)) } + customTextEntities = CachedCustomTextEntities(text: message.text, textEntities: entities) } } + if let customTextEntities, !customTextEntities.textEntities.isEmpty { + entities.append(contentsOf: customTextEntities.textEntities) + } + let messageString: NSAttributedString if !message.text.isEmpty && entities.count > 0 { var messageText = message.text @@ -2574,6 +2599,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { strongSelf.currentItemHeight = itemHeight strongSelf.cachedChatListText = chatListText strongSelf.cachedChatListSearchResult = chatListSearchResult + strongSelf.cachedCustomTextEntities = customTextEntities strongSelf.onlineIsVoiceChat = onlineIsVoiceChat var animateOnline = animateOnline diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 54e82f5b4c..398a57590d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -17271,9 +17271,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) case let .withBotStartPayload(startPayload): if case .peer(peerId.id) = strongSelf.chatLocation { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { - $0.updatedBotStartPayload(startPayload.payload) - }) + strongSelf.startBot(startPayload.payload) } else if let navigationController = strongSelf.effectiveNavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), botStart: startPayload, keepStack: .always)) } diff --git a/submodules/TelegramUI/Sources/ChatLoadingNode.swift b/submodules/TelegramUI/Sources/ChatLoadingNode.swift index 58da776a90..b194b51613 100644 --- a/submodules/TelegramUI/Sources/ChatLoadingNode.swift +++ b/submodules/TelegramUI/Sources/ChatLoadingNode.swift @@ -209,7 +209,9 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode { if self.context.sharedContext.energyUsageSettings.fullTranslucency { Queue.mainQueue().after(0.3) { - self.backgroundNode?.updateIsLooping(true) + if !self.didAnimateOut { + self.backgroundNode?.updateIsLooping(true) + } } } } @@ -282,11 +284,12 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode { self.borderMaskNode.bounds = self.borderMaskNode.bounds.offsetBy(dx: 0.0, dy: inset) } + private var didAnimateOut = false func animateOut(_ historyNode: ChatHistoryNode, completion: @escaping () -> Void = {}) { guard let listNode = historyNode as? ListView, let (size, _, _) = self.validLayout else { return } - + self.didAnimateOut = true self.backgroundNode?.updateIsLooping(false) let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring)