mirror of https://github.com/procxx/kepka.git
Add global search by username in block user box.
This commit is contained in:
parent
46dab1a6b4
commit
2ce2a14228
|
@ -152,9 +152,9 @@ void PeerListBox::refreshRows() {
|
||||||
_inner->refreshRows();
|
_inner->refreshRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerListBox::setSearchable(bool searchable) {
|
void PeerListBox::setSearchMode(SearchMode mode) {
|
||||||
_inner->setSearchable(searchable);
|
_inner->setSearchMode(mode);
|
||||||
if (searchable) {
|
if (mode != SearchMode::None) {
|
||||||
if (!_select) {
|
if (!_select) {
|
||||||
_select = createMultiSelect();
|
_select = createMultiSelect();
|
||||||
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); });
|
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); });
|
||||||
|
@ -180,6 +180,18 @@ void PeerListBox::setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoResults)
|
||||||
_inner->setSearchNoResults(std::move(searchNoResults));
|
_inner->setSearchNoResults(std::move(searchNoResults));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerListBox::setSearchLoadingText(const QString &searchLoadingText) {
|
||||||
|
if (searchLoadingText.isEmpty()) {
|
||||||
|
setSearchLoading(nullptr);
|
||||||
|
} else {
|
||||||
|
setSearchLoading(object_ptr<Ui::FlatLabel>(this, searchLoadingText, Ui::FlatLabel::InitType::Simple, st::membersAbout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerListBox::setSearchLoading(object_ptr<Ui::FlatLabel> searchLoading) {
|
||||||
|
_inner->setSearchLoading(std::move(searchLoading));
|
||||||
|
}
|
||||||
|
|
||||||
PeerListBox::Row::Row(PeerData *peer) : _peer(peer) {
|
PeerListBox::Row::Row(PeerData *peer) : _peer(peer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,14 +306,34 @@ void PeerListBox::Inner::appendRow(std::unique_ptr<Row> row) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerListBox::Inner::appendGlobalSearchRow(std::unique_ptr<Row> row) {
|
||||||
|
t_assert(showingSearch());
|
||||||
|
if (_rowsByPeer.find(row->peer()) == _rowsByPeer.cend()) {
|
||||||
|
row->setAbsoluteIndex(_globalSearchRows.size());
|
||||||
|
row->setIsGlobalSearchResult(true);
|
||||||
|
addRowEntry(row.get());
|
||||||
|
_filterResults.push_back(row.get());
|
||||||
|
_globalSearchRows.push_back(std::move(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::addRowEntry(Row *row) {
|
void PeerListBox::Inner::addRowEntry(Row *row) {
|
||||||
_rowsByPeer.emplace(row->peer(), row);
|
_rowsByPeer.emplace(row->peer(), row);
|
||||||
if (_searchable) {
|
if (addingToSearchIndex()) {
|
||||||
addToSearchIndex(row);
|
addToSearchIndex(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PeerListBox::Inner::addingToSearchIndex() const {
|
||||||
|
// If we started indexing already, we continue.
|
||||||
|
return (_searchMode != SearchMode::None) || !_searchIndex.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::addToSearchIndex(Row *row) {
|
void PeerListBox::Inner::addToSearchIndex(Row *row) {
|
||||||
|
if (row->isGlobalSearchResult()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
removeFromSearchIndex(row);
|
removeFromSearchIndex(row);
|
||||||
row->setNameFirstChars(row->peer()->chars);
|
row->setNameFirstChars(row->peer()->chars);
|
||||||
for_const (auto ch, row->nameFirstChars()) {
|
for_const (auto ch, row->nameFirstChars()) {
|
||||||
|
@ -348,20 +380,21 @@ PeerListBox::Row *PeerListBox::Inner::findRow(PeerData *peer) {
|
||||||
|
|
||||||
void PeerListBox::Inner::removeRow(Row *row) {
|
void PeerListBox::Inner::removeRow(Row *row) {
|
||||||
auto index = row->absoluteIndex();
|
auto index = row->absoluteIndex();
|
||||||
t_assert(index >= 0 && index < _rows.size());
|
auto isGlobalSearchResult = row->isGlobalSearchResult();
|
||||||
t_assert(_rows[index].get() == row);
|
auto &eraseFrom = isGlobalSearchResult ? _globalSearchRows : _rows;
|
||||||
|
|
||||||
|
t_assert(index >= 0 && index < eraseFrom.size());
|
||||||
|
t_assert(eraseFrom[index].get() == row);
|
||||||
|
|
||||||
setSelected(Selected());
|
setSelected(Selected());
|
||||||
setPressed(Selected());
|
setPressed(Selected());
|
||||||
|
|
||||||
_rowsByPeer.erase(row->peer());
|
_rowsByPeer.erase(row->peer());
|
||||||
if (_searchable) {
|
removeFromSearchIndex(row);
|
||||||
removeFromSearchIndex(row);
|
|
||||||
}
|
|
||||||
_filterResults.erase(std::find(_filterResults.begin(), _filterResults.end(), row), _filterResults.end());
|
_filterResults.erase(std::find(_filterResults.begin(), _filterResults.end(), row), _filterResults.end());
|
||||||
_rows.erase(_rows.begin() + index);
|
eraseFrom.erase(eraseFrom.begin() + index);
|
||||||
for (auto i = index, count = int(_rows.size()); i != count; ++i) {
|
for (auto i = index, count = int(eraseFrom.size()); i != count; ++i) {
|
||||||
_rows[i]->setAbsoluteIndex(i);
|
eraseFrom[i]->setAbsoluteIndex(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreSelection();
|
restoreSelection();
|
||||||
|
@ -379,16 +412,22 @@ void PeerListBox::Inner::setAbout(object_ptr<Ui::FlatLabel> about) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int PeerListBox::Inner::labelHeight() const {
|
int PeerListBox::Inner::labelHeight() const {
|
||||||
if (showingSearch()) {
|
auto computeLabelHeight = [](auto &label) {
|
||||||
if (_filterResults.empty() && _searchNoResults) {
|
if (!label) {
|
||||||
return st::membersAboutLimitPadding.top() + _searchNoResults->height() + st::membersAboutLimitPadding.bottom();
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return st::membersAboutLimitPadding.top() + label->height() + st::membersAboutLimitPadding.bottom();
|
||||||
|
};
|
||||||
|
if (showingSearch()) {
|
||||||
|
if (!_filterResults.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (globalSearchLoading()) {
|
||||||
|
return computeLabelHeight(_searchLoading);
|
||||||
|
}
|
||||||
|
return computeLabelHeight(_searchNoResults);
|
||||||
}
|
}
|
||||||
if (_about) {
|
return computeLabelHeight(_about);
|
||||||
return st::membersAboutLimitPadding.top() + _about->height() + st::membersAboutLimitPadding.bottom();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::refreshRows() {
|
void PeerListBox::Inner::refreshRows() {
|
||||||
|
@ -400,7 +439,11 @@ void PeerListBox::Inner::refreshRows() {
|
||||||
}
|
}
|
||||||
if (_searchNoResults) {
|
if (_searchNoResults) {
|
||||||
_searchNoResults->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top());
|
_searchNoResults->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top());
|
||||||
_searchNoResults->setVisible(showingSearch() && _filterResults.empty());
|
_searchNoResults->setVisible(showingSearch() && _filterResults.empty() && !globalSearchLoading());
|
||||||
|
}
|
||||||
|
if (_searchLoading) {
|
||||||
|
_searchLoading->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top());
|
||||||
|
_searchLoading->setVisible(showingSearch() && _filterResults.empty() && globalSearchLoading());
|
||||||
}
|
}
|
||||||
if (_visibleBottom > 0) {
|
if (_visibleBottom > 0) {
|
||||||
checkScrollForPreload();
|
checkScrollForPreload();
|
||||||
|
@ -408,13 +451,27 @@ void PeerListBox::Inner::refreshRows() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::setSearchable(bool searchable) {
|
void PeerListBox::Inner::setSearchMode(SearchMode mode) {
|
||||||
// We don't destroy a search index if we have one already.
|
if (_searchMode != mode) {
|
||||||
if (searchable && !_searchable) {
|
if (!addingToSearchIndex()) {
|
||||||
_searchable = true;
|
for_const (auto &row, _rows) {
|
||||||
for_const (auto &row, _rows) {
|
addToSearchIndex(row.get());
|
||||||
addToSearchIndex(row.get());
|
}
|
||||||
}
|
}
|
||||||
|
_searchMode = mode;
|
||||||
|
if (_searchMode == SearchMode::Global) {
|
||||||
|
if (!_searchLoading) {
|
||||||
|
setSearchLoading(object_ptr<Ui::FlatLabel>(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearGlobalSearchRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerListBox::Inner::clearGlobalSearchRows() {
|
||||||
|
while (!_globalSearchRows.empty()) {
|
||||||
|
removeRow(_globalSearchRows.back().get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,6 +482,13 @@ void PeerListBox::Inner::setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoRe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerListBox::Inner::setSearchLoading(object_ptr<Ui::FlatLabel> searchLoading) {
|
||||||
|
_searchLoading = std::move(searchLoading);
|
||||||
|
if (_searchLoading) {
|
||||||
|
_searchLoading->setParent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::paintEvent(QPaintEvent *e) {
|
void PeerListBox::Inner::paintEvent(QPaintEvent *e) {
|
||||||
QRect r(e->rect());
|
QRect r(e->rect());
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
@ -545,10 +609,37 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||||
p.drawTextRight(actionRight, actionTop, width(), row->action(), actionWidth);
|
p.drawTextRight(actionRight, actionTop, width(), row->action(), actionWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto statusHasOnlineColor = (row->statusType() == Row::StatusType::Online);
|
|
||||||
p.setFont(st::contactsStatusFont);
|
p.setFont(st::contactsStatusFont);
|
||||||
p.setPen(statusHasOnlineColor ? st::contactsStatusFgOnline : (selected ? st::contactsStatusFgOver : st::contactsStatusFg));
|
if (row->isGlobalSearchResult() && !peer->userName().isEmpty()) {
|
||||||
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), row->status());
|
auto username = peer->userName();
|
||||||
|
if (!_globalSearchHighlight.isEmpty() && username.startsWith(_globalSearchHighlight, Qt::CaseInsensitive)) {
|
||||||
|
auto availableWidth = width() - namex - st::contactsPadding.right();
|
||||||
|
auto highlightedPart = '@' + username.mid(0, _globalSearchHighlight.size());
|
||||||
|
auto grayedPart = username.mid(_globalSearchHighlight.size());
|
||||||
|
auto highlightedWidth = st::contactsStatusFont->width(highlightedPart);
|
||||||
|
if (highlightedWidth >= availableWidth || grayedPart.isEmpty()) {
|
||||||
|
if (highlightedWidth > availableWidth) {
|
||||||
|
highlightedPart = st::contactsStatusFont->elided(highlightedPart, availableWidth);
|
||||||
|
}
|
||||||
|
p.setPen(st::contactsStatusFgOnline);
|
||||||
|
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), highlightedPart);
|
||||||
|
} else {
|
||||||
|
grayedPart = st::contactsStatusFont->elided(grayedPart, availableWidth - highlightedWidth);
|
||||||
|
auto grayedWidth = st::contactsStatusFont->width(grayedPart);
|
||||||
|
p.setPen(st::contactsStatusFgOnline);
|
||||||
|
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), highlightedPart);
|
||||||
|
p.setPen(selected ? st::contactsStatusFgOver : st::contactsStatusFg);
|
||||||
|
p.drawTextLeft(namex + highlightedWidth, st::contactsPadding.top() + st::contactsStatusTop, width(), grayedPart);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.setPen(st::contactsStatusFgOnline);
|
||||||
|
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), '@' + username);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto statusHasOnlineColor = (row->statusType() == Row::StatusType::Online);
|
||||||
|
p.setPen(statusHasOnlineColor ? st::contactsStatusFgOnline : (selected ? st::contactsStatusFgOver : st::contactsStatusFg));
|
||||||
|
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), row->status());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::selectSkip(int direction) {
|
void PeerListBox::Inner::selectSkip(int direction) {
|
||||||
|
@ -664,6 +755,7 @@ void PeerListBox::Inner::searchQueryChanged(QString query) {
|
||||||
|
|
||||||
_searchQuery = query;
|
_searchQuery = query;
|
||||||
_filterResults.clear();
|
_filterResults.clear();
|
||||||
|
clearGlobalSearchRows();
|
||||||
if (!searchWordsList.isEmpty()) {
|
if (!searchWordsList.isEmpty()) {
|
||||||
auto minimalList = (const std::vector<Row*>*)nullptr;
|
auto minimalList = (const std::vector<Row*>*)nullptr;
|
||||||
for_const (auto &searchWord, searchWordsList) {
|
for_const (auto &searchWord, searchWordsList) {
|
||||||
|
@ -703,11 +795,96 @@ void PeerListBox::Inner::searchQueryChanged(QString query) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_searchMode == SearchMode::Global) {
|
||||||
|
needGlobalSearch();
|
||||||
|
}
|
||||||
refreshRows();
|
refreshRows();
|
||||||
restoreSelection();
|
restoreSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerListBox::Inner::needGlobalSearch() {
|
||||||
|
if (!globalSearchInCache()) {
|
||||||
|
if (!_globalSearchTimer) {
|
||||||
|
_globalSearchTimer = object_ptr<SingleTimer>(this);
|
||||||
|
_globalSearchTimer->setTimeoutHandler([this] { globalSearchOnServer(); });
|
||||||
|
}
|
||||||
|
_globalSearchTimer->start(AutoSearchTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerListBox::Inner::globalSearchInCache() {
|
||||||
|
auto it = _globalSearchCache.find(_searchQuery);
|
||||||
|
if (it != _globalSearchCache.cend()) {
|
||||||
|
_globalSearchQuery = _searchQuery;
|
||||||
|
_globalSearchRequestId = 0;
|
||||||
|
globalSearchDone(it->second, _globalSearchRequestId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerListBox::Inner::globalSearchOnServer() {
|
||||||
|
_globalSearchQuery = _searchQuery;
|
||||||
|
_globalSearchRequestId = MTP::send(MTPcontacts_Search(MTP_string(_globalSearchQuery), MTP_int(SearchPeopleLimit)), ::rpcDone(base::lambda_guarded(this, [this](const MTPcontacts_Found &result, mtpRequestId requestId) {
|
||||||
|
globalSearchDone(result, requestId);
|
||||||
|
})), ::rpcFail(base::lambda_guarded(this, [this](const RPCError &error, mtpRequestId requestId) {
|
||||||
|
return globalSearchFail(error, requestId);
|
||||||
|
})));
|
||||||
|
_globalSearchQueries.emplace(_globalSearchRequestId, _globalSearchQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerListBox::Inner::globalSearchDone(const MTPcontacts_Found &result, mtpRequestId requestId) {
|
||||||
|
auto query = _globalSearchQuery;
|
||||||
|
auto it = _globalSearchQueries.find(requestId);
|
||||||
|
if (it != _globalSearchQueries.cend()) {
|
||||||
|
query = it->second;
|
||||||
|
_globalSearchCache[query] = result;
|
||||||
|
_globalSearchQueries.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_globalSearchRequestId == requestId) {
|
||||||
|
_globalSearchRequestId = 0;
|
||||||
|
if (result.type() == mtpc_contacts_found) {
|
||||||
|
auto &contacts = result.c_contacts_found();
|
||||||
|
App::feedUsers(contacts.vusers);
|
||||||
|
App::feedChats(contacts.vchats);
|
||||||
|
|
||||||
|
_globalSearchHighlight = query;
|
||||||
|
if (!_globalSearchHighlight.isEmpty() && _globalSearchHighlight[0] == '@') {
|
||||||
|
_globalSearchHighlight = _globalSearchHighlight.mid(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for_const (auto &mtpPeer, contacts.vresults.v) {
|
||||||
|
if (auto peer = App::peerLoaded(peerFromMTP(mtpPeer))) {
|
||||||
|
if (findRow(peer)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (auto row = _controller->createGlobalRow(peer)) {
|
||||||
|
appendGlobalSearchRow(std::move(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refreshRows();
|
||||||
|
updateSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerListBox::Inner::globalSearchFail(const RPCError &error, mtpRequestId requestId) {
|
||||||
|
if (MTP::isDefaultHandledError(error)) return false;
|
||||||
|
|
||||||
|
if (_globalSearchRequestId == requestId) {
|
||||||
|
_globalSearchRequestId = 0;
|
||||||
|
refreshRows();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerListBox::Inner::globalSearchLoading() const {
|
||||||
|
return (_globalSearchTimer && _globalSearchTimer->isActive()) || _globalSearchRequestId;
|
||||||
|
}
|
||||||
|
|
||||||
void PeerListBox::Inner::submitted() {
|
void PeerListBox::Inner::submitted() {
|
||||||
if (auto row = getRow(_selected.index)) {
|
if (auto row = getRow(_selected.index)) {
|
||||||
_controller->rowClicked(row->peer());
|
_controller->rowClicked(row->peer());
|
||||||
|
@ -834,6 +1011,7 @@ PeerListBox::Row *PeerListBox::Inner::getRow(RowIndex index) {
|
||||||
|
|
||||||
PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(Row *row, RowIndex hint) {
|
PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(Row *row, RowIndex hint) {
|
||||||
if (!showingSearch()) {
|
if (!showingSearch()) {
|
||||||
|
t_assert(!row->isGlobalSearchResult());
|
||||||
return RowIndex(row->absoluteIndex());
|
return RowIndex(row->absoluteIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,7 +1032,7 @@ PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(Row *row, RowIndex
|
||||||
|
|
||||||
void PeerListBox::Inner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
void PeerListBox::Inner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
|
||||||
if (auto row = findRow(peer)) {
|
if (auto row = findRow(peer)) {
|
||||||
if (_searchable) {
|
if (addingToSearchIndex()) {
|
||||||
addToSearchIndex(row);
|
addToSearchIndex(row);
|
||||||
}
|
}
|
||||||
row->refreshName();
|
row->refreshName();
|
||||||
|
|
|
@ -83,6 +83,12 @@ public:
|
||||||
bool disabled() const {
|
bool disabled() const {
|
||||||
return _disabled;
|
return _disabled;
|
||||||
}
|
}
|
||||||
|
bool isGlobalSearchResult() const {
|
||||||
|
return _isGlobalSearchResult;
|
||||||
|
}
|
||||||
|
void setIsGlobalSearchResult(bool isGlobalSearchResult) {
|
||||||
|
_isGlobalSearchResult = isGlobalSearchResult;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename UpdateCallback>
|
template <typename UpdateCallback>
|
||||||
void addRipple(QSize size, QPoint point, UpdateCallback updateCallback);
|
void addRipple(QSize size, QPoint point, UpdateCallback updateCallback);
|
||||||
|
@ -110,6 +116,7 @@ public:
|
||||||
bool _disabled = false;
|
bool _disabled = false;
|
||||||
int _absoluteIndex = -1;
|
int _absoluteIndex = -1;
|
||||||
OrderedSet<QChar> _nameFirstChars;
|
OrderedSet<QChar> _nameFirstChars;
|
||||||
|
bool _isGlobalSearchResult = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,6 +128,9 @@ public:
|
||||||
}
|
}
|
||||||
virtual void preloadRows() {
|
virtual void preloadRows() {
|
||||||
}
|
}
|
||||||
|
virtual std::unique_ptr<Row> createGlobalRow(PeerData *peer) {
|
||||||
|
return std::unique_ptr<Row>();
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~Controller() = default;
|
virtual ~Controller() = default;
|
||||||
|
|
||||||
|
@ -152,9 +162,16 @@ public:
|
||||||
void setAboutText(const QString &aboutText);
|
void setAboutText(const QString &aboutText);
|
||||||
void setAbout(object_ptr<Ui::FlatLabel> about);
|
void setAbout(object_ptr<Ui::FlatLabel> about);
|
||||||
void refreshRows();
|
void refreshRows();
|
||||||
void setSearchable(bool searchable);
|
enum class SearchMode {
|
||||||
|
None,
|
||||||
|
Local,
|
||||||
|
Global,
|
||||||
|
};
|
||||||
|
void setSearchMode(SearchMode mode);
|
||||||
void setSearchNoResultsText(const QString &noResultsText);
|
void setSearchNoResultsText(const QString &noResultsText);
|
||||||
void setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoResults);
|
void setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoResults);
|
||||||
|
void setSearchLoadingText(const QString &searchLoadingText);
|
||||||
|
void setSearchLoading(object_ptr<Ui::FlatLabel> searchLoading);
|
||||||
|
|
||||||
// callback takes two iterators, like [](auto &begin, auto &end).
|
// callback takes two iterators, like [](auto &begin, auto &end).
|
||||||
template <typename ReorderCallback>
|
template <typename ReorderCallback>
|
||||||
|
@ -212,8 +229,9 @@ public:
|
||||||
int fullRowsCount() const;
|
int fullRowsCount() const;
|
||||||
void setAbout(object_ptr<Ui::FlatLabel> about);
|
void setAbout(object_ptr<Ui::FlatLabel> about);
|
||||||
void refreshRows();
|
void refreshRows();
|
||||||
void setSearchable(bool searchable);
|
void setSearchMode(SearchMode mode);
|
||||||
void setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoResults);
|
void setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoResults);
|
||||||
|
void setSearchLoading(object_ptr<Ui::FlatLabel> searchLoading);
|
||||||
|
|
||||||
template <typename ReorderCallback>
|
template <typename ReorderCallback>
|
||||||
void reorderRows(ReorderCallback &&callback) {
|
void reorderRows(ReorderCallback &&callback) {
|
||||||
|
@ -241,6 +259,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshIndices();
|
void refreshIndices();
|
||||||
|
void appendGlobalSearchRow(std::unique_ptr<Row> row);
|
||||||
|
|
||||||
struct RowIndex {
|
struct RowIndex {
|
||||||
RowIndex() = default;
|
RowIndex() = default;
|
||||||
|
@ -289,6 +308,7 @@ private:
|
||||||
|
|
||||||
void addRowEntry(Row *row);
|
void addRowEntry(Row *row);
|
||||||
void addToSearchIndex(Row *row);
|
void addToSearchIndex(Row *row);
|
||||||
|
bool addingToSearchIndex() const;
|
||||||
void removeFromSearchIndex(Row *row);
|
void removeFromSearchIndex(Row *row);
|
||||||
bool showingSearch() const {
|
bool showingSearch() const {
|
||||||
return !_searchQuery.isEmpty();
|
return !_searchQuery.isEmpty();
|
||||||
|
@ -303,6 +323,14 @@ private:
|
||||||
|
|
||||||
int labelHeight() const;
|
int labelHeight() const;
|
||||||
|
|
||||||
|
void needGlobalSearch();
|
||||||
|
bool globalSearchInCache();
|
||||||
|
void globalSearchOnServer();
|
||||||
|
void globalSearchDone(const MTPcontacts_Found &result, mtpRequestId requestId);
|
||||||
|
bool globalSearchFail(const RPCError &error, mtpRequestId requestId);
|
||||||
|
bool globalSearchLoading() const;
|
||||||
|
void clearGlobalSearchRows();
|
||||||
|
|
||||||
Controller *_controller = nullptr;
|
Controller *_controller = nullptr;
|
||||||
int _rowHeight = 0;
|
int _rowHeight = 0;
|
||||||
int _visibleTop = 0;
|
int _visibleTop = 0;
|
||||||
|
@ -315,14 +343,23 @@ private:
|
||||||
std::vector<std::unique_ptr<Row>> _rows;
|
std::vector<std::unique_ptr<Row>> _rows;
|
||||||
std::map<PeerData*, Row*> _rowsByPeer;
|
std::map<PeerData*, Row*> _rowsByPeer;
|
||||||
|
|
||||||
bool _searchable = false;
|
SearchMode _searchMode = SearchMode::None;
|
||||||
std::map<QChar, std::vector<Row*>> _searchIndex;
|
std::map<QChar, std::vector<Row*>> _searchIndex;
|
||||||
QString _searchQuery;
|
QString _searchQuery;
|
||||||
std::vector<Row*> _filterResults;
|
std::vector<Row*> _filterResults;
|
||||||
|
|
||||||
object_ptr<Ui::FlatLabel> _about = { nullptr };
|
object_ptr<Ui::FlatLabel> _about = { nullptr };
|
||||||
object_ptr<Ui::FlatLabel> _searchNoResults = { nullptr };
|
object_ptr<Ui::FlatLabel> _searchNoResults = { nullptr };
|
||||||
|
object_ptr<Ui::FlatLabel> _searchLoading = { nullptr };
|
||||||
|
|
||||||
QPoint _lastMousePosition;
|
QPoint _lastMousePosition;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Row>> _globalSearchRows;
|
||||||
|
object_ptr<SingleTimer> _globalSearchTimer = { nullptr };
|
||||||
|
QString _globalSearchQuery;
|
||||||
|
QString _globalSearchHighlight;
|
||||||
|
mtpRequestId _globalSearchRequestId = 0;
|
||||||
|
std::map<QString, MTPcontacts_Found> _globalSearchCache;
|
||||||
|
std::map<mtpRequestId, QString> _globalSearchQueries;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -166,7 +166,7 @@ std::unique_ptr<PeerListBox::Row> BlockedBoxController::createRow(UserData *user
|
||||||
void BlockUserBoxController::prepare() {
|
void BlockUserBoxController::prepare() {
|
||||||
view()->setTitle(lang(lng_blocked_list_add_title));
|
view()->setTitle(lang(lng_blocked_list_add_title));
|
||||||
view()->addButton(lang(lng_cancel), [this] { view()->closeBox(); });
|
view()->addButton(lang(lng_cancel), [this] { view()->closeBox(); });
|
||||||
view()->setSearchable(true);
|
view()->setSearchMode(PeerListBox::SearchMode::Global);
|
||||||
view()->setSearchNoResultsText(lang(lng_blocked_list_not_found));
|
view()->setSearchNoResultsText(lang(lng_blocked_list_not_found));
|
||||||
|
|
||||||
rebuildRows();
|
rebuildRows();
|
||||||
|
@ -249,6 +249,13 @@ void BlockUserBoxController::rowClicked(PeerData *peer) {
|
||||||
view()->closeBox();
|
view()->closeBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<PeerListBox::Row> BlockUserBoxController::createGlobalRow(PeerData *peer) {
|
||||||
|
if (auto user = peer->asUser()) {
|
||||||
|
return createRow(App::history(user));
|
||||||
|
}
|
||||||
|
return std::unique_ptr<Row>();
|
||||||
|
}
|
||||||
|
|
||||||
bool BlockUserBoxController::appendRow(History *history) {
|
bool BlockUserBoxController::appendRow(History *history) {
|
||||||
if (auto row = view()->findRow(history->peer)) {
|
if (auto row = view()->findRow(history->peer)) {
|
||||||
updateIsBlocked(row, history->peer->asUser());
|
updateIsBlocked(row, history->peer->asUser());
|
||||||
|
|
|
@ -50,6 +50,7 @@ class BlockUserBoxController : public QObject, public PeerListBox::Controller, p
|
||||||
public:
|
public:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
void rowClicked(PeerData *peer) override;
|
void rowClicked(PeerData *peer) override;
|
||||||
|
std::unique_ptr<PeerListBox::Row> createGlobalRow(PeerData *peer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void rebuildRows();
|
void rebuildRows();
|
||||||
|
|
Loading…
Reference in New Issue