mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-04 23:40:58 +00:00
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();
|
||||
}
|
||||
|
||||
void PeerListBox::setSearchable(bool searchable) {
|
||||
_inner->setSearchable(searchable);
|
||||
if (searchable) {
|
||||
void PeerListBox::setSearchMode(SearchMode mode) {
|
||||
_inner->setSearchMode(mode);
|
||||
if (mode != SearchMode::None) {
|
||||
if (!_select) {
|
||||
_select = createMultiSelect();
|
||||
_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));
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
_rowsByPeer.emplace(row->peer(), row);
|
||||
if (_searchable) {
|
||||
if (addingToSearchIndex()) {
|
||||
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) {
|
||||
if (row->isGlobalSearchResult()) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeFromSearchIndex(row);
|
||||
row->setNameFirstChars(row->peer()->chars);
|
||||
for_const (auto ch, row->nameFirstChars()) {
|
||||
@ -348,20 +380,21 @@ PeerListBox::Row *PeerListBox::Inner::findRow(PeerData *peer) {
|
||||
|
||||
void PeerListBox::Inner::removeRow(Row *row) {
|
||||
auto index = row->absoluteIndex();
|
||||
t_assert(index >= 0 && index < _rows.size());
|
||||
t_assert(_rows[index].get() == row);
|
||||
auto isGlobalSearchResult = row->isGlobalSearchResult();
|
||||
auto &eraseFrom = isGlobalSearchResult ? _globalSearchRows : _rows;
|
||||
|
||||
t_assert(index >= 0 && index < eraseFrom.size());
|
||||
t_assert(eraseFrom[index].get() == row);
|
||||
|
||||
setSelected(Selected());
|
||||
setPressed(Selected());
|
||||
|
||||
_rowsByPeer.erase(row->peer());
|
||||
if (_searchable) {
|
||||
removeFromSearchIndex(row);
|
||||
}
|
||||
removeFromSearchIndex(row);
|
||||
_filterResults.erase(std::find(_filterResults.begin(), _filterResults.end(), row), _filterResults.end());
|
||||
_rows.erase(_rows.begin() + index);
|
||||
for (auto i = index, count = int(_rows.size()); i != count; ++i) {
|
||||
_rows[i]->setAbsoluteIndex(i);
|
||||
eraseFrom.erase(eraseFrom.begin() + index);
|
||||
for (auto i = index, count = int(eraseFrom.size()); i != count; ++i) {
|
||||
eraseFrom[i]->setAbsoluteIndex(i);
|
||||
}
|
||||
|
||||
restoreSelection();
|
||||
@ -379,16 +412,22 @@ void PeerListBox::Inner::setAbout(object_ptr<Ui::FlatLabel> about) {
|
||||
}
|
||||
|
||||
int PeerListBox::Inner::labelHeight() const {
|
||||
if (showingSearch()) {
|
||||
if (_filterResults.empty() && _searchNoResults) {
|
||||
return st::membersAboutLimitPadding.top() + _searchNoResults->height() + st::membersAboutLimitPadding.bottom();
|
||||
auto computeLabelHeight = [](auto &label) {
|
||||
if (!label) {
|
||||
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 st::membersAboutLimitPadding.top() + _about->height() + st::membersAboutLimitPadding.bottom();
|
||||
}
|
||||
return 0;
|
||||
return computeLabelHeight(_about);
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::refreshRows() {
|
||||
@ -400,7 +439,11 @@ void PeerListBox::Inner::refreshRows() {
|
||||
}
|
||||
if (_searchNoResults) {
|
||||
_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) {
|
||||
checkScrollForPreload();
|
||||
@ -408,13 +451,27 @@ void PeerListBox::Inner::refreshRows() {
|
||||
update();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setSearchable(bool searchable) {
|
||||
// We don't destroy a search index if we have one already.
|
||||
if (searchable && !_searchable) {
|
||||
_searchable = true;
|
||||
for_const (auto &row, _rows) {
|
||||
addToSearchIndex(row.get());
|
||||
void PeerListBox::Inner::setSearchMode(SearchMode mode) {
|
||||
if (_searchMode != mode) {
|
||||
if (!addingToSearchIndex()) {
|
||||
for_const (auto &row, _rows) {
|
||||
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) {
|
||||
QRect r(e->rect());
|
||||
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);
|
||||
}
|
||||
|
||||
auto statusHasOnlineColor = (row->statusType() == Row::StatusType::Online);
|
||||
p.setFont(st::contactsStatusFont);
|
||||
p.setPen(statusHasOnlineColor ? st::contactsStatusFgOnline : (selected ? st::contactsStatusFgOver : st::contactsStatusFg));
|
||||
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), row->status());
|
||||
if (row->isGlobalSearchResult() && !peer->userName().isEmpty()) {
|
||||
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) {
|
||||
@ -664,6 +755,7 @@ void PeerListBox::Inner::searchQueryChanged(QString query) {
|
||||
|
||||
_searchQuery = query;
|
||||
_filterResults.clear();
|
||||
clearGlobalSearchRows();
|
||||
if (!searchWordsList.isEmpty()) {
|
||||
auto minimalList = (const std::vector<Row*>*)nullptr;
|
||||
for_const (auto &searchWord, searchWordsList) {
|
||||
@ -703,11 +795,96 @@ void PeerListBox::Inner::searchQueryChanged(QString query) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_searchMode == SearchMode::Global) {
|
||||
needGlobalSearch();
|
||||
}
|
||||
refreshRows();
|
||||
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() {
|
||||
if (auto row = getRow(_selected.index)) {
|
||||
_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) {
|
||||
if (!showingSearch()) {
|
||||
t_assert(!row->isGlobalSearchResult());
|
||||
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) {
|
||||
if (auto row = findRow(peer)) {
|
||||
if (_searchable) {
|
||||
if (addingToSearchIndex()) {
|
||||
addToSearchIndex(row);
|
||||
}
|
||||
row->refreshName();
|
||||
|
@ -83,6 +83,12 @@ public:
|
||||
bool disabled() const {
|
||||
return _disabled;
|
||||
}
|
||||
bool isGlobalSearchResult() const {
|
||||
return _isGlobalSearchResult;
|
||||
}
|
||||
void setIsGlobalSearchResult(bool isGlobalSearchResult) {
|
||||
_isGlobalSearchResult = isGlobalSearchResult;
|
||||
}
|
||||
|
||||
template <typename UpdateCallback>
|
||||
void addRipple(QSize size, QPoint point, UpdateCallback updateCallback);
|
||||
@ -110,6 +116,7 @@ public:
|
||||
bool _disabled = false;
|
||||
int _absoluteIndex = -1;
|
||||
OrderedSet<QChar> _nameFirstChars;
|
||||
bool _isGlobalSearchResult = false;
|
||||
|
||||
};
|
||||
|
||||
@ -121,6 +128,9 @@ public:
|
||||
}
|
||||
virtual void preloadRows() {
|
||||
}
|
||||
virtual std::unique_ptr<Row> createGlobalRow(PeerData *peer) {
|
||||
return std::unique_ptr<Row>();
|
||||
}
|
||||
|
||||
virtual ~Controller() = default;
|
||||
|
||||
@ -152,9 +162,16 @@ public:
|
||||
void setAboutText(const QString &aboutText);
|
||||
void setAbout(object_ptr<Ui::FlatLabel> about);
|
||||
void refreshRows();
|
||||
void setSearchable(bool searchable);
|
||||
enum class SearchMode {
|
||||
None,
|
||||
Local,
|
||||
Global,
|
||||
};
|
||||
void setSearchMode(SearchMode mode);
|
||||
void setSearchNoResultsText(const QString &noResultsText);
|
||||
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).
|
||||
template <typename ReorderCallback>
|
||||
@ -212,8 +229,9 @@ public:
|
||||
int fullRowsCount() const;
|
||||
void setAbout(object_ptr<Ui::FlatLabel> about);
|
||||
void refreshRows();
|
||||
void setSearchable(bool searchable);
|
||||
void setSearchMode(SearchMode mode);
|
||||
void setSearchNoResults(object_ptr<Ui::FlatLabel> searchNoResults);
|
||||
void setSearchLoading(object_ptr<Ui::FlatLabel> searchLoading);
|
||||
|
||||
template <typename ReorderCallback>
|
||||
void reorderRows(ReorderCallback &&callback) {
|
||||
@ -241,6 +259,7 @@ protected:
|
||||
|
||||
private:
|
||||
void refreshIndices();
|
||||
void appendGlobalSearchRow(std::unique_ptr<Row> row);
|
||||
|
||||
struct RowIndex {
|
||||
RowIndex() = default;
|
||||
@ -289,6 +308,7 @@ private:
|
||||
|
||||
void addRowEntry(Row *row);
|
||||
void addToSearchIndex(Row *row);
|
||||
bool addingToSearchIndex() const;
|
||||
void removeFromSearchIndex(Row *row);
|
||||
bool showingSearch() const {
|
||||
return !_searchQuery.isEmpty();
|
||||
@ -303,6 +323,14 @@ private:
|
||||
|
||||
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;
|
||||
int _rowHeight = 0;
|
||||
int _visibleTop = 0;
|
||||
@ -315,14 +343,23 @@ private:
|
||||
std::vector<std::unique_ptr<Row>> _rows;
|
||||
std::map<PeerData*, Row*> _rowsByPeer;
|
||||
|
||||
bool _searchable = false;
|
||||
SearchMode _searchMode = SearchMode::None;
|
||||
std::map<QChar, std::vector<Row*>> _searchIndex;
|
||||
QString _searchQuery;
|
||||
std::vector<Row*> _filterResults;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _about = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _searchNoResults = { nullptr };
|
||||
object_ptr<Ui::FlatLabel> _searchLoading = { nullptr };
|
||||
|
||||
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() {
|
||||
view()->setTitle(lang(lng_blocked_list_add_title));
|
||||
view()->addButton(lang(lng_cancel), [this] { view()->closeBox(); });
|
||||
view()->setSearchable(true);
|
||||
view()->setSearchMode(PeerListBox::SearchMode::Global);
|
||||
view()->setSearchNoResultsText(lang(lng_blocked_list_not_found));
|
||||
|
||||
rebuildRows();
|
||||
@ -249,6 +249,13 @@ void BlockUserBoxController::rowClicked(PeerData *peer) {
|
||||
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) {
|
||||
if (auto row = view()->findRow(history->peer)) {
|
||||
updateIsBlocked(row, history->peer->asUser());
|
||||
|
@ -50,6 +50,7 @@ class BlockUserBoxController : public QObject, public PeerListBox::Controller, p
|
||||
public:
|
||||
void prepare() override;
|
||||
void rowClicked(PeerData *peer) override;
|
||||
std::unique_ptr<PeerListBox::Row> createGlobalRow(PeerData *peer) override;
|
||||
|
||||
private:
|
||||
void rebuildRows();
|
||||
|
Loading…
Reference in New Issue
Block a user