mirror of
https://github.com/telegramdesktop/tdesktop
synced 2024-12-26 16:43:33 +00:00
Use PeerListBox content in info profile.
This commit is contained in:
parent
1a0e524b49
commit
292e57ffc7
@ -333,6 +333,29 @@ contactsMarginBottom: 4px;
|
||||
membersMarginTop: 10px;
|
||||
membersMarginBottom: 10px;
|
||||
|
||||
peerListBox: PeerList(defaultPeerList) {
|
||||
padding: margins(
|
||||
0px,
|
||||
membersMarginTop,
|
||||
0px,
|
||||
membersMarginBottom);
|
||||
item: PeerListItem(defaultPeerListItem) {
|
||||
height: 56px;
|
||||
photoSize: contactsPhotoSize;
|
||||
photoPosition: point(16px, 7px);
|
||||
namePosition: point(74px, 9px);
|
||||
statusPosition: point(74px, 30px);
|
||||
button: OutlineButton(defaultPeerListButton) {
|
||||
textBg: contactsBg;
|
||||
textBgOver: contactsBgOver;
|
||||
ripple: contactsRipple;
|
||||
}
|
||||
statusFg: contactsStatusFg;
|
||||
statusFgOver: contactsStatusFgOver;
|
||||
statusFgActive: contactsStatusFgOnline;
|
||||
}
|
||||
}
|
||||
|
||||
localStorageBoxSkip: 10px;
|
||||
|
||||
shareRowsTop: 12px;
|
||||
|
@ -22,10 +22,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "auth_session.h"
|
||||
#include "mainwidget.h"
|
||||
#include "ui/widgets/multi_select.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/effects/round_checkbox.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
@ -34,7 +36,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "storage/file_download.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
|
||||
PeerListBox::PeerListBox(QWidget*, std::unique_ptr<PeerListController> controller, base::lambda<void(not_null<PeerListBox*>)> init)
|
||||
PeerListBox::PeerListBox(
|
||||
QWidget*,
|
||||
std::unique_ptr<PeerListController> controller,
|
||||
base::lambda<void(not_null<PeerListBox*>)> init)
|
||||
: _controller(std::move(controller))
|
||||
, _init(std::move(init)) {
|
||||
Expects(_controller != nullptr);
|
||||
@ -49,12 +54,12 @@ void PeerListBox::createMultiSelect() {
|
||||
| rpl::start(
|
||||
[this](int) { updateScrollSkips(); },
|
||||
lifetime());
|
||||
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { _inner->submitted(); });
|
||||
_select->entity()->setSubmittedCallback([this](bool chtrlShiftEnter) { content()->submitted(); });
|
||||
_select->entity()->setQueryChangedCallback([this](const QString &query) { searchQueryChanged(query); });
|
||||
_select->entity()->setItemRemovedCallback([this](uint64 itemId) {
|
||||
if (auto peer = App::peerLoaded(itemId)) {
|
||||
if (auto row = peerListFindRow(peer->id)) {
|
||||
_inner->changeCheckState(row, false, PeerListRow::SetStyle::Animated);
|
||||
content()->changeCheckState(row, false, PeerListRow::SetStyle::Animated);
|
||||
update();
|
||||
}
|
||||
_controller->itemDeselectedHook(peer);
|
||||
@ -82,7 +87,13 @@ void PeerListBox::updateScrollSkips() {
|
||||
}
|
||||
|
||||
void PeerListBox::prepare() {
|
||||
_inner = setInnerWidget(object_ptr<Inner>(this, _controller.get()), st::boxLayerScroll);
|
||||
setContent(setInnerWidget(
|
||||
object_ptr<PeerListContent>(
|
||||
this,
|
||||
_controller.get(),
|
||||
st::peerListBox),
|
||||
st::boxLayerScroll));
|
||||
content()->resizeToWidth(st::boxWideWidth);
|
||||
|
||||
_controller->setDelegate(this);
|
||||
|
||||
@ -93,7 +104,10 @@ void PeerListBox::prepare() {
|
||||
onScrollToY(0);
|
||||
}
|
||||
|
||||
connect(_inner, SIGNAL(mustScrollTo(int, int)), this, SLOT(onScrollToY(int, int)));
|
||||
content()->scrollToRequests()
|
||||
| rpl::start([this](Ui::ScrollToRequest request) {
|
||||
onScrollToY(request.ymin, request.ymax);
|
||||
}, lifetime());
|
||||
|
||||
if (_init) {
|
||||
_init(this);
|
||||
@ -102,13 +116,13 @@ void PeerListBox::prepare() {
|
||||
|
||||
void PeerListBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Down) {
|
||||
_inner->selectSkip(1);
|
||||
content()->selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner->selectSkip(-1);
|
||||
content()->selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner->selectSkipPage(height(), 1);
|
||||
content()->selectSkipPage(height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner->selectSkipPage(height(), -1);
|
||||
content()->selectSkipPage(height(), -1);
|
||||
} else if (e->key() == Qt::Key_Escape && _select && !_select->entity()->getQuery().isEmpty()) {
|
||||
_select->entity()->clearQuery();
|
||||
} else {
|
||||
@ -118,7 +132,7 @@ void PeerListBox::keyPressEvent(QKeyEvent *e) {
|
||||
|
||||
void PeerListBox::searchQueryChanged(const QString &query) {
|
||||
onScrollToY(0);
|
||||
_inner->searchQueryChanged(query);
|
||||
content()->searchQueryChanged(query);
|
||||
}
|
||||
|
||||
void PeerListBox::resizeEvent(QResizeEvent *e) {
|
||||
@ -131,7 +145,7 @@ void PeerListBox::resizeEvent(QResizeEvent *e) {
|
||||
updateScrollSkips();
|
||||
}
|
||||
|
||||
_inner->resizeToWidth(width());
|
||||
content()->resizeToWidth(width());
|
||||
}
|
||||
|
||||
void PeerListBox::paintEvent(QPaintEvent *e) {
|
||||
@ -143,53 +157,19 @@ void PeerListBox::paintEvent(QPaintEvent *e) {
|
||||
|
||||
void PeerListBox::setInnerFocus() {
|
||||
if (!_select || _select->isHiddenOrHiding()) {
|
||||
_inner->setFocus();
|
||||
content()->setFocus();
|
||||
} else {
|
||||
_select->entity()->setInnerFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::peerListAppendRow(std::unique_ptr<PeerListRow> row) {
|
||||
_inner->appendRow(std::move(row));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListAppendSearchRow(std::unique_ptr<PeerListRow> row) {
|
||||
_inner->appendSearchRow(std::move(row));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListAppendFoundRow(not_null<PeerListRow*> row) {
|
||||
_inner->appendFoundRow(row);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListPrependRow(std::unique_ptr<PeerListRow> row) {
|
||||
_inner->prependRow(std::move(row));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListPrependRowFromSearchResult(not_null<PeerListRow*> row) {
|
||||
_inner->prependRowFromSearchResult(row);
|
||||
}
|
||||
|
||||
PeerListRow *PeerListBox::peerListFindRow(PeerListRowId id) {
|
||||
return _inner->findRow(id);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListUpdateRow(not_null<PeerListRow*> row) {
|
||||
_inner->updateRow(row);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListRemoveRow(not_null<PeerListRow*> row) {
|
||||
_inner->removeRow(row);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListConvertRowToSearchResult(not_null<PeerListRow*> row) {
|
||||
_inner->convertRowToSearchResult(row);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSetRowChecked(not_null<PeerListRow*> row, bool checked) {
|
||||
void PeerListBox::peerListSetRowChecked(
|
||||
not_null<PeerListRow*> row,
|
||||
bool checked) {
|
||||
auto peer = row->peer();
|
||||
if (checked) {
|
||||
addSelectItem(peer, PeerListRow::SetStyle::Animated);
|
||||
_inner->changeCheckState(row, checked, PeerListRow::SetStyle::Animated);
|
||||
PeerListContentDelegate::peerListSetRowChecked(row, checked);
|
||||
peerListUpdateRow(row);
|
||||
|
||||
// This call deletes row from _searchRows.
|
||||
@ -201,40 +181,13 @@ void PeerListBox::peerListSetRowChecked(not_null<PeerListRow*> row, bool checked
|
||||
}
|
||||
}
|
||||
|
||||
int PeerListBox::peerListFullRowsCount() {
|
||||
return _inner->fullRowsCount();
|
||||
}
|
||||
|
||||
not_null<PeerListRow*> PeerListBox::peerListRowAt(int index) {
|
||||
return _inner->rowAt(index);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListRefreshRows() {
|
||||
_inner->refreshRows();
|
||||
}
|
||||
|
||||
void PeerListBox::peerListScrollToTop() {
|
||||
onScrollToY(0);
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSetDescription(object_ptr<Ui::FlatLabel> description) {
|
||||
_inner->setDescription(std::move(description));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSetSearchLoading(object_ptr<Ui::FlatLabel> loading) {
|
||||
_inner->setSearchLoading(std::move(loading));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) {
|
||||
_inner->setSearchNoResults(std::move(noResults));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSetAboveWidget(object_ptr<TWidget> aboveWidget) {
|
||||
_inner->setAboveWidget(std::move(aboveWidget));
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSetSearchMode(PeerListSearchMode mode) {
|
||||
_inner->setSearchMode(mode);
|
||||
PeerListContentDelegate::peerListSetSearchMode(mode);
|
||||
|
||||
auto selectVisible = (mode != PeerListSearchMode::Disabled);
|
||||
if (selectVisible && !_select) {
|
||||
createMultiSelect();
|
||||
@ -247,22 +200,6 @@ void PeerListBox::peerListSetSearchMode(PeerListSearchMode mode) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::peerListSortRows(base::lambda<bool(PeerListRow &a, PeerListRow &b)> compare) {
|
||||
_inner->reorderRows([compare = std::move(compare)](auto &&begin, auto &&end) {
|
||||
std::sort(begin, end, [&compare](auto &&a, auto &&b) {
|
||||
return compare(*a, *b);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void PeerListBox::peerListPartitionRows(base::lambda<bool(PeerListRow &a)> border) {
|
||||
_inner->reorderRows([border = std::move(border)](auto &&begin, auto &&end) {
|
||||
std::stable_partition(begin, end, [&border](auto &¤t) {
|
||||
return border(*current);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
PeerListController::PeerListController(std::unique_ptr<PeerListSearchController> searchController) : _searchController(std::move(searchController)) {
|
||||
if (_searchController) {
|
||||
_searchController->setDelegate(this);
|
||||
@ -418,18 +355,25 @@ void PeerListRow::invalidatePixmapsCache() {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListRow::paintStatusText(Painter &p, int x, int y, int availableWidth, int outerWidth, bool selected) {
|
||||
void PeerListRow::paintStatusText(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int availableWidth,
|
||||
int outerWidth,
|
||||
bool selected) {
|
||||
auto statusHasOnlineColor = (_statusType == PeerListRow::StatusType::Online);
|
||||
p.setFont(st::contactsStatusFont);
|
||||
p.setPen(statusHasOnlineColor ? st::contactsStatusFgOnline : (selected ? st::contactsStatusFgOver : st::contactsStatusFg));
|
||||
p.setPen(statusHasOnlineColor ? st.statusFgActive : (selected ? st.statusFgOver : st.statusFg));
|
||||
_status.drawLeftElided(p, x, y, availableWidth, outerWidth);
|
||||
}
|
||||
|
||||
template <typename UpdateCallback>
|
||||
void PeerListRow::addRipple(QSize size, QPoint point, UpdateCallback updateCallback) {
|
||||
void PeerListRow::addRipple(const style::PeerListItem &st, QSize size, QPoint point, UpdateCallback updateCallback) {
|
||||
if (!_ripple) {
|
||||
auto mask = Ui::RippleAnimation::rectMask(size);
|
||||
_ripple = std::make_unique<Ui::RippleAnimation>(st::contactsRipple, std::move(mask), std::move(updateCallback));
|
||||
_ripple = std::make_unique<Ui::RippleAnimation>(st.button.ripple, std::move(mask), std::move(updateCallback));
|
||||
}
|
||||
_ripple->add(point);
|
||||
}
|
||||
@ -449,18 +393,29 @@ void PeerListRow::paintRipple(Painter &p, TimeMs ms, int x, int y, int outerWidt
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListRow::paintUserpic(Painter &p, TimeMs ms, int x, int y, int outerWidth) {
|
||||
void PeerListRow::paintUserpic(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
TimeMs ms,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth) {
|
||||
if (_disabledState == State::DisabledChecked) {
|
||||
paintDisabledCheckUserpic(p, x, y, outerWidth);
|
||||
paintDisabledCheckUserpic(p, st, x, y, outerWidth);
|
||||
} else if (_checkbox) {
|
||||
_checkbox->paint(p, ms, x, y, outerWidth);
|
||||
} else {
|
||||
peer()->paintUserpicLeft(p, x, y, outerWidth, st::contactsPhotoSize);
|
||||
peer()->paintUserpicLeft(p, x, y, outerWidth, st.photoSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Emulates Ui::RoundImageCheckbox::paint() in a checked state.
|
||||
void PeerListRow::paintDisabledCheckUserpic(Painter &p, int x, int y, int outerWidth) const {
|
||||
void PeerListRow::paintDisabledCheckUserpic(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth) const {
|
||||
auto userpicRadius = st::contactsPhotoCheckbox.imageSmallRadius;
|
||||
auto userpicShift = st::contactsPhotoCheckbox.imageRadius - userpicRadius;
|
||||
auto userpicDiameter = st::contactsPhotoCheckbox.imageRadius * 2;
|
||||
@ -512,7 +467,10 @@ void PeerListRow::lazyInitialize() {
|
||||
}
|
||||
|
||||
void PeerListRow::createCheckbox(base::lambda<void()> updateCallback) {
|
||||
_checkbox = std::make_unique<Ui::RoundImageCheckbox>(st::contactsPhotoCheckbox, std::move(updateCallback), PaintUserpicCallback(_peer));
|
||||
_checkbox = std::make_unique<Ui::RoundImageCheckbox>(
|
||||
st::contactsPhotoCheckbox,
|
||||
std::move(updateCallback),
|
||||
PaintUserpicCallback(_peer));
|
||||
}
|
||||
|
||||
void PeerListRow::setCheckedInternal(bool checked, SetStyle style) {
|
||||
@ -522,9 +480,14 @@ void PeerListRow::setCheckedInternal(bool checked, SetStyle style) {
|
||||
_checkbox->setChecked(checked, speed);
|
||||
}
|
||||
|
||||
PeerListBox::Inner::Inner(QWidget *parent, not_null<PeerListController*> controller) : TWidget(parent)
|
||||
PeerListContent::PeerListContent(
|
||||
QWidget *parent,
|
||||
not_null<PeerListController*> controller,
|
||||
const style::PeerList &st)
|
||||
: RpWidget(parent)
|
||||
, _st(st)
|
||||
, _controller(controller)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) {
|
||||
, _rowHeight(_st.item.height) {
|
||||
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
|
||||
|
||||
using UpdateFlag = Notify::PeerUpdate::Flag;
|
||||
@ -543,7 +506,7 @@ PeerListBox::Inner::Inner(QWidget *parent, not_null<PeerListController*> control
|
||||
});
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::appendRow(std::unique_ptr<PeerListRow> row) {
|
||||
void PeerListContent::appendRow(std::unique_ptr<PeerListRow> row) {
|
||||
Expects(row != nullptr);
|
||||
if (_rowsById.find(row->id()) == _rowsById.cend()) {
|
||||
row->setAbsoluteIndex(_rows.size());
|
||||
@ -552,7 +515,7 @@ void PeerListBox::Inner::appendRow(std::unique_ptr<PeerListRow> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::appendSearchRow(std::unique_ptr<PeerListRow> row) {
|
||||
void PeerListContent::appendSearchRow(std::unique_ptr<PeerListRow> row) {
|
||||
Expects(row != nullptr);
|
||||
Expects(showingSearch());
|
||||
if (_rowsById.find(row->id()) == _rowsById.cend()) {
|
||||
@ -564,7 +527,7 @@ void PeerListBox::Inner::appendSearchRow(std::unique_ptr<PeerListRow> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::appendFoundRow(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::appendFoundRow(not_null<PeerListRow*> row) {
|
||||
Expects(showingSearch());
|
||||
auto index = findRowIndex(row);
|
||||
if (index.value < 0) {
|
||||
@ -572,13 +535,13 @@ void PeerListBox::Inner::appendFoundRow(not_null<PeerListRow*> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::changeCheckState(not_null<PeerListRow*> row, bool checked, PeerListRow::SetStyle style) {
|
||||
void PeerListContent::changeCheckState(not_null<PeerListRow*> row, bool checked, PeerListRow::SetStyle style) {
|
||||
row->setChecked(checked, style, [this, row] {
|
||||
updateRow(row);
|
||||
});
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::addRowEntry(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
|
||||
_rowsById.emplace(row->id(), row);
|
||||
_rowsByPeer[row->peer()].push_back(row);
|
||||
if (addingToSearchIndex()) {
|
||||
@ -590,18 +553,18 @@ void PeerListBox::Inner::addRowEntry(not_null<PeerListRow*> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::invalidatePixmapsCache() {
|
||||
void PeerListContent::invalidatePixmapsCache() {
|
||||
auto invalidate = [](auto &&row) { row->invalidatePixmapsCache(); };
|
||||
base::for_each(_rows, invalidate);
|
||||
base::for_each(_searchRows, invalidate);
|
||||
}
|
||||
|
||||
bool PeerListBox::Inner::addingToSearchIndex() const {
|
||||
bool PeerListContent::addingToSearchIndex() const {
|
||||
// If we started indexing already, we continue.
|
||||
return (_searchMode != PeerListSearchMode::Disabled) || !_searchIndex.empty();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::addToSearchIndex(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::addToSearchIndex(not_null<PeerListRow*> row) {
|
||||
if (row->isSearchResult()) {
|
||||
return;
|
||||
}
|
||||
@ -613,7 +576,7 @@ void PeerListBox::Inner::addToSearchIndex(not_null<PeerListRow*> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::removeFromSearchIndex(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::removeFromSearchIndex(not_null<PeerListRow*> row) {
|
||||
auto &nameFirstChars = row->nameFirstChars();
|
||||
if (!nameFirstChars.empty()) {
|
||||
for_const (auto ch, row->nameFirstChars()) {
|
||||
@ -630,7 +593,7 @@ void PeerListBox::Inner::removeFromSearchIndex(not_null<PeerListRow*> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::prependRow(std::unique_ptr<PeerListRow> row) {
|
||||
void PeerListContent::prependRow(std::unique_ptr<PeerListRow> row) {
|
||||
Expects(row != nullptr);
|
||||
if (_rowsById.find(row->id()) == _rowsById.cend()) {
|
||||
addRowEntry(row.get());
|
||||
@ -639,7 +602,7 @@ void PeerListBox::Inner::prependRow(std::unique_ptr<PeerListRow> row) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::prependRowFromSearchResult(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::prependRowFromSearchResult(not_null<PeerListRow*> row) {
|
||||
if (!row->isSearchResult()) {
|
||||
return;
|
||||
}
|
||||
@ -658,26 +621,26 @@ void PeerListBox::Inner::prependRowFromSearchResult(not_null<PeerListRow*> row)
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::refreshIndices() {
|
||||
void PeerListContent::refreshIndices() {
|
||||
auto index = 0;
|
||||
for (auto &row : _rows) {
|
||||
row->setAbsoluteIndex(index++);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::removeRowAtIndex(std::vector<std::unique_ptr<PeerListRow>> &from, int index) {
|
||||
void PeerListContent::removeRowAtIndex(std::vector<std::unique_ptr<PeerListRow>> &from, int index) {
|
||||
from.erase(from.begin() + index);
|
||||
for (auto i = index, count = int(from.size()); i != count; ++i) {
|
||||
from[i]->setAbsoluteIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
PeerListRow *PeerListBox::Inner::findRow(PeerListRowId id) {
|
||||
PeerListRow *PeerListContent::findRow(PeerListRowId id) {
|
||||
auto it = _rowsById.find(id);
|
||||
return (it == _rowsById.cend()) ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::removeRow(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::removeRow(not_null<PeerListRow*> row) {
|
||||
auto index = row->absoluteIndex();
|
||||
auto isSearchResult = row->isSearchResult();
|
||||
auto &eraseFrom = isSearchResult ? _searchRows : _rows;
|
||||
@ -698,7 +661,7 @@ void PeerListBox::Inner::removeRow(not_null<PeerListRow*> row) {
|
||||
restoreSelection();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::convertRowToSearchResult(not_null<PeerListRow*> row) {
|
||||
void PeerListContent::convertRowToSearchResult(not_null<PeerListRow*> row) {
|
||||
if (row->isSearchResult()) {
|
||||
return;
|
||||
} else if (!showingSearch() || !_controller->hasComplexSearch()) {
|
||||
@ -715,44 +678,44 @@ void PeerListBox::Inner::convertRowToSearchResult(not_null<PeerListRow*> row) {
|
||||
removeRowAtIndex(_rows, index);
|
||||
}
|
||||
|
||||
int PeerListBox::Inner::fullRowsCount() const {
|
||||
int PeerListContent::fullRowsCount() const {
|
||||
return _rows.size();
|
||||
}
|
||||
|
||||
not_null<PeerListRow*> PeerListBox::Inner::rowAt(int index) const {
|
||||
not_null<PeerListRow*> PeerListContent::rowAt(int index) const {
|
||||
Expects(index >= 0 && index < _rows.size());
|
||||
return _rows[index].get();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setDescription(object_ptr<Ui::FlatLabel> description) {
|
||||
void PeerListContent::setDescription(object_ptr<Ui::FlatLabel> description) {
|
||||
_description = std::move(description);
|
||||
if (_description) {
|
||||
_description->setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setSearchLoading(object_ptr<Ui::FlatLabel> loading) {
|
||||
void PeerListContent::setSearchLoading(object_ptr<Ui::FlatLabel> loading) {
|
||||
_searchLoading = std::move(loading);
|
||||
if (_searchLoading) {
|
||||
_searchLoading->setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setSearchNoResults(object_ptr<Ui::FlatLabel> noResults) {
|
||||
void PeerListContent::setSearchNoResults(object_ptr<Ui::FlatLabel> noResults) {
|
||||
_searchNoResults = std::move(noResults);
|
||||
if (_searchNoResults) {
|
||||
_searchNoResults->setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setAboveWidget(object_ptr<TWidget> aboveWidget) {
|
||||
void PeerListContent::setAboveWidget(object_ptr<TWidget> aboveWidget) {
|
||||
_aboveWidget = std::move(aboveWidget);
|
||||
if (_aboveWidget) {
|
||||
_aboveWidget->setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
int PeerListBox::Inner::labelHeight() const {
|
||||
int PeerListContent::labelHeight() const {
|
||||
auto computeLabelHeight = [](auto &label) {
|
||||
if (!label) {
|
||||
return 0;
|
||||
@ -771,8 +734,8 @@ int PeerListBox::Inner::labelHeight() const {
|
||||
return computeLabelHeight(_description);
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::refreshRows() {
|
||||
resizeToWidth(st::boxWideWidth);
|
||||
void PeerListContent::refreshRows() {
|
||||
resizeToWidth(width());
|
||||
if (_visibleBottom > 0) {
|
||||
checkScrollForPreload();
|
||||
}
|
||||
@ -780,7 +743,7 @@ void PeerListBox::Inner::refreshRows() {
|
||||
update();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setSearchMode(PeerListSearchMode mode) {
|
||||
void PeerListContent::setSearchMode(PeerListSearchMode mode) {
|
||||
if (_searchMode != mode) {
|
||||
if (!addingToSearchIndex()) {
|
||||
for_const (auto &row, _rows) {
|
||||
@ -790,7 +753,11 @@ void PeerListBox::Inner::setSearchMode(PeerListSearchMode mode) {
|
||||
_searchMode = mode;
|
||||
if (_controller->hasComplexSearch()) {
|
||||
if (!_searchLoading) {
|
||||
setSearchLoading(object_ptr<Ui::FlatLabel>(this, lang(lng_contacts_loading), Ui::FlatLabel::InitType::Simple, st::membersAbout));
|
||||
setSearchLoading(object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
lang(lng_contacts_loading),
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
st::membersAbout));
|
||||
}
|
||||
} else {
|
||||
clearSearchRows();
|
||||
@ -798,17 +765,17 @@ void PeerListBox::Inner::setSearchMode(PeerListSearchMode mode) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::clearSearchRows() {
|
||||
void PeerListContent::clearSearchRows() {
|
||||
while (!_searchRows.empty()) {
|
||||
removeRow(_searchRows.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
void PeerListContent::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
p.fillRect(r, st::contactsBg);
|
||||
p.fillRect(r, _st.item.button.textBg);
|
||||
|
||||
auto rowsTopCached = rowsTop();
|
||||
auto ms = getms();
|
||||
@ -827,7 +794,7 @@ void PeerListBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
int PeerListBox::Inner::resizeGetHeight(int newWidth) {
|
||||
int PeerListContent::resizeGetHeight(int newWidth) {
|
||||
_aboveHeight = 0;
|
||||
if (_aboveWidget) {
|
||||
_aboveWidget->resizeToWidth(newWidth);
|
||||
@ -839,6 +806,7 @@ int PeerListBox::Inner::resizeGetHeight(int newWidth) {
|
||||
_aboveHeight = _aboveWidget->height();
|
||||
}
|
||||
}
|
||||
auto rowsCount = shownRowsCount();
|
||||
auto labelTop = rowsTop() + qMax(1, shownRowsCount()) * _rowHeight;
|
||||
if (_description) {
|
||||
_description->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth);
|
||||
@ -852,20 +820,22 @@ int PeerListBox::Inner::resizeGetHeight(int newWidth) {
|
||||
_searchLoading->moveToLeft(st::contactsPadding.left(), labelTop + st::membersAboutLimitPadding.top(), newWidth);
|
||||
_searchLoading->setVisible(showingSearch() && _filterResults.empty() && _controller->isSearchLoading());
|
||||
}
|
||||
return labelTop + labelHeight() + st::membersMarginBottom;
|
||||
auto label = labelHeight();
|
||||
return ((label > 0 || rowsCount > 0) ? (labelTop + label) : 0)
|
||||
+ _st.padding.bottom();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::enterEventHook(QEvent *e) {
|
||||
void PeerListContent::enterEventHook(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::leaveEventHook(QEvent *e) {
|
||||
void PeerListContent::leaveEventHook(QEvent *e) {
|
||||
_mouseSelection = false;
|
||||
setMouseTracking(false);
|
||||
setSelected(Selected());
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
void PeerListContent::mouseMoveEvent(QMouseEvent *e) {
|
||||
auto position = e->globalPos();
|
||||
if (_mouseSelection || _lastMousePosition != position) {
|
||||
_lastMousePosition = position;
|
||||
@ -874,7 +844,7 @@ void PeerListBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
void PeerListContent::mousePressEvent(QMouseEvent *e) {
|
||||
_mouseSelection = true;
|
||||
_lastMousePosition = e->globalPos();
|
||||
updateSelection();
|
||||
@ -893,12 +863,12 @@ void PeerListBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
} else {
|
||||
auto size = QSize(width(), _rowHeight);
|
||||
auto point = mapFromGlobal(QCursor::pos()) - QPoint(0, getRowTop(_selected.index));
|
||||
row->addRipple(size, point, std::move(updateCallback));
|
||||
row->addRipple(_st.item, size, point, std::move(updateCallback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
void PeerListContent::mouseReleaseEvent(QMouseEvent *e) {
|
||||
updateRow(_pressed.index);
|
||||
updateRow(_selected.index);
|
||||
|
||||
@ -915,7 +885,7 @@ void PeerListBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setPressed(Selected pressed) {
|
||||
void PeerListContent::setPressed(Selected pressed) {
|
||||
if (auto row = getRow(_pressed.index)) {
|
||||
row->stopLastRipple();
|
||||
row->stopLastActionRipple();
|
||||
@ -923,7 +893,7 @@ void PeerListBox::Inner::setPressed(Selected pressed) {
|
||||
_pressed = pressed;
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||
void PeerListContent::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||
auto row = getRow(index);
|
||||
Assert(row != nullptr);
|
||||
row->lazyInitialize();
|
||||
@ -934,17 +904,26 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||
auto selected = (active.index == index);
|
||||
auto actionSelected = (selected && active.action);
|
||||
|
||||
p.fillRect(0, 0, width(), _rowHeight, selected ? st::contactsBgOver : st::contactsBg);
|
||||
auto &bg = selected
|
||||
? _st.item.button.textBgOver
|
||||
: _st.item.button.textBg;
|
||||
p.fillRect(0, 0, width(), _rowHeight, bg);
|
||||
row->paintRipple(p, ms, 0, 0, width());
|
||||
row->paintUserpic(p, ms, st::contactsPadding.left(), st::contactsPadding.top(), width());
|
||||
row->paintUserpic(
|
||||
p,
|
||||
_st.item,
|
||||
ms,
|
||||
_st.item.photoPosition.x(),
|
||||
_st.item.photoPosition.y(),
|
||||
width());
|
||||
|
||||
p.setPen(st::contactsNameFg);
|
||||
|
||||
auto actionSize = row->actionSize();
|
||||
auto actionMargins = actionSize.isEmpty() ? QMargins() : row->actionMargins();
|
||||
auto &name = row->name();
|
||||
auto namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
|
||||
auto namew = width() - namex - st::contactsPadding.right();
|
||||
auto namex = _st.item.namePosition.x();
|
||||
auto namew = width() - namex - _st.item.photoPosition.x();
|
||||
if (!actionSize.isEmpty()) {
|
||||
namew -= actionMargins.left() + actionSize.width() + actionMargins.right();
|
||||
}
|
||||
@ -952,14 +931,14 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||
if (row->needsVerifiedIcon()) {
|
||||
auto icon = &st::dialogsVerifiedIcon;
|
||||
namew -= icon->width();
|
||||
icon->paint(p, namex + qMin(name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width());
|
||||
icon->paint(p, namex + qMin(name.maxWidth(), namew), _st.item.namePosition.y(), width());
|
||||
}
|
||||
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
|
||||
p.setPen(anim::pen(st::contactsNameFg, st::contactsNameCheckedFg, nameCheckedRatio));
|
||||
name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width());
|
||||
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());
|
||||
|
||||
if (!actionSize.isEmpty()) {
|
||||
auto actionLeft = width() - st::contactsPadding.right() - actionMargins.right() - actionSize.width();
|
||||
auto actionLeft = width() - _st.item.photoPosition.x() - actionMargins.right() - actionSize.width();
|
||||
auto actionTop = actionMargins.top();
|
||||
row->paintAction(p, ms, actionLeft, actionTop, width(), actionSelected);
|
||||
}
|
||||
@ -975,22 +954,22 @@ void PeerListBox::Inner::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||
if (highlightedWidth > availableWidth) {
|
||||
highlightedPart = st::contactsStatusFont->elided(highlightedPart, availableWidth);
|
||||
}
|
||||
p.setPen(st::contactsStatusFgOnline);
|
||||
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), highlightedPart);
|
||||
p.setPen(_st.item.statusFgActive);
|
||||
p.drawTextLeft(_st.item.statusPosition.x(), _st.item.statusPosition.y(), 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);
|
||||
p.setPen(_st.item.statusFgActive);
|
||||
p.drawTextLeft(_st.item.statusPosition.x(), _st.item.statusPosition.y(), width(), highlightedPart);
|
||||
p.setPen(selected ? _st.item.statusFgOver : _st.item.statusFg);
|
||||
p.drawTextLeft(_st.item.statusPosition.x() + highlightedWidth, _st.item.statusPosition.y(), width(), grayedPart);
|
||||
}
|
||||
} else {
|
||||
row->paintStatusText(p, namex, st::contactsPadding.top() + st::contactsStatusTop, statusw, width(), selected);
|
||||
row->paintStatusText(p, _st.item, _st.item.statusPosition.x(), _st.item.statusPosition.y(), statusw, width(), selected);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::selectSkip(int direction) {
|
||||
void PeerListContent::selectSkip(int direction) {
|
||||
if (_pressed.index.value >= 0) {
|
||||
return;
|
||||
}
|
||||
@ -1049,19 +1028,19 @@ void PeerListBox::Inner::selectSkip(int direction) {
|
||||
if (newSelectedIndex >= 0) {
|
||||
auto top = (newSelectedIndex > 0) ? getRowTop(RowIndex(newSelectedIndex)) : 0;
|
||||
auto bottom = (newSelectedIndex + 1 < rowsCount) ? getRowTop(RowIndex(newSelectedIndex + 1)) : height();
|
||||
emit mustScrollTo(top, bottom);
|
||||
_scrollToRequests.fire({ top, bottom });
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::selectSkipPage(int height, int direction) {
|
||||
void PeerListContent::selectSkipPage(int height, int direction) {
|
||||
auto rowsToSkip = height / _rowHeight;
|
||||
if (!rowsToSkip) return;
|
||||
selectSkip(rowsToSkip * direction);
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::loadProfilePhotos() {
|
||||
void PeerListContent::loadProfilePhotos() {
|
||||
if (_visibleTop >= _visibleBottom) return;
|
||||
|
||||
auto yFrom = _visibleTop;
|
||||
@ -1086,13 +1065,13 @@ void PeerListBox::Inner::loadProfilePhotos() {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::checkScrollForPreload() {
|
||||
void PeerListContent::checkScrollForPreload() {
|
||||
if (_visibleBottom + PreloadHeightsCount * (_visibleBottom - _visibleTop) > height()) {
|
||||
_controller->loadMoreRows();
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::searchQueryChanged(QString query) {
|
||||
void PeerListContent::searchQueryChanged(QString query) {
|
||||
auto searchWordsList = TextUtilities::PrepareSearchWords(query);
|
||||
auto normalizedQuery = searchWordsList.isEmpty() ? QString() : searchWordsList.join(' ');
|
||||
if (_normalizedSearchQuery != normalizedQuery) {
|
||||
@ -1144,7 +1123,7 @@ void PeerListBox::Inner::searchQueryChanged(QString query) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setSearchQuery(const QString &query, const QString &normalizedQuery) {
|
||||
void PeerListContent::setSearchQuery(const QString &query, const QString &normalizedQuery) {
|
||||
setSelected(Selected());
|
||||
setPressed(Selected());
|
||||
_searchQuery = query;
|
||||
@ -1154,13 +1133,13 @@ void PeerListBox::Inner::setSearchQuery(const QString &query, const QString &nor
|
||||
clearSearchRows();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::submitted() {
|
||||
void PeerListContent::submitted() {
|
||||
if (auto row = getRow(_selected.index)) {
|
||||
_controller->rowClicked(row);
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::visibleTopBottomUpdated(
|
||||
void PeerListContent::visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) {
|
||||
_visibleTop = visibleTop;
|
||||
@ -1169,7 +1148,7 @@ void PeerListBox::Inner::visibleTopBottomUpdated(
|
||||
checkScrollForPreload();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::setSelected(Selected selected) {
|
||||
void PeerListContent::setSelected(Selected selected) {
|
||||
updateRow(_selected.index);
|
||||
if (_selected != selected) {
|
||||
_selected = selected;
|
||||
@ -1178,12 +1157,12 @@ void PeerListBox::Inner::setSelected(Selected selected) {
|
||||
}
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::restoreSelection() {
|
||||
void PeerListContent::restoreSelection() {
|
||||
_lastMousePosition = QCursor::pos();
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::updateSelection() {
|
||||
void PeerListContent::updateSelection() {
|
||||
if (!_mouseSelection) return;
|
||||
|
||||
auto point = mapFromGlobal(_lastMousePosition);
|
||||
@ -1204,35 +1183,35 @@ void PeerListBox::Inner::updateSelection() {
|
||||
setSelected(selected);
|
||||
}
|
||||
|
||||
QRect PeerListBox::Inner::getActionRect(not_null<PeerListRow*> row, RowIndex index) const {
|
||||
QRect PeerListContent::getActionRect(not_null<PeerListRow*> row, RowIndex index) const {
|
||||
auto actionSize = row->actionSize();
|
||||
if (actionSize.isEmpty()) {
|
||||
return QRect();
|
||||
}
|
||||
auto actionMargins = row->actionMargins();
|
||||
auto actionRight = st::contactsPadding.right() + actionMargins.right();
|
||||
auto actionRight = _st.item.photoPosition.x() + actionMargins.right();
|
||||
auto actionTop = actionMargins.top();
|
||||
auto actionLeft = width() - actionRight - actionSize.width();
|
||||
auto rowTop = getRowTop(index);
|
||||
return myrtlrect(actionLeft, rowTop + actionTop, actionSize.width(), actionSize.height());
|
||||
}
|
||||
|
||||
int PeerListBox::Inner::rowsTop() const {
|
||||
return _aboveHeight + st::membersMarginTop;
|
||||
int PeerListContent::rowsTop() const {
|
||||
return _aboveHeight + _st.padding.top();
|
||||
}
|
||||
|
||||
int PeerListBox::Inner::getRowTop(RowIndex index) const {
|
||||
int PeerListContent::getRowTop(RowIndex index) const {
|
||||
if (index.value >= 0) {
|
||||
return rowsTop() + index.value * _rowHeight;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::updateRow(not_null<PeerListRow*> row, RowIndex hint) {
|
||||
void PeerListContent::updateRow(not_null<PeerListRow*> row, RowIndex hint) {
|
||||
updateRow(findRowIndex(row, hint));
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::updateRow(RowIndex index) {
|
||||
void PeerListContent::updateRow(RowIndex index) {
|
||||
if (index.value < 0) {
|
||||
return;
|
||||
}
|
||||
@ -1249,12 +1228,12 @@ void PeerListBox::Inner::updateRow(RowIndex index) {
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
bool PeerListBox::Inner::enumerateShownRows(Callback callback) {
|
||||
bool PeerListContent::enumerateShownRows(Callback callback) {
|
||||
return enumerateShownRows(0, shownRowsCount(), std::move(callback));
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
bool PeerListBox::Inner::enumerateShownRows(int from, int to, Callback callback) {
|
||||
bool PeerListContent::enumerateShownRows(int from, int to, Callback callback) {
|
||||
Assert(0 <= from);
|
||||
Assert(from <= to);
|
||||
if (showingSearch()) {
|
||||
@ -1275,7 +1254,7 @@ bool PeerListBox::Inner::enumerateShownRows(int from, int to, Callback callback)
|
||||
return true;
|
||||
}
|
||||
|
||||
PeerListRow *PeerListBox::Inner::getRow(RowIndex index) {
|
||||
PeerListRow *PeerListContent::getRow(RowIndex index) {
|
||||
if (index.value >= 0) {
|
||||
if (showingSearch()) {
|
||||
if (index.value < _filterResults.size()) {
|
||||
@ -1288,7 +1267,7 @@ PeerListRow *PeerListBox::Inner::getRow(RowIndex index) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(not_null<PeerListRow*> row, RowIndex hint) {
|
||||
PeerListContent::RowIndex PeerListContent::findRowIndex(not_null<PeerListRow*> row, RowIndex hint) {
|
||||
if (!showingSearch()) {
|
||||
Assert(!row->isSearchResult());
|
||||
return RowIndex(row->absoluteIndex());
|
||||
@ -1309,7 +1288,7 @@ PeerListBox::Inner::RowIndex PeerListBox::Inner::findRowIndex(not_null<PeerListR
|
||||
return result;
|
||||
}
|
||||
|
||||
void PeerListBox::Inner::handleNameChanged(const Notify::PeerUpdate &update) {
|
||||
void PeerListContent::handleNameChanged(const Notify::PeerUpdate &update) {
|
||||
auto byPeer = _rowsByPeer.find(update.peer);
|
||||
if (byPeer != _rowsByPeer.cend()) {
|
||||
for (auto row : byPeer->second) {
|
||||
|
@ -20,10 +20,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <rpl/event_stream.h>
|
||||
#include "ui/rp_widget.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "mtproto/sender.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
namespace style {
|
||||
struct PeerList;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
class RippleAnimation;
|
||||
class RoundImageCheckbox;
|
||||
@ -31,6 +37,7 @@ class MultiSelect;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
class FlatLabel;
|
||||
struct ScrollToRequest;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Notify {
|
||||
@ -135,10 +142,20 @@ public:
|
||||
void invalidatePixmapsCache();
|
||||
|
||||
template <typename UpdateCallback>
|
||||
void addRipple(QSize size, QPoint point, UpdateCallback updateCallback);
|
||||
void addRipple(
|
||||
const style::PeerListItem &st,
|
||||
QSize size,
|
||||
QPoint point,
|
||||
UpdateCallback updateCallback);
|
||||
void stopLastRipple();
|
||||
void paintRipple(Painter &p, TimeMs ms, int x, int y, int outerWidth);
|
||||
void paintUserpic(Painter &p, TimeMs ms, int x, int y, int outerWidth);
|
||||
void paintUserpic(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
TimeMs ms,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth);
|
||||
float64 checkedRatio();
|
||||
|
||||
void setNameFirstChars(const OrderedSet<QChar> &nameFirstChars) {
|
||||
@ -149,7 +166,14 @@ public:
|
||||
}
|
||||
|
||||
virtual void lazyInitialize();
|
||||
virtual void paintStatusText(Painter &p, int x, int y, int availableWidth, int outerWidth, bool selected);
|
||||
virtual void paintStatusText(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int availableWidth,
|
||||
int outerWidth,
|
||||
bool selected);
|
||||
|
||||
protected:
|
||||
bool isInitialized() const {
|
||||
@ -159,7 +183,12 @@ protected:
|
||||
private:
|
||||
void createCheckbox(base::lambda<void()> updateCallback);
|
||||
void setCheckedInternal(bool checked, SetStyle style);
|
||||
void paintDisabledCheckUserpic(Painter &p, int x, int y, int outerWidth) const;
|
||||
void paintDisabledCheckUserpic(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth) const;
|
||||
void setStatusText(const QString &text);
|
||||
|
||||
PeerListRowId _id = 0;
|
||||
@ -323,78 +352,14 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class PeerListBox : public BoxContent, public PeerListDelegate {
|
||||
class PeerListContent
|
||||
: public Ui::RpWidget
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
PeerListBox(QWidget*, std::unique_ptr<PeerListController> controller, base::lambda<void(not_null<PeerListBox*>)> init);
|
||||
|
||||
void peerListSetTitle(base::lambda<QString()> title) override {
|
||||
setTitle(std::move(title));
|
||||
}
|
||||
void peerListSetAdditionalTitle(base::lambda<QString()> title) override {
|
||||
setAdditionalTitle(std::move(title));
|
||||
}
|
||||
void peerListSetDescription(object_ptr<Ui::FlatLabel> description) override;
|
||||
void peerListSetSearchLoading(object_ptr<Ui::FlatLabel> loading) override;
|
||||
void peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) override;
|
||||
void peerListSetAboveWidget(object_ptr<TWidget> aboveWidget) override;
|
||||
void peerListSetSearchMode(PeerListSearchMode mode) override;
|
||||
void peerListAppendRow(std::unique_ptr<PeerListRow> row) override;
|
||||
void peerListAppendSearchRow(std::unique_ptr<PeerListRow> row) override;
|
||||
void peerListAppendFoundRow(not_null<PeerListRow*> row) override;
|
||||
void peerListPrependRow(std::unique_ptr<PeerListRow> row) override;
|
||||
void peerListPrependRowFromSearchResult(not_null<PeerListRow*> row) override;
|
||||
void peerListUpdateRow(not_null<PeerListRow*> row) override;
|
||||
void peerListRemoveRow(not_null<PeerListRow*> row) override;
|
||||
void peerListConvertRowToSearchResult(not_null<PeerListRow*> row) override;
|
||||
void peerListSetRowChecked(not_null<PeerListRow*> row, bool checked) override;
|
||||
not_null<PeerListRow*> peerListRowAt(int index) override;
|
||||
bool peerListIsRowSelected(not_null<PeerData*> peer) override;
|
||||
int peerListSelectedRowsCount() override;
|
||||
std::vector<not_null<PeerData*>> peerListCollectSelectedRows() override;
|
||||
void peerListRefreshRows() override;
|
||||
void peerListScrollToTop() override;
|
||||
int peerListFullRowsCount() override;
|
||||
PeerListRow *peerListFindRow(PeerListRowId id) override;
|
||||
void peerListSortRows(base::lambda<bool(PeerListRow &a, PeerListRow &b)> compare) override;
|
||||
void peerListPartitionRows(base::lambda<bool(PeerListRow &a)> border) override;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void peerListAddSelectedRowInBunch(not_null<PeerData*> peer) override {
|
||||
addSelectItem(peer, PeerListRow::SetStyle::Fast);
|
||||
}
|
||||
void peerListFinishSelectedRowsBunch() override;
|
||||
|
||||
void addSelectItem(not_null<PeerData*> peer, PeerListRow::SetStyle style);
|
||||
void createMultiSelect();
|
||||
int getTopScrollSkip() const;
|
||||
void updateScrollSkips();
|
||||
void searchQueryChanged(const QString &query);
|
||||
|
||||
object_ptr<Ui::SlideWrap<Ui::MultiSelect>> _select = { nullptr };
|
||||
|
||||
class Inner;
|
||||
QPointer<Inner> _inner;
|
||||
|
||||
std::unique_ptr<PeerListController> _controller;
|
||||
base::lambda<void(PeerListBox*)> _init;
|
||||
bool _scrollBottomFixed = true;
|
||||
|
||||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class PeerListBox::Inner : public TWidget, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Inner(QWidget *parent, not_null<PeerListController*> controller);
|
||||
PeerListContent(
|
||||
QWidget *parent,
|
||||
not_null<PeerListController*> controller,
|
||||
const style::PeerList &st);
|
||||
|
||||
void selectSkip(int direction);
|
||||
void selectSkipPage(int height, int direction);
|
||||
@ -436,8 +401,9 @@ public:
|
||||
refreshIndices();
|
||||
}
|
||||
|
||||
signals:
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
rpl::producer<Ui::ScrollToRequest> scrollToRequests() const {
|
||||
return _scrollToRequests.events();
|
||||
}
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
@ -528,6 +494,7 @@ private:
|
||||
|
||||
void clearSearchRows();
|
||||
|
||||
const style::PeerList &_st;
|
||||
not_null<PeerListController*> _controller;
|
||||
PeerListSearchMode _searchMode = PeerListSearchMode::Disabled;
|
||||
|
||||
@ -539,6 +506,8 @@ private:
|
||||
Selected _pressed;
|
||||
bool _mouseSelection = false;
|
||||
|
||||
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
|
||||
|
||||
std::vector<std::unique_ptr<PeerListRow>> _rows;
|
||||
std::map<PeerListRowId, not_null<PeerListRow*>> _rowsById;
|
||||
std::map<PeerData*, std::vector<not_null<PeerListRow*>>> _rowsByPeer;
|
||||
@ -560,3 +529,156 @@ private:
|
||||
std::vector<std::unique_ptr<PeerListRow>> _searchRows;
|
||||
|
||||
};
|
||||
|
||||
class PeerListContentDelegate : public PeerListDelegate {
|
||||
public:
|
||||
void setContent(PeerListContent *content) {
|
||||
_content = content;
|
||||
}
|
||||
|
||||
void peerListAppendRow(
|
||||
std::unique_ptr<PeerListRow> row) override {
|
||||
_content->appendRow(std::move(row));
|
||||
}
|
||||
void peerListAppendSearchRow(
|
||||
std::unique_ptr<PeerListRow> row) override {
|
||||
_content->appendSearchRow(std::move(row));
|
||||
}
|
||||
void peerListAppendFoundRow(
|
||||
not_null<PeerListRow*> row) override {
|
||||
_content->appendFoundRow(row);
|
||||
}
|
||||
void peerListPrependRow(
|
||||
std::unique_ptr<PeerListRow> row) override {
|
||||
_content->prependRow(std::move(row));
|
||||
}
|
||||
void peerListPrependRowFromSearchResult(
|
||||
not_null<PeerListRow*> row) override {
|
||||
_content->prependRowFromSearchResult(row);
|
||||
}
|
||||
PeerListRow *peerListFindRow(PeerListRowId id) override {
|
||||
return _content->findRow(id);
|
||||
}
|
||||
void peerListUpdateRow(not_null<PeerListRow*> row) override {
|
||||
_content->updateRow(row);
|
||||
}
|
||||
void peerListRemoveRow(not_null<PeerListRow*> row) override {
|
||||
_content->removeRow(row);
|
||||
}
|
||||
void peerListConvertRowToSearchResult(
|
||||
not_null<PeerListRow*> row) override {
|
||||
_content->convertRowToSearchResult(row);
|
||||
}
|
||||
void peerListSetRowChecked(
|
||||
not_null<PeerListRow*> row,
|
||||
bool checked) override {
|
||||
_content->changeCheckState(
|
||||
row,
|
||||
checked,
|
||||
PeerListRow::SetStyle::Animated);
|
||||
}
|
||||
int peerListFullRowsCount() override {
|
||||
return _content->fullRowsCount();
|
||||
}
|
||||
not_null<PeerListRow*> peerListRowAt(int index) override {
|
||||
return _content->rowAt(index);
|
||||
}
|
||||
void peerListRefreshRows() override {
|
||||
_content->refreshRows();
|
||||
}
|
||||
void peerListSetDescription(object_ptr<Ui::FlatLabel> description) override {
|
||||
_content->setDescription(std::move(description));
|
||||
}
|
||||
void peerListSetSearchLoading(object_ptr<Ui::FlatLabel> loading) override {
|
||||
_content->setSearchLoading(std::move(loading));
|
||||
}
|
||||
void peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) override {
|
||||
_content->setSearchNoResults(std::move(noResults));
|
||||
}
|
||||
void peerListSetAboveWidget(object_ptr<TWidget> aboveWidget) override {
|
||||
_content->setAboveWidget(std::move(aboveWidget));
|
||||
}
|
||||
void peerListSetSearchMode(PeerListSearchMode mode) override {
|
||||
_content->setSearchMode(mode);
|
||||
}
|
||||
void peerListSortRows(
|
||||
base::lambda<bool(PeerListRow &a, PeerListRow &b)> compare) override {
|
||||
_content->reorderRows([compare = std::move(compare)](
|
||||
auto &&begin,
|
||||
auto &&end) {
|
||||
std::sort(begin, end, [&compare](auto &&a, auto &&b) {
|
||||
return compare(*a, *b);
|
||||
});
|
||||
});
|
||||
}
|
||||
void peerListPartitionRows(
|
||||
base::lambda<bool(PeerListRow &a)> border) override {
|
||||
_content->reorderRows([border = std::move(border)](
|
||||
auto &&begin,
|
||||
auto &&end) {
|
||||
std::stable_partition(begin, end, [&border](
|
||||
auto &¤t) {
|
||||
return border(*current);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
not_null<PeerListContent*> content() const {
|
||||
return _content;
|
||||
}
|
||||
|
||||
private:
|
||||
PeerListContent *_content = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class PeerListBox : public BoxContent, public PeerListContentDelegate {
|
||||
public:
|
||||
PeerListBox(
|
||||
QWidget*,
|
||||
std::unique_ptr<PeerListController> controller,
|
||||
base::lambda<void(not_null<PeerListBox*>)> init);
|
||||
|
||||
void peerListSetTitle(base::lambda<QString()> title) override {
|
||||
setTitle(std::move(title));
|
||||
}
|
||||
void peerListSetAdditionalTitle(base::lambda<QString()> title) override {
|
||||
setAdditionalTitle(std::move(title));
|
||||
}
|
||||
void peerListSetSearchMode(PeerListSearchMode mode) override;
|
||||
void peerListSetRowChecked(
|
||||
not_null<PeerListRow*> row,
|
||||
bool checked) override;
|
||||
bool peerListIsRowSelected(not_null<PeerData*> peer) override;
|
||||
int peerListSelectedRowsCount() override;
|
||||
std::vector<not_null<PeerData*>> peerListCollectSelectedRows() override;
|
||||
void peerListScrollToTop() override;
|
||||
|
||||
protected:
|
||||
void prepare() override;
|
||||
void setInnerFocus() override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void peerListAddSelectedRowInBunch(not_null<PeerData*> peer) override {
|
||||
addSelectItem(peer, PeerListRow::SetStyle::Fast);
|
||||
}
|
||||
void peerListFinishSelectedRowsBunch() override;
|
||||
|
||||
void addSelectItem(not_null<PeerData*> peer, PeerListRow::SetStyle style);
|
||||
void createMultiSelect();
|
||||
int getTopScrollSkip() const;
|
||||
void updateScrollSkips();
|
||||
void searchQueryChanged(const QString &query);
|
||||
|
||||
object_ptr<Ui::SlideWrap<Ui::MultiSelect>> _select = { nullptr };
|
||||
|
||||
std::unique_ptr<PeerListController> _controller;
|
||||
base::lambda<void(PeerListBox*)> _init;
|
||||
bool _scrollBottomFixed = true;
|
||||
|
||||
};
|
||||
|
@ -77,7 +77,14 @@ public:
|
||||
return _items.front()->id;
|
||||
}
|
||||
|
||||
void paintStatusText(Painter &p, int x, int y, int availableWidth, int outerWidth, bool selected) override;
|
||||
void paintStatusText(
|
||||
Painter &p,
|
||||
const style::PeerListItem &st,
|
||||
int x,
|
||||
int y,
|
||||
int availableWidth,
|
||||
int outerWidth,
|
||||
bool selected) override;
|
||||
void addActionRipple(QPoint point, base::lambda<void()> updateCallback) override;
|
||||
void stopLastActionRipple() override;
|
||||
|
||||
@ -111,7 +118,7 @@ BoxController::Row::Row(HistoryItem *item) : PeerListRow(item->history()->peer,
|
||||
refreshStatus();
|
||||
}
|
||||
|
||||
void BoxController::Row::paintStatusText(Painter &p, int x, int y, int availableWidth, int outerWidth, bool selected) {
|
||||
void BoxController::Row::paintStatusText(Painter &p, const style::PeerListItem &st, int x, int y, int availableWidth, int outerWidth, bool selected) {
|
||||
auto icon = ([this] {
|
||||
switch (_type) {
|
||||
case Type::In: return &st::callArrowIn;
|
||||
@ -125,7 +132,7 @@ void BoxController::Row::paintStatusText(Painter &p, int x, int y, int available
|
||||
x += shift;
|
||||
availableWidth -= shift;
|
||||
|
||||
PeerListRow::paintStatusText(p, x, y, availableWidth, outerWidth, selected);
|
||||
PeerListRow::paintStatusText(p, st, x, y, availableWidth, outerWidth, selected);
|
||||
}
|
||||
|
||||
void BoxController::Row::paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) {
|
||||
|
@ -90,7 +90,7 @@ membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
||||
scrollMargin: margins(0px, 5px, 0px, 5px);
|
||||
scrollPadding: margins(0px, 3px, 0px, 3px);
|
||||
}
|
||||
membersInnerItem: defaultProfileMemberItem;
|
||||
membersInnerItem: defaultPeerListItem;
|
||||
|
||||
historyFileOutImage: icon {{ "history_file_image", historyFileOutIconFg }};
|
||||
historyFileOutImageSelected: icon {{ "history_file_image", historyFileOutIconFgSelected }};
|
||||
|
@ -224,10 +224,12 @@ infoSharedMediaButton: infoProfileButton;
|
||||
infoSharedMediaBottomSkip: 12px;
|
||||
|
||||
infoMembersHeader: 56px;
|
||||
infoMembersItem: ProfilePeerListItem(defaultProfileMemberItem) {
|
||||
photoPosition: point(18px, 6px);
|
||||
namePosition: point(79px, 11px);
|
||||
statusPosition: point(79px, 31px);
|
||||
infoMembersList: PeerList(defaultPeerList) {
|
||||
item: PeerListItem(defaultPeerListItem) {
|
||||
photoPosition: point(18px, 6px);
|
||||
namePosition: point(79px, 11px);
|
||||
statusPosition: point(79px, 31px);
|
||||
}
|
||||
}
|
||||
infoMembersButtonPosition: point(12px, 9px);
|
||||
infoMembersButtonIconPosition: point(6px, 6px);
|
||||
|
@ -139,6 +139,10 @@ void ContentWidget::scrollTopRestore(int scrollTop) {
|
||||
_scroll->scrollToY(scrollTop);
|
||||
}
|
||||
|
||||
void ContentWidget::scrollTo(const Ui::ScrollToRequest &request) {
|
||||
_scroll->scrollTo(request);
|
||||
}
|
||||
|
||||
bool ContentWidget::wheelEventFromFloatPlayer(QEvent *e) {
|
||||
return _scroll->viewportEvent(e);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ enum class SharedMediaType : char;
|
||||
|
||||
namespace Ui {
|
||||
class ScrollArea;
|
||||
struct ScrollToRequest;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Info {
|
||||
@ -132,6 +133,8 @@ protected:
|
||||
int scrollTopSave() const;
|
||||
void scrollTopRestore(int scrollTop);
|
||||
|
||||
void scrollTo(const Ui::ScrollToRequest &request);
|
||||
|
||||
private:
|
||||
RpWidget *doSetInnerWidget(
|
||||
object_ptr<RpWidget> inner,
|
||||
|
@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "styles/style_info.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
|
||||
@ -55,6 +56,7 @@ InnerWidget::InnerWidget(
|
||||
_content->heightValue()
|
||||
| rpl::start([this](int height) {
|
||||
TWidget::resizeToWidth(width());
|
||||
_desiredHeight.fire(countDesiredHeight());
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
@ -70,7 +72,7 @@ rpl::producer<bool> InnerWidget::canHideDetails() const {
|
||||
|
||||
object_ptr<Ui::RpWidget> InnerWidget::setupContent(
|
||||
RpWidget *parent,
|
||||
rpl::producer<Wrap> &&wrapValue) const {
|
||||
rpl::producer<Wrap> &&wrapValue) {
|
||||
auto result = object_ptr<Ui::VerticalLayout>(parent);
|
||||
auto cover = result->add(object_ptr<Cover>(
|
||||
result,
|
||||
@ -97,10 +99,24 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
|
||||
// }
|
||||
}
|
||||
if (_peer->isChat() || _peer->isMegagroup()) {
|
||||
result->add(object_ptr<Members>(
|
||||
_members = result->add(object_ptr<Members>(
|
||||
result,
|
||||
_controller,
|
||||
std::move(wrapValue),
|
||||
_peer));
|
||||
_peer)
|
||||
);
|
||||
_members->scrollToRequests()
|
||||
| rpl::start([this](Ui::ScrollToRequest request) {
|
||||
auto min = (request.ymin < 0)
|
||||
? request.ymin
|
||||
: mapFromGlobal(_members->mapToGlobal({ 0, request.ymin })).y();
|
||||
auto max = (request.ymin < 0)
|
||||
? mapFromGlobal(_members->mapToGlobal({ 0, 0 })).y()
|
||||
: (request.ymax < 0)
|
||||
? request.ymax
|
||||
: mapFromGlobal(_members->mapToGlobal({ 0, request.ymax })).y();
|
||||
_scrollToRequests.fire({ min, max });
|
||||
}, _members->lifetime());
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
@ -367,6 +383,12 @@ object_ptr<Ui::SlideWrap<>> InnerWidget::createSlideSkipWidget(
|
||||
return Ui::CreateSlideSkipWidget(parent, st::infoProfileSkip);
|
||||
}
|
||||
|
||||
int InnerWidget::countDesiredHeight() const {
|
||||
return _content->height() + (_members
|
||||
? (_members->desiredHeight() - _members->height())
|
||||
: 0);
|
||||
}
|
||||
|
||||
void InnerWidget::visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) {
|
||||
|
@ -31,6 +31,7 @@ namespace Ui {
|
||||
class VerticalLayout;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
struct ScrollToRequest;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Info {
|
||||
@ -40,6 +41,7 @@ enum class Wrap;
|
||||
namespace Profile {
|
||||
|
||||
class Memento;
|
||||
class Members;
|
||||
|
||||
class InnerWidget final : public Ui::RpWidget {
|
||||
public:
|
||||
@ -61,6 +63,14 @@ public:
|
||||
void saveState(not_null<Memento*> memento);
|
||||
void restoreState(not_null<Memento*> memento);
|
||||
|
||||
rpl::producer<Ui::ScrollToRequest> scrollToRequests() const {
|
||||
return _scrollToRequests.events();
|
||||
}
|
||||
|
||||
rpl::producer<int> desiredHeightValue() const override {
|
||||
return _desiredHeight.events_starting_with(countDesiredHeight());
|
||||
}
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
void visibleTopBottomUpdated(
|
||||
@ -70,7 +80,7 @@ protected:
|
||||
private:
|
||||
object_ptr<RpWidget> setupContent(
|
||||
RpWidget *parent,
|
||||
rpl::producer<Wrap> &&wrapValue) const;
|
||||
rpl::producer<Wrap> &&wrapValue);
|
||||
object_ptr<RpWidget> setupDetails(RpWidget *parent) const;
|
||||
object_ptr<RpWidget> setupSharedMedia(RpWidget *parent) const;
|
||||
object_ptr<RpWidget> setupMuteToggle(RpWidget *parent) const;
|
||||
@ -86,6 +96,8 @@ private:
|
||||
object_ptr<Ui::SlideWrap<RpWidget>> createSlideSkipWidget(
|
||||
RpWidget *parent) const;
|
||||
|
||||
int countDesiredHeight() const;
|
||||
|
||||
bool canHideDetailsEver() const;
|
||||
rpl::producer<bool> canHideDetails() const;
|
||||
|
||||
@ -94,8 +106,12 @@ private:
|
||||
|
||||
int _minHeight = 0;
|
||||
|
||||
Members *_members = nullptr;
|
||||
object_ptr<RpWidget> _content;
|
||||
|
||||
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
|
||||
rpl::event_stream<int> _desiredHeight;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Profile
|
||||
|
@ -24,11 +24,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "info/profile/info_profile_members_controllers.h"
|
||||
#include "info/info_memento.h"
|
||||
#include "profile/profile_block_group_members.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
@ -44,10 +47,12 @@ constexpr auto kEnableSearchMembersAfterCount = 50;
|
||||
|
||||
Members::Members(
|
||||
QWidget *parent,
|
||||
not_null<Window::Controller*> controller,
|
||||
rpl::producer<Wrap> &&wrapValue,
|
||||
not_null<PeerData*> peer)
|
||||
: RpWidget(parent)
|
||||
, _peer(peer)
|
||||
, _controller(CreateMembersController(_peer))
|
||||
, _labelWrap(this)
|
||||
, _label(setupHeader())
|
||||
, _addMember(this, st::infoMembersAddMember)
|
||||
@ -57,13 +62,30 @@ Members::Members(
|
||||
langFactory(lng_participant_filter))
|
||||
, _search(this, st::infoMembersSearch)
|
||||
, _cancelSearch(this, st::infoMembersCancelSearch)
|
||||
, _list(setupList(this)) {
|
||||
, _list(setupList(this, _controller.get())) {
|
||||
setupButtons();
|
||||
std::move(wrapValue)
|
||||
| rpl::start([this](Wrap wrap) {
|
||||
_wrap = wrap;
|
||||
updateSearchOverrides();
|
||||
}, lifetime());
|
||||
setContent(_list.data());
|
||||
_controller->setDelegate(static_cast<PeerListDelegate*>(this));
|
||||
}
|
||||
|
||||
int Members::desiredHeight() const {
|
||||
auto desired = st::infoMembersHeader;
|
||||
auto count = [this] {
|
||||
if (auto chat = _peer->asChat()) {
|
||||
return chat->count;
|
||||
} else if (auto channel = _peer->asChannel()) {
|
||||
return channel->membersCount();
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
desired += qMax(count, _list->fullRowsCount())
|
||||
* st::infoMembersList.item.height;
|
||||
return qMax(height(), desired);
|
||||
}
|
||||
|
||||
object_ptr<Ui::FlatLabel> Members::setupHeader() {
|
||||
@ -128,12 +150,24 @@ void Members::setupButtons() {
|
||||
}
|
||||
|
||||
object_ptr<Members::ListWidget> Members::setupList(
|
||||
RpWidget *parent) const {
|
||||
RpWidget *parent,
|
||||
not_null<PeerListController*> controller) const {
|
||||
auto result = object_ptr<ListWidget>(
|
||||
parent,
|
||||
_peer,
|
||||
::Profile::GroupMembersWidget::TitleVisibility::Hidden,
|
||||
st::infoMembersItem);
|
||||
controller,
|
||||
st::infoMembersList);
|
||||
result->scrollToRequests()
|
||||
| rpl::start([this](Ui::ScrollToRequest request) {
|
||||
auto addmin = (request.ymin < 0)
|
||||
? 0
|
||||
: st::infoMembersHeader;
|
||||
auto addmax = (request.ymax < 0)
|
||||
? 0
|
||||
: st::infoMembersHeader;
|
||||
_scrollToRequests.fire({
|
||||
request.ymin + addmin,
|
||||
request.ymax + addmax });
|
||||
}, result->lifetime());
|
||||
result->moveToLeft(0, st::infoMembersHeader);
|
||||
parent->widthValue()
|
||||
| rpl::start([list = result.data()](int newWidth) {
|
||||
@ -141,7 +175,7 @@ object_ptr<Members::ListWidget> Members::setupList(
|
||||
}, result->lifetime());
|
||||
result->heightValue()
|
||||
| rpl::start([parent](int listHeight) {
|
||||
auto newHeight = (listHeight > 0)
|
||||
auto newHeight = (listHeight > st::membersMarginBottom)
|
||||
? (st::infoMembersHeader + listHeight)
|
||||
: 0;
|
||||
parent->resize(parent->width(), newHeight);
|
||||
@ -182,6 +216,15 @@ int Members::resizeGetHeight(int newWidth) {
|
||||
st::infoMembersSearchTop,
|
||||
cancelLeft - fieldLeft,
|
||||
_searchField->height());
|
||||
connect(_searchField, &Ui::FlatInput::cancelled, this, [this] {
|
||||
cancelSearch();
|
||||
});
|
||||
connect(_searchField, &Ui::FlatInput::changed, this, [this] {
|
||||
applySearch();
|
||||
});
|
||||
connect(_searchField, &Ui::FlatInput::submitted, this, [this] {
|
||||
forceSearchSubmit();
|
||||
});
|
||||
|
||||
_labelWrap->resize(
|
||||
searchCurrentLeft - st::infoBlockHeaderPosition.x(),
|
||||
@ -267,7 +310,12 @@ void Members::cancelSearch() {
|
||||
}
|
||||
|
||||
void Members::applySearch() {
|
||||
peerListScrollToTop();
|
||||
content()->searchQueryChanged(_searchField->getLastText());
|
||||
}
|
||||
|
||||
void Members::forceSearchSubmit() {
|
||||
content()->submitted();
|
||||
}
|
||||
|
||||
void Members::visibleTopBottomUpdated(
|
||||
@ -276,6 +324,42 @@ void Members::visibleTopBottomUpdated(
|
||||
setChildVisibleTopBottom(_list, visibleTop, visibleBottom);
|
||||
}
|
||||
|
||||
void Members::peerListSetTitle(base::lambda<QString()> title) {
|
||||
}
|
||||
|
||||
void Members::peerListSetAdditionalTitle(
|
||||
base::lambda<QString()> title) {
|
||||
}
|
||||
|
||||
bool Members::peerListIsRowSelected(not_null<PeerData*> peer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int Members::peerListSelectedRowsCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<not_null<PeerData*>> Members::peerListCollectSelectedRows() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Members::peerListScrollToTop() {
|
||||
_scrollToRequests.fire({ -1, -1 });
|
||||
}
|
||||
|
||||
void Members::peerListAddSelectedRowInBunch(not_null<PeerData*> peer) {
|
||||
Unexpected("Item selection in Info::Profile::Members.");
|
||||
}
|
||||
|
||||
void Members::peerListFinishSelectedRowsBunch() {
|
||||
}
|
||||
|
||||
void Members::peerListSetDescription(
|
||||
object_ptr<Ui::FlatLabel> description) {
|
||||
description.destroy();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Profile
|
||||
} // namespace Info
|
||||
|
||||
|
@ -21,16 +21,19 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#pragma once
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
|
||||
namespace Ui {
|
||||
class FlatInput;
|
||||
class CrossButton;
|
||||
class IconButton;
|
||||
class FlatLabel;
|
||||
struct ScrollToRequest;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Profile {
|
||||
class GroupMembersWidget;
|
||||
class ParticipantsBoxController;
|
||||
} // namespace Profile
|
||||
|
||||
namespace Info {
|
||||
@ -39,13 +42,22 @@ enum class Wrap;
|
||||
|
||||
namespace Profile {
|
||||
|
||||
class Members : public Ui::RpWidget {
|
||||
class Members
|
||||
: public Ui::RpWidget
|
||||
, private PeerListContentDelegate {
|
||||
public:
|
||||
Members(
|
||||
QWidget *parent,
|
||||
not_null<Window::Controller*> controller,
|
||||
rpl::producer<Wrap> &&wrapValue,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
rpl::producer<Ui::ScrollToRequest> scrollToRequests() const {
|
||||
return _scrollToRequests.events();
|
||||
}
|
||||
|
||||
int desiredHeight() const;
|
||||
|
||||
protected:
|
||||
void visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
@ -53,11 +65,26 @@ protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
using ListWidget = ::Profile::GroupMembersWidget;
|
||||
using ListWidget = PeerListContent;
|
||||
|
||||
// PeerListContentDelegate interface.
|
||||
void peerListSetTitle(base::lambda<QString()> title) override;
|
||||
void peerListSetAdditionalTitle(
|
||||
base::lambda<QString()> title) override;
|
||||
bool peerListIsRowSelected(not_null<PeerData*> peer) override;
|
||||
int peerListSelectedRowsCount() override;
|
||||
std::vector<not_null<PeerData*>> peerListCollectSelectedRows() override;
|
||||
void peerListScrollToTop() override;
|
||||
void peerListAddSelectedRowInBunch(
|
||||
not_null<PeerData*> peer) override;
|
||||
void peerListFinishSelectedRowsBunch() override;
|
||||
void peerListSetDescription(
|
||||
object_ptr<Ui::FlatLabel> description) override;
|
||||
|
||||
object_ptr<Ui::FlatLabel> setupHeader();
|
||||
object_ptr<ListWidget> setupList(
|
||||
RpWidget *parent) const;
|
||||
RpWidget *parent,
|
||||
not_null<PeerListController*> controller) const;
|
||||
|
||||
void setupButtons();
|
||||
void updateSearchOverrides();
|
||||
@ -67,10 +94,12 @@ private:
|
||||
void toggleSearch();
|
||||
void cancelSearch();
|
||||
void applySearch();
|
||||
void forceSearchSubmit();
|
||||
void searchAnimationCallback();
|
||||
|
||||
Wrap _wrap;
|
||||
not_null<PeerData*> _peer;
|
||||
std::unique_ptr<PeerListController> _controller;
|
||||
object_ptr<Ui::RpWidget> _labelWrap;
|
||||
object_ptr<Ui::FlatLabel> _label;
|
||||
object_ptr<Ui::IconButton> _addMember;
|
||||
@ -83,6 +112,8 @@ private:
|
||||
bool _searchShown = false;
|
||||
base::Timer _searchTimer;
|
||||
|
||||
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Profile
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "info/profile/info_profile_members_controllers.h"
|
||||
|
||||
#include "profile/profile_channel_controllers.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "apiwrap.h"
|
||||
#include "auth_session.h"
|
||||
#include "observer_peer.h"
|
||||
|
||||
namespace Info {
|
||||
namespace Profile {
|
||||
namespace {
|
||||
|
||||
class ChatMembersController
|
||||
: public PeerListController
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
ChatMembersController(not_null<ChatData*> chat);
|
||||
|
||||
void prepare() override;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
|
||||
private:
|
||||
void rebuildRows();
|
||||
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user);
|
||||
|
||||
not_null<ChatData*> _chat;
|
||||
|
||||
};
|
||||
|
||||
ChatMembersController::ChatMembersController(not_null<ChatData*> chat)
|
||||
: PeerListController()
|
||||
, _chat(chat) {
|
||||
}
|
||||
|
||||
void ChatMembersController::prepare() {
|
||||
setSearchNoResultsText(lang(lng_blocked_list_not_found));
|
||||
delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
|
||||
delegate()->peerListSetTitle(langFactory(lng_channel_admins));
|
||||
|
||||
rebuildRows();
|
||||
if (!delegate()->peerListFullRowsCount()) {
|
||||
Auth().api().requestFullPeer(_chat);
|
||||
}
|
||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(
|
||||
Notify::PeerUpdate::Flag::MembersChanged,
|
||||
[this](const Notify::PeerUpdate &update) {
|
||||
if (update.peer == _chat) {
|
||||
rebuildRows();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void ChatMembersController::rebuildRows() {
|
||||
if (_chat->participants.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<not_null<UserData*>> users;
|
||||
auto &participants = _chat->participants;
|
||||
for (auto i = participants.cbegin(), e = participants.cend();
|
||||
i != e;
|
||||
++i) {
|
||||
users.push_back(i.key());
|
||||
}
|
||||
auto now = unixtime();
|
||||
base::sort(users, [now](auto a, auto b) {
|
||||
return App::onlineForSort(a, now)
|
||||
> App::onlineForSort(b, now);
|
||||
});
|
||||
base::for_each(users, [this](not_null<UserData*> user) {
|
||||
if (auto row = createRow(user)) {
|
||||
delegate()->peerListAppendRow(std::move(row));
|
||||
}
|
||||
});
|
||||
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> ChatMembersController::createRow(not_null<UserData*> user) {
|
||||
return std::make_unique<PeerListRow>(user);
|
||||
}
|
||||
|
||||
void ChatMembersController::rowClicked(not_null<PeerListRow*> row) {
|
||||
Ui::showPeerProfile(row->peer());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<PeerListController> CreateMembersController(
|
||||
not_null<PeerData*> peer) {
|
||||
if (auto chat = peer->asChat()) {
|
||||
return std::make_unique<ChatMembersController>(chat);
|
||||
} else if (auto channel = peer->asChannel()) {
|
||||
using ChannelMembersController
|
||||
= ::Profile::ParticipantsBoxController;
|
||||
return std::make_unique<ChannelMembersController>(
|
||||
channel,
|
||||
ChannelMembersController::Role::Profile);
|
||||
}
|
||||
Unexpected("Peer type in CreateMembersController()");
|
||||
}
|
||||
|
||||
} // namespace Profile
|
||||
} // namespace Info
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class PeerListController;
|
||||
|
||||
namespace Info {
|
||||
namespace Profile {
|
||||
|
||||
std::unique_ptr<PeerListController> CreateMembersController(
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
} // namespace Profile
|
||||
} // namespace Info
|
@ -52,6 +52,15 @@ Widget::Widget(
|
||||
controller,
|
||||
peer));
|
||||
_inner->move(0, 0);
|
||||
_inner->scrollToRequests()
|
||||
| rpl::start([this](Ui::ScrollToRequest request) {
|
||||
if (request.ymin < 0) {
|
||||
scrollTopRestore(
|
||||
qMin(scrollTopSave(), request.ymax));
|
||||
} else {
|
||||
scrollTo(request);
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
Section Widget::section() const {
|
||||
|
@ -121,7 +121,7 @@ profileInviteLinkText: FlatLabel(profileBlockTextPart) {
|
||||
|
||||
profileLimitReachedSkip: 6px;
|
||||
|
||||
profileMemberItem: ProfilePeerListItem(defaultProfileMemberItem) {
|
||||
profileMemberItem: PeerListItem(defaultPeerListItem) {
|
||||
left: 8px;
|
||||
bottom: profileBlockMarginBottom;
|
||||
button: defaultLeftOutlineButton;
|
||||
|
@ -39,7 +39,7 @@ GroupMembersWidget::GroupMembersWidget(
|
||||
QWidget *parent,
|
||||
PeerData *peer,
|
||||
TitleVisibility titleVisibility,
|
||||
const style::ProfilePeerListItem &st)
|
||||
const style::PeerListItem &st)
|
||||
: PeerListWidget(parent
|
||||
, peer
|
||||
, (titleVisibility == TitleVisibility::Visible) ? lang(lng_profile_participants_section) : QString()
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
Visible,
|
||||
Hidden,
|
||||
};
|
||||
GroupMembersWidget(QWidget *parent, PeerData *peer, TitleVisibility titleVisibility = TitleVisibility::Visible, const style::ProfilePeerListItem &st = st::profileMemberItem);
|
||||
GroupMembersWidget(QWidget *parent, PeerData *peer, TitleVisibility titleVisibility = TitleVisibility::Visible, const style::PeerListItem &st = st::profileMemberItem);
|
||||
|
||||
int onlineCount() const {
|
||||
return _onlineCount;
|
||||
|
@ -33,7 +33,7 @@ PeerListWidget::Item::Item(PeerData *peer) : peer(peer) {
|
||||
|
||||
PeerListWidget::Item::~Item() = default;
|
||||
|
||||
PeerListWidget::PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const style::ProfilePeerListItem &st, const QString &removeText)
|
||||
PeerListWidget::PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const style::PeerListItem &st, const QString &removeText)
|
||||
: BlockWidget(parent, peer, title)
|
||||
, _st(st)
|
||||
, _removeText(removeText)
|
||||
|
@ -36,7 +36,7 @@ namespace Profile {
|
||||
|
||||
class PeerListWidget : public BlockWidget {
|
||||
public:
|
||||
PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const style::ProfilePeerListItem &st = st::profileMemberItem, const QString &removeText = QString());
|
||||
PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const style::PeerListItem &st = st::profileMemberItem, const QString &removeText = QString());
|
||||
|
||||
struct Item {
|
||||
explicit Item(PeerData *peer);
|
||||
@ -136,7 +136,7 @@ private:
|
||||
|
||||
void paintItem(Painter &p, int x, int y, Item *item, bool selected, bool selectedRemove, TimeMs ms);
|
||||
|
||||
const style::ProfilePeerListItem &_st;
|
||||
const style::PeerListItem &_st;
|
||||
|
||||
base::lambda<void()> _preloadMoreCallback;
|
||||
base::lambda<void(PeerData*)> _selectedCallback;
|
||||
|
@ -38,7 +38,8 @@ constexpr auto kParticipantsPerPage = 200;
|
||||
|
||||
} // namespace
|
||||
|
||||
ParticipantsBoxController::ParticipantsBoxController(not_null<ChannelData*> channel, Role role) : PeerListController(CreateSearchController(channel, role, &_additional))
|
||||
ParticipantsBoxController::ParticipantsBoxController(not_null<ChannelData*> channel, Role role)
|
||||
: PeerListController(CreateSearchController(channel, role, &_additional))
|
||||
, _channel(channel)
|
||||
, _role(role) {
|
||||
if (_channel->mgInfo) {
|
||||
@ -46,10 +47,17 @@ ParticipantsBoxController::ParticipantsBoxController(not_null<ChannelData*> chan
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListSearchController> ParticipantsBoxController::CreateSearchController(not_null<ChannelData*> channel, Role role, not_null<Additional*> additional) {
|
||||
std::unique_ptr<PeerListSearchController>
|
||||
ParticipantsBoxController::CreateSearchController(
|
||||
not_null<ChannelData*> channel,
|
||||
Role role,
|
||||
not_null<Additional*> additional) {
|
||||
// In admins box complex search is used for adding new admins.
|
||||
if (role != Role::Admins || channel->canAddAdmins()) {
|
||||
return std::make_unique<ParticipantsBoxSearchController>(channel, role, additional);
|
||||
return std::make_unique<ParticipantsBoxSearchController>(
|
||||
channel,
|
||||
role,
|
||||
additional);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -86,6 +94,7 @@ void ParticipantsBoxController::Start(not_null<ChannelData*> channel, Role role)
|
||||
}
|
||||
|
||||
void ParticipantsBoxController::addNewItem() {
|
||||
Expects(_role != Role::Profile);
|
||||
if (_role == Role::Members) {
|
||||
if (_channel->membersCount() >= Global::ChatSizeMax()) {
|
||||
Ui::show(
|
||||
@ -131,7 +140,10 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createSearchRow(not_null
|
||||
|
||||
template <typename Callback>
|
||||
void ParticipantsBoxController::HandleParticipant(const MTPChannelParticipant &participant, Role role, not_null<Additional*> additional, Callback callback) {
|
||||
if ((role == Role::Members || role == Role::Admins) && participant.type() == mtpc_channelParticipantAdmin) {
|
||||
if ((role == Role::Profile
|
||||
|| role == Role::Members
|
||||
|| role == Role::Admins)
|
||||
&& participant.type() == mtpc_channelParticipantAdmin) {
|
||||
auto &admin = participant.c_channelParticipantAdmin();
|
||||
if (auto user = App::userLoaded(admin.vuser_id.v)) {
|
||||
additional->adminRights[user] = admin.vadmin_rights;
|
||||
@ -152,13 +164,20 @@ void ParticipantsBoxController::HandleParticipant(const MTPChannelParticipant &p
|
||||
}
|
||||
callback(user);
|
||||
}
|
||||
} else if ((role == Role::Members || role == Role::Admins) && participant.type() == mtpc_channelParticipantCreator) {
|
||||
} else if ((role == Role::Profile
|
||||
|| role == Role::Members
|
||||
|| role == Role::Admins)
|
||||
&& participant.type() == mtpc_channelParticipantCreator) {
|
||||
auto &creator = participant.c_channelParticipantCreator();
|
||||
if (auto user = App::userLoaded(creator.vuser_id.v)) {
|
||||
additional->creator = user;
|
||||
callback(user);
|
||||
}
|
||||
} else if ((role == Role::Members || role == Role::Restricted || role == Role::Kicked) && participant.type() == mtpc_channelParticipantBanned) {
|
||||
} else if ((role == Role::Profile
|
||||
|| role == Role::Members
|
||||
|| role == Role::Restricted
|
||||
|| role == Role::Kicked)
|
||||
&& participant.type() == mtpc_channelParticipantBanned) {
|
||||
auto &banned = participant.c_channelParticipantBanned();
|
||||
if (auto user = App::userLoaded(banned.vuser_id.v)) {
|
||||
additional->restrictedRights[user] = banned.vbanned_rights;
|
||||
@ -172,12 +191,16 @@ void ParticipantsBoxController::HandleParticipant(const MTPChannelParticipant &p
|
||||
}
|
||||
callback(user);
|
||||
}
|
||||
} else if (role == Role::Members && participant.type() == mtpc_channelParticipant) {
|
||||
} else if ((role == Role::Profile
|
||||
|| role == Role::Members)
|
||||
&& participant.type() == mtpc_channelParticipant) {
|
||||
auto &member = participant.c_channelParticipant();
|
||||
if (auto user = App::userLoaded(member.vuser_id.v)) {
|
||||
callback(user);
|
||||
}
|
||||
} else if (role == Role::Members && participant.type() == mtpc_channelParticipantSelf) {
|
||||
} else if ((role == Role::Profile
|
||||
|| role == Role::Members)
|
||||
&& participant.type() == mtpc_channelParticipantSelf) {
|
||||
auto &member = participant.c_channelParticipantSelf();
|
||||
if (auto user = App::userLoaded(member.vuser_id.v)) {
|
||||
callback(user);
|
||||
@ -191,6 +214,7 @@ void ParticipantsBoxController::prepare() {
|
||||
auto titleKey = [this] {
|
||||
switch (_role) {
|
||||
case Role::Admins: return lng_channel_admins;
|
||||
case Role::Profile:
|
||||
case Role::Members: return lng_profile_participants_section;
|
||||
case Role::Restricted: return lng_restricted_list_title;
|
||||
case Role::Kicked: return lng_banned_list_title;
|
||||
@ -219,7 +243,7 @@ void ParticipantsBoxController::loadMoreRows() {
|
||||
}
|
||||
|
||||
auto filter = [this] {
|
||||
if (_role == Role::Members) {
|
||||
if (_role == Role::Members || _role == Role::Profile) {
|
||||
return MTP_channelParticipantsRecent();
|
||||
} else if (_role == Role::Admins) {
|
||||
return MTP_channelParticipantsAdmins();
|
||||
@ -261,7 +285,8 @@ void ParticipantsBoxController::loadMoreRows() {
|
||||
}
|
||||
|
||||
bool ParticipantsBoxController::feedMegagroupLastParticipants() {
|
||||
if (_role != Role::Members || _offset > 0) {
|
||||
if ((_role != Role::Members && _role != Role::Profile)
|
||||
|| _offset > 0) {
|
||||
return false;
|
||||
}
|
||||
auto megagroup = _channel->asMegagroup();
|
||||
@ -322,7 +347,7 @@ void ParticipantsBoxController::rowActionClicked(not_null<PeerListRow*> row) {
|
||||
auto user = row->peer()->asUser();
|
||||
Expects(user != nullptr);
|
||||
|
||||
if (_role == Role::Members) {
|
||||
if (_role == Role::Members || _role == Role::Profile) {
|
||||
kickMember(user);
|
||||
} else if (_role == Role::Admins) {
|
||||
showAdmin(user);
|
||||
@ -617,6 +642,7 @@ bool ParticipantsBoxSearchController::loadMoreRows() {
|
||||
auto filter = [this] {
|
||||
switch (_role) {
|
||||
case Role::Admins: // Search for members, appoint as admin on found.
|
||||
case Role::Profile:
|
||||
case Role::Members: return MTP_channelParticipantsSearch(MTP_string(_query));
|
||||
case Role::Restricted: return MTP_channelParticipantsBanned(MTP_string(_query));
|
||||
case Role::Kicked: return MTP_channelParticipantsKicked(MTP_string(_query));
|
||||
|
@ -27,9 +27,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
namespace Profile {
|
||||
|
||||
// Viewing admins, banned or restricted users list with search.
|
||||
class ParticipantsBoxController : public PeerListController, private base::Subscriber, private MTP::Sender, public base::enable_weak_from_this {
|
||||
class ParticipantsBoxController
|
||||
: public PeerListController
|
||||
, private base::Subscriber
|
||||
, private MTP::Sender
|
||||
, public base::enable_weak_from_this {
|
||||
public:
|
||||
enum class Role {
|
||||
Profile,
|
||||
Members,
|
||||
Admins,
|
||||
Restricted,
|
||||
|
@ -39,11 +39,11 @@ public:
|
||||
event_stream(event_stream &&other);
|
||||
|
||||
template <typename OtherValue>
|
||||
void fire_forward(OtherValue &&value);
|
||||
void fire(Value &&value) {
|
||||
void fire_forward(OtherValue &&value) const;
|
||||
void fire(Value &&value) const {
|
||||
return fire_forward(std::move(value));
|
||||
}
|
||||
void fire_copy(const Value &value) {
|
||||
void fire_copy(const Value &value) const {
|
||||
return fire_forward(value);
|
||||
}
|
||||
producer<Value, no_error> events() const;
|
||||
@ -76,7 +76,8 @@ inline event_stream<Value>::event_stream(event_stream &&other)
|
||||
|
||||
template <typename Value>
|
||||
template <typename OtherValue>
|
||||
inline void event_stream<Value>::fire_forward(OtherValue &&value) {
|
||||
inline void event_stream<Value>::fire_forward(
|
||||
OtherValue &&value) const {
|
||||
if (!_consumers) {
|
||||
return;
|
||||
}
|
||||
|
@ -685,6 +685,10 @@ void ScrollArea::leaveEventHook(QEvent *e) {
|
||||
return QScrollArea::leaveEvent(e);
|
||||
}
|
||||
|
||||
void ScrollArea::scrollTo(ScrollToRequest request) {
|
||||
scrollToY(request.ymin, request.ymax);
|
||||
}
|
||||
|
||||
void ScrollArea::scrollToY(int toTop, int toBottom) {
|
||||
myEnsureResized(widget());
|
||||
myEnsureResized(this);
|
||||
|
@ -34,21 +34,29 @@ enum class TouchScrollState {
|
||||
|
||||
class ScrollArea;
|
||||
|
||||
struct ScrollToRequest {
|
||||
ScrollToRequest(int ymin, int ymax)
|
||||
: ymin(ymin)
|
||||
, ymax(ymax) {
|
||||
}
|
||||
|
||||
int ymin = 0;
|
||||
int ymax = 0;
|
||||
|
||||
};
|
||||
|
||||
class ScrollShadow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ScrollShadow(ScrollArea *parent, const style::ScrollArea *st);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
public slots:
|
||||
|
||||
void changeVisibility(bool shown);
|
||||
|
||||
private:
|
||||
|
||||
const style::ScrollArea *_st;
|
||||
|
||||
};
|
||||
@ -210,6 +218,8 @@ public:
|
||||
return _scrollTopUpdated.events_starting_with(scrollTop());
|
||||
}
|
||||
|
||||
void scrollTo(ScrollToRequest request);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
||||
|
||||
|
@ -1052,7 +1052,7 @@ MediaPlayerButton {
|
||||
ripple: RippleAnimation;
|
||||
}
|
||||
|
||||
ProfilePeerListItem {
|
||||
PeerListItem {
|
||||
left: pixels;
|
||||
bottom: pixels;
|
||||
height: pixels;
|
||||
@ -1068,31 +1068,43 @@ ProfilePeerListItem {
|
||||
statusFgActive: color;
|
||||
}
|
||||
|
||||
defaultProfileMemberItem: ProfilePeerListItem {
|
||||
PeerList {
|
||||
padding: margins;
|
||||
item: PeerListItem;
|
||||
}
|
||||
|
||||
defaultPeerListButton: OutlineButton {
|
||||
outlineWidth: 0px;
|
||||
|
||||
textBg: windowBg;
|
||||
textBgOver: windowBgOver;
|
||||
|
||||
textFg: windowSubTextFg;
|
||||
textFgOver: windowSubTextFgOver;
|
||||
|
||||
font: normalFont;
|
||||
padding: margins(11px, 5px, 11px, 5px);
|
||||
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
|
||||
defaultPeerListItem: PeerListItem {
|
||||
height: 58px;
|
||||
photoPosition: point(12px, 6px);
|
||||
namePosition: point(68px, 11px);
|
||||
statusPosition: point(68px, 31px);
|
||||
photoSize: 46px;
|
||||
button: OutlineButton {
|
||||
outlineWidth: 0px;
|
||||
|
||||
textBg: windowBg;
|
||||
textBgOver: windowBgOver;
|
||||
|
||||
textFg: windowSubTextFg;
|
||||
textFgOver: windowSubTextFgOver;
|
||||
|
||||
font: normalFont;
|
||||
padding: margins(11px, 5px, 11px, 5px);
|
||||
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
button: defaultPeerListButton;
|
||||
statusFg: windowSubTextFg;
|
||||
statusFgOver: windowSubTextFgOver;
|
||||
statusFgActive: windowActiveTextFg;
|
||||
}
|
||||
|
||||
defaultPeerList: PeerList {
|
||||
padding: margins(0px, 0px, 0px, 0px);
|
||||
item: defaultPeerListItem;
|
||||
}
|
||||
|
||||
InfoTopBar {
|
||||
height: pixels;
|
||||
back: IconButton;
|
||||
|
@ -233,6 +233,8 @@
|
||||
<(src_loc)/info/profile/info_profile_inner_widget.h
|
||||
<(src_loc)/info/profile/info_profile_members.cpp
|
||||
<(src_loc)/info/profile/info_profile_members.h
|
||||
<(src_loc)/info/profile/info_profile_members_controllers.cpp
|
||||
<(src_loc)/info/profile/info_profile_members_controllers.h
|
||||
<(src_loc)/info/profile/info_profile_text.cpp
|
||||
<(src_loc)/info/profile/info_profile_text.h
|
||||
<(src_loc)/info/profile/info_profile_values.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user