mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 13:17:08 +02:00
Show and play 'allowed to speak' notification.
This commit is contained in:
parent
4d4a349f09
commit
ed4dea2b0e
8 changed files with 124 additions and 40 deletions
|
@ -2002,7 +2002,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_group_call_recording_stop" = "Stop recording";
|
||||
"lng_group_call_recording_started" = "Voice chat recording started.";
|
||||
"lng_group_call_recording_stopped" = "Voice chat recording stopped.";
|
||||
"lng_group_call_recording_saved" = "Audio saved to Saved Messages";
|
||||
"lng_group_call_recording_saved" = "Audio saved to Saved Messages.";
|
||||
"lng_group_call_recording_start_sure" = "Do you want to start recording this chat and save the result into an audio file?\n\nOther members will see the chat is being recorded.";
|
||||
"lng_group_call_recording_stop_sure" = "Do you want to stop recording this chat?";
|
||||
"lng_group_call_recording_start_field" = "Recording Title";
|
||||
|
|
|
@ -9,5 +9,6 @@
|
|||
<file alias="group_call_start.mp3">../../sounds/group_call_start.mp3</file>
|
||||
<file alias="group_call_connect.mp3">../../sounds/group_call_connect.mp3</file>
|
||||
<file alias="group_call_end.mp3">../../sounds/group_call_end.mp3</file>
|
||||
<file alias="group_call_allowed.mp3">../../sounds/group_call_allowed.mp3</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
BIN
Telegram/Resources/sounds/group_call_allowed.mp3
Normal file
BIN
Telegram/Resources/sounds/group_call_allowed.mp3
Normal file
Binary file not shown.
|
@ -201,6 +201,17 @@ GroupCall::GroupCall(
|
|||
}
|
||||
}, _lifetime);
|
||||
|
||||
_instanceState.value(
|
||||
) | rpl::filter([=] {
|
||||
return _hadJoinedState;
|
||||
}) | rpl::start_with_next([=](InstanceState state) {
|
||||
if (state == InstanceState::Disconnected) {
|
||||
playConnectingSound();
|
||||
} else {
|
||||
stopConnectingSound();
|
||||
}
|
||||
}, _lifetime);
|
||||
|
||||
checkGlobalShortcutAvailability();
|
||||
|
||||
const auto id = inputCall.c_inputGroupCall().vid().v;
|
||||
|
@ -269,12 +280,6 @@ void GroupCall::setState(State state) {
|
|||
if (const auto call = _peer->groupCall(); call && call->id() == _id) {
|
||||
call->setInCall();
|
||||
}
|
||||
} else if (state == State::Connecting || state == State::Joining) {
|
||||
if (_hadJoinedState) {
|
||||
playConnectingSound();
|
||||
}
|
||||
} else {
|
||||
stopConnectingSound();
|
||||
}
|
||||
|
||||
if (false
|
||||
|
@ -462,9 +467,10 @@ void GroupCall::rejoin(not_null<PeerData*> as) {
|
|||
MTP_dataJSON(MTP_bytes(json))
|
||||
)).done([=](const MTPUpdates &updates) {
|
||||
_mySsrc = ssrc;
|
||||
setState(_instanceConnected
|
||||
? State::Joined
|
||||
: State::Connecting);
|
||||
setState((_instanceState.current()
|
||||
== InstanceState::Disconnected)
|
||||
? State::Connecting
|
||||
: State::Joined);
|
||||
applyMeInCallLocally();
|
||||
maybeSendMutedUpdate(wasMuteState);
|
||||
_peer->session().api().applyUpdates(updates);
|
||||
|
@ -903,6 +909,9 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
|
|||
} else if (muted() == MuteState::ForceMuted
|
||||
|| muted() == MuteState::RaisedHand) {
|
||||
setMuted(MuteState::Muted);
|
||||
if (!_instanceTransitioning) {
|
||||
notifyAboutAllowedToSpeak();
|
||||
}
|
||||
} else if (data.is_muted() && muted() != MuteState::Muted) {
|
||||
setMuted(MuteState::Muted);
|
||||
}
|
||||
|
@ -1269,19 +1278,37 @@ void GroupCall::checkJoined() {
|
|||
|
||||
void GroupCall::setInstanceConnected(
|
||||
tgcalls::GroupNetworkState networkState) {
|
||||
const auto connected = networkState.isConnected;
|
||||
if (_instanceConnected == connected) {
|
||||
const auto inTransit = networkState.isTransitioningFromBroadcastToRtc;
|
||||
const auto instanceState = !networkState.isConnected
|
||||
? InstanceState::Disconnected
|
||||
: inTransit
|
||||
? InstanceState::TransitionToRtc
|
||||
: InstanceState::Connected;
|
||||
const auto connected = (instanceState != InstanceState::Disconnected);
|
||||
if (_instanceState.current() == instanceState
|
||||
&& _instanceTransitioning == inTransit) {
|
||||
return;
|
||||
}
|
||||
_instanceConnected = connected;
|
||||
const auto nowCanSpeak = connected
|
||||
&& _instanceTransitioning
|
||||
&& !inTransit
|
||||
&& (muted() == MuteState::Muted);
|
||||
_instanceTransitioning = inTransit;
|
||||
_instanceState = instanceState;
|
||||
if (state() == State::Connecting && connected) {
|
||||
setState(State::Joined);
|
||||
if (networkState.isTransitioningFromBroadcastToRtc) {
|
||||
// #TODO calls play sound?..
|
||||
}
|
||||
} else if (state() == State::Joined && !connected) {
|
||||
setState(State::Connecting);
|
||||
}
|
||||
if (nowCanSpeak) {
|
||||
notifyAboutAllowedToSpeak();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCall::notifyAboutAllowedToSpeak() {
|
||||
_delegate->groupCallPlaySound(
|
||||
Delegate::GroupCallSound::AllowedToSpeak);
|
||||
_allowedToSpeakNotifications.fire({});
|
||||
}
|
||||
|
||||
void GroupCall::setInstanceMode(InstanceMode mode) {
|
||||
|
@ -1342,13 +1369,9 @@ void GroupCall::sendSelfUpdate(SendUpdateType type) {
|
|||
}).send();
|
||||
}
|
||||
|
||||
rpl::producer<bool> GroupCall::connectingValue() const {
|
||||
auto GroupCall::instanceStateValue() const -> rpl::producer<InstanceState> {
|
||||
using namespace rpl::mappers;
|
||||
return _state.value() | rpl::map(
|
||||
_1 == State::Creating
|
||||
|| _1 == State::Joining
|
||||
|| _1 == State::Connecting
|
||||
) | rpl::distinct_until_changed();
|
||||
return _instanceState.value();
|
||||
}
|
||||
|
||||
void GroupCall::setCurrentAudioDevice(bool input, const QString &deviceId) {
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
enum class GroupCallSound {
|
||||
Started,
|
||||
Connecting,
|
||||
AllowedToSpeak,
|
||||
Ended,
|
||||
};
|
||||
virtual void groupCallPlaySound(GroupCallSound sound) = 0;
|
||||
|
@ -151,7 +152,13 @@ public:
|
|||
[[nodiscard]] rpl::producer<State> stateValue() const {
|
||||
return _state.value();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<bool> connectingValue() const;
|
||||
|
||||
enum class InstanceState {
|
||||
Disconnected,
|
||||
TransitionToRtc,
|
||||
Connected,
|
||||
};
|
||||
[[nodiscard]] rpl::producer<InstanceState> instanceStateValue() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<LevelUpdate> levelUpdates() const {
|
||||
return _levelUpdates.events();
|
||||
|
@ -159,6 +166,9 @@ public:
|
|||
[[nodiscard]] rpl::producer<Group::RejoinEvent> rejoinEvents() const {
|
||||
return _rejoinEvents.events();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<> allowedToSpeakNotifications() const {
|
||||
return _allowedToSpeakNotifications.events();
|
||||
}
|
||||
static constexpr auto kSpeakLevelThreshold = 0.2;
|
||||
|
||||
void setCurrentAudioDevice(bool input, const QString &deviceId);
|
||||
|
@ -232,6 +242,7 @@ private:
|
|||
|
||||
void checkGlobalShortcutAvailability();
|
||||
void checkJoined();
|
||||
void notifyAboutAllowedToSpeak();
|
||||
|
||||
void playConnectingSound();
|
||||
void stopConnectingSound();
|
||||
|
@ -260,7 +271,9 @@ private:
|
|||
not_null<History*> _history; // Can change in legacy group migration.
|
||||
MTP::Sender _api;
|
||||
rpl::variable<State> _state = State::Creating;
|
||||
bool _instanceConnected = false;
|
||||
rpl::variable<InstanceState> _instanceState
|
||||
= InstanceState::Disconnected;
|
||||
bool _instanceTransitioning = false;
|
||||
InstanceMode _instanceMode = InstanceMode::None;
|
||||
base::flat_set<uint32> _unresolvedSsrcs;
|
||||
std::vector<tgcalls::GroupParticipantDescription> _preparedParticipants;
|
||||
|
@ -290,6 +303,7 @@ private:
|
|||
rpl::event_stream<LevelUpdate> _levelUpdates;
|
||||
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;
|
||||
rpl::event_stream<Group::RejoinEvent> _rejoinEvents;
|
||||
rpl::event_stream<> _allowedToSpeakNotifications;
|
||||
base::Timer _lastSpokeCheckTimer;
|
||||
base::Timer _checkJoinedTimer;
|
||||
|
||||
|
|
|
@ -281,6 +281,30 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
|
|||
initControls();
|
||||
initLayout();
|
||||
showAndActivate();
|
||||
|
||||
call->allowedToSpeakNotifications(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (isActive()) {
|
||||
Ui::Toast::Show(
|
||||
widget(),
|
||||
tr::lng_group_call_can_speak_here(tr::now));
|
||||
} else {
|
||||
const auto real = _peer->groupCall();
|
||||
const auto name = (real
|
||||
&& (real->id() == call->id())
|
||||
&& !real->title().isEmpty())
|
||||
? real->title()
|
||||
: _peer->name;
|
||||
Ui::Toast::Show(Ui::Toast::Config{
|
||||
.text = tr::lng_group_call_can_speak(
|
||||
tr::now,
|
||||
lt_chat,
|
||||
Ui::Text::WithEntities(name),
|
||||
Ui::Text::RichLangValue),
|
||||
.st = &st::defaultToast,
|
||||
});
|
||||
}
|
||||
}, widget()->lifetime());
|
||||
}
|
||||
|
||||
GroupPanel::~GroupPanel() {
|
||||
|
@ -507,13 +531,18 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
|||
}
|
||||
}, _callLifetime);
|
||||
|
||||
using namespace rpl::mappers;
|
||||
rpl::combine(
|
||||
_call->mutedValue() | MapPushToTalkToActive(),
|
||||
_call->connectingValue()
|
||||
_call->instanceStateValue()
|
||||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](MuteState mute, bool connecting) {
|
||||
) | rpl::filter(
|
||||
_2 != GroupCall::InstanceState::TransitionToRtc
|
||||
) | rpl::start_with_next([=](
|
||||
MuteState mute,
|
||||
GroupCall::InstanceState state) {
|
||||
_mute->setState(Ui::CallMuteButtonState{
|
||||
.text = (connecting
|
||||
.text = (state == GroupCall::InstanceState::Disconnected
|
||||
? tr::lng_group_call_connecting(tr::now)
|
||||
: mute == MuteState::ForceMuted
|
||||
? tr::lng_group_call_force_muted(tr::now)
|
||||
|
@ -522,7 +551,7 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
|||
: mute == MuteState::Muted
|
||||
? tr::lng_group_call_unmute(tr::now)
|
||||
: tr::lng_group_call_you_are_live(tr::now)),
|
||||
.subtext = (connecting
|
||||
.subtext = (state == GroupCall::InstanceState::Disconnected
|
||||
? QString()
|
||||
: mute == MuteState::ForceMuted
|
||||
? tr::lng_group_call_raise_hand_tip(tr::now)
|
||||
|
@ -531,7 +560,7 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
|||
: mute == MuteState::Muted
|
||||
? tr::lng_group_call_unmute_sub(tr::now)
|
||||
: QString()),
|
||||
.type = (connecting
|
||||
.type = (state == GroupCall::InstanceState::Disconnected
|
||||
? Ui::CallMuteButtonType::Connecting
|
||||
: mute == MuteState::ForceMuted
|
||||
? Ui::CallMuteButtonType::ForceMuted
|
||||
|
|
|
@ -146,6 +146,7 @@ void Instance::groupCallPlaySound(GroupCallSound sound) {
|
|||
switch (sound) {
|
||||
case GroupCallSound::Started: return "group_call_start";
|
||||
case GroupCallSound::Ended: return "group_call_end";
|
||||
case GroupCallSound::AllowedToSpeak: return "group_call_allowed";
|
||||
case GroupCallSound::Connecting: return "group_call_connect";
|
||||
}
|
||||
Unexpected("GroupCallSound in Instance::groupCallPlaySound.");
|
||||
|
|
|
@ -57,14 +57,14 @@ constexpr auto kHideBlobsDuration = crl::time(500);
|
|||
constexpr auto kBlobLevelDuration = crl::time(250);
|
||||
constexpr auto kBlobUpdateInterval = crl::time(100);
|
||||
|
||||
auto BarStateFromMuteState(MuteState state, bool connecting) {
|
||||
return (connecting
|
||||
auto BarStateFromMuteState(MuteState state, GroupCall::InstanceState instanceState) {
|
||||
return (instanceState == GroupCall::InstanceState::Disconnected)
|
||||
? BarState::Connecting
|
||||
: (state == MuteState::ForceMuted || state == MuteState::RaisedHand)
|
||||
? BarState::ForceMuted
|
||||
: state == MuteState::Muted
|
||||
: (state == MuteState::Muted)
|
||||
? BarState::Muted
|
||||
: BarState::Active);
|
||||
: BarState::Active;
|
||||
};
|
||||
|
||||
auto LinearBlobs() {
|
||||
|
@ -293,17 +293,20 @@ void TopBar::initControls() {
|
|||
_call
|
||||
? mapToState(_call->muted())
|
||||
: _groupCall->muted(),
|
||||
false));
|
||||
GroupCall::InstanceState::Connected));
|
||||
using namespace rpl::mappers;
|
||||
auto muted = _call
|
||||
? rpl::combine(
|
||||
_call->mutedValue() | rpl::map(mapToState),
|
||||
rpl::single(false)) | rpl::type_erased()
|
||||
rpl::single(GroupCall::InstanceState::Connected)
|
||||
) | rpl::type_erased()
|
||||
: rpl::combine(
|
||||
(_groupCall->mutedValue()
|
||||
| MapPushToTalkToActive()
|
||||
| rpl::distinct_until_changed()
|
||||
| rpl::type_erased()),
|
||||
_groupCall->connectingValue());
|
||||
_groupCall->instanceStateValue()
|
||||
) | rpl::filter(_2 != GroupCall::InstanceState::TransitionToRtc);
|
||||
std::move(
|
||||
muted
|
||||
) | rpl::map(
|
||||
|
@ -465,9 +468,14 @@ void TopBar::initBlobsUnder(
|
|||
auto hideBlobs = rpl::combine(
|
||||
rpl::single(anim::Disabled()) | rpl::then(anim::Disables()),
|
||||
Core::App().appDeactivatedValue(),
|
||||
group->connectingValue()
|
||||
) | rpl::map([](bool animDisabled, bool hide, bool connecting) {
|
||||
return connecting || animDisabled || hide;
|
||||
group->instanceStateValue()
|
||||
) | rpl::map([](
|
||||
bool animDisabled,
|
||||
bool hide,
|
||||
GroupCall::InstanceState instanceState) {
|
||||
return (instanceState == GroupCall::InstanceState::Disconnected)
|
||||
|| animDisabled
|
||||
|| hide;
|
||||
});
|
||||
|
||||
std::move(
|
||||
|
@ -557,7 +565,12 @@ void TopBar::subscribeToMembersChanges(not_null<GroupCall*> call) {
|
|||
return call && real && (real->id() == call->id());
|
||||
}) | rpl::take(
|
||||
1
|
||||
) | rpl::map([=](not_null<Data::GroupCall*> real) {
|
||||
) | rpl::before_next([=](not_null<Data::GroupCall*> real) {
|
||||
real->titleValue() | rpl::start_with_next([=] {
|
||||
updateInfoLabels();
|
||||
}, lifetime());
|
||||
}) | rpl::map([=](not_null<Data::GroupCall*> real) {
|
||||
|
||||
return HistoryView::GroupCallTracker::ContentByCall(
|
||||
real,
|
||||
st::groupCallTopBarUserpics.size);
|
||||
|
@ -616,9 +629,12 @@ void TopBar::setInfoLabels() {
|
|||
_shortInfoLabel->setText(shortName.toUpper());
|
||||
} else if (const auto group = _groupCall.get()) {
|
||||
const auto peer = group->peer();
|
||||
const auto real = peer->groupCall();
|
||||
const auto name = peer->name;
|
||||
const auto text = _isGroupConnecting.current()
|
||||
? tr::lng_group_call_connecting(tr::now)
|
||||
: (real && real->id() == group->id() && !real->title().isEmpty())
|
||||
? real->title().toUpper()
|
||||
: name.toUpper();
|
||||
_fullInfoLabel->setText(text);
|
||||
_shortInfoLabel->setText(text);
|
||||
|
|
Loading…
Add table
Reference in a new issue