mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Append server-side topic search results.
This commit is contained in:
parent
d6ee5b3456
commit
60aef7871a
9 changed files with 224 additions and 73 deletions
|
@ -34,7 +34,7 @@ constexpr auto kTopicsFirstLoad = 20;
|
||||||
constexpr auto kLoadedTopicsMinCount = 20;
|
constexpr auto kLoadedTopicsMinCount = 20;
|
||||||
constexpr auto kTopicsPerPage = 500;
|
constexpr auto kTopicsPerPage = 500;
|
||||||
constexpr auto kStalePerRequest = 100;
|
constexpr auto kStalePerRequest = 100;
|
||||||
constexpr auto kGeneralColorId = 0xA9A9A9;
|
// constexpr auto kGeneralColorId = 0xA9A9A9;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -113,8 +113,7 @@ void Forum::preloadTopics() {
|
||||||
void Forum::reloadTopics() {
|
void Forum::reloadTopics() {
|
||||||
_topicsList.setLoaded(false);
|
_topicsList.setLoaded(false);
|
||||||
session().api().request(base::take(_requestId)).cancel();
|
session().api().request(base::take(_requestId)).cancel();
|
||||||
_offsetDate = 0;
|
_offset = {};
|
||||||
_offsetId = _offsetTopicId = 0;
|
|
||||||
for (const auto &[rootId, topic] : _topics) {
|
for (const auto &[rootId, topic] : _topics) {
|
||||||
if (!topic->creating()) {
|
if (!topic->creating()) {
|
||||||
_staleRootIds.emplace(topic->rootId());
|
_staleRootIds.emplace(topic->rootId());
|
||||||
|
@ -127,18 +126,22 @@ void Forum::requestTopics() {
|
||||||
if (_topicsList.loaded() || _requestId) {
|
if (_topicsList.loaded() || _requestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto firstLoad = !_offsetDate;
|
const auto firstLoad = !_offset.date;
|
||||||
const auto loadCount = firstLoad ? kTopicsFirstLoad : kTopicsPerPage;
|
const auto loadCount = firstLoad ? kTopicsFirstLoad : kTopicsPerPage;
|
||||||
_requestId = session().api().request(MTPchannels_GetForumTopics(
|
_requestId = session().api().request(MTPchannels_GetForumTopics(
|
||||||
MTP_flags(0),
|
MTP_flags(0),
|
||||||
channel()->inputChannel,
|
channel()->inputChannel,
|
||||||
MTPstring(), // q
|
MTPstring(), // q
|
||||||
MTP_int(_offsetDate),
|
MTP_int(_offset.date),
|
||||||
MTP_int(_offsetId),
|
MTP_int(_offset.id),
|
||||||
MTP_int(_offsetTopicId),
|
MTP_int(_offset.topicId),
|
||||||
MTP_int(loadCount)
|
MTP_int(loadCount)
|
||||||
)).done([=](const MTPmessages_ForumTopics &result) {
|
)).done([=](const MTPmessages_ForumTopics &result) {
|
||||||
applyReceivedTopics(result, true);
|
applyReceivedTopics(result, _offset);
|
||||||
|
const auto &list = result.data().vtopics().v;
|
||||||
|
if (list.isEmpty() || list.size() == result.data().vcount().v) {
|
||||||
|
_topicsList.setLoaded();
|
||||||
|
}
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
_chatsListChanges.fire({});
|
_chatsListChanges.fire({});
|
||||||
if (_topicsList.loaded()) {
|
if (_topicsList.loaded()) {
|
||||||
|
@ -155,10 +158,6 @@ void Forum::requestTopics() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Forum::applyReceivedTopics(const MTPmessages_ForumTopics &result) {
|
|
||||||
applyReceivedTopics(result, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Forum::applyTopicDeleted(MsgId rootId) {
|
void Forum::applyTopicDeleted(MsgId rootId) {
|
||||||
_topicsDeleted.emplace(rootId);
|
_topicsDeleted.emplace(rootId);
|
||||||
|
|
||||||
|
@ -176,7 +175,19 @@ void Forum::applyTopicDeleted(MsgId rootId) {
|
||||||
|
|
||||||
void Forum::applyReceivedTopics(
|
void Forum::applyReceivedTopics(
|
||||||
const MTPmessages_ForumTopics &topics,
|
const MTPmessages_ForumTopics &topics,
|
||||||
bool updateOffset) {
|
ForumOffsets &updateOffsets) {
|
||||||
|
applyReceivedTopics(topics, [&](not_null<ForumTopic*> topic) {
|
||||||
|
if (const auto last = topic->lastServerMessage()) {
|
||||||
|
updateOffsets.date = last->date();
|
||||||
|
updateOffsets.id = last->id;
|
||||||
|
}
|
||||||
|
updateOffsets.topicId = topic->rootId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Forum::applyReceivedTopics(
|
||||||
|
const MTPmessages_ForumTopics &topics,
|
||||||
|
Fn<void(not_null<ForumTopic*>)> callback) {
|
||||||
const auto &data = topics.data();
|
const auto &data = topics.data();
|
||||||
owner().processUsers(data.vusers());
|
owner().processUsers(data.vusers());
|
||||||
owner().processChats(data.vchats());
|
owner().processChats(data.vchats());
|
||||||
|
@ -189,9 +200,6 @@ void Forum::applyReceivedTopics(
|
||||||
});
|
});
|
||||||
_staleRootIds.remove(rootId);
|
_staleRootIds.remove(rootId);
|
||||||
topic.match([&](const MTPDforumTopicDeleted &data) {
|
topic.match([&](const MTPDforumTopicDeleted &data) {
|
||||||
if (updateOffset) {
|
|
||||||
LOG(("API Error: Got a deleted topic in getForumTopics."));
|
|
||||||
}
|
|
||||||
applyTopicDeleted(rootId);
|
applyTopicDeleted(rootId);
|
||||||
}, [&](const MTPDforumTopic &data) {
|
}, [&](const MTPDforumTopic &data) {
|
||||||
_topicsDeleted.remove(rootId);
|
_topicsDeleted.remove(rootId);
|
||||||
|
@ -204,26 +212,18 @@ void Forum::applyReceivedTopics(
|
||||||
).first->second.get()
|
).first->second.get()
|
||||||
: i->second.get();
|
: i->second.get();
|
||||||
raw->applyTopic(data);
|
raw->applyTopic(data);
|
||||||
if (updateOffset) {
|
if (callback) {
|
||||||
if (const auto last = raw->lastServerMessage()) {
|
callback(raw);
|
||||||
_offsetDate = last->date();
|
|
||||||
_offsetId = last->id;
|
|
||||||
}
|
|
||||||
_offsetTopicId = rootId;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (updateOffset
|
|
||||||
&& (list.isEmpty() || list.size() == data.vcount().v)) {
|
|
||||||
_topicsList.setLoaded();
|
|
||||||
}
|
|
||||||
if (!_staleRootIds.empty()) {
|
if (!_staleRootIds.empty()) {
|
||||||
requestSomeStale();
|
requestSomeStale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Forum::requestSomeStale() {
|
void Forum::requestSomeStale() {
|
||||||
if (_staleRequestId || (!_offsetId && _requestId)) {
|
if (_staleRequestId || (!_offset.id && _requestId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto type = Histories::RequestType::History;
|
const auto type = Histories::RequestType::History;
|
||||||
|
|
|
@ -24,6 +24,16 @@ namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
|
||||||
|
struct ForumOffsets {
|
||||||
|
TimeId date = 0;
|
||||||
|
MsgId id = 0;
|
||||||
|
MsgId topicId = 0;
|
||||||
|
|
||||||
|
friend inline constexpr auto operator<=>(
|
||||||
|
ForumOffsets,
|
||||||
|
ForumOffsets) = default;
|
||||||
|
};
|
||||||
|
|
||||||
class Forum final {
|
class Forum final {
|
||||||
public:
|
public:
|
||||||
explicit Forum(not_null<History*> history);
|
explicit Forum(not_null<History*> history);
|
||||||
|
@ -57,7 +67,12 @@ public:
|
||||||
[[nodiscard]] ForumTopic *enforceTopicFor(MsgId rootId);
|
[[nodiscard]] ForumTopic *enforceTopicFor(MsgId rootId);
|
||||||
[[nodiscard]] bool topicDeleted(MsgId rootId) const;
|
[[nodiscard]] bool topicDeleted(MsgId rootId) const;
|
||||||
|
|
||||||
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
void applyReceivedTopics(
|
||||||
|
const MTPmessages_ForumTopics &topics,
|
||||||
|
ForumOffsets &updateOffsets);
|
||||||
|
void applyReceivedTopics(
|
||||||
|
const MTPmessages_ForumTopics &topics,
|
||||||
|
Fn<void(not_null<ForumTopic*>)> callback = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] MsgId reserveCreatingId(
|
[[nodiscard]] MsgId reserveCreatingId(
|
||||||
const QString &title,
|
const QString &title,
|
||||||
|
@ -84,10 +99,6 @@ private:
|
||||||
void requestSomeStale();
|
void requestSomeStale();
|
||||||
void finishTopicRequest(MsgId rootId);
|
void finishTopicRequest(MsgId rootId);
|
||||||
|
|
||||||
void applyReceivedTopics(
|
|
||||||
const MTPmessages_ForumTopics &topics,
|
|
||||||
bool updateOffset);
|
|
||||||
|
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
|
||||||
base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics;
|
base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics;
|
||||||
|
@ -100,9 +111,7 @@ private:
|
||||||
mtpRequestId _staleRequestId = 0;
|
mtpRequestId _staleRequestId = 0;
|
||||||
|
|
||||||
mtpRequestId _requestId = 0;
|
mtpRequestId _requestId = 0;
|
||||||
TimeId _offsetDate = 0;
|
ForumOffsets _offset;
|
||||||
MsgId _offsetId = 0;
|
|
||||||
MsgId _offsetTopicId = 0;
|
|
||||||
|
|
||||||
base::flat_set<MsgId> _creatingRootIds;
|
base::flat_set<MsgId> _creatingRootIds;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history_unread_things.h"
|
#include "history/history_unread_things.h"
|
||||||
#include "history/view/history_view_item_preview.h"
|
#include "history/view/history_view_item_preview.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/color_int_conversion.h"
|
#include "ui/color_int_conversion.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
@ -148,6 +149,7 @@ ForumTopic::ForumTopic(not_null<Forum*> forum, MsgId rootId)
|
||||||
rootId))
|
rootId))
|
||||||
, _rootId(rootId)
|
, _rootId(rootId)
|
||||||
, _lastKnownServerMessageId(rootId)
|
, _lastKnownServerMessageId(rootId)
|
||||||
|
, _creationDate(creating() ? base::unixtime::now() : 0)
|
||||||
, _flags(creating() ? Flag::My : Flag()) {
|
, _flags(creating() ? Flag::My : Flag()) {
|
||||||
Thread::setMuted(owner().notifySettings().isMuted(this));
|
Thread::setMuted(owner().notifySettings().isMuted(this));
|
||||||
|
|
||||||
|
@ -201,6 +203,10 @@ MsgId ForumTopic::rootId() const {
|
||||||
return _rootId;
|
return _rootId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeId ForumTopic::creationDate() const {
|
||||||
|
return _creationDate;
|
||||||
|
}
|
||||||
|
|
||||||
bool ForumTopic::my() const {
|
bool ForumTopic::my() const {
|
||||||
return (_flags & Flag::My);
|
return (_flags & Flag::My);
|
||||||
}
|
}
|
||||||
|
@ -261,6 +267,8 @@ void ForumTopic::readTillEnd() {
|
||||||
void ForumTopic::applyTopic(const MTPDforumTopic &data) {
|
void ForumTopic::applyTopic(const MTPDforumTopic &data) {
|
||||||
Expects(_rootId == data.vid().v);
|
Expects(_rootId == data.vid().v);
|
||||||
|
|
||||||
|
_creationDate = data.vdate().v;
|
||||||
|
|
||||||
applyTitle(qs(data.vtitle()));
|
applyTitle(qs(data.vtitle()));
|
||||||
if (const auto iconId = data.vicon_emoji_id()) {
|
if (const auto iconId = data.vicon_emoji_id()) {
|
||||||
applyIconId(iconId->v);
|
applyIconId(iconId->v);
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
[[nodiscard]] not_null<Forum*> forum() const;
|
[[nodiscard]] not_null<Forum*> forum() const;
|
||||||
[[nodiscard]] rpl::producer<> destroyed() const;
|
[[nodiscard]] rpl::producer<> destroyed() const;
|
||||||
[[nodiscard]] MsgId rootId() const;
|
[[nodiscard]] MsgId rootId() const;
|
||||||
|
[[nodiscard]] TimeId creationDate() const;
|
||||||
|
|
||||||
[[nodiscard]] bool my() const;
|
[[nodiscard]] bool my() const;
|
||||||
[[nodiscard]] bool canWrite() const;
|
[[nodiscard]] bool canWrite() const;
|
||||||
|
@ -171,6 +172,7 @@ private:
|
||||||
base::flat_set<QString> _titleWords;
|
base::flat_set<QString> _titleWords;
|
||||||
base::flat_set<QChar> _titleFirstLetters;
|
base::flat_set<QChar> _titleFirstLetters;
|
||||||
int _titleVersion = 0;
|
int _titleVersion = 0;
|
||||||
|
TimeId _creationDate = 0;
|
||||||
int32 _colorId = 0;
|
int32 _colorId = 0;
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
|
|
||||||
|
|
|
@ -2061,6 +2061,18 @@ void InnerWidget::onHashtagFilterUpdate(QStringView newFilter) {
|
||||||
clearMouseSelection(true);
|
clearMouseSelection(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerWidget::appendToFiltered(Key key) {
|
||||||
|
for (const auto &row : _filterResults) {
|
||||||
|
if (row->key() == key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto row = std::make_unique<Row>(key, _filterResults.size());
|
||||||
|
const auto [i, ok] = _filterResultsGlobal.emplace(key, std::move(row));
|
||||||
|
_filterResults.emplace_back(i->second.get());
|
||||||
|
trackSearchResultsHistory(key.owningHistory());
|
||||||
|
}
|
||||||
|
|
||||||
InnerWidget::~InnerWidget() {
|
InnerWidget::~InnerWidget() {
|
||||||
clearSearchResults();
|
clearSearchResults();
|
||||||
}
|
}
|
||||||
|
@ -2069,10 +2081,14 @@ void InnerWidget::clearSearchResults(bool clearPeerSearchResults) {
|
||||||
if (clearPeerSearchResults) _peerSearchResults.clear();
|
if (clearPeerSearchResults) _peerSearchResults.clear();
|
||||||
_searchResults.clear();
|
_searchResults.clear();
|
||||||
_searchResultsLifetime.destroy();
|
_searchResultsLifetime.destroy();
|
||||||
|
_searchResultsHistories.clear();
|
||||||
_searchedCount = _searchedMigratedCount = 0;
|
_searchedCount = _searchedMigratedCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::trackSearchResultsHistory(not_null<History*> history) {
|
void InnerWidget::trackSearchResultsHistory(not_null<History*> history) {
|
||||||
|
if (!_searchResultsHistories.emplace(history).second) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto channel = history->peer->asChannel();
|
const auto channel = history->peer->asChannel();
|
||||||
if (!channel || channel->isBroadcast()) {
|
if (!channel || channel->isBroadcast()) {
|
||||||
return;
|
return;
|
||||||
|
@ -2088,19 +2104,51 @@ void InnerWidget::trackSearchResultsHistory(not_null<History*> history) {
|
||||||
row->invalidateTopic();
|
row->invalidateTopic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto removed = false;
|
||||||
|
for (auto i = begin(_filterResultsGlobal)
|
||||||
|
; i != end(_filterResultsGlobal);) {
|
||||||
|
if (const auto topic = i->first.topic()) {
|
||||||
|
if (topic->channel() == channel) {
|
||||||
|
removed = true;
|
||||||
|
_filterResults.erase(
|
||||||
|
ranges::remove(_filterResults, i->first, &Row::key),
|
||||||
|
end(_filterResults));
|
||||||
|
i = _filterResultsGlobal.erase(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (removed) {
|
||||||
|
refresh();
|
||||||
|
clearMouseSelection(true);
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
}, _searchResultsLifetime);
|
}, _searchResultsLifetime);
|
||||||
|
|
||||||
if (const auto forum = channel->forum()) {
|
if (const auto forum = channel->forum()) {
|
||||||
forum->topicDestroyed(
|
forum->topicDestroyed(
|
||||||
) | rpl::start_with_next([=](not_null<Data::ForumTopic*> topic) {
|
) | rpl::start_with_next([=](not_null<Data::ForumTopic*> topic) {
|
||||||
const auto from = ranges::remove(
|
auto removed = false;
|
||||||
|
const auto sfrom = ranges::remove(
|
||||||
_searchResults,
|
_searchResults,
|
||||||
topic.get(),
|
topic.get(),
|
||||||
&FakeRow::topic);
|
&FakeRow::topic);
|
||||||
if (from != end(_searchResults)) {
|
if (sfrom != end(_searchResults)) {
|
||||||
_searchResults.erase(from, end(_searchResults));
|
_searchResults.erase(sfrom, end(_searchResults));
|
||||||
refresh(true);
|
removed = true;
|
||||||
|
}
|
||||||
|
const auto ffrom = ranges::remove(
|
||||||
|
_filterResults,
|
||||||
|
topic.get(),
|
||||||
|
&Row::topic);
|
||||||
|
if (ffrom != end(_filterResults)) {
|
||||||
|
_filterResults.erase(ffrom, end(_filterResults));
|
||||||
|
removed = true;
|
||||||
|
}
|
||||||
|
_filterResultsGlobal.erase(Key(topic));
|
||||||
|
if (removed) {
|
||||||
|
refresh();
|
||||||
clearMouseSelection(true);
|
clearMouseSelection(true);
|
||||||
}
|
}
|
||||||
}, _searchResultsLifetime);
|
}, _searchResultsLifetime);
|
||||||
|
@ -2133,6 +2181,10 @@ void InnerWidget::setLoadMoreCallback(Fn<void()> callback) {
|
||||||
_loadMoreCallback = std::move(callback);
|
_loadMoreCallback = std::move(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setLoadMoreFilteredCallback(Fn<void()> callback) {
|
||||||
|
_loadMoreFilteredCallback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
auto InnerWidget::chosenRow() const -> rpl::producer<ChosenRow> {
|
auto InnerWidget::chosenRow() const -> rpl::producer<ChosenRow> {
|
||||||
return _chosenRow.events();
|
return _chosenRow.events();
|
||||||
}
|
}
|
||||||
|
@ -2183,8 +2235,14 @@ void InnerWidget::visibleTopBottomUpdated(
|
||||||
_visibleTop = visibleTop;
|
_visibleTop = visibleTop;
|
||||||
_visibleBottom = visibleBottom;
|
_visibleBottom = visibleBottom;
|
||||||
loadPeerPhotos();
|
loadPeerPhotos();
|
||||||
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop)
|
const auto loadTill = _visibleTop
|
||||||
>= height()) {
|
+ PreloadHeightsCount * (_visibleBottom - _visibleTop);
|
||||||
|
if (_state == WidgetState::Filtered && loadTill >= peerSearchOffset()) {
|
||||||
|
if (_loadMoreFilteredCallback) {
|
||||||
|
_loadMoreFilteredCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loadTill >= height()) {
|
||||||
if (_loadMoreCallback) {
|
if (_loadMoreCallback) {
|
||||||
_loadMoreCallback();
|
_loadMoreCallback();
|
||||||
}
|
}
|
||||||
|
@ -2310,31 +2368,12 @@ void InnerWidget::peerSearchReceived(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto alreadyAdded = [&](not_null<PeerData*> peer) {
|
|
||||||
for (const auto &row : _filterResults) {
|
|
||||||
if (const auto history = row->history()) {
|
|
||||||
if (history->peer == peer) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
_peerSearchQuery = query.toLower().trimmed();
|
_peerSearchQuery = query.toLower().trimmed();
|
||||||
_peerSearchResults.clear();
|
_peerSearchResults.clear();
|
||||||
_peerSearchResults.reserve(result.size());
|
_peerSearchResults.reserve(result.size());
|
||||||
for (const auto &mtpPeer : my) {
|
for (const auto &mtpPeer : my) {
|
||||||
if (const auto peer = session().data().peerLoaded(peerFromMTP(mtpPeer))) {
|
if (const auto peer = session().data().peerLoaded(peerFromMTP(mtpPeer))) {
|
||||||
if (alreadyAdded(peer)) {
|
appendToFiltered(peer->owner().history(peer));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto row = std::make_unique<Row>(
|
|
||||||
peer->owner().history(peer),
|
|
||||||
_filterResults.size());
|
|
||||||
const auto [i, ok] = _filterResultsGlobal.emplace(
|
|
||||||
peer,
|
|
||||||
std::move(row));
|
|
||||||
_filterResults.emplace_back(i->second.get());
|
|
||||||
} else {
|
} else {
|
||||||
LOG(("API Error: "
|
LOG(("API Error: "
|
||||||
"user %1 was not loaded in InnerWidget::peopleReceived()"
|
"user %1 was not loaded in InnerWidget::peopleReceived()"
|
||||||
|
|
|
@ -131,10 +131,12 @@ public:
|
||||||
|
|
||||||
void applyFilterUpdate(QString newFilter, bool force = false);
|
void applyFilterUpdate(QString newFilter, bool force = false);
|
||||||
void onHashtagFilterUpdate(QStringView newFilter);
|
void onHashtagFilterUpdate(QStringView newFilter);
|
||||||
|
void appendToFiltered(Key key);
|
||||||
|
|
||||||
PeerData *updateFromParentDrag(QPoint globalPosition);
|
PeerData *updateFromParentDrag(QPoint globalPosition);
|
||||||
|
|
||||||
void setLoadMoreCallback(Fn<void()> callback);
|
void setLoadMoreCallback(Fn<void()> callback);
|
||||||
|
void setLoadMoreFilteredCallback(Fn<void()> callback);
|
||||||
[[nodiscard]] rpl::producer<> listBottomReached() const;
|
[[nodiscard]] rpl::producer<> listBottomReached() const;
|
||||||
[[nodiscard]] rpl::producer<> cancelSearchFromUserRequests() const;
|
[[nodiscard]] rpl::producer<> cancelSearchFromUserRequests() const;
|
||||||
[[nodiscard]] rpl::producer<ChosenRow> chosenRow() const;
|
[[nodiscard]] rpl::producer<ChosenRow> chosenRow() const;
|
||||||
|
@ -389,9 +391,7 @@ private:
|
||||||
bool _hashtagDeletePressed = false;
|
bool _hashtagDeletePressed = false;
|
||||||
|
|
||||||
std::vector<not_null<Row*>> _filterResults;
|
std::vector<not_null<Row*>> _filterResults;
|
||||||
base::flat_map<
|
base::flat_map<Key, std::unique_ptr<Row>> _filterResultsGlobal;
|
||||||
not_null<PeerData*>,
|
|
||||||
std::unique_ptr<Row>> _filterResultsGlobal;
|
|
||||||
int _filteredSelected = -1;
|
int _filteredSelected = -1;
|
||||||
int _filteredPressed = -1;
|
int _filteredPressed = -1;
|
||||||
|
|
||||||
|
@ -404,6 +404,7 @@ private:
|
||||||
int _peerSearchPressed = -1;
|
int _peerSearchPressed = -1;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<FakeRow>> _searchResults;
|
std::vector<std::unique_ptr<FakeRow>> _searchResults;
|
||||||
|
base::flat_set<not_null<History*>> _searchResultsHistories;
|
||||||
rpl::lifetime _searchResultsLifetime;
|
rpl::lifetime _searchResultsLifetime;
|
||||||
int _searchedCount = 0;
|
int _searchedCount = 0;
|
||||||
int _searchedMigratedCount = 0;
|
int _searchedMigratedCount = 0;
|
||||||
|
@ -432,6 +433,7 @@ private:
|
||||||
std::unique_ptr<Ui::VideoUserpic>> _videoUserpics;
|
std::unique_ptr<Ui::VideoUserpic>> _videoUserpics;
|
||||||
|
|
||||||
Fn<void()> _loadMoreCallback;
|
Fn<void()> _loadMoreCallback;
|
||||||
|
Fn<void()> _loadMoreFilteredCallback;
|
||||||
rpl::event_stream<> _listBottomReached;
|
rpl::event_stream<> _listBottomReached;
|
||||||
rpl::event_stream<ChosenRow> _chosenRow;
|
rpl::event_stream<ChosenRow> _chosenRow;
|
||||||
rpl::event_stream<> _updated;
|
rpl::event_stream<> _updated;
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
#include "dialogs/dialogs_entry.h"
|
#include "dialogs/dialogs_entry.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
#include "history/view/history_view_top_bar_widget.h"
|
#include "history/view/history_view_top_bar_widget.h"
|
||||||
#include "history/view/history_view_contact_status.h"
|
#include "history/view/history_view_contact_status.h"
|
||||||
#include "history/view/history_view_requests_bar.h"
|
#include "history/view/history_view_requests_bar.h"
|
||||||
|
@ -350,6 +351,14 @@ Widget::Widget(
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
_inner->setLoadMoreFilteredCallback([=] {
|
||||||
|
const auto state = _inner->state();
|
||||||
|
if (state == WidgetState::Filtered
|
||||||
|
&& !_topicSearchFull
|
||||||
|
&& searchForTopicsRequired(_topicSearchQuery)) {
|
||||||
|
searchTopics();
|
||||||
|
}
|
||||||
|
});
|
||||||
_inner->setLoadMoreCallback([=] {
|
_inner->setLoadMoreCallback([=] {
|
||||||
const auto state = _inner->state();
|
const auto state = _inner->state();
|
||||||
if (state == WidgetState::Filtered
|
if (state == WidgetState::Filtered
|
||||||
|
@ -358,7 +367,7 @@ Widget::Widget(
|
||||||
&& _searchFull
|
&& _searchFull
|
||||||
&& !_searchFullMigrated))) {
|
&& !_searchFullMigrated))) {
|
||||||
searchMore();
|
searchMore();
|
||||||
} else if (_openedForum) {
|
} else if (_openedForum && state == WidgetState::Default) {
|
||||||
_openedForum->forum()->requestTopics();
|
_openedForum->forum()->requestTopics();
|
||||||
} else {
|
} else {
|
||||||
const auto folder = _inner->shownFolder();
|
const auto folder = _inner->shownFolder();
|
||||||
|
@ -728,6 +737,7 @@ void Widget::changeOpenedSubsection(
|
||||||
refreshTopBars();
|
refreshTopBars();
|
||||||
updateControlsVisibility(true);
|
updateControlsVisibility(true);
|
||||||
_peerSearchRequest = 0;
|
_peerSearchRequest = 0;
|
||||||
|
_api.request(base::take(_topicSearchRequest)).cancel();
|
||||||
if (animated == anim::type::normal) {
|
if (animated == anim::type::normal) {
|
||||||
_connecting->setForceHidden(true);
|
_connecting->setForceHidden(true);
|
||||||
_cacheOver = grabForFolderSlideAnimation();
|
_cacheOver = grabForFolderSlideAnimation();
|
||||||
|
@ -749,6 +759,7 @@ void Widget::changeOpenedForum(ChannelData *forum, anim::type animated) {
|
||||||
cancelSearch();
|
cancelSearch();
|
||||||
}
|
}
|
||||||
_openedForum = forum;
|
_openedForum = forum;
|
||||||
|
_api.request(base::take(_topicSearchRequest)).cancel();
|
||||||
_inner->changeOpenedForum(forum);
|
_inner->changeOpenedForum(forum);
|
||||||
}, (forum != nullptr), animated);
|
}, (forum != nullptr), animated);
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1168,7 @@ bool Widget::searchMessages(bool searchCache) {
|
||||||
if (q.isEmpty() && !_searchFromAuthor) {
|
if (q.isEmpty() && !_searchFromAuthor) {
|
||||||
cancelSearchRequest();
|
cancelSearchRequest();
|
||||||
_api.request(base::take(_peerSearchRequest)).cancel();
|
_api.request(base::take(_peerSearchRequest)).cancel();
|
||||||
|
_api.request(base::take(_topicSearchRequest)).cancel();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (searchCache) {
|
if (searchCache) {
|
||||||
|
@ -1284,14 +1296,36 @@ bool Widget::searchMessages(bool searchCache) {
|
||||||
MTP_vector<MTPUser>(0)),
|
MTP_vector<MTPUser>(0)),
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
if (searchForTopicsRequired(query)) {
|
||||||
|
if (searchCache) {
|
||||||
|
if (_topicSearchQuery != query) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
} else if (_topicSearchQuery != query) {
|
||||||
|
_topicSearchQuery = query;
|
||||||
|
_topicSearchFull = false;
|
||||||
|
searchTopics();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_topicSearchQuery = query;
|
||||||
|
_topicSearchFull = true;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::searchForPeersRequired(const QString &query) const {
|
bool Widget::searchForPeersRequired(const QString &query) const {
|
||||||
if (_searchInChat || _openedForum || query.isEmpty()) {
|
return !_searchInChat
|
||||||
return false;
|
&& !_openedForum
|
||||||
}
|
&& !query.isEmpty()
|
||||||
return (query[0] != '#');
|
&& (query[0] != '#');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::searchForTopicsRequired(const QString &query) const {
|
||||||
|
return !_searchInChat
|
||||||
|
&& _openedForum
|
||||||
|
&& !query.isEmpty()
|
||||||
|
&& (query[0] != '#')
|
||||||
|
&& !_openedForum->forum()->topicsList()->loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::needSearchMessages() {
|
void Widget::needSearchMessages() {
|
||||||
|
@ -1337,6 +1371,45 @@ void Widget::searchMessages(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::searchTopics() {
|
||||||
|
if (_topicSearchRequest || _topicSearchFull) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_api.request(base::take(_topicSearchRequest)).cancel();
|
||||||
|
_topicSearchRequest = _api.request(MTPchannels_GetForumTopics(
|
||||||
|
MTP_flags(MTPchannels_GetForumTopics::Flag::f_q),
|
||||||
|
_openedForum->inputChannel,
|
||||||
|
MTP_string(_topicSearchQuery),
|
||||||
|
MTP_int(_topicSearchOffsetDate),
|
||||||
|
MTP_int(_topicSearchOffsetId),
|
||||||
|
MTP_int(_topicSearchOffsetTopicId),
|
||||||
|
MTP_int(kSearchPerPage)
|
||||||
|
)).done([=](const MTPmessages_ForumTopics &result) {
|
||||||
|
_topicSearchRequest = 0;
|
||||||
|
const auto savedTopicId = _topicSearchOffsetId;
|
||||||
|
const auto byCreation = result.data().is_order_by_create_date();
|
||||||
|
_openedForum->forum()->applyReceivedTopics(result, [&](
|
||||||
|
not_null<Data::ForumTopic*> topic) {
|
||||||
|
_topicSearchOffsetTopicId = topic->rootId();
|
||||||
|
if (byCreation) {
|
||||||
|
_topicSearchOffsetId = _topicSearchOffsetTopicId;
|
||||||
|
_topicSearchOffsetDate = topic->creationDate();
|
||||||
|
} else if (const auto last = topic->lastServerMessage()) {
|
||||||
|
_topicSearchOffsetId = last->id;
|
||||||
|
_topicSearchOffsetDate = last->date();
|
||||||
|
}
|
||||||
|
_inner->appendToFiltered(topic);
|
||||||
|
});
|
||||||
|
if (_topicSearchOffsetTopicId != savedTopicId) {
|
||||||
|
_inner->refresh();
|
||||||
|
} else {
|
||||||
|
_topicSearchFull = true;
|
||||||
|
}
|
||||||
|
}).fail([=] {
|
||||||
|
_topicSearchFull = true;
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::searchMore() {
|
void Widget::searchMore() {
|
||||||
if (_searchRequest || _searchInHistoryRequest) {
|
if (_searchRequest || _searchInHistoryRequest) {
|
||||||
return;
|
return;
|
||||||
|
@ -1833,6 +1906,11 @@ void Widget::clearSearchCache() {
|
||||||
}
|
}
|
||||||
_searchQuery = QString();
|
_searchQuery = QString();
|
||||||
_searchQueryFrom = nullptr;
|
_searchQueryFrom = nullptr;
|
||||||
|
_topicSearchQuery = QString();
|
||||||
|
_topicSearchOffsetDate = 0;
|
||||||
|
_topicSearchOffsetId = _topicSearchOffsetTopicId = 0;
|
||||||
|
_api.request(base::take(_peerSearchRequest)).cancel();
|
||||||
|
_api.request(base::take(_topicSearchRequest)).cancel();
|
||||||
cancelSearchRequest();
|
cancelSearchRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
void scrollToEntry(const RowDescriptor &entry);
|
void scrollToEntry(const RowDescriptor &entry);
|
||||||
|
|
||||||
void searchMessages(const QString &query, Key inChat = {});
|
void searchMessages(const QString &query, Key inChat = {});
|
||||||
|
void searchTopics();
|
||||||
void searchMore();
|
void searchMore();
|
||||||
|
|
||||||
void updateForwardBar();
|
void updateForwardBar();
|
||||||
|
@ -150,7 +151,8 @@ private:
|
||||||
void setupMainMenuToggle();
|
void setupMainMenuToggle();
|
||||||
void setupDownloadBar();
|
void setupDownloadBar();
|
||||||
void setupShortcuts();
|
void setupShortcuts();
|
||||||
bool searchForPeersRequired(const QString &query) const;
|
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
||||||
|
[[nodiscard]] bool searchForTopicsRequired(const QString &query) const;
|
||||||
void setSearchInChat(Key chat, PeerData *from = nullptr);
|
void setSearchInChat(Key chat, PeerData *from = nullptr);
|
||||||
void showCalendar();
|
void showCalendar();
|
||||||
void showSearchFrom();
|
void showSearchFrom();
|
||||||
|
@ -244,6 +246,13 @@ private:
|
||||||
bool _peerSearchFull = false;
|
bool _peerSearchFull = false;
|
||||||
mtpRequestId _peerSearchRequest = 0;
|
mtpRequestId _peerSearchRequest = 0;
|
||||||
|
|
||||||
|
QString _topicSearchQuery;
|
||||||
|
TimeId _topicSearchOffsetDate = 0;
|
||||||
|
MsgId _topicSearchOffsetId = 0;
|
||||||
|
MsgId _topicSearchOffsetTopicId = 0;
|
||||||
|
bool _topicSearchFull = false;
|
||||||
|
mtpRequestId _topicSearchRequest = 0;
|
||||||
|
|
||||||
QString _searchQuery;
|
QString _searchQuery;
|
||||||
PeerData *_searchQueryFrom = nullptr;
|
PeerData *_searchQueryFrom = nullptr;
|
||||||
int32 _searchNextRate = 0;
|
int32 _searchNextRate = 0;
|
||||||
|
|
|
@ -624,9 +624,13 @@ void PaintRow(
|
||||||
} else {
|
} else {
|
||||||
p.setPen(context.active
|
p.setPen(context.active
|
||||||
? st::dialogsNameFgActive
|
? st::dialogsNameFgActive
|
||||||
: context.selected
|
: entry->folder()
|
||||||
? st::dialogsArchiveFgOver
|
? (context.selected
|
||||||
: st::dialogsArchiveFg);
|
? st::dialogsArchiveFgOver
|
||||||
|
: st::dialogsArchiveFg)
|
||||||
|
: (context.selected
|
||||||
|
? st::dialogsNameFgOver
|
||||||
|
: st::dialogsNameFg));
|
||||||
auto text = entry->chatListName(); // TODO feed name with emoji
|
auto text = entry->chatListName(); // TODO feed name with emoji
|
||||||
auto textWidth = st::semiboldFont->width(text);
|
auto textWidth = st::semiboldFont->width(text);
|
||||||
if (textWidth > rectForName.width()) {
|
if (textWidth > rectForName.width()) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue