From 46976c4e03ef083555d07d62a694a4bd27d2dce9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 27 May 2018 11:24:47 +0300 Subject: [PATCH] Display signal bars in calls. --- Telegram/SourceFiles/calls/calls.style | 21 ++++ Telegram/SourceFiles/calls/calls_call.cpp | 45 +++++++- Telegram/SourceFiles/calls/calls_call.h | 17 +++- Telegram/SourceFiles/calls/calls_panel.cpp | 102 ++++++++++++++++++- Telegram/SourceFiles/calls/calls_panel.h | 29 ++++++ Telegram/SourceFiles/calls/calls_top_bar.cpp | 19 +++- Telegram/SourceFiles/calls/calls_top_bar.h | 2 + 7 files changed, 223 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 4d211b014..77d104202 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -10,6 +10,14 @@ using "basic.style"; using "ui/widgets/widgets.style"; using "window/window.style"; +CallSignalBars { + width: pixels; + radius: pixels; + skip: pixels; + color: color; + inactiveOpacity: double; +} + callWidth: 300px; callHeight: 470px; callShadow: Shadow { @@ -189,3 +197,16 @@ callDebugLabel: FlatLabel(defaultFlatLabel) { margin: callDebugPadding; } callPanelDuration: 150; + +callPanelSignalBars: CallSignalBars { + width: 3px; + radius: 1px; + skip: 1px; + color: callNameFg; + inactiveOpacity: 0.5; +} +callBarSignalBars: CallSignalBars(callPanelSignalBars) { + color: callBarFg; +} +callSignalMargin: 8px; +callSignalPadding: 4px; diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 980b3ae59..635b11ced 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -558,6 +558,12 @@ void Call::createAndStartController(const MTPDphoneCall &call) { const auto call = static_cast(controller->implData); call->handleControllerStateChange(controller, state); }; + callbacks.signalBarCountChanged = []( + tgvoip::VoIPController *controller, + int count) { + const auto call = static_cast(controller->implData); + call->handleControllerBarCountChange(controller, count); + }; _controller.create(); if (_mute) { @@ -584,9 +590,12 @@ void Call::createAndStartController(const MTPDphoneCall &call) { _controller->Connect(); } -void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int state) { +void Call::handleControllerStateChange( + tgvoip::VoIPController *controller, + int state) { // NB! Can be called from an arbitrary thread! - // Expects(controller == _controller.get()); This can be called from ~VoIPController()! + // This can be called from ~VoIPController()! + // Expects(controller == _controller.get()); Expects(controller->implData == static_cast(this)); switch (state) { @@ -615,6 +624,26 @@ void Call::handleControllerStateChange(tgvoip::VoIPController *controller, int s } } +void Call::handleControllerBarCountChange( + tgvoip::VoIPController *controller, + int count) { + // NB! Can be called from an arbitrary thread! + // This can be called from ~VoIPController()! + // Expects(controller == _controller.get()); + Expects(controller->implData == static_cast(this)); + + InvokeQueued(this, [=] { + setSignalBarCount(count); + }); +} + +void Call::setSignalBarCount(int count) { + if (_signalBarCount != count) { + _signalBarCount = count; + _signalBarCountChanged.notify(count); + } +} + template bool Call::checkCallCommonFields(const T &call) { auto checkFailed = [this] { @@ -708,6 +737,9 @@ void Call::setState(State state) { void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) { Expects(type != FinishType::None); + + setSignalBarCount(kSignalBarFinished); + auto finalState = (type == FinishType::Ended) ? State::Ended : State::Failed; auto hangupState = (type == FinishType::Ended) ? State::HangingUp : State::FailedHangingUp; if (_state == State::Requesting) { @@ -742,11 +774,15 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) { } void Call::setStateQueued(State state) { - InvokeQueued(this, [this, state] { setState(state); }); + InvokeQueued(this, [=] { + setState(state); + }); } void Call::setFailedQueued(int error) { - InvokeQueued(this, [this, error] { handleControllerError(error); }); + InvokeQueued(this, [=] { + handleControllerError(error); + }); } void Call::handleRequestError(const RPCError &error) { @@ -778,6 +814,7 @@ void Call::destroyController() { _controller.reset(); DEBUG_LOG(("Call Info: Call controller destroyed.")); } + setSignalBarCount(kSignalBarFinished); } Call::~Call() { diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index a72d5150b..ce1f9ffd7 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -93,6 +93,13 @@ public: return _stateChanged; } + static constexpr auto kSignalBarStarting = -1; + static constexpr auto kSignalBarFinished = -2; + static constexpr auto kSignalBarCount = 4; + base::Observable &signalBarCountChanged() { + return _signalBarCountChanged; + } + void setMute(bool mute); bool isMute() const { return _mute; @@ -146,7 +153,12 @@ private: void startWaitingTrack(); void generateModExpFirst(base::const_byte_span randomSeed); - void handleControllerStateChange(tgvoip::VoIPController *controller, int state); + void handleControllerStateChange( + tgvoip::VoIPController *controller, + int state); + void handleControllerBarCountChange( + tgvoip::VoIPController *controller, + int count); void createAndStartController(const MTPDphoneCall &call); template @@ -159,6 +171,7 @@ private: void setState(State state); void setStateQueued(State state); void setFailedQueued(int error); + void setSignalBarCount(int count); void destroyController(); not_null _delegate; @@ -168,6 +181,8 @@ private: FinishType _finishAfterRequestingCall = FinishType::None; bool _answerAfterDhConfigReceived = false; base::Observable _stateChanged; + int _signalBarCount = kSignalBarStarting; + base::Observable _signalBarCountChanged; TimeMs _startTime = 0; base::DelayedCallTimer _finishByTimeoutTimer; base::Timer _discardByTimeoutTimer; diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 93eaf8374..77d21b413 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -67,6 +67,66 @@ private: }; +SignalBars::SignalBars( + QWidget *parent, + not_null call, + const style::CallSignalBars &st, + base::lambda displayedChangedCallback) +: RpWidget(parent) +, _st(st) +, _displayedChangedCallback(std::move(displayedChangedCallback)) { + resize( + _st.width + (_st.width + _st.skip) * (Call::kSignalBarCount - 1), + _st.width * Call::kSignalBarCount); + subscribe(call->signalBarCountChanged(), [=](int count) { + changed(count); + }); +} + +bool SignalBars::isDisplayed() const { + return (_count >= 0); +} + +void SignalBars::paintEvent(QPaintEvent *e) { + if (!isDisplayed()) { + return; + } + + Painter p(this); + + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.setBrush(_st.color); + for (auto i = 0; i < Call::kSignalBarCount; ++i) { + p.setOpacity((i < _count) ? 1. : _st.inactiveOpacity); + const auto barHeight = (i + 1) * _st.width; + const auto barLeft = i * (_st.width + _st.skip); + const auto barTop = height() - barHeight; + p.drawRoundedRect( + barLeft, + barTop, + _st.width, + barHeight, + _st.radius, + _st.radius); + } + p.setOpacity(1.); +} + +void SignalBars::changed(int count) { + if (_count == Call::kSignalBarFinished) { + return; + } + if (_count != count) { + const auto wasDisplayed = isDisplayed(); + _count = count; + if (isDisplayed() != wasDisplayed && _displayedChangedCallback) { + _displayedChangedCallback(); + } + update(); + } +} + Panel::Button::Button(QWidget *parent, const style::CallButton &stFrom, const style::CallButton *stTo) : Ui::RippleButton(parent, stFrom.button.ripple) , _stFrom(&stFrom) , _stTo(stTo) { @@ -238,7 +298,8 @@ Panel::Panel(not_null call) , _cancel(this, object_ptr