Show forum messages search results with topics.

This commit is contained in:
John Preston 2022-10-26 16:33:58 +04:00
parent 88d1a502a5
commit d6ee5b3456
9 changed files with 235 additions and 177 deletions

View file

@ -712,9 +712,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
p.translate(0, st::searchedBarHeight); p.translate(0, st::searchedBarHeight);
auto skip = searchedOffset(); auto skip = searchedOffset();
auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _searchResults.size()); auto from = floorclamp(r.y() - skip, _st->height, 0, _searchResults.size());
auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _searchResults.size()); auto to = ceilclamp(r.y() + r.height() - skip, _st->height, 0, _searchResults.size());
p.translate(0, from * st::dialogsRowHeight); p.translate(0, from * _st->height);
if (from < _searchResults.size()) { if (from < _searchResults.size()) {
for (; from < to; ++from) { for (; from < to; ++from) {
const auto &result = _searchResults[from]; const auto &result = _searchResults[from];
@ -725,7 +725,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
? _searchedPressed ? _searchedPressed
: _searchedSelected)); : _searchedSelected));
Ui::RowPainter::Paint(p, result.get(), { Ui::RowPainter::Paint(p, result.get(), {
.st = &st::defaultDialogRow, .st = _st,
.folder = _openedFolder, .folder = _openedFolder,
.forum = _openedForum, .forum = _openedForum,
.filter = _filterId, .filter = _filterId,
@ -738,7 +738,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
.narrow = (fullWidth < st::columnMinimalWidthLeft), .narrow = (fullWidth < st::columnMinimalWidthLeft),
.displayUnreadInfo = showUnreadInSearchResults, .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()) { if (!_waitingForSearch && !_searchResults.empty()) {
auto skip = searchedOffset(); 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()) { if (searchedSelected < 0 || searchedSelected >= _searchResults.size()) {
searchedSelected = -1; searchedSelected = -1;
} }
@ -1205,7 +1205,7 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) {
[this, peer = result->peer] { updateSearchResult(peer); }); [this, peer = result->peer] { updateSearchResult(peer); });
} else if (base::in_range(_searchedPressed, 0, _searchResults.size())) { } else if (base::in_range(_searchedPressed, 0, _searchResults.size())) {
auto &row = _searchResults[_searchedPressed]; 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() if (anim::Disabled()
&& (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) { && (!_pressed || !_pressed->entry()->isPinnedDialog(_filterId))) {
@ -1789,8 +1789,8 @@ void InnerWidget::updateDialogRow(
for (const auto &result : _searchResults) { for (const auto &result : _searchResults) {
if (isSearchResultActive(result.get(), row)) { if (isSearchResultActive(result.get(), row)) {
updateRow( updateRow(
add + index * st::dialogsRowHeight, add + index * _st->height,
st::dialogsRowHeight); _st->height);
break; break;
} }
++index; ++index;
@ -1836,7 +1836,7 @@ void InnerWidget::updateSelectedRow(Key key) {
} else if (_peerSearchSelected >= 0) { } else if (_peerSearchSelected >= 0) {
update(0, peerSearchOffset() + _peerSearchSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight); update(0, peerSearchOffset() + _peerSearchSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight);
} else if (_searchedSelected >= 0) { } 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) { void InnerWidget::clearSearchResults(bool clearPeerSearchResults) {
if (clearPeerSearchResults) _peerSearchResults.clear(); if (clearPeerSearchResults) _peerSearchResults.clear();
_searchResults.clear(); _searchResults.clear();
_searchResultsLifetime.destroy();
_searchedCount = _searchedMigratedCount = 0; _searchedCount = _searchedMigratedCount = 0;
_lastSearchDate = 0; }
_lastSearchPeer = nullptr;
_lastSearchId = _lastSearchMigratedId = 0; void InnerWidget::trackSearchResultsHistory(not_null<History*> 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<Data::ForumTopic*> 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) { PeerData *InnerWidget::updateFromParentDrag(QPoint globalPosition) {
@ -2210,8 +2243,8 @@ bool InnerWidget::hasHistoryInResults(not_null<History*> history) const {
return false; return false;
} }
bool InnerWidget::searchReceived( void InnerWidget::searchReceived(
const QVector<MTPMessage> &messages, std::vector<not_null<HistoryItem*>> messages,
HistoryItem *inject, HistoryItem *inject,
SearchRequestType type, SearchRequestType type,
int fullCount) { int fullCount) {
@ -2219,10 +2252,12 @@ bool InnerWidget::searchReceived(
if (type == SearchRequestType::FromStart || type == SearchRequestType::PeerFromStart) { if (type == SearchRequestType::FromStart || type == SearchRequestType::PeerFromStart) {
clearSearchResults(false); clearSearchResults(false);
} }
auto isGlobalSearch = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset); const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart)
auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset); || (type == SearchRequestType::MigratedFromOffset);
TimeId lastDateFound = 0; const auto key = _openedForum
? Key(_openedForum->history())
: _searchInChat;
if (inject if (inject
&& (!_searchInChat && (!_searchInChat
|| inject->history() == _searchInChat.history())) { || inject->history() == _searchInChat.history())) {
@ -2230,49 +2265,25 @@ bool InnerWidget::searchReceived(
const auto index = int(_searchResults.size()); const auto index = int(_searchResults.size());
_searchResults.push_back( _searchResults.push_back(
std::make_unique<FakeRow>( std::make_unique<FakeRow>(
_searchInChat, key,
inject, inject,
[=] { repaintSearchResult(index); })); [=] { repaintSearchResult(index); }));
trackSearchResultsHistory(inject->history());
++fullCount; ++fullCount;
} }
for (const auto &message : messages) { for (const auto &item : messages) {
auto msgId = IdFromMessage(message); const auto history = item->history();
auto peerId = PeerFromMessage(message); if (!uniquePeers || !hasHistoryInResults(history)) {
auto lastDate = DateFromMessage(message); const auto index = int(_searchResults.size());
if (const auto peer = session().data().peerLoaded(peerId)) { _searchResults.push_back(
if (lastDate) { std::make_unique<FakeRow>(
const auto item = session().data().addNewMessage( key,
message, item,
MessageFlags(), [=] { repaintSearchResult(index); }));
NewMessageType::Existing); trackSearchResultsHistory(history);
const auto history = item->history(); if (uniquePeers && !history->unreadCountKnown()) {
if (!uniquePeers || !hasHistoryInResults(history)) { history->owner().histories().requestDialogEntry(history);
const auto index = int(_searchResults.size());
_searchResults.push_back(
std::make_unique<FakeRow>(
_searchInChat,
item,
[=] { repaintSearchResult(index); }));
if (uniquePeers && !history->unreadCountKnown()) {
history->owner().histories().requestDialogEntry(history);
}
}
lastDateFound = lastDate;
if (isGlobalSearch) {
_lastSearchDate = lastDateFound;
}
} }
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) { if (isMigratedSearch) {
@ -2289,8 +2300,6 @@ bool InnerWidget::searchReceived(
} }
refresh(); refresh();
return lastDateFound != 0;
} }
void InnerWidget::peerSearchReceived( void InnerWidget::peerSearchReceived(
@ -2397,9 +2406,9 @@ void InnerWidget::refresh(bool toTop) {
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
if (_waitingForSearch) { 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 { } else {
h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight); h = searchedOffset() + (_searchResults.size() * _st->height);
} }
} }
resize(width(), h); resize(width(), h);
@ -2585,9 +2594,9 @@ void InnerWidget::refreshSearchInChatLabel() {
void InnerWidget::repaintSearchResult(int index) { void InnerWidget::repaintSearchResult(int index) {
rtlupdate( rtlupdate(
0, 0,
searchedOffset() + index * st::dialogsRowHeight, searchedOffset() + index * _st->height,
width(), width(),
st::dialogsRowHeight); _st->height);
} }
void InnerWidget::clearFilter() { void InnerWidget::clearFilter() {
@ -2603,9 +2612,6 @@ void InnerWidget::clearFilter() {
_filterResultsGlobal.clear(); _filterResultsGlobal.clear();
_peerSearchResults.clear(); _peerSearchResults.clear();
_searchResults.clear(); _searchResults.clear();
_lastSearchDate = 0;
_lastSearchPeer = nullptr;
_lastSearchId = _lastSearchMigratedId = 0;
_filter = QString(); _filter = QString();
refresh(true); refresh(true);
} }
@ -2718,10 +2724,10 @@ void InnerWidget::selectSkip(int32 direction) {
} else { } else {
_mustScrollTo.fire({ _mustScrollTo.fire({
searchedOffset() searchedOffset()
+ _searchedSelected * st::dialogsRowHeight + _searchedSelected * _st->height
+ (_searchedSelected ? 0 : -st::searchedBarHeight), + (_searchedSelected ? 0 : -st::searchedBarHeight),
searchedOffset() searchedOffset()
+ (_searchedSelected + 1) * st::dialogsRowHeight, + (_searchedSelected + 1) * _st->height,
}); });
} }
} }
@ -2738,8 +2744,8 @@ void InnerWidget::scrollToEntry(const RowDescriptor &entry) {
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
for (int32 i = 0, c = _searchResults.size(); i < c; ++i) { for (int32 i = 0, c = _searchResults.size(); i < c; ++i) {
if (isSearchResultActive(_searchResults[i].get(), entry)) { if (isSearchResultActive(_searchResults[i].get(), entry)) {
fromY = searchedOffset() + i * st::dialogsRowHeight; fromY = searchedOffset() + i * _st->height;
rowHeight = st::dialogsRowHeight; rowHeight = _st->height;
break; break;
} }
} }
@ -2936,9 +2942,11 @@ ChosenRow InnerWidget::computeChosenRow() const {
}; };
} else if (base::in_range(_searchedSelected, 0, _searchResults.size())) { } else if (base::in_range(_searchedSelected, 0, _searchResults.size())) {
const auto result = _searchResults[_searchedSelected].get(); const auto result = _searchResults[_searchedSelected].get();
const auto topic = result->topic();
const auto item = result->item();
return { return {
result->item()->history(), (topic ? (Entry*)topic : (Entry*)item->history()),
result->item()->position() item->position()
}; };
} }
} }
@ -3168,22 +3176,6 @@ RowDescriptor InnerWidget::chatListEntryLast() const {
return RowDescriptor(); 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() { void InnerWidget::setupOnlineStatusCheck() {
session().changes().peerUpdates( session().changes().peerUpdates(
Data::PeerUpdate::Flag::OnlineStatus Data::PeerUpdate::Flag::OnlineStatus

View file

@ -85,8 +85,8 @@ public:
QWidget *parent, QWidget *parent,
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller);
bool searchReceived( void searchReceived(
const QVector<MTPMessage> &result, std::vector<not_null<HistoryItem*>> result,
HistoryItem *inject, HistoryItem *inject,
SearchRequestType type, SearchRequestType type,
int fullCount); int fullCount);
@ -117,10 +117,6 @@ public:
[[nodiscard]] Data::Folder *shownFolder() const; [[nodiscard]] Data::Folder *shownFolder() const;
[[nodiscard]] Data::Forum *shownForum() 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]] WidgetState state() const;
[[nodiscard]] not_null<const style::DialogRow*> st() const { [[nodiscard]] not_null<const style::DialogRow*> st() const {
@ -333,6 +329,8 @@ private:
void clearSearchResults(bool clearPeerSearchResults = true); void clearSearchResults(bool clearPeerSearchResults = true);
void updateSelectedRow(Key key = Key()); void updateSelectedRow(Key key = Key());
void trackSearchResultsHistory(not_null<History*> history);
void trackSearchResultsForum(Data::Forum *forum);
[[nodiscard]] not_null<IndexedList*> shownDialogs() const; [[nodiscard]] not_null<IndexedList*> shownDialogs() const;
@ -406,16 +404,12 @@ private:
int _peerSearchPressed = -1; int _peerSearchPressed = -1;
std::vector<std::unique_ptr<FakeRow>> _searchResults; std::vector<std::unique_ptr<FakeRow>> _searchResults;
rpl::lifetime _searchResultsLifetime;
int _searchedCount = 0; int _searchedCount = 0;
int _searchedMigratedCount = 0; int _searchedMigratedCount = 0;
int _searchedSelected = -1; int _searchedSelected = -1;
int _searchedPressed = -1; int _searchedPressed = -1;
int _lastSearchDate = 0;
PeerData *_lastSearchPeer = nullptr;
MsgId _lastSearchId = 0;
MsgId _lastSearchMigratedId = 0;
WidgetState _state = WidgetState::Default; WidgetState _state = WidgetState::Default;
object_ptr<Ui::FlatLabel> _empty = { nullptr }; object_ptr<Ui::FlatLabel> _empty = { nullptr };

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/ui/dialogs_video_userpic.h" #include "dialogs/ui/dialogs_video_userpic.h"
#include "dialogs/ui/dialogs_layout.h" #include "dialogs/ui/dialogs_layout.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_forum.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
#include "history/history.h" #include "history/history.h"
@ -351,6 +352,25 @@ FakeRow::FakeRow(
: _searchInChat(searchInChat) : _searchInChat(searchInChat)
, _item(item) , _item(item)
, _repaint(std::move(repaint)) { , _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 { const Ui::Text::String &FakeRow::name() const {

View file

@ -147,7 +147,7 @@ private:
}; };
class FakeRow : public BasicRow { class FakeRow final : public BasicRow, public base::has_weak_ptr {
public: public:
FakeRow( FakeRow(
Key searchInChat, Key searchInChat,
@ -157,6 +157,9 @@ public:
[[nodiscard]] Key searchInChat() const { [[nodiscard]] Key searchInChat() const {
return _searchInChat; return _searchInChat;
} }
[[nodiscard]] Data::ForumTopic *topic() const {
return _topic;
}
[[nodiscard]] not_null<HistoryItem*> item() const { [[nodiscard]] not_null<HistoryItem*> item() const {
return _item; return _item;
} }
@ -171,11 +174,14 @@ public:
} }
[[nodiscard]] const Ui::Text::String &name() const; [[nodiscard]] const Ui::Text::String &name() const;
void invalidateTopic();
private: private:
friend class Ui::RowPainter; friend class Ui::RowPainter;
const Key _searchInChat; const Key _searchInChat;
const not_null<HistoryItem*> _item; const not_null<HistoryItem*> _item;
Data::ForumTopic *_topic = nullptr;
const Fn<void()> _repaint; const Fn<void()> _repaint;
mutable Ui::MessageView _itemView; mutable Ui::MessageView _itemView;
mutable Ui::PeerBadge _badge; mutable Ui::PeerBadge _badge;

View file

@ -344,7 +344,9 @@ Widget::Widget(
setupMainMenuToggle(); setupMainMenuToggle();
setupShortcuts(); setupShortcuts();
_searchForNarrowFilters->setClickedCallback([=] { Ui::showChatsList(&session()); }); _searchForNarrowFilters->setClickedCallback([=] {
Ui::showChatsList(&session());
});
setAcceptDrops(true); setAcceptDrops(true);
@ -446,7 +448,11 @@ void Widget::chosenRow(const ChosenRow &row) {
controller()->openFolder(folder); controller()->openFolder(folder);
} }
if (openSearchResult && !session().supportMode()) { if (openSearchResult && !session().supportMode()) {
escape(); if (_subsectionTopBar) {
_subsectionTopBar->toggleSearch(false, anim::type::instant);
} else {
escape();
}
} }
} }
@ -1336,15 +1342,13 @@ void Widget::searchMore() {
return; return;
} }
if (!_searchFull) { if (!_searchFull) {
auto offsetPeer = _inner->lastSearchPeer();
auto offsetId = _inner->lastSearchId();
if (const auto peer = searchInPeer()) { if (const auto peer = searchInPeer()) {
auto &histories = session().data().histories(); auto &histories = session().data().histories();
const auto topic = searchInTopic(); const auto topic = searchInTopic();
const auto type = Data::Histories::RequestType::History; const auto type = Data::Histories::RequestType::History;
const auto history = session().data().history(peer); const auto history = session().data().history(peer);
_searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) { _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) {
const auto type = offsetId const auto type = _lastSearchId
? SearchRequestType::PeerFromOffset ? SearchRequestType::PeerFromOffset
: SearchRequestType::PeerFromStart; : SearchRequestType::PeerFromStart;
using Flag = MTPmessages_Search::Flag; using Flag = MTPmessages_Search::Flag;
@ -1356,11 +1360,11 @@ void Widget::searchMore() {
(_searchQueryFrom (_searchQueryFrom
? _searchQueryFrom->input ? _searchQueryFrom->input
: MTP_inputPeerEmpty()), : MTP_inputPeerEmpty()),
MTPint(), // top_msg_id MTP_int(topic ? topic->rootId() : 0),
MTP_inputMessagesFilterEmpty(), MTP_inputMessagesFilterEmpty(),
MTP_int(0), // min_date MTP_int(0), // min_date
MTP_int(0), // max_date MTP_int(0), // max_date
MTP_int(offsetId), MTP_int(_lastSearchId),
MTP_int(0), // add_offset MTP_int(0), // add_offset
MTP_int(kSearchPerPage), MTP_int(kSearchPerPage),
MTP_int(0), // max_id MTP_int(0), // max_id
@ -1375,13 +1379,13 @@ void Widget::searchMore() {
_searchInHistoryRequest = 0; _searchInHistoryRequest = 0;
finish(); finish();
}).send(); }).send();
if (!offsetId) { if (!_lastSearchId) {
_searchQueries.emplace(_searchRequest, _searchQuery); _searchQueries.emplace(_searchRequest, _searchQuery);
} }
return _searchRequest; return _searchRequest;
}); });
} else { } else {
const auto type = offsetId const auto type = _lastSearchId
? SearchRequestType::FromOffset ? SearchRequestType::FromOffset
: SearchRequestType::FromStart; : SearchRequestType::FromStart;
const auto flags = session().settings().skipArchiveInSearch() const auto flags = session().settings().skipArchiveInSearch()
@ -1396,27 +1400,26 @@ void Widget::searchMore() {
MTP_int(0), // min_date MTP_int(0), // min_date
MTP_int(0), // max_date MTP_int(0), // max_date
MTP_int(_searchNextRate), MTP_int(_searchNextRate),
offsetPeer (_lastSearchPeer
? offsetPeer->input ? _lastSearchPeer->input
: MTP_inputPeerEmpty(), : MTP_inputPeerEmpty()),
MTP_int(offsetId), MTP_int(_lastSearchId),
MTP_int(kSearchPerPage) MTP_int(kSearchPerPage)
)).done([=](const MTPmessages_Messages &result) { )).done([=](const MTPmessages_Messages &result) {
searchReceived(type, result, _searchRequest); searchReceived(type, result, _searchRequest);
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
searchFailed(type, error, _searchRequest); searchFailed(type, error, _searchRequest);
}).send(); }).send();
if (!offsetId) { if (!_lastSearchId) {
_searchQueries.emplace(_searchRequest, _searchQuery); _searchQueries.emplace(_searchRequest, _searchQuery);
} }
} }
} else if (_searchInMigrated && !_searchFullMigrated) { } else if (_searchInMigrated && !_searchFullMigrated) {
auto offsetMigratedId = _inner->lastSearchMigratedId();
auto &histories = session().data().histories(); auto &histories = session().data().histories();
const auto type = Data::Histories::RequestType::History; const auto type = Data::Histories::RequestType::History;
const auto history = _searchInMigrated; const auto history = _searchInMigrated;
_searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) { _searchInHistoryRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) {
const auto type = offsetMigratedId const auto type = _lastSearchMigratedId
? SearchRequestType::MigratedFromOffset ? SearchRequestType::MigratedFromOffset
: SearchRequestType::MigratedFromStart; : SearchRequestType::MigratedFromStart;
const auto flags = _searchQueryFrom const auto flags = _searchQueryFrom
@ -1433,7 +1436,7 @@ void Widget::searchMore() {
MTP_inputMessagesFilterEmpty(), MTP_inputMessagesFilterEmpty(),
MTP_int(0), // min_date MTP_int(0), // min_date
MTP_int(0), // max_date MTP_int(0), // max_date
MTP_int(offsetMigratedId), MTP_int(_lastSearchMigratedId),
MTP_int(0), // add_offset MTP_int(0), // add_offset
MTP_int(kSearchPerPage), MTP_int(kSearchPerPage),
MTP_int(0), // max_id MTP_int(0), // max_id
@ -1475,37 +1478,69 @@ void Widget::searchReceived(
if (_searchRequest != requestId) { if (_searchRequest != requestId) {
return; return;
} }
switch (result.type()) { if (type == SearchRequestType::FromStart
case mtpc_messages_messages: { || type == SearchRequestType::PeerFromStart) {
auto &d = result.c_messages_messages(); _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<MTPMessage> &messages) {
auto result = std::vector<not_null<HistoryItem*>>();
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) { if (_searchRequest != 0) {
// Don't apply cached data! // Don't apply cached data!
session().data().processUsers(d.vusers()); session().data().processUsers(data.vusers());
session().data().processChats(d.vchats()); session().data().processChats(data.vchats());
} }
auto &msgs = d.vmessages().v;
_inner->searchReceived(msgs, inject, type, msgs.size());
if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) {
_searchFullMigrated = true; _searchFullMigrated = true;
} else { } else {
_searchFull = true; _searchFull = true;
} }
} break; auto list = process(data.vmessages());
fullCount = list.size();
case mtpc_messages_messagesSlice: { return list;
auto &d = result.c_messages_messagesSlice(); }, [&](const MTPDmessages_messagesSlice &data) {
if (_searchRequest != 0) { if (_searchRequest != 0) {
// Don't apply cached data! // Don't apply cached data!
session().data().processUsers(d.vusers()); session().data().processUsers(data.vusers());
session().data().processChats(d.vchats()); session().data().processChats(data.vchats());
} }
auto &msgs = d.vmessages().v; auto list = process(data.vmessages());
const auto someAdded = _inner->searchReceived(msgs, inject, type, d.vcount().v); const auto nextRate = data.vnext_rate();
const auto nextRate = d.vnext_rate();
const auto rateUpdated = nextRate && (nextRate->v != _searchNextRate); const auto rateUpdated = nextRate && (nextRate->v != _searchNextRate);
const auto finished = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset) const auto finished = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset)
? !rateUpdated ? !rateUpdated
: !someAdded; : list.empty();
if (rateUpdated) { if (rateUpdated) {
_searchNextRate = nextRate->v; _searchNextRate = nextRate->v;
} }
@ -1516,13 +1551,12 @@ void Widget::searchReceived(
_searchFull = true; _searchFull = true;
} }
} }
} break; fullCount = data.vcount().v;
return list;
case mtpc_messages_channelMessages: { }, [&](const MTPDmessages_channelMessages &data) {
auto &d = result.c_messages_channelMessages(); if (const auto peer = searchInPeer()) {
if (const auto peer = _openedForum ? _openedForum : _searchInChat.peer()) {
if (const auto channel = peer->asChannel()) { if (const auto channel = peer->asChannel()) {
channel->ptsReceived(d.vpts().v); channel->ptsReceived(data.vpts().v);
} else { } else {
LOG(("API Error: " LOG(("API Error: "
"received messages.channelMessages when no channel " "received messages.channelMessages when no channel "
@ -1535,28 +1569,29 @@ void Widget::searchReceived(
} }
if (_searchRequest != 0) { if (_searchRequest != 0) {
// Don't apply cached data! // Don't apply cached data!
session().data().processUsers(d.vusers()); session().data().processUsers(data.vusers());
session().data().processChats(d.vchats()); session().data().processChats(data.vchats());
} }
auto &msgs = d.vmessages().v; auto list = process(data.vmessages());
if (!_inner->searchReceived(msgs, inject, type, d.vcount().v)) { if (list.empty()) {
if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) {
_searchFullMigrated = true; _searchFullMigrated = true;
} else { } else {
_searchFull = true; _searchFull = true;
} }
} }
} break; fullCount = data.vcount().v;
return list;
case mtpc_messages_messagesNotModified: { }, [&](const MTPDmessages_messagesNotModified &) {
LOG(("API Error: received messages.messagesNotModified! (Widget::searchReceived)")); LOG(("API Error: received messages.messagesNotModified! (Widget::searchReceived)"));
if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) {
_searchFullMigrated = true; _searchFullMigrated = true;
} else { } else {
_searchFull = true; _searchFull = true;
} }
} break; return std::vector<not_null<HistoryItem*>>();
} });
_inner->searchReceived(messages, inject, type, fullCount);
_searchRequest = 0; _searchRequest = 0;
listScrollUpdated(); listScrollUpdated();
@ -1808,8 +1843,10 @@ void Widget::showCalendar() {
} }
void Widget::showSearchFrom() { void Widget::showSearchFrom() {
if (const auto peer = _searchInChat.peer()) { if (const auto peer = searchInPeer()) {
const auto chat = _searchInChat; const auto chat = _openedForum
? Key(_openedForum->forum()->history())
: _searchInChat;
auto box = SearchFromBox( auto box = SearchFromBox(
peer, peer,
crl::guard(this, [=](not_null<PeerData*> from) { crl::guard(this, [=](not_null<PeerData*> from) {
@ -1914,7 +1951,7 @@ void Widget::updateJumpToDateVisibility(bool fast) {
void Widget::updateSearchFromVisibility(bool fast) { void Widget::updateSearchFromVisibility(bool fast) {
auto visible = [&] { auto visible = [&] {
if (const auto peer = _searchInChat.peer()) { if (const auto peer = searchInPeer()) {
if (peer->isChat() || peer->isMegagroup()) { if (peer->isChat() || peer->isMegagroup()) {
return !_searchFromAuthor; return !_searchFromAuthor;
} }
@ -2197,6 +2234,8 @@ bool Widget::cancelSearch() {
setFocus(); setFocus();
return true; return true;
} }
_lastSearchPeer = nullptr;
_lastSearchId = _lastSearchMigratedId = 0;
_inner->clearFilter(); _inner->clearFilter();
clearSearchField(); clearSearchField();
applyFilterUpdate(); applyFilterUpdate();

View file

@ -252,6 +252,10 @@ private:
int _searchInHistoryRequest = 0; // Not real mtpRequestId. int _searchInHistoryRequest = 0; // Not real mtpRequestId.
mtpRequestId _searchRequest = 0; mtpRequestId _searchRequest = 0;
PeerData *_lastSearchPeer = nullptr;
MsgId _lastSearchId = 0;
MsgId _lastSearchMigratedId = 0;
base::flat_map<QString, MTPmessages_Messages> _searchCache; base::flat_map<QString, MTPmessages_Messages> _searchCache;
Api::SingleMessageSearch _singleMessageSearch; Api::SingleMessageSearch _singleMessageSearch;
base::flat_map<mtpRequestId, QString> _searchQueries; base::flat_map<mtpRequestId, QString> _searchQueries;

View file

@ -243,7 +243,6 @@ void PaintRow(
Painter &p, Painter &p,
not_null<const BasicRow*> row, not_null<const BasicRow*> row,
not_null<Entry*> entry, not_null<Entry*> entry,
Dialogs::Key chat,
VideoUserpic *videoUserpic, VideoUserpic *videoUserpic,
PeerData *from, PeerData *from,
Ui::PeerBadge &fromBadge, Ui::PeerBadge &fromBadge,
@ -274,8 +273,8 @@ void PaintRow(
p.fillRect(fullRect, bg); p.fillRect(fullRect, bg);
row->paintRipple(p, 0, 0, context.width, &ripple->c); row->paintRipple(p, 0, 0, context.width, &ripple->c);
const auto history = chat.history(); const auto history = entry->asHistory();
const auto thread = chat.thread(); const auto thread = entry->asThread();
if (flags & Flag::SavedMessages) { if (flags & Flag::SavedMessages) {
EmptyUserpic::PaintSavedMessages( EmptyUserpic::PaintSavedMessages(
@ -512,7 +511,7 @@ void PaintRow(
if (!thread) { if (!thread) {
return nullptr; return nullptr;
} else if (const auto topic = thread->asTopic() } else if (const auto topic = thread->asTopic()
; topic && topic->closed()) { ; !context.search && topic && topic->closed()) {
return &(context.active return &(context.active
? st::dialogsLockIconActive ? st::dialogsLockIconActive
: context.selected : context.selected
@ -927,11 +926,10 @@ void RowPainter::Paint(
p, p,
row, row,
entry, entry,
row->key(),
videoUserpic, videoUserpic,
from, from,
entry->chatListPeerBadge(), entry->chatListPeerBadge(),
[=] { history->updateChatListEntry(); }, [=] { entry->updateChatListEntry(); },
entry->chatListNameText(), entry->chatListNameText(),
nullptr, nullptr,
item, item,
@ -947,14 +945,17 @@ void RowPainter::Paint(
Painter &p, Painter &p,
not_null<const FakeRow*> row, not_null<const FakeRow*> row,
const PaintContext &context) { const PaintContext &context) {
auto item = row->item(); const auto item = row->item();
auto history = item->history(); 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; auto cloudDraft = nullptr;
const auto from = [&] { const auto from = [&] {
if (row->searchInChat()) { return topic
return item->displayFrom(); ? nullptr
} : row->searchInChat()
return history->peer->migrateTo() ? item->displayFrom()
: history->peer->migrateTo()
? history->peer->migrateTo() ? history->peer->migrateTo()
: history->peer.get(); : history->peer.get();
}(); }();
@ -971,7 +972,9 @@ void RowPainter::Paint(
return nullptr; return nullptr;
}(); }();
const auto previewOptions = [&]() -> HistoryView::ToPreviewOptions { 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 (const auto peer = searchChat.peer()) {
if (!peer->isChannel() || peer->isMegagroup()) { if (!peer->isChannel() || peer->isMegagroup()) {
return { .hideSender = true }; return { .hideSender = true };
@ -982,7 +985,7 @@ void RowPainter::Paint(
}(); }();
const auto badgesState = context.displayUnreadInfo const auto badgesState = context.displayUnreadInfo
? history->chatListBadgesState() ? entry->chatListBadgesState()
: BadgesState(); : BadgesState();
const auto displayPinnedIcon = false; const auto displayPinnedIcon = false;
@ -1007,17 +1010,18 @@ void RowPainter::Paint(
} }
row->itemView().paint(p, itemRect, context); row->itemView().paint(p, itemRect, context);
}; };
const auto showSavedMessages = history->peer->isSelf() const auto showSavedMessages = history
&& history->peer->isSelf()
&& !row->searchInChat(); && !row->searchInChat();
const auto showRepliesMessages = history->peer->isRepliesChat() const auto showRepliesMessages = history
&& history->peer->isRepliesChat()
&& !row->searchInChat(); && !row->searchInChat();
const auto flags = (showSavedMessages ? Flag::SavedMessages : Flag(0)) const auto flags = (showSavedMessages ? Flag::SavedMessages : Flag(0))
| (showRepliesMessages ? Flag::RepliesMessages : Flag(0)); | (showRepliesMessages ? Flag::RepliesMessages : Flag(0));
PaintRow( PaintRow(
p, p,
row, row,
history, entry,
history,
nullptr, nullptr,
from, from,
row->badge(), row->badge(),

View file

@ -334,8 +334,7 @@ HistoryMessage::HistoryMessage(
config.replyTo = data.is_reply_to_scheduled() config.replyTo = data.is_reply_to_scheduled()
? history->owner().scheduledMessages().localMessageId(id) ? history->owner().scheduledMessages().localMessageId(id)
: id; : id;
config.replyToTop = data.vreply_to_top_id().value_or( config.replyToTop = data.vreply_to_top_id().value_or(id);
data.vreply_to_msg_id().v);
config.replyIsTopicPost = data.is_forum_topic(); config.replyIsTopicPost = data.is_forum_topic();
}); });
} }
@ -385,9 +384,9 @@ HistoryMessage::HistoryMessage(
? peerFromMTP(*data.vreply_to_peer_id()) ? peerFromMTP(*data.vreply_to_peer_id())
: history->peer->id; : history->peer->id;
if (!peer || peer == history->peer->id) { if (!peer || peer == history->peer->id) {
config.replyTo = data.vreply_to_msg_id().v; const auto id = data.vreply_to_msg_id().v;
config.replyToTop = data.vreply_to_top_id().value_or( config.replyTo = id;
data.vreply_to_msg_id().v); config.replyToTop = data.vreply_to_top_id().value_or(id);
} }
}); });
} }

View file

@ -1607,9 +1607,9 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
dependent->peerId = (peerId != history()->peer->id) dependent->peerId = (peerId != history()->peer->id)
? peerId ? peerId
: 0; : 0;
dependent->msgId = data.vreply_to_msg_id().v; const auto id = data.vreply_to_msg_id().v;
dependent->topId = data.vreply_to_top_id().value_or( dependent->msgId = id;
data.vreply_to_msg_id().v); dependent->topId = data.vreply_to_top_id().value_or(id);
dependent->topicPost = data.is_forum_topic() dependent->topicPost = data.is_forum_topic()
|| Has<HistoryServiceTopicInfo>(); || Has<HistoryServiceTopicInfo>();
if (!updateDependent()) { if (!updateDependent()) {