Add push-to-talk release delay.

This commit is contained in:
John Preston 2020-12-06 16:44:20 +04:00
parent 80b7858f5e
commit 72a8b92827
7 changed files with 111 additions and 11 deletions

View file

@ -1839,6 +1839,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_push_to_talk" = "Push to Talk"; "lng_group_call_push_to_talk" = "Push to Talk";
"lng_group_call_ptt_shortcut" = "Edit Shortcut"; "lng_group_call_ptt_shortcut" = "Edit Shortcut";
"lng_group_call_ptt_recording" = "Stop Recording"; "lng_group_call_ptt_recording" = "Stop Recording";
"lng_group_call_ptt_delay_ms" = "{amount} ms";
"lng_group_call_ptt_delay_s" = "{amount}s";
"lng_group_call_ptt_delay" = "Push to Talk release delay: {delay}";
"lng_group_call_share" = "Share Invite Link"; "lng_group_call_share" = "Share Invite Link";
"lng_group_call_end" = "End Voice Chat"; "lng_group_call_end" = "End Voice Chat";
"lng_group_call_join" = "Join"; "lng_group_call_join" = "Join";

View file

@ -670,6 +670,23 @@ groupCallBoxLabel: FlatLabel(boxLabel) {
groupCallRowBlobMinRadius: 27px; groupCallRowBlobMinRadius: 27px;
groupCallRowBlobMaxRadius: 29px; groupCallRowBlobMaxRadius: 29px;
groupCallDelayLabel: LabelSimple(defaultLabelSimple) {
textFg: groupCallMembersFg;
font: boxTextFont;
}
groupCallDelayLabelMargin: margins(22px, 10px, 20px, 5px);
groupCallDelaySlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
activeFg: groupCallActiveFg;
inactiveFg: groupCallMemberNotJoinedStatus;
activeFgOver: groupCallActiveFg;
inactiveFgOver: groupCallMemberNotJoinedStatus;
activeFgDisabled: groupCallActiveFg;
inactiveFgDisabled: groupCallMemberNotJoinedStatus;
receivedTillFg: groupCallMemberNotJoinedStatus;
}
groupCallDelayMargin: margins(22px, 5px, 20px, 10px);
callTopBarMuteCrossLine: CrossLineAnimation { callTopBarMuteCrossLine: CrossLineAnimation {
fg: callBarFg; fg: callBarFg;
icon: icon {{ "calls/call_record_active", callBarFg }}; icon: icon {{ "calls/call_record_active", callBarFg }};

View file

@ -52,7 +52,8 @@ GroupCall::GroupCall(
, _history(channel->owner().history(channel)) , _history(channel->owner().history(channel))
, _api(&_channel->session().mtp()) , _api(&_channel->session().mtp())
, _lastSpokeCheckTimer([=] { checkLastSpoke(); }) , _lastSpokeCheckTimer([=] { checkLastSpoke(); })
, _checkJoinedTimer([=] { checkJoined(); }) { , _checkJoinedTimer([=] { checkJoined(); })
, _pushToTalkCancelTimer([=] { pushToTalkCancel(); }) {
_muted.value( _muted.value(
) | rpl::combine_previous( ) | rpl::combine_previous(
) | rpl::start_with_next([=](MuteState previous, MuteState state) { ) | rpl::start_with_next([=](MuteState previous, MuteState state) {
@ -781,12 +782,28 @@ void GroupCall::applyGlobalShortcutChanges() {
} }
_pushToTalk = shortcut; _pushToTalk = shortcut;
_shortcutManager->startWatching(_pushToTalk, [=](bool pressed) { _shortcutManager->startWatching(_pushToTalk, [=](bool pressed) {
if (muted() != MuteState::ForceMuted const auto delay = Core::App().settings().groupCallPushToTalkDelay();
&& muted() != MuteState::Active) { if (muted() == MuteState::ForceMuted
setMuted(pressed ? MuteState::PushToTalk : MuteState::Muted); || muted() == MuteState::Active) {
return;
} else if (pressed) {
_pushToTalkCancelTimer.cancel();
setMuted(MuteState::PushToTalk);
} else if (delay) {
_pushToTalkCancelTimer.callOnce(delay);
} else {
pushToTalkCancel();
} }
}); });
} }
void GroupCall::pushToTalkCancel() {
_pushToTalkCancelTimer.cancel();
if (muted() == MuteState::PushToTalk) {
setMuted(MuteState::Muted);
}
}
//void GroupCall::setAudioVolume(bool input, float level) { //void GroupCall::setAudioVolume(bool input, float level) {
// if (_instance) { // if (_instance) {
// if (input) { // if (input) {

View file

@ -152,6 +152,7 @@ private:
gsl::span<const std::pair<std::uint32_t, float>> data); gsl::span<const std::pair<std::uint32_t, float>> data);
void setInstanceConnected(bool connected); void setInstanceConnected(bool connected);
void checkLastSpoke(); void checkLastSpoke();
void pushToTalkCancel();
void checkJoined(); void checkJoined();
@ -183,6 +184,7 @@ private:
std::shared_ptr<GlobalShortcutManager> _shortcutManager; std::shared_ptr<GlobalShortcutManager> _shortcutManager;
std::shared_ptr<GlobalShortcutValue> _pushToTalk; std::shared_ptr<GlobalShortcutValue> _pushToTalk;
base::Timer _pushToTalkCancelTimer;
bool _pushToTalkStarted = false; bool _pushToTalkStarted = false;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_group_panel.h" // LeaveGroupCallBox. #include "calls/calls_group_panel.h" // LeaveGroupCallBox.
#include "calls/calls_instance.h" #include "calls/calls_instance.h"
#include "ui/widgets/level_meter.h" #include "ui/widgets/level_meter.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
@ -36,6 +37,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Calls { namespace Calls {
namespace { namespace {
constexpr auto kDelaysCount = 201;
void SaveCallJoinMuted( void SaveCallJoinMuted(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
uint64 callId, uint64 callId,
@ -56,6 +59,22 @@ void SaveCallJoinMuted(
)).send(); )).send();
} }
[[nodiscard]] crl::time DelayByIndex(int index) {
return index * crl::time(10);
}
[[nodiscard]] QString FormatDelay(crl::time delay) {
return (delay < crl::time(1000))
? tr::lng_group_call_ptt_delay_ms(
tr::now,
lt_amount,
QString::number(delay))
: tr::lng_group_call_ptt_delay_s(
tr::now,
lt_amount,
QString::number(delay / 1000., 'f', 2));
}
} // namespace } // namespace
void GroupCallSettingsBox( void GroupCallSettingsBox(
@ -164,6 +183,7 @@ void GroupCallSettingsBox(
rpl::variable<QString> recordText = tr::lng_group_call_ptt_shortcut(); rpl::variable<QString> recordText = tr::lng_group_call_ptt_shortcut();
rpl::variable<QString> shortcutText; rpl::variable<QString> shortcutText;
GlobalShortcut shortcut; GlobalShortcut shortcut;
crl::time delay = 0;
bool recording = false; bool recording = false;
}; };
const auto manager = call->ensureGlobalShortcutManager(); const auto manager = call->ensureGlobalShortcutManager();
@ -171,6 +191,7 @@ void GroupCallSettingsBox(
const auto state = box->lifetime().make_state<PushToTalkState>(); const auto state = box->lifetime().make_state<PushToTalkState>();
state->shortcut = manager->shortcutFromSerialized( state->shortcut = manager->shortcutFromSerialized(
settings.groupCallPushToTalkShortcut()); settings.groupCallPushToTalkShortcut());
state->delay = settings.groupCallPushToTalkDelay();
state->shortcutText = state->shortcut state->shortcutText = state->shortcut
? state->shortcut->toDisplayString() ? state->shortcut->toDisplayString()
: QString(); : QString();
@ -240,16 +261,40 @@ void GroupCallSettingsBox(
recordingWrap->toggle(toggled, anim::type::normal); recordingWrap->toggle(toggled, anim::type::normal);
}, pushToTalk->lifetime()); }, pushToTalk->lifetime());
const auto label = layout->add(
object_ptr<Ui::LabelSimple>(layout, st::groupCallDelayLabel),
st::groupCallDelayLabelMargin);
const auto value = std::clamp(
state->delay,
crl::time(0),
DelayByIndex(kDelaysCount - 1));
const auto callback = [=](crl::time delay) {
state->delay = delay;
label->setText(tr::lng_group_call_ptt_delay(
tr::now,
lt_delay,
FormatDelay(delay)));
Core::App().settings().setGroupCallPushToTalkDelay(delay);
Core::App().saveSettingsDelayed();
};
callback(value);
const auto slider = layout->add(
object_ptr<Ui::MediaSlider>(layout, st::groupCallDelaySlider),
st::groupCallDelayMargin);
slider->resize(st::groupCallDelaySlider.seekSize);
slider->setPseudoDiscrete(
kDelaysCount,
DelayByIndex,
value,
callback);
box->boxClosing( box->boxClosing(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
call->applyGlobalShortcutChanges(); call->applyGlobalShortcutChanges();
}, box->lifetime()); }, box->lifetime());
auto boxKeyFilter = [=](not_null<QEvent*> e) { auto boxKeyFilter = [=](not_null<QEvent*> e) {
if (e->type() != QEvent::KeyPress) { return (e->type() == QEvent::KeyPress && state->recording)
return base::EventFilterResult::Continue;
}
return (state->recording)
? base::EventFilterResult::Cancel ? base::EventFilterResult::Cancel
: base::EventFilterResult::Continue; : base::EventFilterResult::Continue;
}; };

View file

@ -111,7 +111,8 @@ QByteArray Settings::serialize() const {
<< _callVideoInputDeviceId << _callVideoInputDeviceId
<< qint32(_ipRevealWarning ? 1 : 0) << qint32(_ipRevealWarning ? 1 : 0)
<< qint32(_groupCallPushToTalk ? 1 : 0) << qint32(_groupCallPushToTalk ? 1 : 0)
<< _groupCallPushToTalkShortcut; << _groupCallPushToTalkShortcut
<< qint64(_groupCallPushToTalkDelay);
} }
return result; return result;
} }
@ -181,6 +182,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 ipRevealWarning = _ipRevealWarning ? 1 : 0; qint32 ipRevealWarning = _ipRevealWarning ? 1 : 0;
qint32 groupCallPushToTalk = _groupCallPushToTalk ? 1 : 0; qint32 groupCallPushToTalk = _groupCallPushToTalk ? 1 : 0;
QByteArray groupCallPushToTalkShortcut = _groupCallPushToTalkShortcut; QByteArray groupCallPushToTalkShortcut = _groupCallPushToTalkShortcut;
qint64 groupCallPushToTalkDelay = _groupCallPushToTalkDelay;
stream >> themesAccentColors; stream >> themesAccentColors;
if (!stream.atEnd()) { if (!stream.atEnd()) {
@ -270,9 +272,11 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) { if (!stream.atEnd()) {
stream stream
>> groupCallPushToTalk >> groupCallPushToTalk
>> groupCallPushToTalkShortcut; >> groupCallPushToTalkShortcut
>> groupCallPushToTalkDelay;
} }
if (stream.status() != QDataStream::Ok) { if (false && stream.status() != QDataStream::Ok) {
AssertIsDebug();
LOG(("App Error: " LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()")); "Bad data for Core::Settings::constructFromSerialized()"));
return; return;
@ -365,6 +369,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
_systemDarkModeEnabled = (systemDarkModeEnabled == 1); _systemDarkModeEnabled = (systemDarkModeEnabled == 1);
_groupCallPushToTalk = (groupCallPushToTalk == 1); _groupCallPushToTalk = (groupCallPushToTalk == 1);
_groupCallPushToTalkShortcut = groupCallPushToTalkShortcut; _groupCallPushToTalkShortcut = groupCallPushToTalkShortcut;
_groupCallPushToTalkDelay = groupCallPushToTalkDelay;
} }
bool Settings::chatWide() const { bool Settings::chatWide() const {
@ -471,6 +476,10 @@ void Settings::resetOnLastLogout() {
//_callInputVolume = 100; //_callInputVolume = 100;
//_callAudioDuckingEnabled = true; //_callAudioDuckingEnabled = true;
_groupCallPushToTalk = false;
_groupCallPushToTalkShortcut = QByteArray();
_groupCallPushToTalkDelay = 20;
//_themesAccentColors = Window::Theme::AccentColors(); //_themesAccentColors = Window::Theme::AccentColors();
_lastSeenWarningSeen = false; _lastSeenWarningSeen = false;

View file

@ -229,6 +229,12 @@ public:
void setGroupCallPushToTalkShortcut(const QByteArray &serialized) { void setGroupCallPushToTalkShortcut(const QByteArray &serialized) {
_groupCallPushToTalkShortcut = serialized; _groupCallPushToTalkShortcut = serialized;
} }
[[nodiscard]] crl::time groupCallPushToTalkDelay() const {
return _groupCallPushToTalkDelay;
}
void setGroupCallPushToTalkDelay(crl::time delay) {
_groupCallPushToTalkDelay = delay;
}
[[nodiscard]] Window::Theme::AccentColors &themesAccentColors() { [[nodiscard]] Window::Theme::AccentColors &themesAccentColors() {
return _themesAccentColors; return _themesAccentColors;
} }
@ -527,6 +533,7 @@ private:
bool _callAudioDuckingEnabled = true; bool _callAudioDuckingEnabled = true;
bool _groupCallPushToTalk = false; bool _groupCallPushToTalk = false;
QByteArray _groupCallPushToTalkShortcut; QByteArray _groupCallPushToTalkShortcut;
crl::time _groupCallPushToTalkDelay = 20;
Window::Theme::AccentColors _themesAccentColors; Window::Theme::AccentColors _themesAccentColors;
bool _lastSeenWarningSeen = false; bool _lastSeenWarningSeen = false;
Ui::SendFilesWay _sendFilesWay; Ui::SendFilesWay _sendFilesWay;