Respect raise_hand_rating in participants list.

This commit is contained in:
John Preston 2021-03-09 16:26:30 +04:00
parent 4d8ac05d28
commit 50265afe93

View file

@ -127,9 +127,15 @@ public:
[[nodiscard]] bool speaking() const { [[nodiscard]] bool speaking() const {
return _speaking; return _speaking;
} }
[[nodiscard]] crl::time speakingLastTime() const {
return _speakingLastTime;
}
[[nodiscard]] int volume() const { [[nodiscard]] int volume() const {
return _volume; return _volume;
} }
[[nodiscard]] uint64 raisedHandRating() const {
return _raisedHandRating;
}
void addActionRipple(QPoint point, Fn<void()> updateCallback) override; void addActionRipple(QPoint point, Fn<void()> updateCallback) override;
void stopLastActionRipple() override; void stopLastActionRipple() override;
@ -242,6 +248,8 @@ private:
Ui::Animations::Simple _activeAnimation; // For icon cross animation. Ui::Animations::Simple _activeAnimation; // For icon cross animation.
Ui::Animations::Simple _arcsAnimation; // For volume arcs animation. Ui::Animations::Simple _arcsAnimation; // For volume arcs animation.
QString _aboutText; QString _aboutText;
crl::time _speakingLastTime = 0;
uint64 _raisedHandRating = 0;
uint32 _ssrc = 0; uint32 _ssrc = 0;
int _volume = Group::kDefaultVolume; int _volume = Group::kDefaultVolume;
bool _sounding = false; bool _sounding = false;
@ -317,7 +325,12 @@ private:
const Data::GroupCall::Participant *participant); const Data::GroupCall::Participant *participant);
void removeRow(not_null<Row*> row); void removeRow(not_null<Row*> row);
void updateRowLevel(not_null<Row*> row, float level); void updateRowLevel(not_null<Row*> row, float level);
void checkSpeakingRowPosition(not_null<Row*> row); void checkRowPosition(not_null<Row*> row);
[[nodiscard]] bool needToReorder(not_null<Row*> row) const;
[[nodiscard]] bool allRowsAboveAreSpeaking(not_null<Row*> row) const;
[[nodiscard]] bool allRowsAboveMoreImportantThanHand(
not_null<Row*> row,
uint64 raiseHandRating) const;
Row *findRow(not_null<PeerData*> participantPeer) const; Row *findRow(not_null<PeerData*> participantPeer) const;
[[nodiscard]] Data::GroupCall *resolvedRealCall() const; [[nodiscard]] Data::GroupCall *resolvedRealCall() const;
@ -379,21 +392,23 @@ void Row::updateState(const Data::GroupCall::Participant *participant) {
setState(State::Invited); setState(State::Invited);
setSounding(false); setSounding(false);
setSpeaking(false); setSpeaking(false);
_raisedHandRating = 0;
} else if (!participant->muted } else if (!participant->muted
|| (participant->sounding && participant->ssrc != 0)) { || (participant->sounding && participant->ssrc != 0)) {
setState(participant->mutedByMe ? State::MutedByMe : State::Active); setState(participant->mutedByMe ? State::MutedByMe : State::Active);
setSounding(participant->sounding && participant->ssrc != 0); setSounding(participant->sounding && participant->ssrc != 0);
setSpeaking(participant->speaking && participant->ssrc != 0); setSpeaking(participant->speaking && participant->ssrc != 0);
_raisedHandRating = 0;
} else if (participant->canSelfUnmute) { } else if (participant->canSelfUnmute) {
setState(participant->mutedByMe setState(participant->mutedByMe
? State::MutedByMe ? State::MutedByMe
: State::Inactive); : State::Inactive);
setSounding(false); setSounding(false);
setSpeaking(false); setSpeaking(false);
_raisedHandRating = 0;
} else { } else {
setState(participant->raisedHandRating _raisedHandRating = participant->raisedHandRating;
? State::RaisedHand setState(_raisedHandRating ? State::RaisedHand : State::Muted);
: State::Muted);
setSounding(false); setSounding(false);
setSpeaking(false); setSpeaking(false);
} }
@ -507,12 +522,19 @@ void Row::setVolume(int volume) {
void Row::updateLevel(float level) { void Row::updateLevel(float level) {
Expects(_blobsAnimation != nullptr); Expects(_blobsAnimation != nullptr);
const auto spoke = (level >= GroupCall::kSpeakLevelThreshold)
? crl::now()
: crl::time();
if (spoke && _speaking) {
_speakingLastTime = spoke;
}
if (_skipLevelUpdate) { if (_skipLevelUpdate) {
return; return;
} }
if (level >= GroupCall::kSpeakLevelThreshold) { if (spoke) {
_blobsAnimation->lastSoundingUpdateTime = crl::now(); _blobsAnimation->lastSoundingUpdateTime = spoke;
} }
_blobsAnimation->blobs.setLevel(level); _blobsAnimation->blobs.setLevel(level);
} }
@ -1003,14 +1025,16 @@ void MembersController::updateRow(
auto reorderIfInvitedBeforeIndex = 0; auto reorderIfInvitedBeforeIndex = 0;
auto countChange = 0; auto countChange = 0;
if (const auto row = findRow(now.peer)) { if (const auto row = findRow(now.peer)) {
if (now.speaking && (!was || !was->speaking)) {
checkSpeakingRowPosition(row);
}
if (row->state() == Row::State::Invited) { if (row->state() == Row::State::Invited) {
reorderIfInvitedBeforeIndex = row->absoluteIndex(); reorderIfInvitedBeforeIndex = row->absoluteIndex();
countChange = 1; countChange = 1;
} }
updateRow(row, &now); 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)) { } else if (auto row = createRow(now)) {
if (row->speaking()) { if (row->speaking()) {
delegate()->peerListPrependRow(std::move(row)); delegate()->peerListPrependRow(std::move(row));
@ -1045,39 +1069,107 @@ void MembersController::updateRow(
} }
} }
void MembersController::checkSpeakingRowPosition(not_null<Row*> row) { bool MembersController::allRowsAboveAreSpeaking(not_null<Row*> row) const {
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.
const auto count = delegate()->peerListFullRowsCount(); const auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) { for (auto i = 0; i != count; ++i) {
const auto above = delegate()->peerListRowAt(i); const auto above = delegate()->peerListRowAt(i);
if (above == row) { if (above == row) {
// All rows above are speaking. // All rows above are speaking.
return; return true;
} else if (!static_cast<Row*>(above.get())->speaking()) { } else if (!static_cast<Row*>(above.get())->speaking()) {
break; break;
} }
} }
// Someone started speaking and has a non-speaking row above him. Sort. return false;
const auto proj = [&](const PeerListRow &other) { }
if (&other == row.get()) {
// Bring this new one to the top. bool MembersController::allRowsAboveMoreImportantThanHand(
return 0; not_null<Row*> row,
} else if (static_cast<const Row&>(other).speaking()) { uint64 raiseHandRating) const {
// Bring all the speaking ones below him. Expects(raiseHandRating > 0);
return 1;
} else { const auto count = delegate()->peerListFullRowsCount();
return 2; 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<Row*>(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*> 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<Row*>(next.get())->state();
if ((state != Row::State::Muted) && (state != Row::State::RaisedHand)) {
return true;
}
if (!rating && static_cast<Row*>(next.get())->raisedHandRating()) {
return true;
}
return false;
}
void MembersController::checkRowPosition(not_null<Row*> 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<uint64>::max();
const auto proj = [&](const PeerListRow &other) {
const auto &real = static_cast<const Row&>(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<uint64>::max() - 2);
}; };
delegate()->peerListSortRows([&]( delegate()->peerListSortRows([&](
const PeerListRow &a, const PeerListRow &a,
const PeerListRow &b) { const PeerListRow &b) {
return proj(a) < proj(b); return proj(a) > proj(b);
}); });
} }
@ -1342,9 +1434,7 @@ void MembersController::rowClicked(not_null<PeerListRow*> row) {
auto saved = base::take(_menu); auto saved = base::take(_menu);
for (const auto peer : base::take(_menuCheckRowsAfterHidden)) { for (const auto peer : base::take(_menuCheckRowsAfterHidden)) {
if (const auto row = findRow(peer)) { if (const auto row = findRow(peer)) {
if (row->speaking()) { checkRowPosition(row);
checkSpeakingRowPosition(row);
}
} }
} }
_menu = std::move(saved); _menu = std::move(saved);