From 50265afe93d10fc48cff57400d9ebbe51b80b952 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 9 Mar 2021 16:26:30 +0400 Subject: [PATCH] Respect raise_hand_rating in participants list. --- .../SourceFiles/calls/calls_group_members.cpp | 152 ++++++++++++++---- 1 file changed, 121 insertions(+), 31 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_group_members.cpp b/Telegram/SourceFiles/calls/calls_group_members.cpp index 2e8edb8a7a..e66085eced 100644 --- a/Telegram/SourceFiles/calls/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/calls_group_members.cpp @@ -127,9 +127,15 @@ public: [[nodiscard]] bool speaking() const { return _speaking; } + [[nodiscard]] crl::time speakingLastTime() const { + return _speakingLastTime; + } [[nodiscard]] int volume() const { return _volume; } + [[nodiscard]] uint64 raisedHandRating() const { + return _raisedHandRating; + } void addActionRipple(QPoint point, Fn updateCallback) override; void stopLastActionRipple() override; @@ -242,6 +248,8 @@ private: Ui::Animations::Simple _activeAnimation; // For icon cross animation. Ui::Animations::Simple _arcsAnimation; // For volume arcs animation. QString _aboutText; + crl::time _speakingLastTime = 0; + uint64 _raisedHandRating = 0; uint32 _ssrc = 0; int _volume = Group::kDefaultVolume; bool _sounding = false; @@ -317,7 +325,12 @@ private: const Data::GroupCall::Participant *participant); void removeRow(not_null row); void updateRowLevel(not_null row, float level); - void checkSpeakingRowPosition(not_null row); + void checkRowPosition(not_null row); + [[nodiscard]] bool needToReorder(not_null row) const; + [[nodiscard]] bool allRowsAboveAreSpeaking(not_null row) const; + [[nodiscard]] bool allRowsAboveMoreImportantThanHand( + not_null row, + uint64 raiseHandRating) const; Row *findRow(not_null participantPeer) const; [[nodiscard]] Data::GroupCall *resolvedRealCall() const; @@ -379,21 +392,23 @@ void Row::updateState(const Data::GroupCall::Participant *participant) { setState(State::Invited); setSounding(false); setSpeaking(false); + _raisedHandRating = 0; } else if (!participant->muted || (participant->sounding && participant->ssrc != 0)) { setState(participant->mutedByMe ? State::MutedByMe : State::Active); setSounding(participant->sounding && participant->ssrc != 0); setSpeaking(participant->speaking && participant->ssrc != 0); + _raisedHandRating = 0; } else if (participant->canSelfUnmute) { setState(participant->mutedByMe ? State::MutedByMe : State::Inactive); setSounding(false); setSpeaking(false); + _raisedHandRating = 0; } else { - setState(participant->raisedHandRating - ? State::RaisedHand - : State::Muted); + _raisedHandRating = participant->raisedHandRating; + setState(_raisedHandRating ? State::RaisedHand : State::Muted); setSounding(false); setSpeaking(false); } @@ -507,12 +522,19 @@ void Row::setVolume(int volume) { void Row::updateLevel(float level) { Expects(_blobsAnimation != nullptr); + const auto spoke = (level >= GroupCall::kSpeakLevelThreshold) + ? crl::now() + : crl::time(); + if (spoke && _speaking) { + _speakingLastTime = spoke; + } + if (_skipLevelUpdate) { return; } - if (level >= GroupCall::kSpeakLevelThreshold) { - _blobsAnimation->lastSoundingUpdateTime = crl::now(); + if (spoke) { + _blobsAnimation->lastSoundingUpdateTime = spoke; } _blobsAnimation->blobs.setLevel(level); } @@ -1003,14 +1025,16 @@ void MembersController::updateRow( auto reorderIfInvitedBeforeIndex = 0; auto countChange = 0; if (const auto row = findRow(now.peer)) { - if (now.speaking && (!was || !was->speaking)) { - checkSpeakingRowPosition(row); - } if (row->state() == Row::State::Invited) { reorderIfInvitedBeforeIndex = row->absoluteIndex(); countChange = 1; } updateRow(row, &now); + if ((now.speaking && (!was || !was->speaking)) + || (now.raisedHandRating != (was ? was->raisedHandRating : 0)) + || (!now.canSelfUnmute && was && was->canSelfUnmute)) { + checkRowPosition(row); + } } else if (auto row = createRow(now)) { if (row->speaking()) { delegate()->peerListPrependRow(std::move(row)); @@ -1045,39 +1069,107 @@ void MembersController::updateRow( } } -void MembersController::checkSpeakingRowPosition(not_null row) { - if (_menu) { - // Don't reorder rows while we show the popup menu. - _menuCheckRowsAfterHidden.emplace(row->peer()); - return; - } - // Check if there are non-speaking rows above this one. +bool MembersController::allRowsAboveAreSpeaking(not_null row) const { const auto count = delegate()->peerListFullRowsCount(); for (auto i = 0; i != count; ++i) { const auto above = delegate()->peerListRowAt(i); if (above == row) { // All rows above are speaking. - return; + return true; } else if (!static_cast(above.get())->speaking()) { break; } } - // Someone started speaking and has a non-speaking row above him. Sort. - const auto proj = [&](const PeerListRow &other) { - if (&other == row.get()) { - // Bring this new one to the top. - return 0; - } else if (static_cast(other).speaking()) { - // Bring all the speaking ones below him. - return 1; - } else { - return 2; + return false; +} + +bool MembersController::allRowsAboveMoreImportantThanHand( + not_null row, + uint64 raiseHandRating) const { + Expects(raiseHandRating > 0); + + const auto count = delegate()->peerListFullRowsCount(); + for (auto i = 0; i != count; ++i) { + const auto above = delegate()->peerListRowAt(i); + if (above == row) { + // All rows above are 'more important' than this raised hand. + return true; } + const auto real = static_cast(above.get()); + const auto state = real->state(); + if (state == Row::State::Muted + || (state == Row::State::RaisedHand + && real->raisedHandRating() < raiseHandRating)) { + break; + } + } + return false; +} + +bool MembersController::needToReorder(not_null row) const { + // All reorder cases: + // - bring speaking up + // - bring raised hand up + // - bring muted down + + if (row->speaking()) { + return !allRowsAboveAreSpeaking(row); + } + + const auto rating = row->raisedHandRating(); + if (!rating && row->state() != Row::State::Muted) { + return false; + } + if (rating > 0 && !allRowsAboveMoreImportantThanHand(row, rating)) { + return true; + } + const auto index = row->absoluteIndex(); + if (index + 1 == delegate()->peerListFullRowsCount()) { + // Last one, can't bring lower. + return false; + } + const auto next = delegate()->peerListRowAt(index + 1); + const auto state = static_cast(next.get())->state(); + if ((state != Row::State::Muted) && (state != Row::State::RaisedHand)) { + return true; + } + if (!rating && static_cast(next.get())->raisedHandRating()) { + return true; + } + return false; +} + +void MembersController::checkRowPosition(not_null row) { + if (_menu) { + // Don't reorder rows while we show the popup menu. + _menuCheckRowsAfterHidden.emplace(row->peer()); + return; + } else if (!needToReorder(row)) { + return; + } + + // Someone started speaking and has a non-speaking row above him. + // Or someone raised hand and has force muted above him. + // Or someone was forced muted and had can_unmute_self below him. Sort. + static constexpr auto kTop = std::numeric_limits::max(); + const auto proj = [&](const PeerListRow &other) { + const auto &real = static_cast(other); + return real.speaking() + // Speaking 'row' to the top, all other speaking below it. + ? (&real == row.get() ? kTop : (kTop - 1)) + : (real.raisedHandRating() > 0) + // Then all raised hands sorted by rating. + ? real.raisedHandRating() + : (real.state() == Row::State::Muted) + // All force muted at the bottom, but 'row' still above others. + ? (&real == row.get() ? 1ULL : 0ULL) + // All not force-muted lie between raised hands and speaking. + : (std::numeric_limits::max() - 2); }; delegate()->peerListSortRows([&]( const PeerListRow &a, const PeerListRow &b) { - return proj(a) < proj(b); + return proj(a) > proj(b); }); } @@ -1342,9 +1434,7 @@ void MembersController::rowClicked(not_null row) { auto saved = base::take(_menu); for (const auto peer : base::take(_menuCheckRowsAfterHidden)) { if (const auto row = findRow(peer)) { - if (row->speaking()) { - checkSpeakingRowPosition(row); - } + checkRowPosition(row); } } _menu = std::move(saved);