Added radial animation to mute button for connecting state.

This commit is contained in:
23rd 2020-11-30 03:32:46 +03:00 committed by John Preston
parent 4fdd0d19e6
commit c9f003546a
3 changed files with 55 additions and 3 deletions

View file

@ -7,6 +7,7 @@
#include "ui/widgets/call_mute_button.h"
#include "base/event_filter.h"
#include "ui/effects/radial_animation.h"
#include "ui/paint/blobs.h"
#include "ui/painter.h"
@ -92,6 +93,10 @@ bool IsMuted(CallMuteButtonType type) {
return (type != CallMuteButtonType::Active);
}
bool IsConnecting(CallMuteButtonType type) {
return (type == CallMuteButtonType::Connecting);
}
} // namespace
class BlobsWidget final : public RpWidget {
@ -179,6 +184,7 @@ CallMuteButton::CallMuteButton(
: _state(initial)
, _blobs(base::make_unique_q<BlobsWidget>(parent))
, _content(parent, st::callMuteButtonActive, &st::callMuteButtonMuted)
, _radial(nullptr)
, _colors(Colors())
, _crossLineMuteAnimation(st::callMuteCrossLine) {
init();
@ -192,6 +198,21 @@ void CallMuteButton::init() {
});
_content.setText(std::move(text));
_radialShowProgress.value(
) | rpl::start_with_next([=](float64 value) {
if (((value == 0.) || anim::Disabled()) && _radial) {
_radial->stop();
_radial = nullptr;
return;
}
if ((value > 0.) && !anim::Disabled() && !_radial) {
_radial = std::make_unique<InfiniteRadialAnimation>(
[=] { _content.update(); },
st::callConnectingRadial);
_radial->start();
}
}, lifetime());
// State type.
const auto previousType =
lifetime().make_state<CallMuteButtonType>(_state.current().type);
@ -206,6 +227,9 @@ void CallMuteButton::init() {
const auto crossFrom = IsMuted(previous) ? 0. : 1.;
const auto crossTo = IsMuted(type) ? 0. : 1.;
const auto radialShowFrom = IsConnecting(previous) ? 1. : 0.;
const auto radialShowTo = IsConnecting(type) ? 1. : 0.;
const auto gradient = anim::linear_gradient(
_colors.at(previous),
_colors.at(type),
@ -218,12 +242,20 @@ void CallMuteButton::init() {
auto callback = [=](float64 value) {
_blobs->setBrush(QBrush(gradient.gradient(value)));
const auto crossProgress =
InterpolateF(crossFrom, crossTo, value);
const auto crossProgress = (crossFrom == crossTo)
? crossTo
: InterpolateF(crossFrom, crossTo, value);
if (crossProgress != _crossLineProgress) {
_crossLineProgress = crossProgress;
_content.update(_muteIconPosition);
}
const auto radialShowProgress = (radialShowFrom == radialShowTo)
? radialShowTo
: InterpolateF(radialShowFrom, radialShowTo, value);
if (radialShowProgress != _radialShowProgress.current()) {
_radialShowProgress = radialShowProgress;
}
};
_switchAnimation.stop();
@ -265,6 +297,14 @@ void CallMuteButton::contentPaint() {
const auto progress = 1. - _crossLineProgress;
_crossLineMuteAnimation.paint(p, _muteIconPosition.topLeft(), progress);
if (_radial) {
p.setOpacity(_radialShowProgress.current());
_radial->draw(
p,
st::callMuteButtonActive.bgPosition,
_content.width());
}
}
void CallMuteButton::setState(const CallMuteButtonState &state) {
@ -321,7 +361,9 @@ void CallMuteButton::lower() {
}
rpl::lifetime &CallMuteButton::lifetime() {
return _content.lifetime();
return _blobs->lifetime();
}
CallMuteButton::~CallMuteButton() = default;
} // namespace Ui

View file

@ -16,6 +16,7 @@
namespace Ui {
class BlobsWidget;
class InfiniteRadialAnimation;
enum class CallMuteButtonType {
Connecting,
@ -34,6 +35,7 @@ public:
explicit CallMuteButton(
not_null<RpWidget*> parent,
CallMuteButtonState initial = CallMuteButtonState());
~CallMuteButton();
void setState(const CallMuteButtonState &state);
void setLevel(float level);
@ -62,11 +64,13 @@ private:
rpl::variable<CallMuteButtonState> _state;
float _level = 0.;
float64 _crossLineProgress = 0.;
rpl::variable<float64> _radialShowProgress = 0.;
QRect _muteIconPosition;
const base::unique_qptr<BlobsWidget> _blobs;
CallButton _content;
std::unique_ptr<InfiniteRadialAnimation> _radial;
const std::unordered_map<CallMuteButtonType, std::vector<QColor>> _colors;
CrossLineAnimation _crossLineMuteAnimation;

View file

@ -1453,6 +1453,12 @@ callMuteCrossLine: CrossLineAnimation {
stroke: 4px;
}
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: lightButtonFg;
thickness: 4px;
size: size(100px, 100px);
}
// Windows specific title
windowTitleButton: IconButton {