From 418968604c27a868584201f2647bb9fe16fcbeb8 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 22 May 2024 18:23:32 +0400 Subject: [PATCH] Various fixes --- .../Sources/ChatController.swift | 1 + .../Sources/HashtagSearchControllerNode.swift | 23 +++++++++++---- .../HashtagSearchNavigationContentNode.swift | 17 +++++++---- .../Sources/HashtagSearchRecentListNode.swift | 18 ++++++++---- .../Messages/SearchMessages.swift | 4 ++- .../Sources/StarsTransactionScreen.swift | 6 +++- .../ChatControllerNavigateToMessage.swift | 12 ++++++-- .../TelegramUI/Sources/ChatController.swift | 28 ++++++++++++------- .../Sources/ChatControllerNode.swift | 20 ++++++++----- 9 files changed, 92 insertions(+), 37 deletions(-) diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index bf4e60edfc..223e29bb5d 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -990,6 +990,7 @@ public protocol ChatController: ViewController { var alwaysShowSearchResultsAsList: Bool { get set } var includeSavedPeersInSearchResults: Bool { get set } + var showListEmptyResults: Bool { get set } func updatePresentationMode(_ mode: ChatControllerPresentationMode) func beginMessageSearch(_ query: String) diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift index e1fc79ae27..d18914e627 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchControllerNode.swift @@ -45,7 +45,7 @@ final class HashtagSearchControllerNode: ASDisplayNode { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let cleanHashtag = query.replacingOccurrences(of: "#", with: "") - self.searchContentNode = HashtagSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings, initialQuery: cleanHashtag, cancel: { [weak controller] in + self.searchContentNode = HashtagSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings, initialQuery: cleanHashtag, hasCurrentChat: peer != nil, cancel: { [weak controller] in controller?.dismiss() }) @@ -59,6 +59,7 @@ final class HashtagSearchControllerNode: ASDisplayNode { if let peer { self.currentController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .inline(navigationController)) self.currentController?.alwaysShowSearchResultsAsList = true + self.currentController?.showListEmptyResults = true self.currentController?.customNavigationController = navigationController } else { self.currentController = nil @@ -70,12 +71,17 @@ final class HashtagSearchControllerNode: ASDisplayNode { self.myChatContents = myChatContents self.myController = context.sharedContext.makeChatController(context: context, chatLocation: .customChatContents, subject: .customChatContents(contents: myChatContents), botStart: nil, mode: .standard(.default)) self.myController?.alwaysShowSearchResultsAsList = true + self.myController?.showListEmptyResults = true self.myController?.customNavigationController = navigationController + if peer == nil { + self.searchContentNode.selectedIndex = 1 + } let globalChatContents = HashtagSearchGlobalChatContents(context: context, kind: .hashTagSearch, query: cleanHashtag, onlyMy: false) self.globalChatContents = globalChatContents self.globalController = context.sharedContext.makeChatController(context: context, chatLocation: .customChatContents, subject: .customChatContents(contents: globalChatContents), botStart: nil, mode: .standard(.default)) self.globalController?.alwaysShowSearchResultsAsList = true + self.globalController?.showListEmptyResults = true self.globalController?.customNavigationController = navigationController super.init() @@ -88,10 +94,17 @@ final class HashtagSearchControllerNode: ASDisplayNode { if controller.all { self.currentController?.displayNode.isHidden = true - } else { - self.currentController?.displayNode.isHidden = false - self.myController?.displayNode.isHidden = true + self.myController?.displayNode.isHidden = false self.globalController?.displayNode.isHidden = true + } else { + if let _ = peer { + self.currentController?.displayNode.isHidden = false + self.myController?.displayNode.isHidden = true + self.globalController?.displayNode.isHidden = true + } else { + self.myController?.displayNode.isHidden = false + self.globalController?.displayNode.isHidden = true + } } self.searchContentNode.indexUpdated = { [weak self] index in @@ -140,7 +153,7 @@ final class HashtagSearchControllerNode: ASDisplayNode { self?.searchQueryPromise.set(query) } - let _ = addRecentHashtagSearchQuery(engine: context.engine, string: query).startStandalone() + let _ = addRecentHashtagSearchQuery(engine: context.engine, string: query.replacingOccurrences(of: "#", with: "")).startStandalone() self.searchContentNode.onReturn = { query in let _ = addRecentHashtagSearchQuery(engine: context.engine, string: query).startStandalone() } diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchNavigationContentNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchNavigationContentNode.swift index 151e77629d..83c195efe6 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchNavigationContentNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchNavigationContentNode.swift @@ -15,6 +15,7 @@ private let searchBarFont = Font.regular(17.0) final class HashtagSearchNavigationContentNode: NavigationBarContentNode { private var theme: PresentationTheme private let strings: PresentationStrings + private let hasCurrentChat: Bool private let cancel: () -> Void @@ -49,9 +50,10 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode { } } - init(theme: PresentationTheme, strings: PresentationStrings, initialQuery: String, cancel: @escaping () -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, initialQuery: String, hasCurrentChat: Bool, cancel: @escaping () -> Void) { self.theme = theme self.strings = strings + self.hasCurrentChat = hasCurrentChat self.cancel = cancel @@ -101,6 +103,13 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode { self.searchBar.frame = searchBarFrame self.searchBar.updateLayout(boundingSize: searchBarFrame.size, leftInset: leftInset + sideInset, rightInset: rightInset + sideInset, transition: transition) + var items: [TabSelectorComponent.Item] = [] + if self.hasCurrentChat { + items.append(TabSelectorComponent.Item(id: AnyHashable(0), title: self.strings.HashtagSearch_ThisChat)) + } + items.append(TabSelectorComponent.Item(id: AnyHashable(1), title: self.strings.HashtagSearch_MyMessages)) + items.append(TabSelectorComponent.Item(id: AnyHashable(2), title: self.strings.HashtagSearch_PublicPosts)) + let tabSelectorSize = self.tabSelector.update( transition: Transition(transition), component: AnyComponent(TabSelectorComponent( @@ -113,11 +122,7 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode { spacing: 24.0, lineSelection: true ), - items: [ - TabSelectorComponent.Item(id: AnyHashable(0), title: self.strings.HashtagSearch_ThisChat), - TabSelectorComponent.Item(id: AnyHashable(1), title: self.strings.HashtagSearch_MyMessages), - TabSelectorComponent.Item(id: AnyHashable(2), title: self.strings.HashtagSearch_PublicPosts) - ], + items: items, selectedId: AnyHashable(self.selectedIndex), setSelectedId: { [weak self] id in guard let self, let index = id.base as? Int else { diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchRecentListNode.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchRecentListNode.swift index 4ce0ebb0cd..b623808257 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchRecentListNode.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchRecentListNode.swift @@ -287,13 +287,13 @@ final class HashtagSearchRecentQueryItemNode: ItemListRevealOptionsItemNode { strongSelf.addSubnode(textNode) } - let textFrame = CGRect(origin: CGPoint(x: leftInset, y: floorToScreenPixels((nodeLayout.contentSize.height - textLayout.size.height) / 2.0)), size: textLayout.size) + let textFrame = CGRect(origin: CGPoint(x: leftInset + strongSelf.revealOffset, y: floorToScreenPixels((nodeLayout.contentSize.height - textLayout.size.height) / 2.0)), size: textLayout.size) textNode.frame = textFrame if let icon = strongSelf.iconNode.image { - strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: textFrame.minX - icon.size.width - 16.0, y: floorToScreenPixels((nodeLayout.contentSize.height - icon.size.height) / 2.0)), size: icon.size) + strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: textFrame.minX - icon.size.width - 16.0 + strongSelf.revealOffset, y: floorToScreenPixels((nodeLayout.contentSize.height - icon.size.height) / 2.0)), size: icon.size) } - + let separatorHeight = UIScreenPixel let topHighlightInset: CGFloat = separatorHeight @@ -304,7 +304,11 @@ final class HashtagSearchRecentQueryItemNode: ItemListRevealOptionsItemNode { strongSelf.updateLayout(size: nodeLayout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) - strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: RevealOptionKey.delete.rawValue, title: item.strings.Common_Delete, icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)])) + if item.clear { + strongSelf.setRevealOptions((left: [], right: [])) + } else { + strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: RevealOptionKey.delete.rawValue, title: item.strings.Common_Delete, icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)])) + } } }) }) @@ -331,11 +335,15 @@ final class HashtagSearchRecentQueryItemNode: ItemListRevealOptionsItemNode { super.updateRevealOffset(offset: offset, transition: transition) if let params = self.layoutParams, let textNode = self.textNode { - let leftInset: CGFloat = 15.0 + params.leftInset + let leftInset: CGFloat = 62.0 + params.leftInset var textFrame = textNode.frame textFrame.origin.x = leftInset + offset transition.updateFrame(node: textNode, frame: textFrame) + + var iconFrame = self.iconNode.frame + iconFrame.origin.x = textFrame.minX - iconFrame.width - 16.0 + transition.updateFrame(node: self.iconNode, frame: iconFrame) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift index e8e4760a1d..84aedac1f2 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift @@ -516,10 +516,12 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation func _internal_searchHashtagPosts(account: Account, hashtag: String, state: SearchMessagesState?, limit: Int32 = 100) -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> { let remoteSearchResult = account.postbox.transaction { transaction -> (Int32, MessageIndex?, Api.InputPeer) in var lowerBound: MessageIndex? + var peer: Peer? if let state = state, let message = state.main.messages.last { lowerBound = message.index + peer = message.peers[message.id.peerId] } - if let lowerBound = lowerBound, let peer = transaction.getPeer(lowerBound.id.peerId), let inputPeer = apiInputPeer(peer) { + if let lowerBound = lowerBound, let peer, let inputPeer = apiInputPeer(peer) { return (state?.main.nextRate ?? 0, lowerBound, inputPeer) } else { return (0, lowerBound, .inputPeerEmpty) diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift index 19f371a0bb..584423ebb0 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift @@ -259,7 +259,11 @@ private final class StarsTransactionSheetContent: CombinedComponent { id: "transaction", title: "Transaction ID", component: AnyComponent( - MultilineTextComponent(text: .plain(NSAttributedString(string: transactionId, font: tableFont, textColor: tableTextColor)), truncationType: .middle) + MultilineTextComponent( + text: .plain(NSAttributedString(string: transactionId, font: Font.monospace(15.0), textColor: tableTextColor)), + truncationType: .end, + maximumNumberOfLines: 0 + ) ) )) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift index d53572aab0..41fe42586f 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift @@ -85,8 +85,10 @@ extension ChatControllerImpl { } var fromIndex: MessageIndex? + var fromMessage: Message? if let fromId = fromId, let message = self.chatDisplayNode.historyNode.messageInCurrentHistoryView(fromId) { fromIndex = message.index + fromMessage = message } else { if let message = self.chatDisplayNode.historyNode.anchorMessageInCurrentHistoryView() { fromIndex = message.index @@ -110,9 +112,15 @@ extension ChatControllerImpl { } if isPinnedMessages || forceNew, let messageId = messageLocation.messageId { + let peerSignal: Signal + if forceNew, let fromMessage, let peer = fromMessage.peers[fromMessage.id.peerId] { + peerSignal = .single(EnginePeer(peer)) + } else { + peerSignal = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: messageId.peerId)) + } let _ = (combineLatest( - self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: messageId.peerId)), - self.context.engine.messages.getMessagesLoadIfNecessary([messageId], strategy: .local) + peerSignal, + self.context.engine.messages.getMessagesLoadIfNecessary([messageId], strategy: forceNew ? .cloud(skipLocal: false) : .local) |> `catch` { _ in return .single(.result([])) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 6dcb92f230..75f5ae1f65 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -614,6 +614,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } + public var showListEmptyResults: Bool = false { + didSet { + self.chatDisplayNode.showListEmptyResults = self.showListEmptyResults + } + } + public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, mode: ChatControllerPresentationMode = .standard(.default), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], customChatNavigationStack: [EnginePeer.Id]? = nil) { let _ = ChatControllerCount.modify { value in return value + 1 @@ -9525,9 +9531,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func openHashtag(_ hashtag: String, peerName: String?) { - guard let peerId = self.chatLocation.peerId else { - return - } let _ = self.presentVoiceMessageDiscardAlert(action: { if self.resolvePeerByNameDisposable == nil { self.resolvePeerByNameDisposable = MetaDisposable() @@ -9548,9 +9551,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return .single(nil) } } - } else { + } else if let peerId = self.chatLocation.peerId { resolveSignal = self.context.account.postbox.loadedPeerWithId(peerId) |> map(Optional.init) + } else { + resolveSignal = .single(nil) } var cancelImpl: (() -> Void)? let presentationData = self.presentationData @@ -9695,11 +9700,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func openResolved(result: ResolvedUrl, sourceMessageId: MessageId?, progress: Promise? = nil, forceExternal: Bool = false, concealed: Bool = false, commit: @escaping () -> Void = {}) { - guard let peerId = self.chatLocation.peerId else { - return - } + let urlContext: OpenURLContext + let message = sourceMessageId.flatMap { self.chatDisplayNode.historyNode.messageInCurrentHistoryView($0) } - self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: .chat(peerId: peerId, message: message, updatedPresentationData: self.updatedPresentationData), navigationController: self.effectiveNavigationController, forceExternal: forceExternal, openPeer: { [weak self] peerId, navigation in + if let peerId = self.chatLocation.peerId { + urlContext = .chat(peerId: peerId, message: message, updatedPresentationData: self.updatedPresentationData) + } else { + urlContext = .generic + } + self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: urlContext, navigationController: self.effectiveNavigationController, forceExternal: forceExternal, openPeer: { [weak self] peerId, navigation in guard let strongSelf = self else { return } @@ -9765,8 +9774,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G default: break } - }, sendFile: nil, - sendSticker: { [weak self] f, sourceView, sourceRect in + }, sendFile: nil, sendSticker: { [weak self] f, sourceView, sourceRect in return self?.interfaceInteraction?.sendSticker(f, true, sourceView, sourceRect, nil, []) ?? false }, sendEmoji: { [weak self] text, attribute in guard let self, canSendMessagesToChat(self.presentationInterfaceState) else { diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 18f4345f09..079456553b 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -138,6 +138,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { var alwaysShowSearchResultsAsList: Bool = false var includeSavedPeersInSearchResults: Bool = false + var showListEmptyResults: Bool = false private var skippedShowSearchResultsAsListAnimationOnce: Bool = false var inlineSearchResults: ComponentView? @@ -2539,11 +2540,6 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { let context = self.context let chatLocation = self.chatLocation - var showEmptyResults = false - if case let .customChatContents(contents) = self.chatPresentationInterfaceState.subject, case .hashTagSearch = contents.kind { - showEmptyResults = true - } - let _ = inlineSearchResults.update( transition: inlineSearchResultsTransition, component: AnyComponent(ChatInlineSearchResultsListComponent( @@ -2560,13 +2556,23 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { contents: mappedContents, insets: childContentInsets, inputHeight: layout.inputHeight ?? 0.0, - showEmptyResults: showEmptyResults, + showEmptyResults: self.showListEmptyResults, messageSelected: { [weak self] message in guard let self else { return } - if let historyFilter = self.chatPresentationInterfaceState.historyFilter, let reaction = ReactionsMessageAttribute.reactionFromMessageTag(tag: historyFilter.customTag), let peerId = self.chatLocation.peerId, historyFilter.isActive { + if case let .customChatContents(contents) = self.chatPresentationInterfaceState.subject, case .hashTagSearch = contents.kind { + self.controller?.navigateToMessage( + from: message.id, + to: .index(message.index), + scrollPosition: .center(.bottom), + rememberInStack: false, + forceInCurrentChat: false, + forceNew: true, + animated: true + ) + } else if let historyFilter = self.chatPresentationInterfaceState.historyFilter, let reaction = ReactionsMessageAttribute.reactionFromMessageTag(tag: historyFilter.customTag), let peerId = self.chatLocation.peerId, historyFilter.isActive { let _ = (self.context.engine.messages.searchMessages( location: .peer(peerId: peerId, fromId: nil, tags: nil, reactions: [reaction], threadId: self.chatLocation.threadId, minDate: nil, maxDate: nil), query: "",