Added members grouping by role to participants controller.

This commit is contained in:
23rd
2026-07-17 17:34:48 +03:00
parent e946bc2fa2
commit 9fa11844f2
2 changed files with 134 additions and 29 deletions

View File

@@ -1034,33 +1034,37 @@ void ParticipantsOnlineSorter::sort() {
_onlineCount = 0; _onlineCount = 0;
return; return;
} }
const auto now = base::unixtime::now(); if (_sortingEnabled) {
_delegate->peerListSortRows([&]( const auto now = base::unixtime::now();
const PeerListRow &a, _delegate->peerListSortRows([&](
const PeerListRow &b) { const PeerListRow &a,
return Data::SortByOnlineValue(a.peer()->asUser(), now) > const PeerListRow &b) {
Data::SortByOnlineValue(b.peer()->asUser(), now); return Data::SortByOnlineValue(a.peer()->asUser(), now) >
}); Data::SortByOnlineValue(b.peer()->asUser(), now);
});
}
refreshOnlineCount(); refreshOnlineCount();
} }
void ParticipantsOnlineSorter::setSortingEnabled(bool enabled) {
_sortingEnabled = enabled;
}
rpl::producer<int> ParticipantsOnlineSorter::onlineCountValue() const { rpl::producer<int> ParticipantsOnlineSorter::onlineCountValue() const {
return _onlineCount.value(); return _onlineCount.value();
} }
void ParticipantsOnlineSorter::refreshOnlineCount() { void ParticipantsOnlineSorter::refreshOnlineCount() {
const auto now = base::unixtime::now(); const auto now = base::unixtime::now();
auto left = 0, right = _delegate->peerListFullRowsCount(); auto count = 0;
while (right > left) { const auto rows = _delegate->peerListFullRowsCount();
const auto middle = (left + right) / 2; for (auto i = 0; i != rows; ++i) {
const auto row = _delegate->peerListRowAt(middle); const auto user = _delegate->peerListRowAt(i)->peer()->asUser();
if (Data::OnlineTextActive(row->peer()->asUser(), now)) { if (user && Data::OnlineTextActive(user, now)) {
left = middle + 1; ++count;
} else {
right = middle;
} }
} }
_onlineCount = left; _onlineCount = count;
} }
ParticipantsBoxController::SavedState::SavedState( ParticipantsBoxController::SavedState::SavedState(
@@ -1112,6 +1116,20 @@ void ParticipantsBoxController::setupListChangeViewers() {
channel->owner().megagroupParticipantAdded( channel->owner().megagroupParticipantAdded(
channel channel
) | rpl::on_next([=](not_null<UserData*> user) { ) | rpl::on_next([=](not_null<UserData*> user) {
if (_groupByRole.current()) {
if (!delegate()->peerListFindRow(user->id.value)) {
if (auto row = createRow(user)) {
const auto raw = row.get();
delegate()->peerListPrependRow(std::move(row));
if (_stories) {
_stories->process(raw);
}
refreshRows();
resort();
}
}
return;
}
if (delegate()->peerListFullRowsCount() > 0) { if (delegate()->peerListFullRowsCount() > 0) {
if (delegate()->peerListRowAt(0)->peer() == user) { if (delegate()->peerListRowAt(0)->peer() == user) {
return; return;
@@ -1128,9 +1146,7 @@ void ParticipantsBoxController::setupListChangeViewers() {
_stories->process(raw); _stories->process(raw);
} }
refreshRows(); refreshRows();
if (_onlineSorter) { resort();
_onlineSorter->sort();
}
} }
}, lifetime()); }, lifetime());
@@ -1401,9 +1417,7 @@ void ParticipantsBoxController::restoreState(
refreshRows(); refreshRows();
} }
} }
if (_onlineSorter) { resort();
_onlineSorter->sort();
}
} }
} }
@@ -1501,6 +1515,9 @@ void ParticipantsBoxController::prepare() {
} }
} }
recomputeTypeFor(user); recomputeTypeFor(user);
if (_groupByRole.current()) {
resort();
}
refreshRows(); refreshRows();
}, lifetime()); }, lifetime());
@@ -1618,7 +1635,7 @@ void ParticipantsBoxController::rebuildChatParticipants(
} }
} }
} }
_onlineSorter->sort(); resort();
refreshRows(); refreshRows();
chatListReady(); chatListReady();
@@ -1777,9 +1794,7 @@ void ParticipantsBoxController::loadMoreRows() {
|| (firstLoad && delegate()->peerListFullRowsCount() > 0)) { || (firstLoad && delegate()->peerListFullRowsCount() > 0)) {
refreshDescription(); refreshDescription();
} }
if (_onlineSorter) { resort();
_onlineSorter->sort();
}
refreshRows(); refreshRows();
}).fail([this] { }).fail([this] {
_loadRequestId = 0; _loadRequestId = 0;
@@ -1839,9 +1854,7 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() {
// //
//++_offset; //++_offset;
} }
if (_onlineSorter) { resort();
_onlineSorter->sort();
}
return added; return added;
} }
@@ -2644,6 +2657,87 @@ void ParticipantsBoxController::refreshRows() {
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
int ParticipantsBoxController::memberRoleTier(
not_null<PeerData*> peer) const {
const auto user = peer->asUser();
if (user && _additional.isCreator(user)) {
return 0;
} else if (user && user->isBot()) {
return 2;
} else if (user && _additional.adminRights(user).has_value()) {
return 1;
}
return 3;
}
void ParticipantsBoxController::sortByRoleAndName() {
delegate()->peerListSortRows([&](
const PeerListRow &a,
const PeerListRow &b) {
const auto tierA = memberRoleTier(a.peer());
const auto tierB = memberRoleTier(b.peer());
return (tierA != tierB)
? (tierA < tierB)
: (a.peer()->name().compare(
b.peer()->name(),
Qt::CaseInsensitive) < 0);
});
}
void ParticipantsBoxController::applyRoleSectionHeaders() {
const auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) {
const auto row = delegate()->peerListRowAt(i);
row->setSection([&] {
switch (memberRoleTier(row->peer())) {
case 0: return tr::lng_channel_admin_status_creator(tr::now);
case 1: return tr::lng_channel_admins(tr::now);
case 2: return tr::lng_filters_type_bots(tr::now);
}
return tr::lng_profile_participants_section(tr::now);
}());
}
}
void ParticipantsBoxController::resort() {
if (_groupByRole.current()) {
if (_onlineSorter) {
_onlineSorter->setSortingEnabled(false);
_onlineSorter->sort();
}
sortByRoleAndName();
applyRoleSectionHeaders();
delegate()->peerListSetShowSectionHeaders(true);
delegate()->peerListRefreshRows();
} else {
delegate()->peerListSetShowSectionHeaders(false);
if (_onlineSorter) {
_onlineSorter->setSortingEnabled(true);
_onlineSorter->sort();
}
}
}
void ParticipantsBoxController::setGroupByRole(bool grouped) {
if (_groupByRole.current() == grouped) {
return;
}
_groupByRole = grouped;
resort();
}
rpl::producer<bool> ParticipantsBoxController::groupByRoleValue() const {
return _groupByRole.value();
}
auto ParticipantsBoxController::groupByRoleAvailableValue() const
-> rpl::producer<bool> {
if (_peer->isMegagroup()) {
return Info::Profile::CanViewParticipantsValue(_peer->asMegagroup());
}
return rpl::single(true);
}
ParticipantsBoxSearchController::ParticipantsBoxSearchController( ParticipantsBoxSearchController::ParticipantsBoxSearchController(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
Role role, Role role,

View File

@@ -87,6 +87,7 @@ public:
not_null<PeerListDelegate*> delegate); not_null<PeerListDelegate*> delegate);
void sort(); void sort();
void setSortingEnabled(bool enabled);
rpl::producer<int> onlineCountValue() const; rpl::producer<int> onlineCountValue() const;
private: private:
@@ -97,6 +98,7 @@ private:
const not_null<PeerListDelegate*> _delegate; const not_null<PeerListDelegate*> _delegate;
base::Timer _sortByOnlineTimer; base::Timer _sortByOnlineTimer;
rpl::variable<int> _onlineCount = 0; rpl::variable<int> _onlineCount = 0;
bool _sortingEnabled = true;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;
}; };
@@ -228,6 +230,10 @@ public:
[[nodiscard]] rpl::producer<int> onlineCountValue() const; [[nodiscard]] rpl::producer<int> onlineCountValue() const;
[[nodiscard]] rpl::producer<int> fullCountValue() const; [[nodiscard]] rpl::producer<int> fullCountValue() const;
void setGroupByRole(bool grouped);
[[nodiscard]] rpl::producer<bool> groupByRoleValue() const;
[[nodiscard]] rpl::producer<bool> groupByRoleAvailableValue() const;
void setStoriesShown(bool shown); void setStoriesShown(bool shown);
protected: protected:
@@ -314,6 +320,10 @@ private:
void subscribeToCreatorChange(not_null<ChannelData*> channel); void subscribeToCreatorChange(not_null<ChannelData*> channel);
void fullListRefresh(); void fullListRefresh();
void refreshRows(); void refreshRows();
void resort();
void sortByRoleAndName();
void applyRoleSectionHeaders();
[[nodiscard]] int memberRoleTier(not_null<PeerData*> peer) const;
// It may be nullptr in subclasses of this controller. // It may be nullptr in subclasses of this controller.
Window::SessionNavigation *_navigation = nullptr; Window::SessionNavigation *_navigation = nullptr;
@@ -326,6 +336,7 @@ private:
bool _allLoaded = false; bool _allLoaded = false;
ParticipantsAdditionalData _additional; ParticipantsAdditionalData _additional;
std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter; std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
rpl::variable<bool> _groupByRole = false;
rpl::variable<int> _onlineCountValue; rpl::variable<int> _onlineCountValue;
rpl::variable<int> _fullCountValue; rpl::variable<int> _fullCountValue;
Ui::BoxPointer _editBox; Ui::BoxPointer _editBox;