From d6ee5b345644332854c33eb3fa28ef78cf7a245b Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Oct 2022 16:33:58 +0400 Subject: [PATCH] Show forum messages search results with topics. --- .../dialogs/dialogs_inner_widget.cpp | 166 +++++++++--------- .../dialogs/dialogs_inner_widget.h | 16 +- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 20 +++ Telegram/SourceFiles/dialogs/dialogs_row.h | 8 +- .../SourceFiles/dialogs/dialogs_widget.cpp | 143 +++++++++------ Telegram/SourceFiles/dialogs/dialogs_widget.h | 4 + .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 40 +++-- .../SourceFiles/history/history_message.cpp | 9 +- .../SourceFiles/history/history_service.cpp | 6 +- 9 files changed, 235 insertions(+), 177 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 74cad5fde..af8329fb4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -712,9 +712,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) { p.translate(0, st::searchedBarHeight); auto skip = searchedOffset(); - auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _searchResults.size()); - auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _searchResults.size()); - p.translate(0, from * st::dialogsRowHeight); + auto from = floorclamp(r.y() - skip, _st->height, 0, _searchResults.size()); + auto to = ceilclamp(r.y() + r.height() - skip, _st->height, 0, _searchResults.size()); + p.translate(0, from * _st->height); if (from < _searchResults.size()) { for (; from < to; ++from) { const auto &result = _searchResults[from]; @@ -725,7 +725,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { ? _searchedPressed : _searchedSelected)); Ui::RowPainter::Paint(p, result.get(), { - .st = &st::defaultDialogRow, + .st = _st, .folder = _openedFolder, .forum = _openedForum, .filter = _filterId, @@ -738,7 +738,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { .narrow = (fullWidth < st::columnMinimalWidthLeft), .displayUnreadInfo = showUnreadInSearchResults, }); - p.translate(0, st::dialogsRowHeight); + p.translate(0, _st->height); } } } @@ -1141,7 +1141,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { } if (!_waitingForSearch && !_searchResults.empty()) { auto skip = searchedOffset(); - auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / st::dialogsRowHeight) : -1; + auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / _st->height) : -1; if (searchedSelected < 0 || searchedSelected >= _searchResults.size()) { searchedSelected = -1; } @@ -1205,7 +1205,7 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) { [this, peer = result->peer] { updateSearchResult(peer); }); } else if (base::in_range(_searchedPressed, 0, _searchResults.size())) { auto &row = _searchResults[_searchedPressed]; - row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), row->repaint()); + row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * _st->height), QSize(width(), _st->height), row->repaint()); } if (anim::Disabled() && (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) { @@ -1789,8 +1789,8 @@ void InnerWidget::updateDialogRow( for (const auto &result : _searchResults) { if (isSearchResultActive(result.get(), row)) { updateRow( - add + index * st::dialogsRowHeight, - st::dialogsRowHeight); + add + index * _st->height, + _st->height); break; } ++index; @@ -1836,7 +1836,7 @@ void InnerWidget::updateSelectedRow(Key key) { } else if (_peerSearchSelected >= 0) { update(0, peerSearchOffset() + _peerSearchSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight); } else if (_searchedSelected >= 0) { - update(0, searchedOffset() + _searchedSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, searchedOffset() + _searchedSelected * _st->height, width(), _st->height); } } } @@ -2068,10 +2068,43 @@ InnerWidget::~InnerWidget() { void InnerWidget::clearSearchResults(bool clearPeerSearchResults) { if (clearPeerSearchResults) _peerSearchResults.clear(); _searchResults.clear(); + _searchResultsLifetime.destroy(); _searchedCount = _searchedMigratedCount = 0; - _lastSearchDate = 0; - _lastSearchPeer = nullptr; - _lastSearchId = _lastSearchMigratedId = 0; +} + +void InnerWidget::trackSearchResultsHistory(not_null history) { + const auto channel = history->peer->asChannel(); + if (!channel || channel->isBroadcast()) { + return; + } + channel->flagsValue( + ) | rpl::skip( + 1 + ) | rpl::filter([=](const ChannelData::Flags::Change &change) { + return (change.diff & ChannelDataFlag::Forum); + }) | rpl::start_with_next([=] { + for (const auto &row : _searchResults) { + if (row->item()->history()->peer == channel) { + row->invalidateTopic(); + } + } + update(); + }, _searchResultsLifetime); + + if (const auto forum = channel->forum()) { + forum->topicDestroyed( + ) | rpl::start_with_next([=](not_null topic) { + const auto from = ranges::remove( + _searchResults, + topic.get(), + &FakeRow::topic); + if (from != end(_searchResults)) { + _searchResults.erase(from, end(_searchResults)); + refresh(true); + clearMouseSelection(true); + } + }, _searchResultsLifetime); + } } PeerData *InnerWidget::updateFromParentDrag(QPoint globalPosition) { @@ -2210,8 +2243,8 @@ bool InnerWidget::hasHistoryInResults(not_null history) const { return false; } -bool InnerWidget::searchReceived( - const QVector &messages, +void InnerWidget::searchReceived( + std::vector> messages, HistoryItem *inject, SearchRequestType type, int fullCount) { @@ -2219,10 +2252,12 @@ bool InnerWidget::searchReceived( if (type == SearchRequestType::FromStart || type == SearchRequestType::PeerFromStart) { clearSearchResults(false); } - auto isGlobalSearch = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset); - auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset); + const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart) + || (type == SearchRequestType::MigratedFromOffset); - TimeId lastDateFound = 0; + const auto key = _openedForum + ? Key(_openedForum->history()) + : _searchInChat; if (inject && (!_searchInChat || inject->history() == _searchInChat.history())) { @@ -2230,49 +2265,25 @@ bool InnerWidget::searchReceived( const auto index = int(_searchResults.size()); _searchResults.push_back( std::make_unique( - _searchInChat, + key, inject, [=] { repaintSearchResult(index); })); + trackSearchResultsHistory(inject->history()); ++fullCount; } - for (const auto &message : messages) { - auto msgId = IdFromMessage(message); - auto peerId = PeerFromMessage(message); - auto lastDate = DateFromMessage(message); - if (const auto peer = session().data().peerLoaded(peerId)) { - if (lastDate) { - const auto item = session().data().addNewMessage( - message, - MessageFlags(), - NewMessageType::Existing); - const auto history = item->history(); - if (!uniquePeers || !hasHistoryInResults(history)) { - const auto index = int(_searchResults.size()); - _searchResults.push_back( - std::make_unique( - _searchInChat, - item, - [=] { repaintSearchResult(index); })); - if (uniquePeers && !history->unreadCountKnown()) { - history->owner().histories().requestDialogEntry(history); - } - } - lastDateFound = lastDate; - if (isGlobalSearch) { - _lastSearchDate = lastDateFound; - } + for (const auto &item : messages) { + const auto history = item->history(); + if (!uniquePeers || !hasHistoryInResults(history)) { + const auto index = int(_searchResults.size()); + _searchResults.push_back( + std::make_unique( + key, + item, + [=] { repaintSearchResult(index); })); + trackSearchResultsHistory(history); + if (uniquePeers && !history->unreadCountKnown()) { + history->owner().histories().requestDialogEntry(history); } - if (isGlobalSearch) { - _lastSearchPeer = peer; - } - } else { - LOG(("API Error: a search results with not loaded peer %1" - ).arg(peerId.value)); - } - if (isMigratedSearch) { - _lastSearchMigratedId = msgId; - } else { - _lastSearchId = msgId; } } if (isMigratedSearch) { @@ -2289,8 +2300,6 @@ bool InnerWidget::searchReceived( } refresh(); - - return lastDateFound != 0; } void InnerWidget::peerSearchReceived( @@ -2397,9 +2406,9 @@ void InnerWidget::refresh(bool toTop) { } } else if (_state == WidgetState::Filtered) { if (_waitingForSearch) { - h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight) + ((_searchResults.empty() && !_searchInChat) ? -st::searchedBarHeight : 0); + h = searchedOffset() + (_searchResults.size() * _st->height) + ((_searchResults.empty() && !_searchInChat) ? -st::searchedBarHeight : 0); } else { - h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight); + h = searchedOffset() + (_searchResults.size() * _st->height); } } resize(width(), h); @@ -2585,9 +2594,9 @@ void InnerWidget::refreshSearchInChatLabel() { void InnerWidget::repaintSearchResult(int index) { rtlupdate( 0, - searchedOffset() + index * st::dialogsRowHeight, + searchedOffset() + index * _st->height, width(), - st::dialogsRowHeight); + _st->height); } void InnerWidget::clearFilter() { @@ -2603,9 +2612,6 @@ void InnerWidget::clearFilter() { _filterResultsGlobal.clear(); _peerSearchResults.clear(); _searchResults.clear(); - _lastSearchDate = 0; - _lastSearchPeer = nullptr; - _lastSearchId = _lastSearchMigratedId = 0; _filter = QString(); refresh(true); } @@ -2718,10 +2724,10 @@ void InnerWidget::selectSkip(int32 direction) { } else { _mustScrollTo.fire({ searchedOffset() - + _searchedSelected * st::dialogsRowHeight + + _searchedSelected * _st->height + (_searchedSelected ? 0 : -st::searchedBarHeight), searchedOffset() - + (_searchedSelected + 1) * st::dialogsRowHeight, + + (_searchedSelected + 1) * _st->height, }); } } @@ -2738,8 +2744,8 @@ void InnerWidget::scrollToEntry(const RowDescriptor &entry) { } else if (_state == WidgetState::Filtered) { for (int32 i = 0, c = _searchResults.size(); i < c; ++i) { if (isSearchResultActive(_searchResults[i].get(), entry)) { - fromY = searchedOffset() + i * st::dialogsRowHeight; - rowHeight = st::dialogsRowHeight; + fromY = searchedOffset() + i * _st->height; + rowHeight = _st->height; break; } } @@ -2936,9 +2942,11 @@ ChosenRow InnerWidget::computeChosenRow() const { }; } else if (base::in_range(_searchedSelected, 0, _searchResults.size())) { const auto result = _searchResults[_searchedSelected].get(); + const auto topic = result->topic(); + const auto item = result->item(); return { - result->item()->history(), - result->item()->position() + (topic ? (Entry*)topic : (Entry*)item->history()), + item->position() }; } } @@ -3168,22 +3176,6 @@ RowDescriptor InnerWidget::chatListEntryLast() const { return RowDescriptor(); } -int32 InnerWidget::lastSearchDate() const { - return _lastSearchDate; -} - -PeerData *InnerWidget::lastSearchPeer() const { - return _lastSearchPeer; -} - -MsgId InnerWidget::lastSearchId() const { - return _lastSearchId; -} - -MsgId InnerWidget::lastSearchMigratedId() const { - return _lastSearchMigratedId; -} - void InnerWidget::setupOnlineStatusCheck() { session().changes().peerUpdates( Data::PeerUpdate::Flag::OnlineStatus diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index a0a80c931..40cba639f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -85,8 +85,8 @@ public: QWidget *parent, not_null controller); - bool searchReceived( - const QVector &result, + void searchReceived( + std::vector> result, HistoryItem *inject, SearchRequestType type, int fullCount); @@ -117,10 +117,6 @@ public: [[nodiscard]] Data::Folder *shownFolder() const; [[nodiscard]] Data::Forum *shownForum() const; - [[nodiscard]] int32 lastSearchDate() const; - [[nodiscard]] PeerData *lastSearchPeer() const; - [[nodiscard]] MsgId lastSearchId() const; - [[nodiscard]] MsgId lastSearchMigratedId() const; [[nodiscard]] WidgetState state() const; [[nodiscard]] not_null st() const { @@ -333,6 +329,8 @@ private: void clearSearchResults(bool clearPeerSearchResults = true); void updateSelectedRow(Key key = Key()); + void trackSearchResultsHistory(not_null history); + void trackSearchResultsForum(Data::Forum *forum); [[nodiscard]] not_null shownDialogs() const; @@ -406,16 +404,12 @@ private: int _peerSearchPressed = -1; std::vector> _searchResults; + rpl::lifetime _searchResultsLifetime; int _searchedCount = 0; int _searchedMigratedCount = 0; int _searchedSelected = -1; int _searchedPressed = -1; - int _lastSearchDate = 0; - PeerData *_lastSearchPeer = nullptr; - MsgId _lastSearchId = 0; - MsgId _lastSearchMigratedId = 0; - WidgetState _state = WidgetState::Default; object_ptr _empty = { nullptr }; diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 5af607cf1..b09221466 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/ui/dialogs_video_userpic.h" #include "dialogs/ui/dialogs_layout.h" #include "data/data_folder.h" +#include "data/data_forum.h" #include "data/data_session.h" #include "data/data_peer_values.h" #include "history/history.h" @@ -351,6 +352,25 @@ FakeRow::FakeRow( : _searchInChat(searchInChat) , _item(item) , _repaint(std::move(repaint)) { + invalidateTopic(); +} + +void FakeRow::invalidateTopic() { + _topic = _item->topic(); + if (_topic) { + return; + } else if (const auto rootId = _item->topicRootId()) { + if (const auto forum = _item->history()->peer->forum()) { + if (!forum->topicDeleted(rootId)) { + forum->requestTopic(rootId, crl::guard(this, [=] { + _topic = _item->topic(); + if (_topic) { + _repaint(); + } + })); + } + } + } } const Ui::Text::String &FakeRow::name() const { diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index 878f33c03..0b460f323 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -147,7 +147,7 @@ private: }; -class FakeRow : public BasicRow { +class FakeRow final : public BasicRow, public base::has_weak_ptr { public: FakeRow( Key searchInChat, @@ -157,6 +157,9 @@ public: [[nodiscard]] Key searchInChat() const { return _searchInChat; } + [[nodiscard]] Data::ForumTopic *topic() const { + return _topic; + } [[nodiscard]] not_null item() const { return _item; } @@ -171,11 +174,14 @@ public: } [[nodiscard]] const Ui::Text::String &name() const; + void invalidateTopic(); + private: friend class Ui::RowPainter; const Key _searchInChat; const not_null _item; + Data::ForumTopic *_topic = nullptr; const Fn _repaint; mutable Ui::MessageView _itemView; mutable Ui::PeerBadge _badge; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index d4c359870..ef73d2dfc 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -344,7 +344,9 @@ Widget::Widget( setupMainMenuToggle(); setupShortcuts(); - _searchForNarrowFilters->setClickedCallback([=] { Ui::showChatsList(&session()); }); + _searchForNarrowFilters->setClickedCallback([=] { + Ui::showChatsList(&session()); + }); setAcceptDrops(true); @@ -446,7 +448,11 @@ void Widget::chosenRow(const ChosenRow &row) { controller()->openFolder(folder); } if (openSearchResult && !session().supportMode()) { - escape(); + if (_subsectionTopBar) { + _subsectionTopBar->toggleSearch(false, anim::type::instant); + } else { + escape(); + } } } @@ -1336,15 +1342,13 @@ void Widget::searchMore() { return; } if (!_searchFull) { - auto offsetPeer = _inner->lastSearchPeer(); - auto offsetId = _inner->lastSearchId(); if (const auto peer = searchInPeer()) { auto &histories = session().data().histories(); const auto topic = searchInTopic(); const auto type = Data::Histories::RequestType::History; const auto history = session().data().history(peer); _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn finish) { - const auto type = offsetId + const auto type = _lastSearchId ? SearchRequestType::PeerFromOffset : SearchRequestType::PeerFromStart; using Flag = MTPmessages_Search::Flag; @@ -1356,11 +1360,11 @@ void Widget::searchMore() { (_searchQueryFrom ? _searchQueryFrom->input : MTP_inputPeerEmpty()), - MTPint(), // top_msg_id + MTP_int(topic ? topic->rootId() : 0), MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date MTP_int(0), // max_date - MTP_int(offsetId), + MTP_int(_lastSearchId), MTP_int(0), // add_offset MTP_int(kSearchPerPage), MTP_int(0), // max_id @@ -1375,13 +1379,13 @@ void Widget::searchMore() { _searchInHistoryRequest = 0; finish(); }).send(); - if (!offsetId) { + if (!_lastSearchId) { _searchQueries.emplace(_searchRequest, _searchQuery); } return _searchRequest; }); } else { - const auto type = offsetId + const auto type = _lastSearchId ? SearchRequestType::FromOffset : SearchRequestType::FromStart; const auto flags = session().settings().skipArchiveInSearch() @@ -1396,27 +1400,26 @@ void Widget::searchMore() { MTP_int(0), // min_date MTP_int(0), // max_date MTP_int(_searchNextRate), - offsetPeer - ? offsetPeer->input - : MTP_inputPeerEmpty(), - MTP_int(offsetId), + (_lastSearchPeer + ? _lastSearchPeer->input + : MTP_inputPeerEmpty()), + MTP_int(_lastSearchId), MTP_int(kSearchPerPage) )).done([=](const MTPmessages_Messages &result) { searchReceived(type, result, _searchRequest); }).fail([=](const MTP::Error &error) { searchFailed(type, error, _searchRequest); }).send(); - if (!offsetId) { + if (!_lastSearchId) { _searchQueries.emplace(_searchRequest, _searchQuery); } } } else if (_searchInMigrated && !_searchFullMigrated) { - auto offsetMigratedId = _inner->lastSearchMigratedId(); auto &histories = session().data().histories(); const auto type = Data::Histories::RequestType::History; const auto history = _searchInMigrated; _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn finish) { - const auto type = offsetMigratedId + const auto type = _lastSearchMigratedId ? SearchRequestType::MigratedFromOffset : SearchRequestType::MigratedFromStart; const auto flags = _searchQueryFrom @@ -1433,7 +1436,7 @@ void Widget::searchMore() { MTP_inputMessagesFilterEmpty(), MTP_int(0), // min_date MTP_int(0), // max_date - MTP_int(offsetMigratedId), + MTP_int(_lastSearchMigratedId), MTP_int(0), // add_offset MTP_int(kSearchPerPage), MTP_int(0), // max_id @@ -1475,37 +1478,69 @@ void Widget::searchReceived( if (_searchRequest != requestId) { return; } - switch (result.type()) { - case mtpc_messages_messages: { - auto &d = result.c_messages_messages(); + if (type == SearchRequestType::FromStart + || type == SearchRequestType::PeerFromStart) { + _lastSearchPeer = nullptr; + _lastSearchId = _lastSearchMigratedId = 0; + } + const auto isGlobalSearch = (type == SearchRequestType::FromStart) + || (type == SearchRequestType::FromOffset); + const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart) + || (type == SearchRequestType::MigratedFromOffset); + const auto process = [&](const MTPVector &messages) { + auto result = std::vector>(); + for (const auto &message : messages.v) { + const auto msgId = IdFromMessage(message); + const auto peerId = PeerFromMessage(message); + const auto lastDate = DateFromMessage(message); + if (const auto peer = session().data().peerLoaded(peerId)) { + if (lastDate) { + const auto item = session().data().addNewMessage( + message, + MessageFlags(), + NewMessageType::Existing); + result.push_back(item); + } + _lastSearchPeer = peer; + } else { + LOG(("API Error: a search results with not loaded peer %1" + ).arg(peerId.value)); + } + if (isMigratedSearch) { + _lastSearchMigratedId = msgId; + } else { + _lastSearchId = msgId; + } + } + return result; + }; + auto fullCount = 0; + auto messages = result.match([&](const MTPDmessages_messages &data) { if (_searchRequest != 0) { // Don't apply cached data! - session().data().processUsers(d.vusers()); - session().data().processChats(d.vchats()); + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); } - auto &msgs = d.vmessages().v; - _inner->searchReceived(msgs, inject, type, msgs.size()); if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { _searchFull = true; } - } break; - - case mtpc_messages_messagesSlice: { - auto &d = result.c_messages_messagesSlice(); + auto list = process(data.vmessages()); + fullCount = list.size(); + return list; + }, [&](const MTPDmessages_messagesSlice &data) { if (_searchRequest != 0) { // Don't apply cached data! - session().data().processUsers(d.vusers()); - session().data().processChats(d.vchats()); + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); } - auto &msgs = d.vmessages().v; - const auto someAdded = _inner->searchReceived(msgs, inject, type, d.vcount().v); - const auto nextRate = d.vnext_rate(); + auto list = process(data.vmessages()); + const auto nextRate = data.vnext_rate(); const auto rateUpdated = nextRate && (nextRate->v != _searchNextRate); const auto finished = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset) ? !rateUpdated - : !someAdded; + : list.empty(); if (rateUpdated) { _searchNextRate = nextRate->v; } @@ -1516,13 +1551,12 @@ void Widget::searchReceived( _searchFull = true; } } - } break; - - case mtpc_messages_channelMessages: { - auto &d = result.c_messages_channelMessages(); - if (const auto peer = _openedForum ? _openedForum : _searchInChat.peer()) { + fullCount = data.vcount().v; + return list; + }, [&](const MTPDmessages_channelMessages &data) { + if (const auto peer = searchInPeer()) { if (const auto channel = peer->asChannel()) { - channel->ptsReceived(d.vpts().v); + channel->ptsReceived(data.vpts().v); } else { LOG(("API Error: " "received messages.channelMessages when no channel " @@ -1535,28 +1569,29 @@ void Widget::searchReceived( } if (_searchRequest != 0) { // Don't apply cached data! - session().data().processUsers(d.vusers()); - session().data().processChats(d.vchats()); + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); } - auto &msgs = d.vmessages().v; - if (!_inner->searchReceived(msgs, inject, type, d.vcount().v)) { + auto list = process(data.vmessages()); + if (list.empty()) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { _searchFull = true; } } - } break; - - case mtpc_messages_messagesNotModified: { + fullCount = data.vcount().v; + return list; + }, [&](const MTPDmessages_messagesNotModified &) { LOG(("API Error: received messages.messagesNotModified! (Widget::searchReceived)")); if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { _searchFull = true; } - } break; - } + return std::vector>(); + }); + _inner->searchReceived(messages, inject, type, fullCount); _searchRequest = 0; listScrollUpdated(); @@ -1808,8 +1843,10 @@ void Widget::showCalendar() { } void Widget::showSearchFrom() { - if (const auto peer = _searchInChat.peer()) { - const auto chat = _searchInChat; + if (const auto peer = searchInPeer()) { + const auto chat = _openedForum + ? Key(_openedForum->forum()->history()) + : _searchInChat; auto box = SearchFromBox( peer, crl::guard(this, [=](not_null from) { @@ -1914,7 +1951,7 @@ void Widget::updateJumpToDateVisibility(bool fast) { void Widget::updateSearchFromVisibility(bool fast) { auto visible = [&] { - if (const auto peer = _searchInChat.peer()) { + if (const auto peer = searchInPeer()) { if (peer->isChat() || peer->isMegagroup()) { return !_searchFromAuthor; } @@ -2197,6 +2234,8 @@ bool Widget::cancelSearch() { setFocus(); return true; } + _lastSearchPeer = nullptr; + _lastSearchId = _lastSearchMigratedId = 0; _inner->clearFilter(); clearSearchField(); applyFilterUpdate(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index f6e975352..a4523cb61 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -252,6 +252,10 @@ private: int _searchInHistoryRequest = 0; // Not real mtpRequestId. mtpRequestId _searchRequest = 0; + PeerData *_lastSearchPeer = nullptr; + MsgId _lastSearchId = 0; + MsgId _lastSearchMigratedId = 0; + base::flat_map _searchCache; Api::SingleMessageSearch _singleMessageSearch; base::flat_map _searchQueries; diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 075ae864d..596612f48 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -243,7 +243,6 @@ void PaintRow( Painter &p, not_null row, not_null entry, - Dialogs::Key chat, VideoUserpic *videoUserpic, PeerData *from, Ui::PeerBadge &fromBadge, @@ -274,8 +273,8 @@ void PaintRow( p.fillRect(fullRect, bg); row->paintRipple(p, 0, 0, context.width, &ripple->c); - const auto history = chat.history(); - const auto thread = chat.thread(); + const auto history = entry->asHistory(); + const auto thread = entry->asThread(); if (flags & Flag::SavedMessages) { EmptyUserpic::PaintSavedMessages( @@ -512,7 +511,7 @@ void PaintRow( if (!thread) { return nullptr; } else if (const auto topic = thread->asTopic() - ; topic && topic->closed()) { + ; !context.search && topic && topic->closed()) { return &(context.active ? st::dialogsLockIconActive : context.selected @@ -927,11 +926,10 @@ void RowPainter::Paint( p, row, entry, - row->key(), videoUserpic, from, entry->chatListPeerBadge(), - [=] { history->updateChatListEntry(); }, + [=] { entry->updateChatListEntry(); }, entry->chatListNameText(), nullptr, item, @@ -947,14 +945,17 @@ void RowPainter::Paint( Painter &p, not_null row, const PaintContext &context) { - auto item = row->item(); - auto history = item->history(); + const auto item = row->item(); + const auto topic = context.forum ? row->topic() : nullptr; + const auto history = topic ? nullptr : item->history().get(); + const auto entry = topic ? (Entry*)topic : (Entry*)history; auto cloudDraft = nullptr; const auto from = [&] { - if (row->searchInChat()) { - return item->displayFrom(); - } - return history->peer->migrateTo() + return topic + ? nullptr + : row->searchInChat() + ? item->displayFrom() + : history->peer->migrateTo() ? history->peer->migrateTo() : history->peer.get(); }(); @@ -971,7 +972,9 @@ void RowPainter::Paint( return nullptr; }(); const auto previewOptions = [&]() -> HistoryView::ToPreviewOptions { - if (const auto searchChat = row->searchInChat()) { + if (topic) { + return {}; + } else if (const auto searchChat = row->searchInChat()) { if (const auto peer = searchChat.peer()) { if (!peer->isChannel() || peer->isMegagroup()) { return { .hideSender = true }; @@ -982,7 +985,7 @@ void RowPainter::Paint( }(); const auto badgesState = context.displayUnreadInfo - ? history->chatListBadgesState() + ? entry->chatListBadgesState() : BadgesState(); const auto displayPinnedIcon = false; @@ -1007,17 +1010,18 @@ void RowPainter::Paint( } row->itemView().paint(p, itemRect, context); }; - const auto showSavedMessages = history->peer->isSelf() + const auto showSavedMessages = history + && history->peer->isSelf() && !row->searchInChat(); - const auto showRepliesMessages = history->peer->isRepliesChat() + const auto showRepliesMessages = history + && history->peer->isRepliesChat() && !row->searchInChat(); const auto flags = (showSavedMessages ? Flag::SavedMessages : Flag(0)) | (showRepliesMessages ? Flag::RepliesMessages : Flag(0)); PaintRow( p, row, - history, - history, + entry, nullptr, from, row->badge(), diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index aaf15e69e..6f18402dd 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -334,8 +334,7 @@ HistoryMessage::HistoryMessage( config.replyTo = data.is_reply_to_scheduled() ? history->owner().scheduledMessages().localMessageId(id) : id; - config.replyToTop = data.vreply_to_top_id().value_or( - data.vreply_to_msg_id().v); + config.replyToTop = data.vreply_to_top_id().value_or(id); config.replyIsTopicPost = data.is_forum_topic(); }); } @@ -385,9 +384,9 @@ HistoryMessage::HistoryMessage( ? peerFromMTP(*data.vreply_to_peer_id()) : history->peer->id; if (!peer || peer == history->peer->id) { - config.replyTo = data.vreply_to_msg_id().v; - config.replyToTop = data.vreply_to_top_id().value_or( - data.vreply_to_msg_id().v); + const auto id = data.vreply_to_msg_id().v; + config.replyTo = id; + config.replyToTop = data.vreply_to_top_id().value_or(id); } }); } diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 3df7d0567..d32d954a7 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -1607,9 +1607,9 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) { dependent->peerId = (peerId != history()->peer->id) ? peerId : 0; - dependent->msgId = data.vreply_to_msg_id().v; - dependent->topId = data.vreply_to_top_id().value_or( - data.vreply_to_msg_id().v); + const auto id = data.vreply_to_msg_id().v; + dependent->msgId = id; + dependent->topId = data.vreply_to_top_id().value_or(id); dependent->topicPost = data.is_forum_topic() || Has(); if (!updateDependent()) {