diff --git a/TelegramUI/AutodownloadSizeLimitItem.swift b/TelegramUI/AutodownloadSizeLimitItem.swift index 72e0397b61..2fe66e3e45 100644 --- a/TelegramUI/AutodownloadSizeLimitItem.swift +++ b/TelegramUI/AutodownloadSizeLimitItem.swift @@ -41,7 +41,7 @@ class AutodownloadSizeLimitItem: ListViewItem, ItemListItem { self.updated = updated } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = AutodownloadSizeLimitItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/AvatarNode.swift b/TelegramUI/AvatarNode.swift index 35afd8f6f3..02eb964124 100644 --- a/TelegramUI/AvatarNode.swift +++ b/TelegramUI/AvatarNode.swift @@ -200,7 +200,7 @@ public final class AvatarNode: ASDisplayNode { } } - public func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil) { + public func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, synchronousLoad: Bool = false) { var representation: TelegramMediaImageRepresentation? var icon = AvatarNodeIcon.none if let overrideImage = overrideImage { @@ -230,7 +230,7 @@ public final class AvatarNode: ASDisplayNode { let theme = account.telegramApplicationContext.currentPresentationData.with { $0 }.theme - if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation, emptyColor: emptyColor) { + if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation, emptyColor: emptyColor, synchronousLoad: synchronousLoad) { self.imageReady.set(self.imageNode.ready) self.imageNode.setSignal(signal) diff --git a/TelegramUI/BotCheckoutHeaderItem.swift b/TelegramUI/BotCheckoutHeaderItem.swift index 548bb82bf7..08f6270969 100644 --- a/TelegramUI/BotCheckoutHeaderItem.swift +++ b/TelegramUI/BotCheckoutHeaderItem.swift @@ -19,7 +19,7 @@ class BotCheckoutHeaderItem: ListViewItem, ItemListItem { self.sectionId = sectionId } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = BotCheckoutHeaderItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/BotCheckoutPriceItem.swift b/TelegramUI/BotCheckoutPriceItem.swift index 5e4c821aa8..476ee6411f 100644 --- a/TelegramUI/BotCheckoutPriceItem.swift +++ b/TelegramUI/BotCheckoutPriceItem.swift @@ -20,7 +20,7 @@ class BotCheckoutPriceItem: ListViewItem, ItemListItem { self.sectionId = sectionId } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = BotCheckoutPriceItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/CalculatingCacheSizeItem.swift b/TelegramUI/CalculatingCacheSizeItem.swift index 071945cdb2..bd9cbdf892 100644 --- a/TelegramUI/CalculatingCacheSizeItem.swift +++ b/TelegramUI/CalculatingCacheSizeItem.swift @@ -16,7 +16,7 @@ class CalculatingCacheSizeItem: ListViewItem, ItemListItem { self.style = style } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = CalculatingCacheSizeItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/CallListCallItem.swift b/TelegramUI/CallListCallItem.swift index 29e99c0b2a..126ee2467d 100644 --- a/TelegramUI/CallListCallItem.swift +++ b/TelegramUI/CallListCallItem.swift @@ -92,7 +92,7 @@ class CallListCallItem: ListViewItem { self.header = nil } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = CallListCallItemNode() let makeLayout = node.asyncLayout() diff --git a/TelegramUI/ChatBotInfoItem.swift b/TelegramUI/ChatBotInfoItem.swift index 8a96f22e5c..6bf0eb7f1b 100644 --- a/TelegramUI/ChatBotInfoItem.swift +++ b/TelegramUI/ChatBotInfoItem.swift @@ -21,7 +21,7 @@ final class ChatBotInfoItem: ListViewItem { self.presentationData = presentationData } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { let node = ChatBotInfoItemNode() diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index d74f76121d..57f7d3732c 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -40,13 +40,27 @@ private enum ChatRecordingActivity { public enum NavigateToMessageLocation { case id(MessageId) case index(MessageIndex) + case upperBound(PeerId) - var messageId: MessageId { + var messageId: MessageId? { switch self { case let .id(id): return id case let .index(index): return index.id + case .upperBound: + return nil + } + } + + var peerId: PeerId { + switch self { + case let .id(id): + return id.peerId + case let .index(index): + return index.id.peerId + case let .upperBound(peerId): + return peerId } } } @@ -162,6 +176,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID private var recordingActivityValue: ChatRecordingActivity = .none private let recordingActivityPromise = ValuePromise(.none, ignoreRepeated: true) private var recordingActivityDisposable: Disposable? + private var acquiredRecordingActivityDisposable: Disposable? private var searchDisposable: MetaDisposable? @@ -752,6 +767,11 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID }, openMessageShareMenu: { [weak self] id in if let strongSelf = self, let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id) { let shareController = ShareController(account: strongSelf.account, subject: .messages(messages)) + shareController.dismissed = { shared in + if shared { + self?.commitPurposefulAction() + } + } strongSelf.chatDisplayNode.dismissInput() strongSelf.present(shareController, in: .window(.root)) } @@ -1194,6 +1214,17 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID isNotAccessible = cachedChannelData.isNotAccessible } + var hasBots: Bool = false + if let cachedGroupData = peerView.cachedData as? CachedGroupData { + if !cachedGroupData.botInfos.isEmpty { + hasBots = true + } + } else if let cachedChannelData = peerView.cachedData as? CachedChannelData { + if !cachedChannelData.botInfos.isEmpty { + hasBots = true + } + } + var explicitelyCanPinMessages: Bool = false if let cachedUserData = peerView.cachedData as? CachedUserData { explicitelyCanPinMessages = cachedUserData.canPinMessages @@ -1207,7 +1238,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID } strongSelf.updateChatPresentationInterfaceState(animated: animated, interactive: false, { return $0.updatedPeer { _ in return renderedPeer - }.updatedIsNotAccessible(isNotAccessible).updatedIsContact(isContact).updatedPeerIsMuted(peerIsMuted).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages) + }.updatedIsNotAccessible(isNotAccessible).updatedIsContact(isContact).updatedHasBots(hasBots).updatedPeerIsMuted(peerIsMuted).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages) }) if !strongSelf.didSetChatLocationInfoReady { strongSelf.didSetChatLocationInfoReady = true @@ -1376,21 +1407,19 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID }) self.recordingActivityDisposable = (self.recordingActivityPromise.get() - |> deliverOnMainQueue).start(next: { [weak self] value in - if let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation { - switch value { - case .voice: - strongSelf.account.updateLocalInputActivity(peerId: peerId, activity: .recordingVoice, isPresent: true) - strongSelf.account.updateLocalInputActivity(peerId: peerId, activity: .recordingInstantVideo, isPresent: false) - case .instantVideo: - strongSelf.account.updateLocalInputActivity(peerId: peerId, activity: .recordingVoice, isPresent: false) - strongSelf.account.updateLocalInputActivity(peerId: peerId, activity: .recordingInstantVideo, isPresent: true) - case .none: - strongSelf.account.updateLocalInputActivity(peerId: peerId, activity: .recordingVoice, isPresent: false) - strongSelf.account.updateLocalInputActivity(peerId: peerId, activity: .recordingInstantVideo, isPresent: false) - } + |> deliverOnMainQueue).start(next: { [weak self] value in + if let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation { + strongSelf.acquiredRecordingActivityDisposable?.dispose() + switch value { + case .voice: + strongSelf.acquiredRecordingActivityDisposable = strongSelf.account.acquireLocalInputActivity(peerId: peerId, activity: .recordingVoice) + case .instantVideo: + strongSelf.acquiredRecordingActivityDisposable = strongSelf.account.acquireLocalInputActivity(peerId: peerId, activity: .recordingInstantVideo) + case .none: + strongSelf.acquiredRecordingActivityDisposable = nil } - }) + } + }) self.presentationDataDisposable = (account.telegramApplicationContext.presentationData |> deliverOnMainQueue).start(next: { [weak self] presentationData in @@ -1495,6 +1524,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID self.unpinMessageDisposable?.dispose() self.inputActivityDisposable?.dispose() self.recordingActivityDisposable?.dispose() + self.acquiredRecordingActivityDisposable?.dispose() self.presentationDataDisposable?.dispose() self.searchDisposable?.dispose() self.applicationInForegroundDisposable?.dispose() @@ -1810,6 +1840,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID var options = transition.options let _ = options.insert(.Synchronous) let _ = options.insert(.LowLatency) + let _ = options.insert(.PreferSynchronousResourceLoading) options.remove(.AnimateInsertion) options.insert(.RequestItemInsertionAnimations) @@ -1933,7 +1964,13 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID if let messageId = strongSelf.historyNavigationStack.removeLast() { strongSelf.navigateToMessage(from: nil, to: .id(messageId.id), rememberInStack: false) } else { - strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory() + if case .known = strongSelf.chatDisplayNode.historyNode.visibleContentOffset() { + strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory() + } else if case let .peer(peerId) = strongSelf.chatLocation { + strongSelf.navigateToMessage(messageLocation: .upperBound(peerId), animated: true) + } else { + strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory() + } } } } @@ -2784,41 +2821,41 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID let postbox = self.account.postbox let previousPeerCache = Atomic<[PeerId: Peer]>(value: [:]) self.peerInputActivitiesDisposable = (self.account.peerInputActivities(peerId: peerId) - |> mapToSignal { activities -> Signal<[(Peer, PeerInputActivity)], NoError> in - var foundAllPeers = true - var cachedResult: [(Peer, PeerInputActivity)] = [] - previousPeerCache.with { dict -> Void in - for (peerId, activity) in activities { - if let peer = dict[peerId] { - cachedResult.append((peer, activity)) - } else { - foundAllPeers = false - break - } - } - } - if foundAllPeers { - return .single(cachedResult) - } else { - return postbox.transaction { transaction -> [(Peer, PeerInputActivity)] in - var result: [(Peer, PeerInputActivity)] = [] - var peerCache: [PeerId: Peer] = [:] - for (peerId, activity) in activities { - if let peer = transaction.getPeer(peerId) { - result.append((peer, activity)) - peerCache[peerId] = peer - } - } - let _ = previousPeerCache.swap(peerCache) - return result + |> mapToSignal { activities -> Signal<[(Peer, PeerInputActivity)], NoError> in + var foundAllPeers = true + var cachedResult: [(Peer, PeerInputActivity)] = [] + previousPeerCache.with { dict -> Void in + for (peerId, activity) in activities { + if let peer = dict[peerId] { + cachedResult.append((peer, activity)) + } else { + foundAllPeers = false + break } } } - |> deliverOnMainQueue).start(next: { [weak self] activities in - if let strongSelf = self { - strongSelf.chatTitleView?.inputActivities = (peerId, activities) + if foundAllPeers { + return .single(cachedResult) + } else { + return postbox.transaction { transaction -> [(Peer, PeerInputActivity)] in + var result: [(Peer, PeerInputActivity)] = [] + var peerCache: [PeerId: Peer] = [:] + for (peerId, activity) in activities { + if let peer = transaction.getPeer(peerId) { + result.append((peer, activity)) + peerCache[peerId] = peer + } + } + let _ = previousPeerCache.swap(peerCache) + return result } - }) + } + } + |> deliverOnMainQueue).start(next: { [weak self] activities in + if let strongSelf = self { + strongSelf.chatTitleView?.inputActivities = (peerId, activities) + } + }) self.sentMessageEventsDisposable.set(self.account.pendingMessageManager.deliveredMessageEvents(peerId: peerId).start(next: { [weak self] _ in if let strongSelf = self { @@ -4357,17 +4394,17 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID } } - if case let .peer(peerId) = self.chatLocation, messageLocation.messageId.peerId != peerId { + if case let .peer(peerId) = self.chatLocation, let messageId = messageLocation.messageId, messageId.peerId != peerId { if let navigationController = self.navigationController as? NavigationController { - navigateToChatController(navigationController: navigationController, account: self.account, chatLocation: .peer(messageLocation.messageId.peerId), messageId: messageLocation.messageId) + navigateToChatController(navigationController: navigationController, account: self.account, chatLocation: .peer(messageId.peerId), messageId: messageId) } - } else if case let .peer(peerId) = self.chatLocation, messageLocation.messageId.peerId == peerId { + } else if case let .peer(peerId) = self.chatLocation, messageLocation.peerId == peerId { if let fromIndex = fromIndex { if let _ = fromId, rememberInStack { self.historyNavigationStack.add(fromIndex) } - if let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageLocation.messageId) { + if let messageId = messageLocation.messageId, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) { self.loadingMessage.set(false) self.messageIndexDisposable.set(nil) self.chatDisplayNode.historyNode.scrollToMessage(from: fromIndex, to: MessageIndex(message), animated: animated, scrollPosition: scrollPosition) @@ -4380,6 +4417,8 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID searchLocation = .id(id) case let .index(index): searchLocation = .index(index) + case .upperBound: + searchLocation = .index(MessageIndex.upperBound(peerId: peerId)) } let historyView = chatHistoryViewForLocation(.InitialSearch(location: searchLocation, count: 50), account: self.account, chatLocation: self.chatLocation, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) let signal = historyView @@ -4455,18 +4494,19 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID } } else { if let fromIndex = fromIndex { - if let _ = fromId, rememberInStack { - self.historyNavigationStack.add(fromIndex) - } - - self.loadingMessage.set(true) let searchLocation: ChatHistoryInitialSearchLocation switch messageLocation { case let .id(id): searchLocation = .id(id) case let .index(index): searchLocation = .index(index) + case .upperBound: + return } + if let _ = fromId, rememberInStack { + self.historyNavigationStack.add(fromIndex) + } + self.loadingMessage.set(true) let historyView = chatHistoryViewForLocation(.InitialSearch(location: searchLocation, count: 50), account: self.account, chatLocation: self.chatLocation, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) let signal = historyView |> mapToSignal { historyView -> Signal in @@ -4491,7 +4531,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, UID strongSelf.chatDisplayNode.historyNode.scrollToMessage(from: fromIndex, to: index, animated: animated, scrollPosition: scrollPosition) completion?() } else { - (strongSelf.navigationController as? NavigationController)?.pushViewController(ChatController(account: strongSelf.account, chatLocation: .peer(messageLocation.messageId.peerId), messageId: messageLocation.messageId)) + (strongSelf.navigationController as? NavigationController)?.pushViewController(ChatController(account: strongSelf.account, chatLocation: .peer(messageLocation.peerId), messageId: messageLocation.messageId)) completion?() } } diff --git a/TelegramUI/ChatControllerNode.swift b/TelegramUI/ChatControllerNode.swift index 56ec52d5df..55ac2739d0 100644 --- a/TelegramUI/ChatControllerNode.swift +++ b/TelegramUI/ChatControllerNode.swift @@ -187,6 +187,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.titleAccessoryPanelContainer.clipsToBounds = true self.historyNode = ChatHistoryListNode(account: account, chatLocation: chatLocation, tagMask: nil, messageId: messageId, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get()) + self.historyNode.rotated = true self.historyNodeContainer = ASDisplayNode() self.historyNodeContainer.addSubnode(self.historyNode) self.loadingNode = ChatLoadingNode(theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper) @@ -238,6 +239,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } self.backgroundNode.contents = chatControllerBackgroundImage(wallpaper: chatPresentationInterfaceState.chatWallpaper, postbox: account.postbox)?.cgImage + self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8) self.addSubnode(self.backgroundNode) self.addSubnode(self.historyNodeContainer) @@ -874,6 +876,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } var listInsets = UIEdgeInsets(top: containerInsets.bottom + contentBottomInset, left: containerInsets.right, bottom: containerInsets.top, right: containerInsets.left) + let listScrollIndicatorInsets = UIEdgeInsets(top: containerInsets.bottom + inputPanelsHeight, left: containerInsets.right, bottom: containerInsets.top, right: containerInsets.left) if case .standard = self.chatPresentationInterfaceState.mode { listInsets.left += layout.safeInsets.left listInsets.right += layout.safeInsets.right @@ -1008,7 +1011,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { listInsets.top = listInsets.top + messageActionSheetControllerAdditionalInset } - listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, duration: duration, curve: listViewCurve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems), additionalScrollDistance, scrollToTop) + listViewTransaction(ListViewUpdateSizeAndInsets(size: contentBounds.size, insets: listInsets, scrollIndicatorInsets: listScrollIndicatorInsets, duration: duration, curve: listViewCurve, ensureTopInsetForOverlayHighlightedItems: ensureTopInsetForOverlayHighlightedItems), additionalScrollDistance, scrollToTop) let navigateButtonsSize = self.navigateButtons.updateLayout(transition: transition) var navigateButtonsFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.right - navigateButtonsSize.width - 6.0, y: layout.size.height - containerInsets.bottom - inputPanelsHeight - navigateButtonsSize.height - 6.0 - bottomOverflowOffset), size: navigateButtonsSize) @@ -1288,6 +1291,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.backgroundNode.contents = chatControllerBackgroundImage(wallpaper: chatPresentationInterfaceState.chatWallpaper, postbox: account.postbox)?.cgImage } + self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8) + let updatedInputFocus = self.chatPresentationInterfaceStateRequiresInputFocus(self.chatPresentationInterfaceState) != self.chatPresentationInterfaceStateRequiresInputFocus(chatPresentationInterfaceState) let updateInputTextState = self.chatPresentationInterfaceState.interfaceState.effectiveInputState != chatPresentationInterfaceState.interfaceState.effectiveInputState self.chatPresentationInterfaceState = chatPresentationInterfaceState diff --git a/TelegramUI/ChatHistoryViewForLocation.swift b/TelegramUI/ChatHistoryViewForLocation.swift index c9e8c1bd09..10fc2f881b 100644 --- a/TelegramUI/ChatHistoryViewForLocation.swift +++ b/TelegramUI/ChatHistoryViewForLocation.swift @@ -148,7 +148,8 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocation, account: Accoun let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up let chatScrollPosition = ChatHistoryViewScrollPosition.index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated) var first = true - return account.viewTracker.aroundMessageHistoryViewForLocation(chatLocation, index: index, anchorIndex: anchorIndex, count: 200, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) |> map { view, updateType, initialData -> ChatHistoryViewUpdate in + return account.viewTracker.aroundMessageHistoryViewForLocation(chatLocation, index: index, anchorIndex: anchorIndex, count: 200, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) + |> map { view, updateType, initialData -> ChatHistoryViewUpdate in let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation) let genericType: ViewUpdateType diff --git a/TelegramUI/ChatHoleItem.swift b/TelegramUI/ChatHoleItem.swift index 57083a356c..838c71e665 100644 --- a/TelegramUI/ChatHoleItem.swift +++ b/TelegramUI/ChatHoleItem.swift @@ -18,7 +18,7 @@ class ChatHoleItem: ListViewItem { //self.header = ChatMessageDateHeader(timestamp: index.timestamp, theme: theme, strings: strings) } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatHoleItemNode() node.layoutForParams(params, item: self, previousItem: previousItem, nextItem: nextItem) diff --git a/TelegramUI/ChatInterfaceInputContexts.swift b/TelegramUI/ChatInterfaceInputContexts.swift index 8b6f9b954e..5936f9d218 100644 --- a/TelegramUI/ChatInterfaceInputContexts.swift +++ b/TelegramUI/ChatInterfaceInputContexts.swift @@ -268,10 +268,10 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte stickersEnabled = false } } - if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser { - if let _ = peer.botInfo { - accessoryItems.append(.commands) - } + if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, let _ = peer.botInfo { + accessoryItems.append(.commands) + } else if chatPresentationInterfaceState.hasBots { + accessoryItems.append(.commands) } accessoryItems.append(.stickers(stickersEnabled)) if let message = chatPresentationInterfaceState.keyboardButtonsMessage, let _ = message.visibleButtonKeyboardMarkup { diff --git a/TelegramUI/ChatInterfaceStateContextQueries.swift b/TelegramUI/ChatInterfaceStateContextQueries.swift index 8850d6ddef..a913a13dd4 100644 --- a/TelegramUI/ChatInterfaceStateContextQueries.swift +++ b/TelegramUI/ChatInterfaceStateContextQueries.swift @@ -311,15 +311,15 @@ func searchQuerySuggestionResultStateForChatInterfacePresentationState(_ chatPre } } - let participants = searchGroupMembers(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peer.id, query: query) - |> map { peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in - let filteredPeers = peers - var sortedPeers: [Peer] = [] - sortedPeers.append(contentsOf: filteredPeers.sorted(by: { lhs, rhs in - let result = lhs.indexName.indexName(.lastNameFirst).compare(rhs.indexName.indexName(.lastNameFirst)) - return result == .orderedAscending - })) - return { _ in return .mentions(sortedPeers) } + let participants = searchPeerMembers(account: account, peerId: peer.id, query: query) + |> map { peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in + let filteredPeers = peers + var sortedPeers: [Peer] = [] + sortedPeers.append(contentsOf: filteredPeers.sorted(by: { lhs, rhs in + let result = lhs.indexName.indexName(.lastNameFirst).compare(rhs.indexName.indexName(.lastNameFirst)) + return result == .orderedAscending + })) + return { _ in return .mentions(sortedPeers) } } return (inputQuery, signal |> then(participants)) diff --git a/TelegramUI/ChatListController.swift b/TelegramUI/ChatListController.swift index aced506fa8..69c0b7fc5a 100644 --- a/TelegramUI/ChatListController.swift +++ b/TelegramUI/ChatListController.swift @@ -410,7 +410,9 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.account, peer: peer) |> deliverOnMainQueue).start(completed: { [weak strongSelf] in if let strongSelf = strongSelf { if let navigationController = strongSelf.navigationController as? NavigationController { - navigateToChatController(navigationController: navigationController, account: strongSelf.account, chatLocation: .peer(messageId.peerId), messageId: messageId) + navigateToChatController(navigationController: navigationController, account: strongSelf.account, chatLocation: .peer(messageId.peerId), messageId: messageId, purposefulAction: { + self?.deactivateSearch(animated: false) + }) strongSelf.chatListDisplayNode.chatListNode.clearHighlightAnimated(true) } } @@ -434,9 +436,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } if let navigationController = strongSelf.navigationController as? NavigationController { navigateToChatController(navigationController: navigationController, account: strongSelf.account, chatLocation: .peer(peer.id), purposefulAction: { [weak self] in - if let strongSelf = self { - strongSelf.deactivateSearch(animated: false) - } + self?.deactivateSearch(animated: false) }) strongSelf.chatListDisplayNode.chatListNode.clearHighlightAnimated(true) } diff --git a/TelegramUI/ChatListHoleItem.swift b/TelegramUI/ChatListHoleItem.swift index 30988c8442..91d5d7a349 100644 --- a/TelegramUI/ChatListHoleItem.swift +++ b/TelegramUI/ChatListHoleItem.swift @@ -16,7 +16,7 @@ class ChatListHoleItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatListHoleItemNode() node.relativePosition = (first: previousItem == nil, last: nextItem == nil) diff --git a/TelegramUI/ChatListItem.swift b/TelegramUI/ChatListItem.swift index 311814e5f2..09409ab48c 100644 --- a/TelegramUI/ChatListItem.swift +++ b/TelegramUI/ChatListItem.swift @@ -50,7 +50,7 @@ class ChatListItem: ListViewItem { self.interaction = interaction } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatListItemNode() let (first, last, firstWithHeader, nextIsPinned) = ChatListItem.mergeType(item: self, previousItem: previousItem, nextItem: nextItem) diff --git a/TelegramUI/ChatListNode.swift b/TelegramUI/ChatListNode.swift index 4471c580be..588914e5f6 100644 --- a/TelegramUI/ChatListNode.swift +++ b/TelegramUI/ChatListNode.swift @@ -348,7 +348,7 @@ final class ChatListNode: ListView { super.init() - //self.verticalScrollIndicatorColor = UIColor(white: 0.3, alpha: 0.8) + self.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor let nodeInteraction = ChatListNodeInteraction(activateSearch: { [weak self] in if let strongSelf = self, let activateSearch = strongSelf.activateSearch { @@ -874,6 +874,7 @@ final class ChatListNode: ListView { if self.keepTopItemOverscrollBackground != nil { self.keepTopItemOverscrollBackground = ListViewKeepTopItemOverscrollBackground(color: theme.chatList.pinnedItemBackgroundColor, direction: true) } + self.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor self.updateState { state in var state = state diff --git a/TelegramUI/ChatListRecentPeersListItem.swift b/TelegramUI/ChatListRecentPeersListItem.swift index 3191d158fb..ffc7bee5fe 100644 --- a/TelegramUI/ChatListRecentPeersListItem.swift +++ b/TelegramUI/ChatListRecentPeersListItem.swift @@ -26,7 +26,7 @@ class ChatListRecentPeersListItem: ListViewItem { self.header = nil } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatListRecentPeersListItemNode() let makeLayout = node.asyncLayout() diff --git a/TelegramUI/ChatListSearchContainerNode.swift b/TelegramUI/ChatListSearchContainerNode.swift index 7edf5d014b..fb2584e30a 100644 --- a/TelegramUI/ChatListSearchContainerNode.swift +++ b/TelegramUI/ChatListSearchContainerNode.swift @@ -522,6 +522,31 @@ private func doesPeerMatchFilter(peer: Peer, filter: ChatListNodePeersFilter) -> return enabled } +private struct ChatListSearchMessagesResult { + let query: String + let messages: [Message] + let readStates: [PeerId: CombinedPeerReadState] + let hasMore: Bool + + func appending(_ other: ChatListSearchMessagesResult) -> ChatListSearchMessagesResult { + var messages: [Message] = self.messages + var ids = Set(self.messages.map { $0.id }) + for message in other.messages { + if !ids.contains(message.id) { + ids.insert(message.id) + messages.append(message) + } + } + messages.sort(by: { MessageIndex($0) > MessageIndex($1) }) + return ChatListSearchMessagesResult(query: query, messages: messages, readStates: self.readStates.merging(other.readStates, uniquingKeysWith: { left, _ in left }), hasMore: other.hasMore) + } +} + +private struct ChatListSearchMessagesContext { + let result: ChatListSearchMessagesResult + let loadMoreIndex: MessageIndex? +} + final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { private let account: Account @@ -569,172 +594,242 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { self.dimNode.backgroundColor = filter.contains(.excludeRecent) ? UIColor.black.withAlphaComponent(0.5) : self.presentationData.theme.chatList.backgroundColor - self.backgroundColor = filter.contains(.excludeRecent) ? nil : self.presentationData.theme.chatList.backgroundColor - self.addSubnode(self.dimNode) self.addSubnode(self.recentListNode) self.addSubnode(self.listNode) + let searchContext = Promise(nil) + let searchContextValue = Atomic(value: nil) + let updateSearchContext: ((ChatListSearchMessagesContext?) -> (ChatListSearchMessagesContext?, Bool)) -> Void = { f in + var shouldUpdate = false + let updated = searchContextValue.modify { current in + let (u, s) = f(current) + shouldUpdate = s + if s { + return u + } else { + return current + } + } + if shouldUpdate { + searchContext.set(.single(updated)) + } + } + self.listNode.isHidden = true + self.listNode.visibleBottomContentOffsetChanged = { offset in + guard case let .known(value) = offset, value < 100.0 else { + return + } + updateSearchContext { previous in + guard let previous = previous else { + return (nil, false) + } + if previous.loadMoreIndex != nil { + return (previous, false) + } + guard let last = previous.result.messages.last else { + return (previous, false) + } + return (ChatListSearchMessagesContext(result: previous.result, loadMoreIndex: MessageIndex(last)), true) + } + } self.recentListNode.isHidden = filter.contains(.excludeRecent) let presentationDataPromise = self.presentationDataPromise - let foundItems = searchQuery.get() - |> mapToSignal { query -> Signal<([ChatListSearchEntry], Bool)?, NoError> in - if let query = query, !query.isEmpty { - let accountPeer = account.postbox.loadedPeerWithId(account.peerId) - |> take(1) - - let foundLocalPeers = account.postbox.searchPeers(query: query.lowercased(), groupId: groupId) - |> mapToSignal { local -> Signal<([PeerView], [RenderedPeer]), NoError> in - return combineLatest(local.map {account.postbox.peerView(id: $0.peerId)}) |> map { views in - return (views, local) - } - } - |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId : UnreadSearchBadge]), NoError> in - return account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in - var unread:[PeerId: UnreadSearchBadge] = [:] - for peerView in viewsAndPeers.0 { - var isMuted: Bool = false - if let nofiticationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings { - switch nofiticationSettings.muteState { - case .muted: - isMuted = true - default: - break - } - } - - let unreadCount = values.count(for: .peer(peerView.peerId)) - if let unreadCount = unreadCount, unreadCount > 0 { - unread[peerView.peerId] = isMuted ? .muted(unreadCount) : .unmuted(unreadCount) - } - } - return (peers: viewsAndPeers.1, unread: unread) - } - } - - let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError> - if groupId == nil { - foundRemotePeers = (.single(([], [], true)) |> then(searchPeers(account: account, query: query) |> map { ($0.0, $0.1, false) } - |> delay(0.2, queue: Queue.concurrentDefaultQueue()))) - } else { - foundRemotePeers = .single(([], [], false)) - } - let location: SearchMessagesLocation - if let groupId = groupId { - location = .group(groupId) - } else { - location = .general - } - - let foundRemoteMessages: Signal<(([Message], [PeerId : CombinedPeerReadState], Int32), Bool), NoError> - if filter.contains(.doNotSearchMessages) { - foundRemoteMessages = .single((([], [:], 0), false)) - } else { - foundRemoteMessages = .single((([], [:], 0), true)) |> then(searchMessages(account: account, location: location, query: query) - |> map { ($0, false) } - |> delay(0.2, queue: Queue.concurrentDefaultQueue())) - } - - - - return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get()) - |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData -> ([ChatListSearchEntry], Bool)? in - var entries: [ChatListSearchEntry] = [] - let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 - var index = 0 - - - let filteredPeer:(Peer, Peer) -> Bool = { peer, accountPeer in - guard !filter.contains(.excludeSavedMessages) || peer.id != accountPeer.id else { return false } - guard !filter.contains(.excludeSecretChats) || peer.id.namespace != Namespaces.Peer.SecretChat else { return false } - guard !filter.contains(.onlyPrivateChats) || peer.id.namespace == Namespaces.Peer.CloudUser else { return false } - - if filter.contains(.onlyGroups) { - var isGroup: Bool = false - if let peer = peer as? TelegramChannel, case .group = peer.info { - isGroup = true - } else if peer.id.namespace == Namespaces.Peer.CloudGroup { - isGroup = true - } - if !isGroup { - return false - } - } - - if filter.contains(.onlyChannels) { - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - return true - } else { - return false - } - } - - return true - } - - var existingPeerIds = Set() - - if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(query.lowercased()) { - if !existingPeerIds.contains(accountPeer.id), filteredPeer(accountPeer, accountPeer) { - existingPeerIds.insert(accountPeer.id) - entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) - index += 1 - } - } - - for renderedPeer in foundLocalPeers.peers { - if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != account.peerId, filteredPeer(peer, accountPeer) { - if !existingPeerIds.contains(peer.id) { - existingPeerIds.insert(peer.id) - var associatedPeer: Peer? - if let associatedPeerId = peer.associatedPeerId { - associatedPeer = renderedPeer.peers[associatedPeerId] - } - entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) - index += 1 - } - } - } - - for peer in foundRemotePeers.0 { - if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { - existingPeerIds.insert(peer.peer.id) - entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) - index += 1 - } - } - - index = 0 - for peer in foundRemotePeers.1 { - if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { - existingPeerIds.insert(peer.peer.id) - entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) - index += 1 - } - } - - if !foundRemotePeers.2 { - index = 0 - for message in foundRemoteMessages.0.0 { - entries.append(.message(message, foundRemoteMessages.0.1[message.id.peerId], presentationData)) - index += 1 - } - } - - if addContact != nil && isViablePhoneNumber(query) { - entries.append(.addContact(query, presentationData.theme, presentationData.strings)) - } - - return (entries, isSearching) - } - } else { - return .single(nil) + let foundItems = self.searchQuery.get() + |> mapToSignal { query -> Signal<([ChatListSearchEntry], Bool)?, NoError> in + guard let query = query, !query.isEmpty else { + return .single(nil) + } + + let accountPeer = account.postbox.loadedPeerWithId(account.peerId) + |> take(1) + + let foundLocalPeers = account.postbox.searchPeers(query: query.lowercased(), groupId: groupId) + |> mapToSignal { local -> Signal<([PeerView], [RenderedPeer]), NoError> in + return combineLatest(local.map {account.postbox.peerView(id: $0.peerId)}) |> map { views in + return (views, local) } } + |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId : UnreadSearchBadge]), NoError> in + return account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in + var unread:[PeerId: UnreadSearchBadge] = [:] + for peerView in viewsAndPeers.0 { + var isMuted: Bool = false + if let nofiticationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings { + switch nofiticationSettings.muteState { + case .muted: + isMuted = true + default: + break + } + } + + let unreadCount = values.count(for: .peer(peerView.peerId)) + if let unreadCount = unreadCount, unreadCount > 0 { + unread[peerView.peerId] = isMuted ? .muted(unreadCount) : .unmuted(unreadCount) + } + } + return (peers: viewsAndPeers.1, unread: unread) + } + } + + let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError> + if groupId == nil { + foundRemotePeers = (.single(([], [], true)) |> then(searchPeers(account: account, query: query) |> map { ($0.0, $0.1, false) } + |> delay(0.2, queue: Queue.concurrentDefaultQueue()))) + } else { + foundRemotePeers = .single(([], [], false)) + } + let location: SearchMessagesLocation + if let groupId = groupId { + location = .group(groupId) + } else { + location = .general + } + + updateSearchContext { _ in + return (nil, true) + } + let foundRemoteMessages: Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> + if filter.contains(.doNotSearchMessages) { + foundRemoteMessages = .single((([], [:], 0), false)) + } else { + let searchSignal = searchMessages(account: account, location: location, query: query, limit: 50) + |> map { result -> ChatListSearchMessagesResult in + return ChatListSearchMessagesResult(query: query, messages: result.0.sorted(by: { MessageIndex($0) > MessageIndex($1) }), readStates: result.1, hasMore: result.2 != 0) + } + + let loadMore = searchContext.get() + |> mapToSignal { searchContext -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in + if let searchContext = searchContext { + if let loadMoreIndex = searchContext.loadMoreIndex { + return searchMessages(account: account, location: location, query: query, lowerBound: loadMoreIndex, limit: 80) + |> map { result -> ChatListSearchMessagesResult in + return ChatListSearchMessagesResult(query: query, messages: result.0.sorted(by: { MessageIndex($0) > MessageIndex($1) }), readStates: result.1, hasMore: result.2 != 0) + } + |> mapToSignal { foundMessages -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in + updateSearchContext { previous in + let updated = ChatListSearchMessagesContext(result: previous?.result.appending(foundMessages) ?? foundMessages, loadMoreIndex: nil) + return (updated, true) + } + return .complete() + } + } else { + return .single(((searchContext.result.messages, searchContext.result.readStates, 0), false)) + } + } else { + return .complete() + } + } + + foundRemoteMessages = .single((([], [:], 0), true)) + |> then( + searchSignal + |> map { foundMessages -> (([Message], [PeerId: CombinedPeerReadState], Int32), Bool) in + updateSearchContext { _ in + return (ChatListSearchMessagesContext(result: foundMessages, loadMoreIndex: nil), true) + } + return ((foundMessages.messages, foundMessages.readStates, 0), false) + } + |> delay(0.2, queue: Queue.concurrentDefaultQueue()) + |> then(loadMore) + ) + } + + return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get()) + |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData -> ([ChatListSearchEntry], Bool)? in + var entries: [ChatListSearchEntry] = [] + let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 + var index = 0 + + let filteredPeer:(Peer, Peer) -> Bool = { peer, accountPeer in + guard !filter.contains(.excludeSavedMessages) || peer.id != accountPeer.id else { return false } + guard !filter.contains(.excludeSecretChats) || peer.id.namespace != Namespaces.Peer.SecretChat else { return false } + guard !filter.contains(.onlyPrivateChats) || peer.id.namespace == Namespaces.Peer.CloudUser else { return false } + + if filter.contains(.onlyGroups) { + var isGroup: Bool = false + if let peer = peer as? TelegramChannel, case .group = peer.info { + isGroup = true + } else if peer.id.namespace == Namespaces.Peer.CloudGroup { + isGroup = true + } + if !isGroup { + return false + } + } + + if filter.contains(.onlyChannels) { + if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + return true + } else { + return false + } + } + + return true + } + + var existingPeerIds = Set() + + if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(query.lowercased()) { + if !existingPeerIds.contains(accountPeer.id), filteredPeer(accountPeer, accountPeer) { + existingPeerIds.insert(accountPeer.id) + entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) + index += 1 + } + } + + for renderedPeer in foundLocalPeers.peers { + if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != account.peerId, filteredPeer(peer, accountPeer) { + if !existingPeerIds.contains(peer.id) { + existingPeerIds.insert(peer.id) + var associatedPeer: Peer? + if let associatedPeerId = peer.associatedPeerId { + associatedPeer = renderedPeer.peers[associatedPeerId] + } + entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) + index += 1 + } + } + } + + for peer in foundRemotePeers.0 { + if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { + existingPeerIds.insert(peer.peer.id) + entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) + index += 1 + } + } + + index = 0 + for peer in foundRemotePeers.1 { + if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { + existingPeerIds.insert(peer.peer.id) + entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) + index += 1 + } + } + + if !foundRemotePeers.2 { + index = 0 + for message in foundRemoteMessages.0.0 { + entries.append(.message(message, foundRemoteMessages.0.1[message.id.peerId], presentationData)) + index += 1 + } + } + + if addContact != nil && isViablePhoneNumber(query) { + entries.append(.addContact(query, presentationData.theme, presentationData.strings)) + } + + return (entries, isSearching) + } + } let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil) @@ -980,6 +1075,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { var options = ListViewDeleteAndInsertOptions() options.insert(.PreferSynchronousDrawing) + options.insert(.PreferSynchronousResourceLoading) if firstTime { } else { //options.insert(.AnimateAlpha) diff --git a/TelegramUI/ChatListSearchItem.swift b/TelegramUI/ChatListSearchItem.swift index bb67a5e85a..f0c5f12e44 100644 --- a/TelegramUI/ChatListSearchItem.swift +++ b/TelegramUI/ChatListSearchItem.swift @@ -22,7 +22,7 @@ class ChatListSearchItem: ListViewItem { self.activate = activate } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatListSearchItemNode() node.placeholder = self.placeholder diff --git a/TelegramUI/ChatMediaInputMetaSectionItemNode.swift b/TelegramUI/ChatMediaInputMetaSectionItemNode.swift index bd0c5d300f..962ad8910d 100644 --- a/TelegramUI/ChatMediaInputMetaSectionItemNode.swift +++ b/TelegramUI/ChatMediaInputMetaSectionItemNode.swift @@ -27,7 +27,7 @@ final class ChatMediaInputMetaSectionItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatMediaInputMetaSectionItemNode() node.contentSize = CGSize(width: 41.0, height: 41.0) diff --git a/TelegramUI/ChatMediaInputPeerSpecificItem.swift b/TelegramUI/ChatMediaInputPeerSpecificItem.swift index f86740663b..aa055998d9 100644 --- a/TelegramUI/ChatMediaInputPeerSpecificItem.swift +++ b/TelegramUI/ChatMediaInputPeerSpecificItem.swift @@ -26,7 +26,7 @@ final class ChatMediaInputPeerSpecificItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatMediaInputPeerSpecificItemNode() node.contentSize = boundingSize diff --git a/TelegramUI/ChatMediaInputRecentGifsItem.swift b/TelegramUI/ChatMediaInputRecentGifsItem.swift index cff613b245..06e0e46ecb 100644 --- a/TelegramUI/ChatMediaInputRecentGifsItem.swift +++ b/TelegramUI/ChatMediaInputRecentGifsItem.swift @@ -20,7 +20,7 @@ final class ChatMediaInputRecentGifsItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatMediaInputRecentGifsItemNode() node.contentSize = CGSize(width: 41.0, height: 41.0) diff --git a/TelegramUI/ChatMediaInputSettingsItem.swift b/TelegramUI/ChatMediaInputSettingsItem.swift index 17941ddb61..1eaaa108f3 100644 --- a/TelegramUI/ChatMediaInputSettingsItem.swift +++ b/TelegramUI/ChatMediaInputSettingsItem.swift @@ -20,7 +20,7 @@ final class ChatMediaInputSettingsItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatMediaInputSettingsItemNode() node.contentSize = CGSize(width: 41.0, height: 41.0) diff --git a/TelegramUI/ChatMediaInputStickerGridItem.swift b/TelegramUI/ChatMediaInputStickerGridItem.swift index 5c5e45c121..82e452a79e 100644 --- a/TelegramUI/ChatMediaInputStickerGridItem.swift +++ b/TelegramUI/ChatMediaInputStickerGridItem.swift @@ -111,7 +111,7 @@ final class ChatMediaInputStickerGridItem: GridItem { } } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = ChatMediaInputStickerGridItemNode() node.interfaceInteraction = self.interfaceInteraction node.inputNodeInteraction = self.inputNodeInteraction diff --git a/TelegramUI/ChatMediaInputStickerPackItem.swift b/TelegramUI/ChatMediaInputStickerPackItem.swift index 44acbc7f47..a3bec90ce6 100644 --- a/TelegramUI/ChatMediaInputStickerPackItem.swift +++ b/TelegramUI/ChatMediaInputStickerPackItem.swift @@ -28,7 +28,7 @@ final class ChatMediaInputStickerPackItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatMediaInputStickerPackItemNode() node.contentSize = boundingSize diff --git a/TelegramUI/ChatMediaInputTrendingItem.swift b/TelegramUI/ChatMediaInputTrendingItem.swift index 5584c2bf32..b3f9d1e217 100644 --- a/TelegramUI/ChatMediaInputTrendingItem.swift +++ b/TelegramUI/ChatMediaInputTrendingItem.swift @@ -20,7 +20,7 @@ final class ChatMediaInputTrendingItem: ListViewItem { self.theme = theme } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatMediaInputTrendingItemNode() node.contentSize = CGSize(width: 41.0, height: 41.0) diff --git a/TelegramUI/ChatMessageActionItemNode.swift b/TelegramUI/ChatMessageActionItemNode.swift index 4c1f75fcca..44696746b9 100644 --- a/TelegramUI/ChatMessageActionItemNode.swift +++ b/TelegramUI/ChatMessageActionItemNode.swift @@ -501,7 +501,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { return mediaHidden } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let makeLabelLayout = TextNode.asyncLayout(self.labelNode) let backgroundLayout = self.filledBackgroundNode.asyncLayout() @@ -563,7 +563,7 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { } return (backgroundSize.width, { boundingWidth in - return (backgroundSize, { [weak self] animation in + return (backgroundSize, { [weak self] animation, _ in if let strongSelf = self { strongSelf.item = item diff --git a/TelegramUI/ChatMessageAttachedContentNode.swift b/TelegramUI/ChatMessageAttachedContentNode.swift index 83e4053988..346aa31179 100644 --- a/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/TelegramUI/ChatMessageAttachedContentNode.swift @@ -262,7 +262,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { self.addSubnode(self.statusNode) } - func asyncLayout() -> (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: AutomaticMediaDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ account: Account, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ title: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ constrainedSize: CGSize) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + func asyncLayout() -> (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: AutomaticMediaDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ account: Account, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ title: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ constrainedSize: CGSize) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let textAsyncLayout = TextNode.asyncLayout(self.textNode) let currentImage = self.media as? TelegramMediaImage let imageLayout = self.inlineImageNode.asyncLayout() @@ -329,7 +329,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { var updateInlineImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? var textCutout = TextNodeCutout() var initialWidth: CGFloat = CGFloat.greatestFiniteMagnitude - var refineContentImageLayout: ((CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition) -> ChatMessageInteractiveMediaNode)))? + var refineContentImageLayout: ((CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode)))? var refineContentFileLayout: ((CGSize) -> (CGFloat, (CGFloat) -> (CGSize, () -> ChatMessageInteractiveFileNode)))? var contentInstantVideoSizeAndApply: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ContainedViewLayoutTransition) -> ChatMessageInteractiveInstantVideoNode)? @@ -560,7 +560,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { } } - var finalizeContentImageLayout: ((CGFloat) -> (CGSize, (ContainedViewLayoutTransition) -> ChatMessageInteractiveMediaNode))? + var finalizeContentImageLayout: ((CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))? if let refineContentImageLayout = refineContentImageLayout { let (refinedWidth, finalizeImageLayout) = refineContentImageLayout(textConstrainedSize, ImageCorners(radius: 4.0)) finalizeContentImageLayout = finalizeImageLayout @@ -634,7 +634,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { imageFrame = CGRect(origin: CGPoint(x: boundingWidth - inlineImageSize.width - insets.right, y: 0.0), size: inlineImageSize) } - var contentImageSizeAndApply: (CGSize, (ContainedViewLayoutTransition) -> ChatMessageInteractiveMediaNode)? + var contentImageSizeAndApply: (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode)? if let finalizeContentImageLayout = finalizeContentImageLayout { let (size, apply) = finalizeContentImageLayout(boundingWidth - insets.left - insets.right) contentImageSizeAndApply = (size, apply) @@ -689,7 +689,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { adjustedStatusFrame = CGRect(origin: CGPoint(x: boundingWidth - statusFrame.size.width - insets.right, y: statusFrame.origin.y), size: statusFrame.size) } - return (adjustedBoundingSize, { [weak self] animation in + return (adjustedBoundingSize, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.account = account strongSelf.message = message @@ -734,7 +734,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { if let (contentImageSize, contentImageApply) = contentImageSizeAndApply { contentMediaHeight = contentImageSize.height - let contentImageNode = contentImageApply(transition) + let contentImageNode = contentImageApply(transition, synchronousLoads) if strongSelf.contentImageNode !== contentImageNode { strongSelf.contentImageNode = contentImageNode strongSelf.addSubnode(contentImageNode) @@ -745,7 +745,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { } contentImageNode.visibility = strongSelf.visibility } - let _ = contentImageApply(transition) + let _ = contentImageApply(transition, synchronousLoads) let contentImageFrame: CGRect if let (_, flags) = mediaAndFlags, flags.contains(.preferMediaBeforeText) { contentImageFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: contentImageSize) diff --git a/TelegramUI/ChatMessageBubbleContentNode.swift b/TelegramUI/ChatMessageBubbleContentNode.swift index 20ca90f13d..5686218d93 100644 --- a/TelegramUI/ChatMessageBubbleContentNode.swift +++ b/TelegramUI/ChatMessageBubbleContentNode.swift @@ -106,7 +106,7 @@ class ChatMessageBubbleContentNode: ASDisplayNode { super.init() } - func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { preconditionFailure() } diff --git a/TelegramUI/ChatMessageBubbleItemNode.swift b/TelegramUI/ChatMessageBubbleItemNode.swift index 6723835879..923de86f5a 100644 --- a/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/TelegramUI/ChatMessageBubbleItemNode.swift @@ -276,8 +276,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { self.view.addGestureRecognizer(replyRecognizer) } - override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) { - var currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))))] = [] + override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) { + var currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))))] = [] for contentNode in self.contentNodes { if let message = contentNode.item?.message { currentContentClassesPropertiesAndLayouts.append((message, type(of: contentNode) as AnyClass, contentNode.supportsMosaic, contentNode.asyncLayoutContent())) @@ -426,7 +426,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { } let maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset) - var contentPropertiesAndPrepareLayouts: [(Message, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))))] = [] + var contentPropertiesAndPrepareLayouts: [(Message, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))))] = [] var addedContentNodes: [(Message, ChatMessageBubbleContentNode)]? let contentNodeMessagesAndClasses = contentNodeMessagesAndClassesForItem(item) @@ -476,7 +476,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { } } - var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void)))] = [] + var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = [] let topNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedTop.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing) let bottomNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedBottom.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing) @@ -837,7 +837,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { } } - var contentNodePropertiesAndFinalize: [(ChatMessageBubbleContentProperties, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))] = [] + var contentNodePropertiesAndFinalize: [(ChatMessageBubbleContentProperties, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))] = [] var maxContentWidth: CGFloat = headerSize.width @@ -987,7 +987,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { } var contentSize = CGSize(width: maxContentWidth, height: 0.0) - var contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, (ListViewItemUpdateAnimation) -> Void)] = [] + var contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, (ListViewItemUpdateAnimation, Bool) -> Void)] = [] var contentNodesHeight: CGFloat = 0.0 var mosaicStatusOrigin: CGPoint? for i in 0 ..< contentNodePropertiesAndFinalize.count { @@ -1119,7 +1119,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { } } - return (layout, { [weak self] animation in + return (layout, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.appliedItem = item @@ -1302,7 +1302,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { var contentNodeIndex = 0 for (relativeFrame, _, apply) in contentNodeFramesPropertiesAndApply { - apply(animation) + apply(animation, synchronousLoads) let contentNode = strongSelf.contentNodes[contentNodeIndex] let contentNodeFrame = relativeFrame.offsetBy(dx: contentOrigin.x, dy: contentOrigin.y) diff --git a/TelegramUI/ChatMessageCallBubbleContentNode.swift b/TelegramUI/ChatMessageCallBubbleContentNode.swift index 33fe5a97f4..e713dc6168 100644 --- a/TelegramUI/ChatMessageCallBubbleContentNode.swift +++ b/TelegramUI/ChatMessageCallBubbleContentNode.swift @@ -54,7 +54,7 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeLabelLayout = TextNode.asyncLayout(self.labelNode) @@ -164,7 +164,7 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode { boundingSize.width += 54.0 return (boundingSize.width, { boundingWidth in - return (boundingSize, { [weak self] animation in + return (boundingSize, { [weak self] animation, _ in if let strongSelf = self { strongSelf.item = item diff --git a/TelegramUI/ChatMessageContactBubbleContentNode.swift b/TelegramUI/ChatMessageContactBubbleContentNode.swift index 34b4407c76..e63970305c 100644 --- a/TelegramUI/ChatMessageContactBubbleContentNode.swift +++ b/TelegramUI/ChatMessageContactBubbleContentNode.swift @@ -49,7 +49,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { self.view.addGestureRecognizer(tapRecognizer) } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let statusLayout = self.dateAndStatusNode.asyncLayout() let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTextLayout = TextNode.asyncLayout(self.textNode) @@ -242,7 +242,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { } } - return (layoutSize, { [weak self] animation in + return (layoutSize, { [weak self] animation, _ in if let strongSelf = self { strongSelf.item = item strongSelf.contact = selectedContact diff --git a/TelegramUI/ChatMessageEventLogPreviousDescriptionContentNode.swift b/TelegramUI/ChatMessageEventLogPreviousDescriptionContentNode.swift index 9c27f2f1bf..350e53845e 100644 --- a/TelegramUI/ChatMessageEventLogPreviousDescriptionContentNode.swift +++ b/TelegramUI/ChatMessageEventLogPreviousDescriptionContentNode.swift @@ -20,7 +20,7 @@ final class ChatMessageEventLogPreviousDescriptionContentNode: ChatMessageBubble fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let contentNodeLayout = self.contentNode.asyncLayout() return { item, layoutConstants, _, _, constrainedSize in @@ -52,11 +52,11 @@ final class ChatMessageEventLogPreviousDescriptionContentNode: ChatMessageBubble return (refinedWidth, { boundingWidth in let (size, apply) = finalizeLayout(boundingWidth) - return (size, { [weak self] animation in + return (size, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item - apply(animation) + apply(animation, synchronousLoads) strongSelf.contentNode.frame = CGRect(origin: CGPoint(), size: size) } diff --git a/TelegramUI/ChatMessageEventLogPreviousLinkContentNode.swift b/TelegramUI/ChatMessageEventLogPreviousLinkContentNode.swift index 807d52cb3f..0567078752 100644 --- a/TelegramUI/ChatMessageEventLogPreviousLinkContentNode.swift +++ b/TelegramUI/ChatMessageEventLogPreviousLinkContentNode.swift @@ -20,7 +20,7 @@ final class ChatMessageEventLogPreviousLinkContentNode: ChatMessageBubbleContent fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let contentNodeLayout = self.contentNode.asyncLayout() return { item, layoutConstants, _, _, constrainedSize in @@ -47,11 +47,11 @@ final class ChatMessageEventLogPreviousLinkContentNode: ChatMessageBubbleContent return (refinedWidth, { boundingWidth in let (size, apply) = finalizeLayout(boundingWidth) - return (size, { [weak self] animation in + return (size, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item - apply(animation) + apply(animation, synchronousLoads) strongSelf.contentNode.frame = CGRect(origin: CGPoint(), size: size) } diff --git a/TelegramUI/ChatMessageEventLogPreviousMessageContentNode.swift b/TelegramUI/ChatMessageEventLogPreviousMessageContentNode.swift index 4a0f614f47..da16f09755 100644 --- a/TelegramUI/ChatMessageEventLogPreviousMessageContentNode.swift +++ b/TelegramUI/ChatMessageEventLogPreviousMessageContentNode.swift @@ -20,7 +20,7 @@ final class ChatMessageEventLogPreviousMessageContentNode: ChatMessageBubbleCont fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let contentNodeLayout = self.contentNode.asyncLayout() return { item, layoutConstants, _, _, constrainedSize in @@ -52,11 +52,11 @@ final class ChatMessageEventLogPreviousMessageContentNode: ChatMessageBubbleCont return (refinedWidth, { boundingWidth in let (size, apply) = finalizeLayout(boundingWidth) - return (size, { [weak self] animation in + return (size, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item - apply(animation) + apply(animation, synchronousLoads) strongSelf.contentNode.frame = CGRect(origin: CGPoint(), size: size) } diff --git a/TelegramUI/ChatMessageFileBubbleContentNode.swift b/TelegramUI/ChatMessageFileBubbleContentNode.swift index 6793126d7e..4d15ebe0c4 100644 --- a/TelegramUI/ChatMessageFileBubbleContentNode.swift +++ b/TelegramUI/ChatMessageFileBubbleContentNode.swift @@ -36,7 +36,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let interactiveFileLayout = self.interactiveFileNode.asyncLayout() return { item, layoutConstants, preparePosition, _, constrainedSize in @@ -79,7 +79,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode { return (refinedWidth + layoutConstants.file.bubbleInsets.left + layoutConstants.file.bubbleInsets.right, { boundingWidth in let (fileSize, fileApply) = finishLayout(boundingWidth - layoutConstants.file.bubbleInsets.left - layoutConstants.file.bubbleInsets.right) - return (CGSize(width: fileSize.width + layoutConstants.file.bubbleInsets.left + layoutConstants.file.bubbleInsets.right, height: fileSize.height + layoutConstants.file.bubbleInsets.top + layoutConstants.file.bubbleInsets.bottom), { [weak self] _ in + return (CGSize(width: fileSize.width + layoutConstants.file.bubbleInsets.left + layoutConstants.file.bubbleInsets.right, height: fileSize.height + layoutConstants.file.bubbleInsets.top + layoutConstants.file.bubbleInsets.bottom), { [weak self] _, _ in if let strongSelf = self { strongSelf.item = item diff --git a/TelegramUI/ChatMessageGameBubbleContentNode.swift b/TelegramUI/ChatMessageGameBubbleContentNode.swift index 649ad762a2..93cf7d9aef 100644 --- a/TelegramUI/ChatMessageGameBubbleContentNode.swift +++ b/TelegramUI/ChatMessageGameBubbleContentNode.swift @@ -33,7 +33,7 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let contentNodeLayout = self.contentNode.asyncLayout() return { item, layoutConstants, _, _, constrainedSize in @@ -79,12 +79,12 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode { return (refinedWidth, { boundingWidth in let (size, apply) = finalizeLayout(boundingWidth) - return (size, { [weak self] animation in + return (size, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item strongSelf.game = game - apply(animation) + apply(animation, synchronousLoads) strongSelf.contentNode.frame = CGRect(origin: CGPoint(), size: size) } diff --git a/TelegramUI/ChatMessageInstantVideoItemNode.swift b/TelegramUI/ChatMessageInstantVideoItemNode.swift index 3c456e6c5f..58d5bd0916 100644 --- a/TelegramUI/ChatMessageInstantVideoItemNode.swift +++ b/TelegramUI/ChatMessageInstantVideoItemNode.swift @@ -66,7 +66,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { self.view.addGestureRecognizer(replyRecognizer) } - override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) { + override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) { let layoutConstants = self.layoutConstants let makeVideoLayout = self.interactiveVideoNode.asyncLayout() @@ -216,7 +216,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { layoutSize.height += actionButtonsSizeAndApply.0.height } - return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation in + return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in if let strongSelf = self { strongSelf.appliedItem = item diff --git a/TelegramUI/ChatMessageInteractiveMediaNode.swift b/TelegramUI/ChatMessageInteractiveMediaNode.swift index ed6e45c3b5..91feaaf21c 100644 --- a/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -141,7 +141,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { } } - func asyncLayout() -> (_ account: Account, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: Bool, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition) -> Void))) { + func asyncLayout() -> (_ account: Account, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: Bool, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> Void))) { let currentMessage = self.message let currentMedia = self.media let imageLayout = self.imageNode.asyncLayout() @@ -254,7 +254,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { drawingSize = nativeSize.aspectFilled(boundingSize) } - var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? + var updateImageSignal: ((Bool) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError>)? var updatedStatusSignal: Signal? var updatedFetchControls: FetchControls? @@ -279,9 +279,13 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { replaceVideoNode = true } if isSecretMedia { - updateImageSignal = chatSecretPhoto(account: account, photoReference: .message(message: MessageReference(message), media: image)) + updateImageSignal = { synchronousLoad in + return chatSecretPhoto(account: account, photoReference: .message(message: MessageReference(message), media: image)) + } } else { - updateImageSignal = chatMessagePhoto(postbox: account.postbox, photoReference: .message(message: MessageReference(message), media: image)) + updateImageSignal = { synchronousLoad in + return chatMessagePhoto(postbox: account.postbox, photoReference: .message(message: MessageReference(message), media: image), synchronousLoad: synchronousLoad) + } } updatedFetchControls = FetchControls(fetch: { manual in @@ -302,7 +306,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { if hasCurrentVideoNode { replaceVideoNode = true } - updateImageSignal = chatWebFileImage(account: account, file: image) + updateImageSignal = { synchronousLoad in + return chatWebFileImage(account: account, file: image) + } updatedFetchControls = FetchControls(fetch: { _ in if let strongSelf = self { @@ -313,12 +319,18 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { }) } else if let file = media as? TelegramMediaFile { if isSecretMedia { - updateImageSignal = chatSecretMessageVideo(account: account, videoReference: .message(message: MessageReference(message), media: file)) + updateImageSignal = { synchronousLoad in + return chatSecretMessageVideo(account: account, videoReference: .message(message: MessageReference(message), media: file)) + } } else { if file.isSticker { - updateImageSignal = chatMessageSticker(account: account, file: file, small: false) + updateImageSignal = { synchronousLoad in + return chatMessageSticker(account: account, file: file, small: false) + } } else { - updateImageSignal = mediaGridMessageVideo(postbox: account.postbox, videoReference: .message(message: MessageReference(message), media: file), onlyFullSize: currentMedia?.id?.namespace == Namespaces.Media.LocalFile) + updateImageSignal = { synchronousLoad in + return mediaGridMessageVideo(postbox: account.postbox, videoReference: .message(message: MessageReference(message), media: file), onlyFullSize: currentMedia?.id?.namespace == Namespaces.Media.LocalFile) + } } } @@ -395,7 +407,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { let imageApply = imageLayout(arguments) - return (boundingSize, { transition in + return (boundingSize, { transition, synchronousLoads in if let strongSelf = self { strongSelf.account = account strongSelf.message = message @@ -451,7 +463,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { } if let updateImageSignal = updateImageSignal { - strongSelf.imageNode.setSignal(updateImageSignal) + strongSelf.imageNode.setSignal(updateImageSignal(synchronousLoads), attemptSynchronously: synchronousLoads) } if let _ = secretBeginTimeAndTimeout { @@ -783,12 +795,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { } } - static func asyncLayout(_ node: ChatMessageInteractiveMediaNode?) -> (_ account: Account, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: Bool, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition) -> ChatMessageInteractiveMediaNode))) { + static func asyncLayout(_ node: ChatMessageInteractiveMediaNode?) -> (_ account: Account, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: Bool, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))) { let currentAsyncLayout = node?.asyncLayout() return { account, theme, strings, message, media, automaticDownload, peerType, automaticPlayback, sizeCalculation, layoutConstants in var imageNode: ChatMessageInteractiveMediaNode - var imageLayout: (_ account: Account, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: Bool, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition) -> Void))) + var imageLayout: (_ account: Account, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: Bool, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> Void))) if let node = node, let currentAsyncLayout = currentAsyncLayout { imageNode = node @@ -806,8 +818,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { return (finalWidth, { boundingWidth in let (finalSize, apply) = finalLayout(boundingWidth) - return (finalSize, { transition in - apply(transition) + return (finalSize, { transition, synchronousLoads in + apply(transition, synchronousLoads) return imageNode }) }) diff --git a/TelegramUI/ChatMessageInvoiceBubbleContentNode.swift b/TelegramUI/ChatMessageInvoiceBubbleContentNode.swift index 0bf933cca8..ac1e6f9f63 100644 --- a/TelegramUI/ChatMessageInvoiceBubbleContentNode.swift +++ b/TelegramUI/ChatMessageInvoiceBubbleContentNode.swift @@ -31,7 +31,7 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let contentNodeLayout = self.contentNode.asyncLayout() return { item, layoutConstants, _, _, constrainedSize in @@ -80,12 +80,12 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode { return (refinedWidth, { boundingWidth in let (size, apply) = finalizeLayout(boundingWidth) - return (size, { [weak self] animation in + return (size, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item strongSelf.invoice = invoice - apply(animation) + apply(animation, synchronousLoads) strongSelf.contentNode.frame = CGRect(origin: CGPoint(), size: size) } diff --git a/TelegramUI/ChatMessageItem.swift b/TelegramUI/ChatMessageItem.swift index d7406bb50d..c82e63dadd 100644 --- a/TelegramUI/ChatMessageItem.swift +++ b/TelegramUI/ChatMessageItem.swift @@ -314,7 +314,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { self.accessoryItem = accessoryItem } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { var viewClassName: AnyClass = ChatMessageBubbleItemNode.self loop: for media in message.media { @@ -356,7 +356,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { Queue.mainQueue().async { completion(node, { - return (nil, { apply(.None) }) + return (nil, { apply(.None, synchronousLoads) }) }) } } @@ -413,7 +413,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { let (layout, apply) = nodeLayout(self, params, top, bottom, dateAtBottom && !self.disableDate) Queue.mainQueue().async { completion(layout, { - apply(animation) + apply(animation, false) if let nodeValue = node() as? ChatMessageItemView { nodeValue.updateSelectionState(animated: false) nodeValue.updateHighlightedState(animated: false) diff --git a/TelegramUI/ChatMessageItemView.swift b/TelegramUI/ChatMessageItemView.swift index 2664474776..e90f1e201d 100644 --- a/TelegramUI/ChatMessageItemView.swift +++ b/TelegramUI/ChatMessageItemView.swift @@ -120,7 +120,7 @@ public class ChatMessageItemView: ListViewItemNode { let (layout, apply) = doLayout(item, params, merged.top, merged.bottom, merged.dateAtBottom) self.contentSize = layout.contentSize self.insets = layout.insets - apply(.None) + apply(.None, false) } } @@ -139,9 +139,9 @@ public class ChatMessageItemView: ListViewItemNode { } } - func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) { + func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) { return { _, _, _, _, _ in - return (ListViewItemNodeLayout(contentSize: CGSize(width: 32.0, height: 32.0), insets: UIEdgeInsets()), { _ in + return (ListViewItemNodeLayout(contentSize: CGSize(width: 32.0, height: 32.0), insets: UIEdgeInsets()), { _, _ in }) } diff --git a/TelegramUI/ChatMessageMapBubbleContentNode.swift b/TelegramUI/ChatMessageMapBubbleContentNode.swift index deadb0b429..326109923d 100644 --- a/TelegramUI/ChatMessageMapBubbleContentNode.swift +++ b/TelegramUI/ChatMessageMapBubbleContentNode.swift @@ -51,7 +51,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { self.view.addGestureRecognizer(tapRecognizer) } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let makeImageLayout = self.imageNode.asyncLayout() let makePinLayout = self.pinNode.asyncLayout() let statusLayout = self.dateAndStatusNode.asyncLayout() @@ -264,7 +264,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { let imageApply = makeImageLayout(arguments) - return (layoutSize, { [weak self] animation in + return (layoutSize, { [weak self] animation, _ in if let strongSelf = self { strongSelf.item = item strongSelf.media = selectedMedia diff --git a/TelegramUI/ChatMessageMediaBubbleContentNode.swift b/TelegramUI/ChatMessageMediaBubbleContentNode.swift index 0f5a6db2cc..ecf76193dc 100644 --- a/TelegramUI/ChatMessageMediaBubbleContentNode.swift +++ b/TelegramUI/ChatMessageMediaBubbleContentNode.swift @@ -44,7 +44,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let interactiveImageLayout = self.interactiveImageNode.asyncLayout() let statusLayout = self.dateAndStatusNode.asyncLayout() @@ -159,7 +159,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { let layoutSize = CGSize(width: layoutWidth, height: imageLayoutSize.height) - return (layoutSize, { [weak self] animation in + return (layoutSize, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item strongSelf.media = selectedMedia @@ -190,7 +190,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.dateAndStatusNode.removeFromSupernode() } - imageApply(transition) + imageApply(transition, synchronousLoads) if let selection = selection { if let selectionNode = strongSelf.selectionNode { diff --git a/TelegramUI/ChatMessageStickerItemNode.swift b/TelegramUI/ChatMessageStickerItemNode.swift index 782cded2be..5de41092ce 100644 --- a/TelegramUI/ChatMessageStickerItemNode.swift +++ b/TelegramUI/ChatMessageStickerItemNode.swift @@ -91,7 +91,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } } - override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) { + override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) { let displaySize = CGSize(width: 162.0, height: 162.0) let telegramFile = self.telegramFile let layoutConstants = self.layoutConstants @@ -278,7 +278,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { let contentHeight = max(imageSize.height, layoutConstants.image.minDimensions.height) - return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: contentHeight), insets: layoutInsets), { [weak self] animation in + return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: contentHeight), insets: layoutInsets), { [weak self] animation, _ in if let strongSelf = self { let updatedImageFrame = imageFrame.offsetBy(dx: 0.0, dy: floor((contentHeight - imageSize.height) / 2.0)) diff --git a/TelegramUI/ChatMessageTextBubbleContentNode.swift b/TelegramUI/ChatMessageTextBubbleContentNode.swift index 634cd74231..0baab2d140 100644 --- a/TelegramUI/ChatMessageTextBubbleContentNode.swift +++ b/TelegramUI/ChatMessageTextBubbleContentNode.swift @@ -54,7 +54,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let textLayout = TextNode.asyncLayout(self.textNode) let statusLayout = self.statusNode.asyncLayout() @@ -202,7 +202,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { adjustedStatusFrame = CGRect(origin: CGPoint(x: boundingWidth - statusFrame.size.width - layoutConstants.text.bubbleInsets.right, y: statusFrame.origin.y), size: statusFrame.size) } - return (boundingSize, { [weak self] animation in + return (boundingSize, { [weak self] animation, _ in if let strongSelf = self { strongSelf.item = item if let updatedCachedChatMessageText = updatedCachedChatMessageText { diff --git a/TelegramUI/ChatMessageWebpageBubbleContentNode.swift b/TelegramUI/ChatMessageWebpageBubbleContentNode.swift index 2ae65ec7fc..6c17de3ef5 100644 --- a/TelegramUI/ChatMessageWebpageBubbleContentNode.swift +++ b/TelegramUI/ChatMessageWebpageBubbleContentNode.swift @@ -161,7 +161,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode { fatalError("init(coder:) has not been implemented") } - override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> Void))) { + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { let contentNodeLayout = self.contentNode.asyncLayout() return { item, layoutConstants, _, _, constrainedSize in @@ -277,12 +277,12 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode { return (refinedWidth, { boundingWidth in let (size, apply) = finalizeLayout(boundingWidth) - return (size, { [weak self] animation in + return (size, { [weak self] animation, synchronousLoads in if let strongSelf = self { strongSelf.item = item strongSelf.webPage = webPage - apply(animation) + apply(animation, synchronousLoads) strongSelf.contentNode.frame = CGRect(origin: CGPoint(), size: size) } diff --git a/TelegramUI/ChatPresentationInterfaceState.swift b/TelegramUI/ChatPresentationInterfaceState.swift index c74025d309..66a32165f7 100644 --- a/TelegramUI/ChatPresentationInterfaceState.swift +++ b/TelegramUI/ChatPresentationInterfaceState.swift @@ -312,6 +312,7 @@ final class ChatPresentationInterfaceState: Equatable { let isNotAccessible: Bool let explicitelyCanPinMessages: Bool let isContact: Bool + let hasBots: Bool let inputTextPanelState: ChatTextInputPanelState let editMessageState: ChatEditInterfaceMessageState? let recordedMediaPreview: ChatRecordedMediaPreview? @@ -350,6 +351,7 @@ final class ChatPresentationInterfaceState: Equatable { self.isNotAccessible = false self.explicitelyCanPinMessages = false self.isContact = false + self.hasBots = false self.inputQueryResults = [:] self.inputMode = .none self.titlePanelContexts = [] @@ -376,13 +378,14 @@ final class ChatPresentationInterfaceState: Equatable { self.mode = mode } - init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isNotAccessible: Bool, explicitelyCanPinMessages: Bool, isContact: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, canReportPeer: Bool, callsAvailable: Bool, callsPrivate: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) { + init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isNotAccessible: Bool, explicitelyCanPinMessages: Bool, isContact: Bool, hasBots: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, canReportPeer: Bool, callsAvailable: Bool, callsPrivate: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) { self.interfaceState = interfaceState self.chatLocation = chatLocation self.renderedPeer = renderedPeer self.isNotAccessible = isNotAccessible self.explicitelyCanPinMessages = explicitelyCanPinMessages self.isContact = isContact + self.hasBots = hasBots self.inputTextPanelState = inputTextPanelState self.editMessageState = editMessageState self.recordedMediaPreview = recordedMediaPreview @@ -428,6 +431,9 @@ final class ChatPresentationInterfaceState: Equatable { if lhs.isContact != rhs.isContact { return false } + if lhs.hasBots != rhs.hasBots { + return false + } if lhs.inputTextPanelState != rhs.inputTextPanelState { return false @@ -569,23 +575,27 @@ final class ChatPresentationInterfaceState: Equatable { } func updatedInterfaceState(_ f: (ChatInterfaceState) -> ChatInterfaceState) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: f(self.interfaceState), chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPeer(_ f: (RenderedPeer?) -> RenderedPeer?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: f(self.renderedPeer), isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedIsNotAccessible(_ isNotAccessible: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedExplicitelyCanPinMessages(_ explicitelyCanPinMessages: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedIsContact(_ isContact: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + } + + func updatedHasBots(_ hasBots: Bool) -> ChatPresentationInterfaceState { + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedInputQueryResult(queryKind: ChatPresentationInputQueryKind, _ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState { @@ -596,103 +606,103 @@ final class ChatPresentationInterfaceState: Equatable { } else { inputQueryResults.removeValue(forKey: queryKind) } - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedInputTextPanelState(_ f: (ChatTextInputPanelState) -> ChatTextInputPanelState) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: f(self.inputTextPanelState), editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: f(self.inputTextPanelState), editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedEditMessageState(_ editMessageState: ChatEditInterfaceMessageState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedRecordedMediaPreview(_ recordedMediaPreview: ChatRecordedMediaPreview?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedInputMode(_ f: (ChatInputMode) -> ChatInputMode) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: f(self.inputMode), titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: f(self.inputMode), titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedTitlePanelContext(_ f: ([ChatTitlePanelContext]) -> [ChatTitlePanelContext]) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: f(self.titlePanelContexts), keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: f(self.titlePanelContexts), keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedKeyboardButtonsMessage(_ message: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: message, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: message, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPinnedMessage(_ pinnedMessage: Message?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPeerIsBlocked(_ peerIsBlocked: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedPeerIsMuted(_ peerIsMuted: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedCanReportPeer(_ canReportPeer: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedCallsAvailable(_ callsAvailable: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedCallsPrivate(_ callsPrivate: Bool) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedBotStartPayload(_ botStartPayload: String?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedChatHistoryState(_ chatHistoryState: ChatHistoryNodeHistoryState?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedUrlPreview(_ urlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedEditingUrlPreview(_ editingUrlPreview: (String, TelegramMediaWebpage)?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedSearch(_ search: ChatSearchData?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedSearchQuerySuggestionResult(_ f: (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: f(self.searchQuerySuggestionResult), chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: f(self.searchQuerySuggestionResult), chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedMode(_ mode: ChatControllerPresentationMode) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: mode) } func updatedTheme(_ theme: PresentationTheme) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedStrings(_ strings: PresentationStrings) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedDateTimeFormat(_ dateTimeFormat: PresentationDateTimeFormat) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } func updatedChatWallpaper(_ chatWallpaper: TelegramWallpaper) -> ChatPresentationInterfaceState { - return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) + return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: chatWallpaper, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) } } diff --git a/TelegramUI/ChatUnreadItem.swift b/TelegramUI/ChatUnreadItem.swift index 0edc0b5575..4bdf4de685 100644 --- a/TelegramUI/ChatUnreadItem.swift +++ b/TelegramUI/ChatUnreadItem.swift @@ -18,7 +18,7 @@ class ChatUnreadItem: ListViewItem { self.header = ChatMessageDateHeader(timestamp: index.timestamp, presentationData: presentationData) } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ChatUnreadItemNode() node.layoutForParams(params, item: self, previousItem: previousItem, nextItem: nextItem) diff --git a/TelegramUI/CommandChatInputPanelItem.swift b/TelegramUI/CommandChatInputPanelItem.swift index c2e4273bba..44e897a764 100644 --- a/TelegramUI/CommandChatInputPanelItem.swift +++ b/TelegramUI/CommandChatInputPanelItem.swift @@ -20,7 +20,7 @@ final class CommandChatInputPanelItem: ListViewItem { self.commandSelected = commandSelected } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = CommandChatInputPanelItemNode() diff --git a/TelegramUI/ContactAddItem.swift b/TelegramUI/ContactAddItem.swift index 0d57699538..72eb2ded4f 100644 --- a/TelegramUI/ContactAddItem.swift +++ b/TelegramUI/ContactAddItem.swift @@ -24,7 +24,7 @@ class ContactsAddItem: ListViewItem { self.header = header } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ContactsAddItemNode() let makeLayout = node.asyncLayout() diff --git a/TelegramUI/ContactListActionItem.swift b/TelegramUI/ContactListActionItem.swift index 2d35c631ca..03735892ed 100644 --- a/TelegramUI/ContactListActionItem.swift +++ b/TelegramUI/ContactListActionItem.swift @@ -18,7 +18,7 @@ class ContactListActionItem: ListViewItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ContactListActionItemNode() let (_, _, firstWithHeader) = ContactListActionItem.mergeType(item: self, previousItem: previousItem, nextItem: nextItem) diff --git a/TelegramUI/ContactListNode.swift b/TelegramUI/ContactListNode.swift index f465c07144..09b432111a 100644 --- a/TelegramUI/ContactListNode.swift +++ b/TelegramUI/ContactListNode.swift @@ -664,6 +664,7 @@ final class ContactListNode: ASDisplayNode { super.init() self.backgroundColor = self.presentationData.theme.chatList.backgroundColor + //self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor self.selectionStateValue = selectionState self.selectionStatePromise.set(.single(selectionState)) @@ -865,6 +866,7 @@ final class ContactListNode: ASDisplayNode { if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings || previousDisableAnimations != presentationData.disableAnimations { strongSelf.backgroundColor = presentationData.theme.chatList.backgroundColor + strongSelf.listNode.verticalScrollIndicatorColor = presentationData.theme.list.scrollIndicatorColor strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, presentationData.disableAnimations))) let authorizationPreviousHidden = strongSelf.authorizationNode.isHidden diff --git a/TelegramUI/ContactsPeerItem.swift b/TelegramUI/ContactsPeerItem.swift index e3c21897d6..5279de07df 100644 --- a/TelegramUI/ContactsPeerItem.swift +++ b/TelegramUI/ContactsPeerItem.swift @@ -195,7 +195,7 @@ class ContactsPeerItem: ListViewItem { } } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ContactsPeerItemNode() let makeLayout = node.asyncLayout() @@ -208,7 +208,7 @@ class ContactsPeerItem: ListViewItem { completion(node, { let (signal, apply) = nodeApply() return (signal, { - apply(false) + apply(false, synchronousLoads) }) }) } @@ -224,7 +224,7 @@ class ContactsPeerItem: ListViewItem { let (nodeLayout, apply) = layout(self, params, first, last, firstWithHeader) Queue.mainQueue().async { completion(nodeLayout, { - apply().1(animation.isAnimated) + apply().1(animation.isAnimated, false) }) } } @@ -379,7 +379,7 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { } } - func asyncLayout() -> (_ item: ContactsPeerItem, _ params: ListViewItemLayoutParams, _ first: Bool, _ last: Bool, _ firstWithHeader: Bool) -> (ListViewItemNodeLayout, () -> (Signal?, (Bool) -> Void)) { + func asyncLayout() -> (_ item: ContactsPeerItem, _ params: ListViewItemLayoutParams, _ first: Bool, _ last: Bool, _ firstWithHeader: Bool) -> (ListViewItemNodeLayout, () -> (Signal?, (Bool, Bool) -> Void)) { let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeStatusLayout = TextNode.asyncLayout(self.statusNode) let currentSelectionNode = self.selectionNode @@ -564,33 +564,33 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { return (nodeLayout, { [weak self] in if let strongSelf = self { - switch item.peer { - case let .peer(peer, _): - if let peer = peer { - var overrideImage: AvatarNodeImageOverride? - if peer.id == item.account.peerId, case .generalSearch = item.peerMode { - overrideImage = .savedMessagesIcon - } - strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor) - } - case let .deviceContact(_, contact): - let letters: [String] - if !contact.firstName.isEmpty && !contact.lastName.isEmpty { - letters = [contact.firstName.substring(to: contact.firstName.index(after: contact.firstName.startIndex)).uppercased(), contact.lastName.substring(to: contact.lastName.index(after: contact.lastName.startIndex)).uppercased()] - } else if !contact.firstName.isEmpty { - letters = [contact.firstName.substring(to: contact.firstName.index(after: contact.firstName.startIndex)).uppercased()] - } else if !contact.lastName.isEmpty { - letters = [contact.lastName.substring(to: contact.lastName.index(after: contact.lastName.startIndex)).uppercased()] - } else { - letters = [" "] - } - strongSelf.avatarNode.setCustomLetters(letters) - } - - return (strongSelf.avatarNode.ready, { [weak strongSelf] animated in + return (.complete(), { [weak strongSelf] animated, synchronousLoads in if let strongSelf = strongSelf { strongSelf.layoutParams = (item, params, first, last, firstWithHeader) + switch item.peer { + case let .peer(peer, _): + if let peer = peer { + var overrideImage: AvatarNodeImageOverride? + if peer.id == item.account.peerId, case .generalSearch = item.peerMode { + overrideImage = .savedMessagesIcon + } + strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoads) + } + case let .deviceContact(_, contact): + let letters: [String] + if !contact.firstName.isEmpty && !contact.lastName.isEmpty { + letters = [contact.firstName[.. Pr primaryColor: .black, controlColor: UIColor(rgb: 0x96979d) ), - mediaPlaceholderColor: UIColor(rgb: 0xe4e4e4) + mediaPlaceholderColor: UIColor(rgb: 0xe4e4e4), + scrollIndicatorColor: UIColor(white: 0.0, alpha: 0.3) ) let chatList = PresentationThemeChatList( diff --git a/TelegramUI/EmojisChatInputPanelItem.swift b/TelegramUI/EmojisChatInputPanelItem.swift index 338c00daa8..8cee508e0f 100644 --- a/TelegramUI/EmojisChatInputPanelItem.swift +++ b/TelegramUI/EmojisChatInputPanelItem.swift @@ -20,7 +20,7 @@ final class EmojisChatInputPanelItem: ListViewItem { self.hashtagSelected = hashtagSelected } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = EmojisChatInputPanelItemNode() diff --git a/TelegramUI/GridHoleItem.swift b/TelegramUI/GridHoleItem.swift index 13af98cafe..ebb10742df 100644 --- a/TelegramUI/GridHoleItem.swift +++ b/TelegramUI/GridHoleItem.swift @@ -5,7 +5,7 @@ import AsyncDisplayKit final class GridHoleItem: GridItem { let section: GridSection? = nil - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { return GridHoleItemNode() } diff --git a/TelegramUI/GridMessageItem.swift b/TelegramUI/GridMessageItem.swift index 8baa83f73a..3a4525350e 100644 --- a/TelegramUI/GridMessageItem.swift +++ b/TelegramUI/GridMessageItem.swift @@ -158,7 +158,7 @@ final class GridMessageItem: GridItem { self.section = GridMessageItemSection(timestamp: message.timestamp, theme: theme, strings: strings) } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = GridMessageItemNode() if let media = mediaForMessage(self.message) { node.setup(account: self.account, item: self, media: media, messageId: self.message.id, controllerInteraction: self.controllerInteraction) diff --git a/TelegramUI/GroupStickerPackCurrentItem.swift b/TelegramUI/GroupStickerPackCurrentItem.swift index 3d1d4c215f..cfffb7b949 100644 --- a/TelegramUI/GroupStickerPackCurrentItem.swift +++ b/TelegramUI/GroupStickerPackCurrentItem.swift @@ -28,7 +28,7 @@ final class GroupStickerPackCurrentItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = GroupStickerPackCurrentItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/HashtagChatInputPanelItem.swift b/TelegramUI/HashtagChatInputPanelItem.swift index d1bec034e4..f9c525a48c 100644 --- a/TelegramUI/HashtagChatInputPanelItem.swift +++ b/TelegramUI/HashtagChatInputPanelItem.swift @@ -18,7 +18,7 @@ final class HashtagChatInputPanelItem: ListViewItem { self.hashtagSelected = hashtagSelected } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = HashtagChatInputPanelItemNode() diff --git a/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift b/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift index 635b97a8e2..1a646c4a17 100644 --- a/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift +++ b/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift @@ -19,7 +19,7 @@ final class HorizontalListContextResultsChatInputPanelItem: ListViewItem { self.resultSelected = resultSelected } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = HorizontalListContextResultsChatInputPanelItemNode() diff --git a/TelegramUI/HorizontalPeerItem.swift b/TelegramUI/HorizontalPeerItem.swift index 98ec1b9f86..c3c6f50c32 100644 --- a/TelegramUI/HorizontalPeerItem.swift +++ b/TelegramUI/HorizontalPeerItem.swift @@ -36,7 +36,7 @@ final class HorizontalPeerItem: ListViewItem { self.unreadBadge = unreadBadge } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = HorizontalPeerItemNode() @@ -168,7 +168,7 @@ final class HorizontalPeerItemNode: ListViewItemNode { if let strongSelf = self { strongSelf.item = item strongSelf.peerNode.theme = itemTheme - strongSelf.peerNode.setup(account: item.account, strings: item.strings, peer: RenderedPeer(peer: item.peer), numberOfLines: 1) + strongSelf.peerNode.setup(account: item.account, strings: item.strings, peer: RenderedPeer(peer: item.peer), numberOfLines: 1, synchronousLoad: false) strongSelf.peerNode.frame = CGRect(origin: CGPoint(), size: itemLayout.size) strongSelf.peerNode.updateSelection(selected: item.isPeerSelected(item.peer.id), animated: false) diff --git a/TelegramUI/HorizontalStickerGridItem.swift b/TelegramUI/HorizontalStickerGridItem.swift index f8eb759542..5f3276f2b7 100644 --- a/TelegramUI/HorizontalStickerGridItem.swift +++ b/TelegramUI/HorizontalStickerGridItem.swift @@ -20,7 +20,7 @@ final class HorizontalStickerGridItem: GridItem { self.interfaceInteraction = interfaceInteraction } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = HorizontalStickerGridItemNode() node.setup(account: self.account, item: self) node.interfaceInteraction = self.interfaceInteraction diff --git a/TelegramUI/ItemListActionItem.swift b/TelegramUI/ItemListActionItem.swift index 84e9811461..1177fdefbb 100644 --- a/TelegramUI/ItemListActionItem.swift +++ b/TelegramUI/ItemListActionItem.swift @@ -38,7 +38,7 @@ class ItemListActionItem: ListViewItem, ItemListItem { self.tag = tag } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListActionItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListActivityTextItem.swift b/TelegramUI/ItemListActivityTextItem.swift index 657b0aa98a..6c04c1ca89 100644 --- a/TelegramUI/ItemListActivityTextItem.swift +++ b/TelegramUI/ItemListActivityTextItem.swift @@ -18,7 +18,7 @@ class ItemListActivityTextItem: ListViewItem, ItemListItem { self.sectionId = sectionId } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListActivityTextItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListAvatarAndNameItem.swift b/TelegramUI/ItemListAvatarAndNameItem.swift index 711f0167c2..9d65d33f11 100644 --- a/TelegramUI/ItemListAvatarAndNameItem.swift +++ b/TelegramUI/ItemListAvatarAndNameItem.swift @@ -201,7 +201,7 @@ class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { } } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListAvatarAndNameInfoItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) @@ -305,7 +305,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite self.updatingAvatarOverlay.displayWithoutProcessing = true self.updatingAvatarOverlay.displaysAsynchronously = false - self.activityIndicator = ActivityIndicator(type: .custom(.white, 24.0, 1.0, false)) + self.activityIndicator = ActivityIndicator(type: .custom(.white, 22.0, 1.0, false)) self.activityIndicator.isHidden = true self.nameNode = TextNode() @@ -630,7 +630,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite } else if case .editSettings = item.mode { overrideImage = AvatarNodeImageOverride.editAvatarIcon } - strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor) + strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor, synchronousLoad: true) } let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: avatarOriginY), size: CGSize(width: 66.0, height: 66.0)) diff --git a/TelegramUI/ItemListCallListItem.swift b/TelegramUI/ItemListCallListItem.swift index 3e1d252f60..4038b39e04 100644 --- a/TelegramUI/ItemListCallListItem.swift +++ b/TelegramUI/ItemListCallListItem.swift @@ -22,7 +22,7 @@ class ItemListCallListItem: ListViewItem, ItemListItem { self.style = style } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListCallListItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListCheckboxItem.swift b/TelegramUI/ItemListCheckboxItem.swift index 0f7fa4b72a..e1fd12d891 100644 --- a/TelegramUI/ItemListCheckboxItem.swift +++ b/TelegramUI/ItemListCheckboxItem.swift @@ -34,7 +34,7 @@ class ItemListCheckboxItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListCheckboxItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListDisclosureItem.swift b/TelegramUI/ItemListDisclosureItem.swift index 8b22861fdd..29fed9b6c2 100644 --- a/TelegramUI/ItemListDisclosureItem.swift +++ b/TelegramUI/ItemListDisclosureItem.swift @@ -51,7 +51,7 @@ class ItemListDisclosureItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListDisclosureItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListLoadingIndicatorEmptyStateItem.swift b/TelegramUI/ItemListLoadingIndicatorEmptyStateItem.swift index 06317b0a90..fc4de40a98 100644 --- a/TelegramUI/ItemListLoadingIndicatorEmptyStateItem.swift +++ b/TelegramUI/ItemListLoadingIndicatorEmptyStateItem.swift @@ -35,7 +35,7 @@ final class ItemListLoadingIndicatorEmptyStateItemNode: ItemListControllerEmptyS init(theme: PresentationTheme) { self.theme = theme - self.indicator = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 40.0, 2.0, false)) + self.indicator = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 22.0, 2.0, false)) super.init() @@ -48,7 +48,7 @@ final class ItemListLoadingIndicatorEmptyStateItemNode: ItemListControllerEmptyS var insets = layout.insets(options: [.statusBar]) insets.top += navigationBarHeight - let size = CGSize(width: 40.0, height: 40.0) + let size = CGSize(width: 22.0, height: 22.0) transition.updateFrame(node: self.indicator, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - size.width) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - size.height) / 2.0)), size: size)) } } diff --git a/TelegramUI/ItemListMultilineInputItem.swift b/TelegramUI/ItemListMultilineInputItem.swift index d875bb428c..291662c5bf 100644 --- a/TelegramUI/ItemListMultilineInputItem.swift +++ b/TelegramUI/ItemListMultilineInputItem.swift @@ -26,7 +26,7 @@ class ItemListMultilineInputItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListMultilineInputItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListMultilineTextItem.swift b/TelegramUI/ItemListMultilineTextItem.swift index 9d996e122d..6f1b9ec295 100644 --- a/TelegramUI/ItemListMultilineTextItem.swift +++ b/TelegramUI/ItemListMultilineTextItem.swift @@ -42,7 +42,7 @@ class ItemListMultilineTextItem: ListViewItem, ItemListItem { self.selectable = action != nil } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListMultilineTextItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListPeerActionItem.swift b/TelegramUI/ItemListPeerActionItem.swift index e5e8742571..4e2da9b0ae 100644 --- a/TelegramUI/ItemListPeerActionItem.swift +++ b/TelegramUI/ItemListPeerActionItem.swift @@ -20,7 +20,7 @@ class ItemListPeerActionItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListPeerActionItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListPeerItem.swift b/TelegramUI/ItemListPeerItem.swift index 9c16f22b12..1b65e2e302 100644 --- a/TelegramUI/ItemListPeerItem.swift +++ b/TelegramUI/ItemListPeerItem.swift @@ -105,7 +105,7 @@ final class ItemListPeerItem: ListViewItem, ItemListItem { self.hasTopGroupInset = hasTopGroupInset } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListPeerItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListRecentSessionItem.swift b/TelegramUI/ItemListRecentSessionItem.swift index 329d3021c2..a043339915 100644 --- a/TelegramUI/ItemListRecentSessionItem.swift +++ b/TelegramUI/ItemListRecentSessionItem.swift @@ -57,7 +57,7 @@ final class ItemListRecentSessionItem: ListViewItem, ItemListItem { self.removeSession = removeSession } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListRecentSessionItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListSecretChatKeyItem.swift b/TelegramUI/ItemListSecretChatKeyItem.swift index 7526fd32be..1543dc33ce 100644 --- a/TelegramUI/ItemListSecretChatKeyItem.swift +++ b/TelegramUI/ItemListSecretChatKeyItem.swift @@ -25,7 +25,7 @@ class ItemListSecretChatKeyItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListSecretChatKeyItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListSectionHeaderItem.swift b/TelegramUI/ItemListSectionHeaderItem.swift index cf9c61892b..fef5dce77f 100644 --- a/TelegramUI/ItemListSectionHeaderItem.swift +++ b/TelegramUI/ItemListSectionHeaderItem.swift @@ -16,7 +16,7 @@ class ItemListSectionHeaderItem: ListViewItem, ItemListItem { self.sectionId = sectionId } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListSectionHeaderItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListSingleLineInputItem.swift b/TelegramUI/ItemListSingleLineInputItem.swift index 03a91dc747..9aca4b1381 100644 --- a/TelegramUI/ItemListSingleLineInputItem.swift +++ b/TelegramUI/ItemListSingleLineInputItem.swift @@ -42,7 +42,7 @@ class ItemListSingleLineInputItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListSingleLineInputItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListStickerPackItem.swift b/TelegramUI/ItemListStickerPackItem.swift index 9ff3a49f66..5d641fcf32 100644 --- a/TelegramUI/ItemListStickerPackItem.swift +++ b/TelegramUI/ItemListStickerPackItem.swift @@ -69,7 +69,7 @@ final class ItemListStickerPackItem: ListViewItem, ItemListItem { self.removePack = removePack } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListStickerPackItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListSwitchItem.swift b/TelegramUI/ItemListSwitchItem.swift index 7bf0cc766a..4351a3290f 100644 --- a/TelegramUI/ItemListSwitchItem.swift +++ b/TelegramUI/ItemListSwitchItem.swift @@ -31,7 +31,7 @@ class ItemListSwitchItem: ListViewItem, ItemListItem { self.updated = updated } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListSwitchItemNode(type: self.type) let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListTextItem.swift b/TelegramUI/ItemListTextItem.swift index 117a3e9a16..385e623766 100644 --- a/TelegramUI/ItemListTextItem.swift +++ b/TelegramUI/ItemListTextItem.swift @@ -28,7 +28,7 @@ class ItemListTextItem: ListViewItem, ItemListItem { self.style = style } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListTextItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListTextWithLabelItem.swift b/TelegramUI/ItemListTextWithLabelItem.swift index 6cf15b0744..faebcaa0ea 100644 --- a/TelegramUI/ItemListTextWithLabelItem.swift +++ b/TelegramUI/ItemListTextWithLabelItem.swift @@ -41,7 +41,7 @@ final class ItemListTextWithLabelItem: ListViewItem, ItemListItem { self.tag = tag } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListTextWithLabelItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ItemListWebsiteItem.swift b/TelegramUI/ItemListWebsiteItem.swift index ba4fb54d2a..475bf6e310 100644 --- a/TelegramUI/ItemListWebsiteItem.swift +++ b/TelegramUI/ItemListWebsiteItem.swift @@ -47,7 +47,7 @@ final class ItemListWebsiteItem: ListViewItem, ItemListItem { self.removeSession = removeSession } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ItemListWebsiteItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/JoinLinkPreviewPeerContentNode.swift b/TelegramUI/JoinLinkPreviewPeerContentNode.swift index 784eade0a5..8edb692dee 100644 --- a/TelegramUI/JoinLinkPreviewPeerContentNode.swift +++ b/TelegramUI/JoinLinkPreviewPeerContentNode.swift @@ -43,7 +43,7 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer self.peerNodes = members.map { peer in let node = SelectablePeerNode() - node.setup(account: account, strings: strings, peer: RenderedPeer(peer: peer)) + node.setup(account: account, strings: strings, peer: RenderedPeer(peer: peer), synchronousLoad: false) node.theme = itemTheme return node } diff --git a/TelegramUI/LanguageSelectionController.swift b/TelegramUI/LanguageSelectionController.swift index c1a9de3cdd..21203960c2 100644 --- a/TelegramUI/LanguageSelectionController.swift +++ b/TelegramUI/LanguageSelectionController.swift @@ -51,7 +51,7 @@ private final class LanguageAccessoryView: UIView { self.check.frame = CGRect(origin: CGPoint(x: floor((size.width - checkSize.width) / 2.0), y: floor((size.height - checkSize.height) / 2.0)), size: checkSize) } - let indicatorSize = self.indicator.measure(CGSize(width: 22.0, height: 22.0)) + let indicatorSize = self.indicator.measure(CGSize(width: 100.0, height: 100.0)) self.indicator.frame = CGRect(origin: CGPoint(x: floor((size.width - indicatorSize.width) / 2.0), y: floor((size.height - indicatorSize.height) / 2.0)), size: indicatorSize) } diff --git a/TelegramUI/ListMessageHoleItem.swift b/TelegramUI/ListMessageHoleItem.swift index e2912456eb..f8a97bd7ba 100644 --- a/TelegramUI/ListMessageHoleItem.swift +++ b/TelegramUI/ListMessageHoleItem.swift @@ -9,7 +9,7 @@ final class ListMessageHoleItem: ListViewItem { public init() { } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = ListMessageHoleItemNode() diff --git a/TelegramUI/ListMessageItem.swift b/TelegramUI/ListMessageItem.swift index 8aa2758844..e7c9fb1888 100644 --- a/TelegramUI/ListMessageItem.swift +++ b/TelegramUI/ListMessageItem.swift @@ -35,7 +35,7 @@ final class ListMessageItem: ListViewItem { self.selection = selection } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { var viewClassName: AnyClass = ListMessageSnippetItemNode.self for media in message.media { diff --git a/TelegramUI/LocalizationListItem.swift b/TelegramUI/LocalizationListItem.swift index bdf5445b9a..26abd42081 100644 --- a/TelegramUI/LocalizationListItem.swift +++ b/TelegramUI/LocalizationListItem.swift @@ -41,7 +41,7 @@ class LocalizationListItem: ListViewItem, ItemListItem { self.removeItem = removeItem } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = LocalizationListItemNode() var neighbors = itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem) diff --git a/TelegramUI/MediaInputPaneTrendingItem.swift b/TelegramUI/MediaInputPaneTrendingItem.swift index aad47a313d..d1bcf0a8b8 100644 --- a/TelegramUI/MediaInputPaneTrendingItem.swift +++ b/TelegramUI/MediaInputPaneTrendingItem.swift @@ -26,7 +26,7 @@ class MediaInputPaneTrendingItem: ListViewItem { self.unread = unread } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = MediaInputPaneTrendingItemNode() let (layout, apply) = node.asyncLayout()(self, params) diff --git a/TelegramUI/MentionChatInputPanelItem.swift b/TelegramUI/MentionChatInputPanelItem.swift index a64706b04d..f1c2bd28dd 100644 --- a/TelegramUI/MentionChatInputPanelItem.swift +++ b/TelegramUI/MentionChatInputPanelItem.swift @@ -22,7 +22,7 @@ final class MentionChatInputPanelItem: ListViewItem { self.peerSelected = peerSelected } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = MentionChatInputPanelItemNode() diff --git a/TelegramUI/NotificationSearchItem.swift b/TelegramUI/NotificationSearchItem.swift index 148dd9d4fc..ae94ef9968 100644 --- a/TelegramUI/NotificationSearchItem.swift +++ b/TelegramUI/NotificationSearchItem.swift @@ -30,7 +30,7 @@ class NotificationSearchItem: ListViewItem, ItemListItem { self.activate = activate } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = NotificationSearchItemNode() node.placeholder = self.placeholder diff --git a/TelegramUI/PeerAvatar.swift b/TelegramUI/PeerAvatar.swift index 87835e8470..ce501fb63f 100644 --- a/TelegramUI/PeerAvatar.swift +++ b/TelegramUI/PeerAvatar.swift @@ -19,42 +19,42 @@ private let roundCorners = { () -> UIImage in return image }() -public func peerAvatarImageData(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?) -> Signal? { +public func peerAvatarImageData(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, synchronousLoad: Bool) -> Signal? { if let smallProfileImage = representation { - let resourceData = account.postbox.mediaBox.resourceData(smallProfileImage.resource) + let resourceData = account.postbox.mediaBox.resourceData(smallProfileImage.resource, attemptSynchronously: synchronousLoad) let imageData = resourceData - |> take(1) - |> mapToSignal { maybeData -> Signal in - if maybeData.complete { - return .single(try? Data(contentsOf: URL(fileURLWithPath: maybeData.path))) - } else { - return Signal { subscriber in - let resourceDataDisposable = resourceData.start(next: { data in - if data.complete { - subscriber.putNext(try? Data(contentsOf: URL(fileURLWithPath: maybeData.path))) - subscriber.putCompletion() - } else { - subscriber.putNext(nil) - } - }, error: { error in - subscriber.putError(error) - }, completed: { + |> take(1) + |> mapToSignal { maybeData -> Signal in + if maybeData.complete { + return .single(try? Data(contentsOf: URL(fileURLWithPath: maybeData.path))) + } else { + return Signal { subscriber in + let resourceDataDisposable = resourceData.start(next: { data in + if data.complete { + subscriber.putNext(try? Data(contentsOf: URL(fileURLWithPath: maybeData.path))) subscriber.putCompletion() - }) - var fetchedDataDisposable: Disposable? - if let peerReference = PeerReference(peer) { - fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start() - } else if let authorOfMessage = authorOfMessage { - fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start() } else { - fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start() - } - return ActionDisposable { - resourceDataDisposable.dispose() - fetchedDataDisposable?.dispose() + subscriber.putNext(nil) } + }, error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + }) + var fetchedDataDisposable: Disposable? + if let peerReference = PeerReference(peer) { + fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start() + } else if let authorOfMessage = authorOfMessage { + fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start() + } else { + fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start() + } + return ActionDisposable { + resourceDataDisposable.dispose() + fetchedDataDisposable?.dispose() } } + } } return imageData } else { @@ -62,24 +62,31 @@ public func peerAvatarImageData(account: Account, peer: Peer, authorOfMessage: M } } -func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), emptyColor: UIColor? = nil) -> Signal? { - if let imageData = peerAvatarImageData(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) { - return imageData |> deliverOn(account.graphicsThreadPool) - |> map { data -> UIImage? in - return generateImage(displayDimensions, contextGenerator: { size, context -> Void in - if let data = data { - if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { - context.setBlendMode(.copy) - context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions)) - context.setBlendMode(.destinationOut) - context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions)) +func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), emptyColor: UIColor? = nil, synchronousLoad: Bool = false) -> Signal? { + if let imageData = peerAvatarImageData(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad) { + return imageData + |> mapToSignal { data -> Signal in + let generate = deferred { () -> Signal in + return .single(generateImage(displayDimensions, contextGenerator: { size, context -> Void in + if let data = data { + if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { + context.setBlendMode(.copy) + context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions)) + context.setBlendMode(.destinationOut) + context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions)) + } + } else if let emptyColor = emptyColor { + context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) + context.setFillColor(emptyColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions)) } - } else if let emptyColor = emptyColor { - context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) - context.setFillColor(emptyColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions)) - } - }) + })) + } + if synchronousLoad { + return generate + } else { + return generate |> runOn(account.graphicsThreadPool) + } } } else { return nil diff --git a/TelegramUI/PermissionInfoItem.swift b/TelegramUI/PermissionInfoItem.swift index c8cb36d150..5e022e2532 100644 --- a/TelegramUI/PermissionInfoItem.swift +++ b/TelegramUI/PermissionInfoItem.swift @@ -16,7 +16,7 @@ class PermissionInfoItem: ListViewItem { self.subject = subject } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = PermissionInfoItemNode() let (layout, apply) = node.asyncLayout()(self, params, nil) diff --git a/TelegramUI/PhotoResources.swift b/TelegramUI/PhotoResources.swift index b93e0b8dd8..e531f59dea 100644 --- a/TelegramUI/PhotoResources.swift +++ b/TelegramUI/PhotoResources.swift @@ -16,11 +16,13 @@ public func largestRepresentationForPhoto(_ photo: TelegramMediaImage) -> Telegr return photo.representationForDisplayAtSize(CGSize(width: 1280.0, height: 1280.0)) } -private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> { +private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false, synchronousLoad: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> { if let smallestRepresentation = smallestImageRepresentation(photoReference.media.representations), let largestRepresentation = photoReference.media.representationForDisplayAtSize(fullRepresentationSize) { - let maybeFullSize = postbox.mediaBox.resourceData(largestRepresentation.resource) + let maybeFullSize = postbox.mediaBox.resourceData(largestRepresentation.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad) - let signal = maybeFullSize |> take(1) |> mapToSignal { maybeData -> Signal<(Data?, Data?, Bool), NoError> in + let signal = maybeFullSize + |> take(1) + |> mapToSignal { maybeData -> Signal<(Data?, Data?, Bool), NoError> in if maybeData.complete { let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single((nil, loadedData, true)) @@ -42,7 +44,7 @@ private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaR let mainThumbnail = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() - let thumbnailDisposable = postbox.mediaBox.resourceData(smallestRepresentation.resource).start(next: { next in + let thumbnailDisposable = postbox.mediaBox.resourceData(smallestRepresentation.resource, attemptSynchronously: synchronousLoad).start(next: { next in subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])) }, error: subscriber.putError, completed: subscriber.putCompletion) @@ -67,7 +69,7 @@ private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaR if autoFetchFullSize { fullSizeData = Signal<(Data?, Bool), NoError> { subscriber in let fetchedFullSizeDisposable = fetchedFullSize.start() - let fullSizeDisposable = postbox.mediaBox.resourceData(largestRepresentation.resource).start(next: { next in + let fullSizeDisposable = postbox.mediaBox.resourceData(largestRepresentation.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad).start(next: { next in subscriber.putNext((next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete)) }, error: subscriber.putError, completed: subscriber.putCompletion) @@ -77,20 +79,23 @@ private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaR } } } else { - fullSizeData = postbox.mediaBox.resourceData(largestRepresentation.resource) - |> map { next -> (Data?, Bool) in - return (next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete) - } + fullSizeData = postbox.mediaBox.resourceData(largestRepresentation.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad) + |> map { next -> (Data?, Bool) in + return (next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete) + } } - return thumbnail |> mapToSignal { thumbnailData in - return fullSizeData |> map { (fullSizeData, complete) in + return thumbnail + |> mapToSignal { thumbnailData in + return fullSizeData + |> map { (fullSizeData, complete) in return (thumbnailData, fullSizeData, complete) } } } - } |> distinctUntilChanged(isEqual: { lhs, rhs in + } + |> distinctUntilChanged(isEqual: { lhs, rhs in if (lhs.0 == nil && lhs.1 == nil) && (rhs.0 == nil && rhs.1 == nil) { return true } else { @@ -591,14 +596,14 @@ func rawMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference) -> S } } -public func chatMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference)) +public func chatMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference, synchronousLoad: synchronousLoad), synchronousLoad: synchronousLoad) |> map { _, generate in return generate } } -public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoError>) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> { +public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoError>, synchronousLoad: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> { return photoData |> map { (thumbnailData, fullSizeData, fullSizeComplete) in return ({ diff --git a/TelegramUI/PresentationTheme.swift b/TelegramUI/PresentationTheme.swift index f20266e2c4..c1b72379cc 100644 --- a/TelegramUI/PresentationTheme.swift +++ b/TelegramUI/PresentationTheme.swift @@ -298,8 +298,9 @@ public final class PresentationThemeList { public let controlSecondaryColor: UIColor public let freeInputField: PresentationInputFieldTheme public let mediaPlaceholderColor: UIColor + public let scrollIndicatorColor: UIColor - public init(blocksBackgroundColor: UIColor, plainBackgroundColor: UIColor, itemPrimaryTextColor: UIColor, itemSecondaryTextColor: UIColor, itemDisabledTextColor: UIColor, itemAccentColor: UIColor, itemHighlightedColor: UIColor, itemDestructiveColor: UIColor, itemPlaceholderTextColor: UIColor, itemBlocksBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemBlocksSeparatorColor: UIColor, itemPlainSeparatorColor: UIColor, disclosureArrowColor: UIColor, sectionHeaderTextColor: UIColor, freeTextColor: UIColor, freeTextErrorColor: UIColor, freeTextSuccessColor: UIColor, freeMonoIcon: UIColor, itemSwitchColors: PresentationThemeSwitch, itemDisclosureActions: PresentationThemeItemDisclosureActions, itemCheckColors: PresentationThemeCheck, controlSecondaryColor: UIColor, freeInputField: PresentationInputFieldTheme, mediaPlaceholderColor: UIColor) { + public init(blocksBackgroundColor: UIColor, plainBackgroundColor: UIColor, itemPrimaryTextColor: UIColor, itemSecondaryTextColor: UIColor, itemDisabledTextColor: UIColor, itemAccentColor: UIColor, itemHighlightedColor: UIColor, itemDestructiveColor: UIColor, itemPlaceholderTextColor: UIColor, itemBlocksBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemBlocksSeparatorColor: UIColor, itemPlainSeparatorColor: UIColor, disclosureArrowColor: UIColor, sectionHeaderTextColor: UIColor, freeTextColor: UIColor, freeTextErrorColor: UIColor, freeTextSuccessColor: UIColor, freeMonoIcon: UIColor, itemSwitchColors: PresentationThemeSwitch, itemDisclosureActions: PresentationThemeItemDisclosureActions, itemCheckColors: PresentationThemeCheck, controlSecondaryColor: UIColor, freeInputField: PresentationInputFieldTheme, mediaPlaceholderColor: UIColor, scrollIndicatorColor: UIColor) { self.blocksBackgroundColor = blocksBackgroundColor self.plainBackgroundColor = plainBackgroundColor self.itemPrimaryTextColor = itemPrimaryTextColor @@ -325,6 +326,7 @@ public final class PresentationThemeList { self.controlSecondaryColor = controlSecondaryColor self.freeInputField = freeInputField self.mediaPlaceholderColor = mediaPlaceholderColor + self.scrollIndicatorColor = scrollIndicatorColor } } diff --git a/TelegramUI/ProxyServerActionSheetController.swift b/TelegramUI/ProxyServerActionSheetController.swift index 6aabbb2625..a93a84e386 100644 --- a/TelegramUI/ProxyServerActionSheetController.swift +++ b/TelegramUI/ProxyServerActionSheetController.swift @@ -230,7 +230,7 @@ private final class ProxyServerActionItemNode: ActionSheetItemNode { self.titleNode.displaysAsynchronously = false self.titleNode.attributedText = NSAttributedString(string: strings.SocksProxySetup_ConnectAndSave, font: Font.regular(20.0), textColor: theme.controlAccentColor) - self.activityIndicator = ActivityIndicator(type: .custom(theme.controlAccentColor, 24.0, 1.5, false)) + self.activityIndicator = ActivityIndicator(type: .custom(theme.controlAccentColor, 22.0, 1.5, false)) self.activityIndicator.isHidden = true self.buttonNode = HighlightableButtonNode() @@ -278,8 +278,9 @@ private final class ProxyServerActionItemNode: ActionSheetItemNode { let labelSize = self.titleNode.updateLayout(CGSize(width: max(1.0, size.width - 10.0), height: size.height)) let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize) + let activitySize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0)) self.titleNode.frame = titleFrame - self.activityIndicator.frame = CGRect(origin: CGPoint(x: 14.0, y: titleFrame.minY - 0.0), size: CGSize(width: 24.0, height: 24.0)) + self.activityIndicator.frame = CGRect(origin: CGPoint(x: 14.0, y: titleFrame.minY - 0.0), size: activitySize) } @objc private func buttonPressed() { diff --git a/TelegramUI/ProxySettingsActionItem.swift b/TelegramUI/ProxySettingsActionItem.swift index 2cd531f0ad..bc821b1738 100644 --- a/TelegramUI/ProxySettingsActionItem.swift +++ b/TelegramUI/ProxySettingsActionItem.swift @@ -25,7 +25,7 @@ class ProxySettingsActionItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ProxySettingsActionItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ProxySettingsServerItem.swift b/TelegramUI/ProxySettingsServerItem.swift index 68927f21d2..844e8a7961 100644 --- a/TelegramUI/ProxySettingsServerItem.swift +++ b/TelegramUI/ProxySettingsServerItem.swift @@ -46,7 +46,7 @@ final class ProxySettingsServerItem: ListViewItem, ItemListItem { self.removeServer = removeServer } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ProxySettingsServerItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/SearchPeerMembers.swift b/TelegramUI/SearchPeerMembers.swift index f0fe46f6fb..eecd21d4ab 100644 --- a/TelegramUI/SearchPeerMembers.swift +++ b/TelegramUI/SearchPeerMembers.swift @@ -15,6 +15,9 @@ func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signa if case .ready = state.loadingState { let normalizedQuery = query.lowercased() subscriber.putNext(state.list.compactMap { participant -> Peer? in + if participant.peer.displayTitle.isEmpty { + return nil + } if normalizedQuery.isEmpty { return participant.peer } @@ -37,13 +40,19 @@ func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signa return ActionDisposable { disposable.dispose() } - } |> runOn(Queue.mainQueue()) + } + |> runOn(Queue.mainQueue()) } return Signal { subscriber in let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.recent(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query.isEmpty ? nil : query, updated: { state in if case .ready = state.loadingState { - subscriber.putNext(state.list.map { $0.peer }) + subscriber.putNext(state.list.compactMap { participant in + if participant.peer.displayTitle.isEmpty { + return nil + } + return participant.peer + }) } }) diff --git a/TelegramUI/SecureIdAuthControllerNode.swift b/TelegramUI/SecureIdAuthControllerNode.swift index f4c8ad882a..7e305227aa 100644 --- a/TelegramUI/SecureIdAuthControllerNode.swift +++ b/TelegramUI/SecureIdAuthControllerNode.swift @@ -35,7 +35,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { self.requestLayout = requestLayout self.interaction = interaction - self.activityIndicator = ActivityIndicator(type: .custom(presentationData.theme.list.freeMonoIcon, 40.0, 2.0, false)) + self.activityIndicator = ActivityIndicator(type: .custom(presentationData.theme.list.freeMonoIcon, 22.0, 2.0, false)) self.activityIndicator.isHidden = true self.scrollNode = ASScrollNode() @@ -114,7 +114,8 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { var insets = layout.insets(options: insetOptions) insets.bottom = max(insets.bottom, layout.safeInsets.bottom) - transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - 40.0) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - 40.0) / 2.0)), size: CGSize(width: 40.0, height: 40.0))) + let activitySize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0)) + transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - activitySize.width) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - activitySize.height) / 2.0)), size: activitySize)) var headerNodeTransition: ContainedViewLayoutTransition = self.headerNode.bounds.height.isZero ? .immediate : transition if self.previousHeaderNodeAlpha.isZero && !self.headerNode.alpha.isZero { diff --git a/TelegramUI/SelectablePeerNode.swift b/TelegramUI/SelectablePeerNode.swift index 72a1f7207c..ae829d7260 100644 --- a/TelegramUI/SelectablePeerNode.swift +++ b/TelegramUI/SelectablePeerNode.swift @@ -109,7 +109,7 @@ final class SelectablePeerNode: ASDisplayNode { } - func setup(account: Account, strings: PresentationStrings, peer: RenderedPeer, numberOfLines: Int = 2) { + func setup(account: Account, strings: PresentationStrings, peer: RenderedPeer, numberOfLines: Int = 2, synchronousLoad: Bool) { self.peer = peer guard let mainPeer = peer.chatMainPeer else { return @@ -127,7 +127,7 @@ final class SelectablePeerNode: ASDisplayNode { } self.textNode.maximumNumberOfLines = UInt(numberOfLines) self.textNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: self.currentSelected ? self.theme.selectedTextColor : defaultColor, paragraphAlignment: .center) - self.avatarNode.setPeer(account: account, peer: mainPeer, overrideImage: overrideImage, emptyColor: self.theme.avatarPlaceholderColor) + self.avatarNode.setPeer(account: account, peer: mainPeer, overrideImage: overrideImage, emptyColor: self.theme.avatarPlaceholderColor, synchronousLoad: synchronousLoad) self.setNeedsLayout() } diff --git a/TelegramUI/SettingsController.swift b/TelegramUI/SettingsController.swift index 25e4419462..b6520a8ec9 100644 --- a/TelegramUI/SettingsController.swift +++ b/TelegramUI/SettingsController.swift @@ -444,6 +444,8 @@ public func settingsController(account: Account, accountManager: AccountManager) let updatePassportDisposable = MetaDisposable() actionsDisposable.add(updatePassportDisposable) + let openEditingDisposable = MetaDisposable() + actionsDisposable.add(openEditingDisposable) let currentAvatarMixin = Atomic(value: nil) @@ -561,13 +563,48 @@ public func settingsController(account: Account, accountManager: AccountManager) openFaq(resolvedUrlPromise) }, openEditing: { - let _ = (account.postbox.transaction { transaction -> (Peer?, CachedPeerData?) in - return (transaction.getPeer(account.peerId), transaction.getPeerCachedData(peerId: account.peerId)) - } |> deliverOnMainQueue).start(next: { peer, cachedData in - if let peer = peer as? TelegramUser, let cachedData = cachedData as? CachedUserData { - pushControllerImpl?(editSettingsController(account: account, currentName: .personName(firstName: peer.firstName ?? "", lastName: peer.lastName ?? ""), currentBioText: cachedData.about ?? "", accountManager: accountManager)) + var cancelImpl: (() -> Void)? + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + let progressSignal = Signal { subscriber in + let controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: { + cancelImpl?() + })) + presentControllerImpl?(controller, nil) + return ActionDisposable { [weak controller] in + Queue.mainQueue().async() { + controller?.dismiss() + } } - }) + } + |> runOn(Queue.mainQueue()) + |> delay(0.15, queue: Queue.mainQueue()) + let progressDisposable = progressSignal.start() + + let peerKey: PostboxViewKey = .peer(peerId: account.peerId, components: []) + let cachedDataKey: PostboxViewKey = .cachedPeerData(peerId: account.peerId) + let signal = (account.postbox.combinedView(keys: [peerKey, cachedDataKey]) + |> mapToSignal { view -> Signal<(TelegramUser, CachedUserData), NoError> in + guard let cachedDataView = view.views[cachedDataKey] as? CachedPeerDataView, let cachedData = cachedDataView.cachedPeerData as? CachedUserData else { + return .complete() + } + guard let peerView = view.views[peerKey] as? PeerView, let peer = peerView.peers[account.peerId] as? TelegramUser else { + return .complete() + } + return .single((peer, cachedData)) + } + |> take(1)) + |> afterDisposed { + Queue.mainQueue().async { + progressDisposable.dispose() + } + } + cancelImpl = { + openEditingDisposable.set(nil) + } + openEditingDisposable.set((signal + |> deliverOnMainQueue).start(next: { peer, cachedData in + pushControllerImpl?(editSettingsController(account: account, currentName: .personName(firstName: peer.firstName ?? "", lastName: peer.lastName ?? ""), currentBioText: cachedData.about ?? "", accountManager: accountManager)) + })) }, updateArchivedPacks: { packs in archivedPacks.set(.single(packs)) }, displayCopyContextMenu: { diff --git a/TelegramUI/ShareController.swift b/TelegramUI/ShareController.swift index 43dbcb552f..d986cbecf6 100644 --- a/TelegramUI/ShareController.swift +++ b/TelegramUI/ShareController.swift @@ -187,7 +187,7 @@ public final class ShareController: ViewController { private var defaultAction: ShareControllerAction? - public var dismissed: (() -> Void)? + public var dismissed: ((Bool) -> Void)? public init(account: Account, subject: ShareControllerSubject, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false) { self.account = account @@ -308,12 +308,13 @@ public final class ShareController: ViewController { self.displayNode = ShareControllerNode(account: self.account, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in self?.requestLayout(transition: transition) }, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare) - self.controllerNode.dismiss = { [weak self] in + self.controllerNode.dismiss = { [weak self] shared in self?.presentingViewController?.dismiss(animated: false, completion: nil) - self?.dismissed?() + self?.dismissed?(shared) } self.controllerNode.cancel = { [weak self] in - self?.dismiss() + self?.controllerNode.view.endEditing(true) + self?.controllerNode.animateOut(shared: false, completion: nil) } self.controllerNode.share = { [weak self] text, peerIds in if let strongSelf = self { @@ -519,7 +520,7 @@ public final class ShareController: ViewController { override public func dismiss(completion: (() -> Void)? = nil) { self.controllerNode.view.endEditing(true) - self.controllerNode.animateOut(completion: completion) + self.controllerNode.animateOut(shared: false, completion: completion) } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { diff --git a/TelegramUI/ShareControllerNode.swift b/TelegramUI/ShareControllerNode.swift index 73a871b6b9..321f47cb8a 100644 --- a/TelegramUI/ShareControllerNode.swift +++ b/TelegramUI/ShareControllerNode.swift @@ -48,7 +48,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate private let inputFieldNode: ShareInputFieldNode private let actionSeparatorNode: ASDisplayNode - var dismiss: (() -> Void)? + var dismiss: ((Bool) -> Void)? var cancel: (() -> Void)? var share: ((String, [PeerId]) -> Signal)? var shareExternal: (() -> Signal)? @@ -469,7 +469,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate let delay = max(minDelay, (timestamp + minDelay) - CACurrentMediaTime()) Queue.mainQueue().after(delay, { if let strongSelf = self { - strongSelf.cancel?() + strongSelf.animateOut(shared: true) } }) } @@ -516,14 +516,14 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate } } - func animateOut(completion: (() -> Void)? = nil) { + func animateOut(shared: Bool, completion: (() -> Void)? = nil) { if self.contentNode != nil { var dimCompleted = false var offsetCompleted = false let internalCompletion: () -> Void = { [weak self] in if let strongSelf = self, dimCompleted && offsetCompleted { - strongSelf.dismiss?() + strongSelf.dismiss?(shared) } completion?() } @@ -541,7 +541,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate internalCompletion() }) } else { - self.dismiss?() + self.dismiss?(false) completion?() } } @@ -596,14 +596,14 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate let delay = max(0.0, (loadingTimestamp + minDelay) - CACurrentMediaTime()) Queue.mainQueue().after(delay, { if let strongSelf = self { - strongSelf.cancel?() + strongSelf.animateOut(shared: true) } }) } else { if reportReady { strongSelf.ready.set(.single(true)) } - strongSelf.cancel?() + strongSelf.animateOut(shared: true) } } })) @@ -697,7 +697,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate let delay = max(0.0, (timestamp + minDelay) - CACurrentMediaTime()) Queue.mainQueue().after(delay, { if let strongSelf = self { - strongSelf.cancel?() + strongSelf.animateOut(shared: true) } }) })) diff --git a/TelegramUI/ShareControllerPeerGridItem.swift b/TelegramUI/ShareControllerPeerGridItem.swift index 0a1cf5cc55..478d7e6e69 100644 --- a/TelegramUI/ShareControllerPeerGridItem.swift +++ b/TelegramUI/ShareControllerPeerGridItem.swift @@ -104,10 +104,10 @@ final class ShareControllerPeerGridItem: GridItem { } } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = ShareControllerPeerGridItemNode() node.controllerInteraction = self.controllerInteraction - node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, search: self.search) + node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, search: self.search, synchronousLoad: synchronousLoad) return node } @@ -117,7 +117,7 @@ final class ShareControllerPeerGridItem: GridItem { return } node.controllerInteraction = self.controllerInteraction - node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, search: self.search) + node.setup(account: self.account, theme: self.theme, strings: self.strings, peer: self.peer, search: self.search, synchronousLoad: false) } } @@ -144,11 +144,11 @@ final class ShareControllerPeerGridItemNode: GridItemNode { self.addSubnode(self.peerNode) } - func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, search: Bool) { + func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, search: Bool, synchronousLoad: Bool) { if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != peer { let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor) self.peerNode.theme = itemTheme - self.peerNode.setup(account: account, strings: strings, peer: peer) + self.peerNode.setup(account: account, strings: strings, peer: peer, synchronousLoad: synchronousLoad) self.currentState = (account, peer, search) self.setNeedsLayout() } diff --git a/TelegramUI/ShareControllerRecentPeersGridItem.swift b/TelegramUI/ShareControllerRecentPeersGridItem.swift index 85189765be..91865972f7 100644 --- a/TelegramUI/ShareControllerRecentPeersGridItem.swift +++ b/TelegramUI/ShareControllerRecentPeersGridItem.swift @@ -21,7 +21,7 @@ final class ShareControllerRecentPeersGridItem: GridItem { self.controllerInteraction = controllerInteraction } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = ShareControllerRecentPeersGridItemNode() node.controllerInteraction = self.controllerInteraction node.setup(account: self.account, theme: self.theme, strings: self.strings) diff --git a/TelegramUI/ShareLoadingContainerNode.swift b/TelegramUI/ShareLoadingContainerNode.swift index 7f3930f2d1..8c179c4ff0 100644 --- a/TelegramUI/ShareLoadingContainerNode.swift +++ b/TelegramUI/ShareLoadingContainerNode.swift @@ -38,7 +38,7 @@ final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContainerNode init(theme: PresentationTheme, forceNativeAppearance: Bool) { self.theme = theme - self.activityIndicator = ActivityIndicator(type: .custom(theme.actionSheet.controlAccentColor, 50.0, 2.0, forceNativeAppearance)) + self.activityIndicator = ActivityIndicator(type: .custom(theme.actionSheet.controlAccentColor, !forceNativeAppearance ? 22.0 : 50.0, 2.0, forceNativeAppearance)) self.statusNode = RadialStatusNode(backgroundNodeColor: .clear) self.doneStatusNode = RadialStatusNode(backgroundNodeColor: .clear) diff --git a/TelegramUI/ShareSearchContainerNode.swift b/TelegramUI/ShareSearchContainerNode.swift index 2cf5079bb3..a7d0624017 100644 --- a/TelegramUI/ShareSearchContainerNode.swift +++ b/TelegramUI/ShareSearchContainerNode.swift @@ -558,7 +558,7 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { if transition.animated { itemTransition = .animated(duration: 0.3, curve: .spring) } - self.contentGridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: nil, updateLayout: nil, itemTransition: itemTransition, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in }) + self.contentGridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: nil, updateLayout: nil, itemTransition: itemTransition, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, synchronousLoads: true), completion: { _ in }) } } diff --git a/TelegramUI/StickerPackPreviewGridItem.swift b/TelegramUI/StickerPackPreviewGridItem.swift index 176b1541fe..275ae6d4fc 100644 --- a/TelegramUI/StickerPackPreviewGridItem.swift +++ b/TelegramUI/StickerPackPreviewGridItem.swift @@ -28,7 +28,7 @@ final class StickerPackPreviewGridItem: GridItem { self.interaction = interaction } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = StickerPackPreviewGridItemNode() node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction) return node diff --git a/TelegramUI/StickerPanePeerSpecificSetupGridItem.swift b/TelegramUI/StickerPanePeerSpecificSetupGridItem.swift index e946bf4668..67b586e24f 100644 --- a/TelegramUI/StickerPanePeerSpecificSetupGridItem.swift +++ b/TelegramUI/StickerPanePeerSpecificSetupGridItem.swift @@ -29,7 +29,7 @@ final class StickerPanePeerSpecificSetupGridItem: GridItem { } } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = StickerPanePeerSpecificSetupGridItemNode() node.setup(item: self) return node diff --git a/TelegramUI/StickerPaneSearchBarPlaceholderItem.swift b/TelegramUI/StickerPaneSearchBarPlaceholderItem.swift index 5e0bd0fa9e..af3d7985e8 100644 --- a/TelegramUI/StickerPaneSearchBarPlaceholderItem.swift +++ b/TelegramUI/StickerPaneSearchBarPlaceholderItem.swift @@ -23,7 +23,7 @@ final class StickerPaneSearchBarPlaceholderItem: GridItem { self.activate = activate } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = StickerPaneSearchBarPlaceholderNode() node.activate = self.activate node.setup(theme: self.theme, strings: self.strings) diff --git a/TelegramUI/StickerPaneSearchGlobaltem.swift b/TelegramUI/StickerPaneSearchGlobaltem.swift index 0ad07fbea7..dc8639fce4 100644 --- a/TelegramUI/StickerPaneSearchGlobaltem.swift +++ b/TelegramUI/StickerPaneSearchGlobaltem.swift @@ -33,7 +33,7 @@ final class StickerPaneSearchGlobalItem: GridItem { self.getItemIsPreviewed = getItemIsPreviewed } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = StickerPaneSearchGlobalItemNode() node.setup(item: self) return node diff --git a/TelegramUI/StickerPaneSearchStickerItem.swift b/TelegramUI/StickerPaneSearchStickerItem.swift index 62f1dc0919..a62a48e602 100644 --- a/TelegramUI/StickerPaneSearchStickerItem.swift +++ b/TelegramUI/StickerPaneSearchStickerItem.swift @@ -82,7 +82,7 @@ final class StickerPaneSearchStickerItem: GridItem { } } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = StickerPaneSearchStickerItemNode() node.inputNodeInteraction = self.inputNodeInteraction node.setup(account: self.account, stickerItem: self.stickerItem) diff --git a/TelegramUI/ThemeGridControllerItem.swift b/TelegramUI/ThemeGridControllerItem.swift index 18927d3012..f909ed94ad 100644 --- a/TelegramUI/ThemeGridControllerItem.swift +++ b/TelegramUI/ThemeGridControllerItem.swift @@ -18,7 +18,7 @@ final class ThemeGridControllerItem: GridItem { self.interaction = interaction } - func node(layout: GridNodeLayout) -> GridItemNode { + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { let node = ThemeGridControllerItemNode() node.setup(account: self.account, wallpaper: self.wallpaper, interaction: self.interaction) return node diff --git a/TelegramUI/ThemeSettingsBrightnessItem.swift b/TelegramUI/ThemeSettingsBrightnessItem.swift index 84421adbea..9d5ce82c7f 100644 --- a/TelegramUI/ThemeSettingsBrightnessItem.swift +++ b/TelegramUI/ThemeSettingsBrightnessItem.swift @@ -19,7 +19,7 @@ class ThemeSettingsBrightnessItem: ListViewItem, ItemListItem { self.updated = updated } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ThemeSettingsBrightnessItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/ThemeSettingsChatPreviewItem.swift b/TelegramUI/ThemeSettingsChatPreviewItem.swift index 1b53aa0adf..a563e6c47d 100644 --- a/TelegramUI/ThemeSettingsChatPreviewItem.swift +++ b/TelegramUI/ThemeSettingsChatPreviewItem.swift @@ -26,7 +26,7 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem { self.dateTimeFormat = dateTimeFormat } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ThemeSettingsChatPreviewItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) @@ -169,7 +169,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { apply() }) } else { - item1.nodeConfiguredForParams(async: { $0() }, params: params, previousItem: nil, nextItem: nil, completion: { node, apply in + item1.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in node1 = node apply().1() }) @@ -188,7 +188,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { apply() }) } else { - item2.nodeConfiguredForParams(async: { $0() }, params: params, previousItem: nil, nextItem: nil, completion: { node, apply in + item2.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in node2 = node apply().1() }) diff --git a/TelegramUI/ThemeSettingsFontSizeItem.swift b/TelegramUI/ThemeSettingsFontSizeItem.swift index 7c0d1e74a4..af902e49fb 100644 --- a/TelegramUI/ThemeSettingsFontSizeItem.swift +++ b/TelegramUI/ThemeSettingsFontSizeItem.swift @@ -19,7 +19,7 @@ class ThemeSettingsFontSizeItem: ListViewItem, ItemListItem { self.updated = updated } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = ThemeSettingsFontSizeItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/TransformImageNode.swift b/TelegramUI/TransformImageNode.swift index 5e362c5aa9..122ae2b5f4 100644 --- a/TelegramUI/TransformImageNode.swift +++ b/TelegramUI/TransformImageNode.swift @@ -47,11 +47,21 @@ public class TransformImageNode: ASDisplayNode { } } - public func setSignal(_ signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>, dispatchOnDisplayLink: Bool = true) { + public func setSignal(_ signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>, attemptSynchronously: Bool = false, dispatchOnDisplayLink: Bool = true) { let argumentsPromise = self.argumentsPromise + var shouldAttemptSynchronously = attemptSynchronously let result = combineLatest(signal, argumentsPromise.get()) - |> deliverOn(Queue.concurrentDefaultQueue()) + |> mapToSignal { transform, arguments -> Signal<((TransformImageArguments) -> DrawingContext?, TransformImageArguments), NoError> in + let result: Signal<((TransformImageArguments) -> DrawingContext?, TransformImageArguments), NoError> = .single((transform, arguments)) + if shouldAttemptSynchronously { + shouldAttemptSynchronously = false + return result + } else { + return result + |> deliverOn(Queue.concurrentDefaultQueue()) + } + } |> mapToThrottled { transform, arguments -> Signal<((TransformImageArguments) -> DrawingContext?, TransformImageArguments, UIImage?)?, NoError> in return deferred { if let context = transform(arguments) { diff --git a/TelegramUI/UserInfoEditingPhoneActionItem.swift b/TelegramUI/UserInfoEditingPhoneActionItem.swift index 18264281f5..cd89e7c3f7 100644 --- a/TelegramUI/UserInfoEditingPhoneActionItem.swift +++ b/TelegramUI/UserInfoEditingPhoneActionItem.swift @@ -16,7 +16,7 @@ class UserInfoEditingPhoneActionItem: ListViewItem, ItemListItem { self.action = action } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = UserInfoEditingPhoneActionItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/UserInfoEditingPhoneItem.swift b/TelegramUI/UserInfoEditingPhoneItem.swift index 8cbbef4493..679682a63e 100644 --- a/TelegramUI/UserInfoEditingPhoneItem.swift +++ b/TelegramUI/UserInfoEditingPhoneItem.swift @@ -37,7 +37,7 @@ class UserInfoEditingPhoneItem: ListViewItem, ItemListItem { self.tag = tag } - func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { async { let node = UserInfoEditingPhoneItemNode() let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) diff --git a/TelegramUI/VerticalListContextResultsChatInputPanelButtonItem.swift b/TelegramUI/VerticalListContextResultsChatInputPanelButtonItem.swift index 01e1163015..a06f354cc3 100644 --- a/TelegramUI/VerticalListContextResultsChatInputPanelButtonItem.swift +++ b/TelegramUI/VerticalListContextResultsChatInputPanelButtonItem.swift @@ -16,7 +16,7 @@ final class VerticalListContextResultsChatInputPanelButtonItem: ListViewItem { self.pressed = pressed } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = VerticalListContextResultsChatInputPanelButtonItemNode() diff --git a/TelegramUI/VerticalListContextResultsChatInputPanelItem.swift b/TelegramUI/VerticalListContextResultsChatInputPanelItem.swift index 12951dc24c..c27f10e946 100644 --- a/TelegramUI/VerticalListContextResultsChatInputPanelItem.swift +++ b/TelegramUI/VerticalListContextResultsChatInputPanelItem.swift @@ -20,7 +20,7 @@ final class VerticalListContextResultsChatInputPanelItem: ListViewItem { self.resultSelected = resultSelected } - public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { + public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, () -> Void)) -> Void) { let configure = { () -> Void in let node = VerticalListContextResultsChatInputPanelItemNode()