Add a hint to unmute your microphone.

This commit is contained in:
John Preston 2021-06-18 17:45:22 +04:00
parent 1cb1f1cbc1
commit 7a588be54f
7 changed files with 166 additions and 35 deletions

View File

@ -1251,7 +1251,7 @@ groupCallTooltip: Tooltip(defaultTooltip) {
}
groupCallNiceTooltip: ImportantTooltip(defaultImportantTooltip) {
bg: importantTooltipBg;
padding: margins(10px, 1px, 10px, 3px);
padding: margins(10px, 3px, 10px, 5px);
radius: 4px;
arrow: 4px;
}

View File

@ -68,4 +68,13 @@ enum class Error {
DisabledNoScreen,
};
enum class StickedTooltip {
Camera = 0x01,
Microphone = 0x02,
};
constexpr inline bool is_flag_type(StickedTooltip) {
return true;
}
using StickedTooltips = base::flags<StickedTooltip>;
} // namespace Calls::Group

View File

@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" // api().kickParticipant.
#include "webrtc/webrtc_video_track.h"
#include "webrtc/webrtc_media_devices.h" // UniqueDesktopCaptureSource.
#include "webrtc/webrtc_audio_input_tester.h"
#include "styles/style_calls.h"
#include "styles/style_layers.h"
@ -71,6 +72,10 @@ constexpr auto kRecordingOpacity = 0.6;
constexpr auto kStartNoConfirmation = TimeId(10);
constexpr auto kControlsBackgroundOpacity = 0.8;
constexpr auto kOverrideActiveColorBgAlpha = 172;
constexpr auto kMicrophoneTooltipAfterLoudCount = 3;
constexpr auto kDropLoudAfterQuietCount = 5;
constexpr auto kMicrophoneTooltipLevelThreshold = 0.2;
constexpr auto kMicrophoneTooltipCheckInterval = crl::time(500);
} // namespace
@ -84,6 +89,49 @@ struct Panel::ControlsBackgroundNarrow {
Ui::RpWidget blocker;
};
class Panel::MicLevelTester final {
public:
explicit MicLevelTester(Fn<void()> show);
[[nodiscard]] bool showTooltip() const;
private:
void check();
Fn<void()> _show;
base::Timer _timer;
Webrtc::AudioInputTester _tester;
int _loudCount = 0;
int _quietCount = 0;
};
Panel::MicLevelTester::MicLevelTester(Fn<void()> show)
: _show(std::move(show))
, _timer([=] { check(); })
, _tester(
Core::App().settings().callAudioBackend(),
Core::App().settings().callInputDeviceId()) {
_timer.callEach(kMicrophoneTooltipCheckInterval);
}
bool Panel::MicLevelTester::showTooltip() const {
return (_loudCount >= kMicrophoneTooltipAfterLoudCount);
}
void Panel::MicLevelTester::check() {
const auto level = _tester.getAndResetLevel();
if (level >= kMicrophoneTooltipLevelThreshold) {
_quietCount = 0;
if (++_loudCount >= kMicrophoneTooltipAfterLoudCount) {
_show();
}
} else if (_loudCount > 0 && ++_quietCount >= kDropLoudAfterQuietCount) {
_quietCount = 0;
_loudCount = 0;
}
}
Panel::Panel(not_null<GroupCall*> call)
: _call(call)
, _peer(call->peer())
@ -112,6 +160,7 @@ Panel::Panel(not_null<GroupCall*> call)
: Ui::CallMuteButtonType::ScheduledSilent),
}))
, _hangup(widget(), st::groupCallHangup)
, _stickedTooltipsShown(Core::App().settings().hiddenGroupCallTooltips())
, _toasts(std::make_unique<Toasts>(this)) {
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
_layerBg->setHideByBackgroundClick(true);
@ -418,7 +467,9 @@ void Panel::initControls() {
}
_call->stateValue(
) | rpl::filter([](State state) {
) | rpl::before_next([=] {
showStickedTooltip();
}) | rpl::filter([](State state) {
return (state == State::HangingUp)
|| (state == State::Ended)
|| (state == State::FailedHangingUp)
@ -515,11 +566,6 @@ void Panel::refreshVideoButtons(std::optional<bool> overrideWideMode) {
}
_video->setProgress(sharing ? 1. : 0.);
}, _video->lifetime());
_call->mutedValue(
) | rpl::start_with_next([=] {
updateButtonsGeometry();
showStickedTooltip();
}, _video->lifetime());
}
if (!_screenShare) {
_screenShare.create(widget(), st::groupCallScreenShareSmall);
@ -562,7 +608,8 @@ void Panel::hideStickedTooltip(
if (hide != StickedTooltipHide::Unavailable) {
_stickedTooltipsShown |= type;
if (hide == StickedTooltipHide::Discarded) {
// #TODO calls save to settings.
Core::App().settings().setHiddenGroupCallTooltip(type);
Core::App().saveSettingsDelayed();
}
}
const auto control = (type == StickedTooltip::Camera)
@ -886,6 +933,9 @@ void Panel::raiseControls() {
}
}
_mute->raise();
if (_niceTooltip) {
_niceTooltip->raise();
}
}
void Panel::setupVideo(not_null<Viewport*> viewport) {
@ -1052,6 +1102,18 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
refreshTopButton();
}, widget()->lifetime());
_call->mutedValue(
) | rpl::skip(1) | rpl::start_with_next([=](MuteState state) {
updateButtonsGeometry();
if (state == MuteState::Active
|| state == MuteState::PushToTalk) {
hideStickedTooltip(
StickedTooltip::Microphone,
StickedTooltipHide::Activated);
}
showStickedTooltip();
}, widget()->lifetime());
updateControlsGeometry();
}
@ -1407,7 +1469,10 @@ bool Panel::updateMode() {
_call->showVideoEndpointLarge({});
}
refreshVideoButtons(wide);
_niceTooltip.destroy();
if (!_stickedTooltipClose
|| _niceTooltipControl.data() != _mute->outer().get()) {
_niceTooltip.destroy();
}
_mode = mode;
if (_title) {
_title->setTextColorOverride(wide
@ -1631,7 +1696,10 @@ void Panel::trackControlOver(not_null<Ui::RpWidget*> control, bool over) {
void Panel::showStickedTooltip() {
static const auto kHasCamera = !Webrtc::GetVideoInputList().empty();
const auto callReady = (_call->state() == State::Joined
|| _call->state() == State::Connecting);
if (!(_stickedTooltipsShown & StickedTooltip::Camera)
&& callReady
&& (_mode.current() == PanelMode::Wide)
&& _video
&& _call->videoIsWorking()
@ -1645,13 +1713,25 @@ void Panel::showStickedTooltip() {
StickedTooltipHide::Unavailable);
if (!(_stickedTooltipsShown & StickedTooltip::Microphone)
&& (_mode.current() == PanelMode::Wide)
&& callReady
&& _mute
&& !_call->mutedByAdmin()
&& false) { // Check if there is incoming sound.
showNiceTooltip(_mute->outer(), NiceTooltipType::Sticked);
&& !_call->mutedByAdmin()) {
if (_stickedTooltipClose) {
// Showing already.
return;
} else if (!_micLevelTester) {
// Check if there is incoming sound.
_micLevelTester = std::make_unique<MicLevelTester>([=] {
showStickedTooltip();
});
}
if (_micLevelTester->showTooltip()) {
_micLevelTester = nullptr;
showNiceTooltip(_mute->outer(), NiceTooltipType::Sticked);
}
return;
}
_micLevelTester = nullptr;
hideStickedTooltip(
StickedTooltip::Microphone,
StickedTooltipHide::Unavailable);
@ -1685,11 +1765,12 @@ void Panel::showNiceTooltip(
}
return rpl::producer<QString>();
}();
if (!text
|| _wideControlsAnimation.animating()
|| !_wideControlsShown
|| _stickedTooltipClose) {
if (!text || _stickedTooltipClose) {
return;
} else if (_wideControlsAnimation.animating() || !_wideControlsShown) {
if (type == NiceTooltipType::Normal) {
return;
}
}
const auto inner = [&]() -> Ui::RpWidget* {
const auto normal = (type == NiceTooltipType::Normal);

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "base/object_ptr.h"
#include "calls/group/calls_group_call.h"
#include "calls/group/calls_group_common.h"
#include "calls/group/calls_choose_join_as.h"
#include "calls/group/ui/desktop_capture_choose_source.h"
#include "ui/effects/animations.h"
@ -64,6 +65,7 @@ class Toasts;
class Members;
class Viewport;
enum class PanelMode;
enum class StickedTooltip;
class Panel final : private Ui::DesktopCapture::ChooseSourceDelegate {
public:
@ -88,19 +90,12 @@ private:
Normal,
Sticked,
};
enum class StickedTooltip {
Camera = 0x01,
Microphone = 0x02,
};
friend constexpr inline bool is_flag_type(StickedTooltip) {
return true;
};
using StickedTooltips = base::flags<StickedTooltip>;
enum class StickedTooltipHide {
Unavailable,
Activated,
Discarded,
};
class MicLevelTester;
std::unique_ptr<Ui::Window> createWindow();
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
@ -236,6 +231,8 @@ private:
const std::unique_ptr<Toasts> _toasts;
base::weak_ptr<Ui::Toast::Instance> _lastToast;
std::unique_ptr<MicLevelTester> _micLevelTester;
rpl::lifetime _peerLifetime;
};

View File

@ -493,8 +493,10 @@ void SettingsBox(
tr::now,
lt_delay,
FormatDelay(delay)));
Core::App().settings().setGroupCallPushToTalkDelay(delay);
applyAndSave();
if (Core::App().settings().groupCallPushToTalkDelay() != delay) {
Core::App().settings().setGroupCallPushToTalkDelay(delay);
applyAndSave();
}
};
callback(value);
const auto slider = pushToTalkInner->add(

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/platform/base_platform_info.h"
#include "webrtc/webrtc_create_adm.h"
#include "ui/gl/gl_detection.h"
#include "calls/group/calls_group_common.h"
#include "facades.h"
namespace Core {
@ -94,23 +95,35 @@ QByteArray Settings::serialize() const {
+ sizeof(qint32) * 5
+ Serialize::stringSize(_downloadPath.current())
+ Serialize::bytearraySize(_downloadPathBookmark)
+ sizeof(qint32) * 12
+ sizeof(qint32) * 9
+ Serialize::stringSize(_callOutputDeviceId)
+ Serialize::stringSize(_callInputDeviceId)
+ Serialize::stringSize(_callVideoInputDeviceId)
+ sizeof(qint32) * 5
+ Serialize::bytearraySize(proxy);
+ sizeof(qint32) * 5;
for (const auto &[key, value] : _soundOverrides) {
size += Serialize::stringSize(key) + Serialize::stringSize(value);
}
size += sizeof(qint32) * 13
+ Serialize::bytearraySize(_videoPipGeometry)
+ sizeof(qint32)
+ (_dictionariesEnabled.current().size() * sizeof(quint64))
+ sizeof(qint32) * 12
+ Serialize::stringSize(_callVideoInputDeviceId)
+ sizeof(qint32) * 2
+ Serialize::bytearraySize(_groupCallPushToTalkShortcut)
+ sizeof(qint64)
+ sizeof(qint32) * 2
+ Serialize::bytearraySize(windowPosition)
+ sizeof(qint32);
for (const auto &[id, rating] : recentEmojiPreloadData) {
size += Serialize::stringSize(id) + sizeof(quint16);
}
size += sizeof(qint32);
for (const auto &[id, variant] : _emojiVariants) {
size += Serialize::stringSize(id) + sizeof(quint8);
}
size += Serialize::bytearraySize(_videoPipGeometry);
size += Serialize::bytearraySize(windowPosition);
size += sizeof(qint32) * 3
+ Serialize::bytearraySize(proxy)
+ sizeof(qint32);
auto result = QByteArray();
result.reserve(size);
@ -200,8 +213,9 @@ QByteArray Settings::serialize() const {
stream
<< qint32(_disableOpenGL ? 1 : 0)
<< qint32(_groupCallNoiseSuppression ? 1 : 0)
<< _workMode.current()
<< proxy;
<< qint32(_workMode.current())
<< proxy
<< qint32(_hiddenGroupCallTooltips.value());
}
return result;
}
@ -281,6 +295,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 groupCallNoiseSuppression = _groupCallNoiseSuppression ? 1 : 0;
qint32 workMode = static_cast<qint32>(_workMode.current());
QByteArray proxy;
qint32 hiddenGroupCallTooltips = qint32(_hiddenGroupCallTooltips.value());
stream >> themesAccentColors;
if (!stream.atEnd()) {
@ -421,6 +436,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> proxy;
}
if (!stream.atEnd()) {
stream >> hiddenGroupCallTooltips;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@ -540,6 +558,16 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
case WorkMode::TrayOnly:
case WorkMode::WindowOnly: _workMode = uncheckedWorkMode; break;
}
_hiddenGroupCallTooltips = [&] {
using Tooltip = Calls::Group::StickedTooltip;
return Tooltip(0)
| ((hiddenGroupCallTooltips & int(Tooltip::Camera))
? Tooltip::Camera
: Tooltip(0))
| ((hiddenGroupCallTooltips & int(Tooltip::Microphone))
? Tooltip::Microphone
: Tooltip(0));
}();
}
QString Settings::getSoundPath(const QString &key) const {
@ -795,6 +823,7 @@ void Settings::resetOnLastLogout() {
_notifyFromAll = true;
_tabbedReplacedWithInfo = false; // per-window
_systemDarkModeEnabled = false;
_hiddenGroupCallTooltips = 0;
_recentEmojiPreload.clear();
_recentEmoji.clear();

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/themes/window_themes_embedded.h"
#include "ui/chat/attach/attach_send_files_way.h"
#include "platform/platform_notifications_manager.h"
#include "base/flags.h"
#include "emoji.h"
enum class RectPart;
@ -27,6 +28,10 @@ namespace Webrtc {
enum class Backend;
} // namespace Webrtc
namespace Calls::Group {
enum class StickedTooltip;
} // namespace Calls::Group
namespace Core {
struct WindowPosition {
@ -574,6 +579,13 @@ public:
_disableOpenGL = value;
}
[[nodiscard]] base::flags<Calls::Group::StickedTooltip> hiddenGroupCallTooltips() const {
return _hiddenGroupCallTooltips;
}
void setHiddenGroupCallTooltip(Calls::Group::StickedTooltip value) {
_hiddenGroupCallTooltips |= value;
}
[[nodiscard]] static bool ThirdColumnByDefault();
[[nodiscard]] static float64 DefaultDialogsWidthRatio();
[[nodiscard]] static qint32 SerializePlaybackSpeed(float64 speed) {
@ -671,6 +683,7 @@ private:
WindowPosition _windowPosition; // per-window
bool _disableOpenGL = false;
rpl::variable<WorkMode> _workMode = WorkMode::WindowAndTray;
base::flags<Calls::Group::StickedTooltip> _hiddenGroupCallTooltips;
bool _tabbedReplacedWithInfo = false; // per-window
rpl::event_stream<bool> _tabbedReplacedWithInfoValue; // per-window