mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add raised hand display in participants list.
This commit is contained in:
parent
fb579f1c10
commit
361e3565d4
11 changed files with 63 additions and 35 deletions
Binary file not shown.
Before Width: | Height: | Size: 718 B |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/calls/group_calls_raised_hand.png
Normal file
BIN
Telegram/Resources/icons/calls/group_calls_raised_hand.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1,008 B |
BIN
Telegram/Resources/icons/calls/group_calls_raised_hand@2x.png
Normal file
BIN
Telegram/Resources/icons/calls/group_calls_raised_hand@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/icons/calls/group_calls_raised_hand@3x.png
Normal file
BIN
Telegram/Resources/icons/calls/group_calls_raised_hand@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -1923,6 +1923,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_group_call_title" = "Voice Chat";
|
"lng_group_call_title" = "Voice Chat";
|
||||||
"lng_group_call_active" = "speaking";
|
"lng_group_call_active" = "speaking";
|
||||||
"lng_group_call_inactive" = "listening";
|
"lng_group_call_inactive" = "listening";
|
||||||
|
"lng_group_call_raised_hand_status" = "wants to speak";
|
||||||
"lng_group_call_settings" = "Settings";
|
"lng_group_call_settings" = "Settings";
|
||||||
"lng_group_call_unmute" = "Unmute";
|
"lng_group_call_unmute" = "Unmute";
|
||||||
"lng_group_call_unmute_sub" = "or hold spacebar to talk";
|
"lng_group_call_unmute_sub" = "or hold spacebar to talk";
|
||||||
|
|
|
@ -588,6 +588,7 @@ groupCallMemberColoredCrossLine: CrossLineAnimation(groupCallMemberInactiveCross
|
||||||
}
|
}
|
||||||
groupCallMemberInvited: icon {{ "calls/group_calls_invited", groupCallMemberInactiveIcon }};
|
groupCallMemberInvited: icon {{ "calls/group_calls_invited", groupCallMemberInactiveIcon }};
|
||||||
groupCallMemberInvitedPosition: point(2px, 12px);
|
groupCallMemberInvitedPosition: point(2px, 12px);
|
||||||
|
groupCallMemberRaisedHand: icon {{ "calls/group_calls_raised_hand", groupCallMemberInactiveStatus }};
|
||||||
|
|
||||||
groupCallSettings: CallButton(callMicrophoneMute) {
|
groupCallSettings: CallButton(callMicrophoneMute) {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
|
|
|
@ -79,16 +79,20 @@ class Row;
|
||||||
|
|
||||||
class RowDelegate {
|
class RowDelegate {
|
||||||
public:
|
public:
|
||||||
|
struct IconState {
|
||||||
|
float64 speaking = 0.;
|
||||||
|
float64 active = 0.;
|
||||||
|
float64 muted = 0.;
|
||||||
|
bool mutedByMe = false;
|
||||||
|
bool raisedHand = false;
|
||||||
|
};
|
||||||
virtual bool rowIsMe(not_null<PeerData*> participantPeer) = 0;
|
virtual bool rowIsMe(not_null<PeerData*> participantPeer) = 0;
|
||||||
virtual bool rowCanMuteMembers() = 0;
|
virtual bool rowCanMuteMembers() = 0;
|
||||||
virtual void rowUpdateRow(not_null<Row*> row) = 0;
|
virtual void rowUpdateRow(not_null<Row*> row) = 0;
|
||||||
virtual void rowPaintIcon(
|
virtual void rowPaintIcon(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
QRect rect,
|
QRect rect,
|
||||||
float64 speaking,
|
IconState state) = 0;
|
||||||
float64 active,
|
|
||||||
float64 muted,
|
|
||||||
bool mutedByMe) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Row final : public PeerListRow {
|
class Row final : public PeerListRow {
|
||||||
|
@ -101,6 +105,7 @@ public:
|
||||||
Active,
|
Active,
|
||||||
Inactive,
|
Inactive,
|
||||||
Muted,
|
Muted,
|
||||||
|
RaisedHand,
|
||||||
MutedByMe,
|
MutedByMe,
|
||||||
Invited,
|
Invited,
|
||||||
};
|
};
|
||||||
|
@ -281,10 +286,7 @@ public:
|
||||||
void rowPaintIcon(
|
void rowPaintIcon(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
QRect rect,
|
QRect rect,
|
||||||
float64 speaking,
|
IconState state) override;
|
||||||
float64 active,
|
|
||||||
float64 muted,
|
|
||||||
bool mutedByMe) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] std::unique_ptr<Row> createRowForMe();
|
[[nodiscard]] std::unique_ptr<Row> createRowForMe();
|
||||||
|
@ -383,14 +385,19 @@ void Row::updateState(const Data::GroupCall::Participant *participant) {
|
||||||
setSounding(participant->sounding && participant->ssrc != 0);
|
setSounding(participant->sounding && participant->ssrc != 0);
|
||||||
setSpeaking(participant->speaking && participant->ssrc != 0);
|
setSpeaking(participant->speaking && participant->ssrc != 0);
|
||||||
} else if (participant->canSelfUnmute) {
|
} else if (participant->canSelfUnmute) {
|
||||||
setState(participant->mutedByMe ? State::MutedByMe : State::Inactive);
|
setState(participant->mutedByMe
|
||||||
|
? State::MutedByMe
|
||||||
|
: State::Inactive);
|
||||||
setSounding(false);
|
setSounding(false);
|
||||||
setSpeaking(false);
|
setSpeaking(false);
|
||||||
} else {
|
} else {
|
||||||
setState(State::Muted);
|
setState(participant->raisedHandRating
|
||||||
|
? State::RaisedHand
|
||||||
|
: State::Muted);
|
||||||
setSounding(false);
|
setSounding(false);
|
||||||
setSpeaking(false);
|
setSpeaking(false);
|
||||||
}
|
}
|
||||||
|
refreshStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Row::setSpeaking(bool speaking) {
|
void Row::setSpeaking(bool speaking) {
|
||||||
|
@ -406,7 +413,8 @@ void Row::setSpeaking(bool speaking) {
|
||||||
|
|
||||||
if (!_speaking
|
if (!_speaking
|
||||||
|| (_state == State::MutedByMe)
|
|| (_state == State::MutedByMe)
|
||||||
|| (_state == State::Muted)) {
|
|| (_state == State::Muted)
|
||||||
|
|| (_state == State::RaisedHand)) {
|
||||||
_statusIcon = nullptr;
|
_statusIcon = nullptr;
|
||||||
} else if (!_statusIcon) {
|
} else if (!_statusIcon) {
|
||||||
_statusIcon = std::make_unique<StatusIcon>(
|
_statusIcon = std::make_unique<StatusIcon>(
|
||||||
|
@ -456,7 +464,6 @@ void Row::setSounding(bool sounding) {
|
||||||
_blobsAnimation->lastTime = crl::now();
|
_blobsAnimation->lastTime = crl::now();
|
||||||
updateLevel(GroupCall::kSpeakLevelThreshold);
|
updateLevel(GroupCall::kSpeakLevelThreshold);
|
||||||
}
|
}
|
||||||
refreshStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Row::setState(State state) {
|
void Row::setState(State state) {
|
||||||
|
@ -464,10 +471,12 @@ void Row::setState(State state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto wasActive = (_state == State::Active);
|
const auto wasActive = (_state == State::Active);
|
||||||
const auto wasMuted = (_state == State::Muted);
|
const auto wasMuted = (_state == State::Muted)
|
||||||
|
|| (_state == State::RaisedHand);
|
||||||
_state = state;
|
_state = state;
|
||||||
const auto nowActive = (_state == State::Active);
|
const auto nowActive = (_state == State::Active);
|
||||||
const auto nowMuted = (_state == State::Muted);
|
const auto nowMuted = (_state == State::Muted)
|
||||||
|
|| (_state == State::RaisedHand);
|
||||||
if (nowActive != wasActive) {
|
if (nowActive != wasActive) {
|
||||||
_activeAnimation.start(
|
_activeAnimation.start(
|
||||||
[=] { _delegate->rowUpdateRow(this); },
|
[=] { _delegate->rowUpdateRow(this); },
|
||||||
|
@ -679,7 +688,9 @@ void Row::paintStatusText(
|
||||||
int outerWidth,
|
int outerWidth,
|
||||||
bool selected) {
|
bool selected) {
|
||||||
const auto &font = st::normalFont;
|
const auto &font = st::normalFont;
|
||||||
const auto about = (_state == State::Inactive || _state == State::Muted)
|
const auto about = (_state == State::Inactive
|
||||||
|
|| _state == State::Muted
|
||||||
|
|| _state == State::RaisedHand)
|
||||||
? _aboutText
|
? _aboutText
|
||||||
: QString();
|
: QString();
|
||||||
if (_aboutText.isEmpty()
|
if (_aboutText.isEmpty()
|
||||||
|
@ -752,12 +763,17 @@ void Row::paintAction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto speaking = _speakingAnimation.value(_speaking ? 1. : 0.);
|
const auto speaking = _speakingAnimation.value(_speaking ? 1. : 0.);
|
||||||
const auto active = _activeAnimation.value(
|
const auto active = _activeAnimation.value((_state == State::Active) ? 1. : 0.);
|
||||||
(_state == State::Active) ? 1. : 0.);
|
|
||||||
const auto muted = _mutedAnimation.value(
|
const auto muted = _mutedAnimation.value(
|
||||||
(_state == State::Muted) ? 1. : 0.);
|
(_state == State::Muted || _state == State::RaisedHand) ? 1. : 0.);
|
||||||
const auto mutedByMe = (_state == State::MutedByMe);
|
const auto mutedByMe = (_state == State::MutedByMe);
|
||||||
_delegate->rowPaintIcon(p, iconRect, speaking, active, muted, mutedByMe);
|
_delegate->rowPaintIcon(p, iconRect, {
|
||||||
|
.speaking = speaking,
|
||||||
|
.active = active,
|
||||||
|
.muted = muted,
|
||||||
|
.mutedByMe = (_state == State::MutedByMe),
|
||||||
|
.raisedHand = (_state == State::RaisedHand),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Row::refreshStatus() {
|
void Row::refreshStatus() {
|
||||||
|
@ -766,6 +782,8 @@ void Row::refreshStatus() {
|
||||||
? u"%1% %2"_q
|
? u"%1% %2"_q
|
||||||
.arg(std::round(_volume / 100.))
|
.arg(std::round(_volume / 100.))
|
||||||
.arg(tr::lng_group_call_active(tr::now))
|
.arg(tr::lng_group_call_active(tr::now))
|
||||||
|
: (_state == State::RaisedHand)
|
||||||
|
? tr::lng_group_call_raised_hand_status(tr::now)
|
||||||
: tr::lng_group_call_inactive(tr::now)),
|
: tr::lng_group_call_inactive(tr::now)),
|
||||||
_speaking);
|
_speaking);
|
||||||
}
|
}
|
||||||
|
@ -1260,24 +1278,25 @@ void MembersController::rowUpdateRow(not_null<Row*> row) {
|
||||||
void MembersController::rowPaintIcon(
|
void MembersController::rowPaintIcon(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
QRect rect,
|
QRect rect,
|
||||||
float64 speaking,
|
IconState state) {
|
||||||
float64 active,
|
|
||||||
float64 muted,
|
|
||||||
bool mutedByMe) {
|
|
||||||
const auto &greenIcon = st::groupCallMemberColoredCrossLine.icon;
|
const auto &greenIcon = st::groupCallMemberColoredCrossLine.icon;
|
||||||
const auto left = rect.x() + (rect.width() - greenIcon.width()) / 2;
|
const auto left = rect.x() + (rect.width() - greenIcon.width()) / 2;
|
||||||
const auto top = rect.y() + (rect.height() - greenIcon.height()) / 2;
|
const auto top = rect.y() + (rect.height() - greenIcon.height()) / 2;
|
||||||
if (speaking == 1. && !mutedByMe) {
|
if (state.speaking == 1. && !state.mutedByMe) {
|
||||||
// Just green icon, no cross, no coloring.
|
// Just green icon, no cross, no coloring.
|
||||||
greenIcon.paintInCenter(p, rect);
|
greenIcon.paintInCenter(p, rect);
|
||||||
return;
|
return;
|
||||||
} else if (speaking == 0.) {
|
} else if (state.speaking == 0.) {
|
||||||
if (active == 1.) {
|
if (state.active == 1.) {
|
||||||
// Just gray icon, no cross, no coloring.
|
// Just gray icon, no cross, no coloring.
|
||||||
st::groupCallMemberInactiveCrossLine.icon.paintInCenter(p, rect);
|
st::groupCallMemberInactiveCrossLine.icon.paintInCenter(p, rect);
|
||||||
return;
|
return;
|
||||||
} else if (active == 0.) {
|
} else if (state.active == 0.) {
|
||||||
if (muted == 1.) {
|
if (state.muted == 1.) {
|
||||||
|
if (state.raisedHand) {
|
||||||
|
st::groupCallMemberRaisedHand.paintInCenter(p, rect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Red crossed icon, colorized once, cached as last frame.
|
// Red crossed icon, colorized once, cached as last frame.
|
||||||
_coloredCrossLine.paint(
|
_coloredCrossLine.paint(
|
||||||
p,
|
p,
|
||||||
|
@ -1286,7 +1305,7 @@ void MembersController::rowPaintIcon(
|
||||||
1.,
|
1.,
|
||||||
st::groupCallMemberMutedIcon->c);
|
st::groupCallMemberMutedIcon->c);
|
||||||
return;
|
return;
|
||||||
} else if (muted == 0.) {
|
} else if (state.muted == 0.) {
|
||||||
// Gray crossed icon, no coloring, cached as last frame.
|
// Gray crossed icon, no coloring, cached as last frame.
|
||||||
_inactiveCrossLine.paint(p, left, top, 1.);
|
_inactiveCrossLine.paint(p, left, top, 1.);
|
||||||
return;
|
return;
|
||||||
|
@ -1295,17 +1314,18 @@ void MembersController::rowPaintIcon(
|
||||||
}
|
}
|
||||||
const auto activeInactiveColor = anim::color(
|
const auto activeInactiveColor = anim::color(
|
||||||
st::groupCallMemberInactiveIcon,
|
st::groupCallMemberInactiveIcon,
|
||||||
(mutedByMe
|
(state.mutedByMe
|
||||||
? st::groupCallMemberMutedIcon
|
? st::groupCallMemberMutedIcon
|
||||||
: st::groupCallMemberActiveIcon),
|
: st::groupCallMemberActiveIcon),
|
||||||
speaking);
|
state.speaking);
|
||||||
const auto iconColor = anim::color(
|
const auto iconColor = anim::color(
|
||||||
activeInactiveColor,
|
activeInactiveColor,
|
||||||
st::groupCallMemberMutedIcon,
|
st::groupCallMemberMutedIcon,
|
||||||
muted);
|
state.muted);
|
||||||
|
|
||||||
// Don't use caching of the last frame, because 'muted' may animate color.
|
// Don't use caching of the last frame,
|
||||||
const auto crossProgress = std::min(1. - active, 0.9999);
|
// because 'muted' may animate color.
|
||||||
|
const auto crossProgress = std::min(1. - state.active, 0.9999);
|
||||||
_inactiveCrossLine.paint(p, left, top, crossProgress, iconColor);
|
_inactiveCrossLine.paint(p, left, top, crossProgress, iconColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1493,6 +1513,7 @@ void MembersController::addMuteActionsToContextMenu(
|
||||||
|
|
||||||
const auto muteState = row->state();
|
const auto muteState = row->state();
|
||||||
const auto isMuted = (muteState == Row::State::Muted)
|
const auto isMuted = (muteState == Row::State::Muted)
|
||||||
|
|| (muteState == Row::State::RaisedHand)
|
||||||
|| (muteState == Row::State::MutedByMe);
|
|| (muteState == Row::State::MutedByMe);
|
||||||
|
|
||||||
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
|
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
|
||||||
|
@ -1553,7 +1574,7 @@ void MembersController::addMuteActionsToContextMenu(
|
||||||
const auto muteAction = [&]() -> QAction* {
|
const auto muteAction = [&]() -> QAction* {
|
||||||
if (muteState == Row::State::Invited
|
if (muteState == Row::State::Invited
|
||||||
|| isMe(participantPeer)
|
|| isMe(participantPeer)
|
||||||
|| (muteState == Row::State::Muted
|
|| (muteState == Row::State::Inactive
|
||||||
&& participantIsCallAdmin
|
&& participantIsCallAdmin
|
||||||
&& _peer->canManageGroupCall())) {
|
&& _peer->canManageGroupCall())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1561,6 +1582,7 @@ void MembersController::addMuteActionsToContextMenu(
|
||||||
auto callback = [=] {
|
auto callback = [=] {
|
||||||
const auto state = row->state();
|
const auto state = row->state();
|
||||||
const auto muted = (state == Row::State::Muted)
|
const auto muted = (state == Row::State::Muted)
|
||||||
|
|| (state == Row::State::RaisedHand)
|
||||||
|| (state == Row::State::MutedByMe);
|
|| (state == Row::State::MutedByMe);
|
||||||
toggleMute(!muted, false);
|
toggleMute(!muted, false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -301,10 +301,13 @@ void GroupCall::applyParticipantsSlice(
|
||||||
: data.is_muted_by_you();
|
: data.is_muted_by_you();
|
||||||
const auto onlyMinLoaded = data.is_min()
|
const auto onlyMinLoaded = data.is_min()
|
||||||
&& (!was || was->onlyMinLoaded);
|
&& (!was || was->onlyMinLoaded);
|
||||||
|
const auto raisedHandRating
|
||||||
|
= data.vraise_hand_rating().value_or_empty();
|
||||||
const auto value = Participant{
|
const auto value = Participant{
|
||||||
.peer = participantPeer,
|
.peer = participantPeer,
|
||||||
.date = data.vdate().v,
|
.date = data.vdate().v,
|
||||||
.lastActive = lastActive,
|
.lastActive = lastActive,
|
||||||
|
.raisedHandRating = raisedHandRating,
|
||||||
.ssrc = uint32(data.vsource().v),
|
.ssrc = uint32(data.vsource().v),
|
||||||
.volume = volume,
|
.volume = volume,
|
||||||
.applyVolumeFromMin = applyVolumeFromMin,
|
.applyVolumeFromMin = applyVolumeFromMin,
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct GroupCallParticipant {
|
||||||
not_null<PeerData*> peer;
|
not_null<PeerData*> peer;
|
||||||
TimeId date = 0;
|
TimeId date = 0;
|
||||||
TimeId lastActive = 0;
|
TimeId lastActive = 0;
|
||||||
|
uint64 raisedHandRating = 0;
|
||||||
uint32 ssrc = 0;
|
uint32 ssrc = 0;
|
||||||
int volume = 0;
|
int volume = 0;
|
||||||
bool applyVolumeFromMin = true;
|
bool applyVolumeFromMin = true;
|
||||||
|
|
Loading…
Add table
Reference in a new issue