From 448b6bb905b70b4660a2864f0568612b985684c7 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 8 Dec 2020 23:16:27 +0300 Subject: [PATCH] Added initial implementation of LinearBlob animation to Calls::TopBar. --- Telegram/SourceFiles/calls/calls.style | 11 ++ Telegram/SourceFiles/calls/calls_top_bar.cpp | 178 +++++++++++++++++++ Telegram/SourceFiles/calls/calls_top_bar.h | 10 ++ Telegram/lib_ui | 2 +- 4 files changed, 200 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 45ed1b11a..bce9ea347 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -750,6 +750,17 @@ groupCallTitle: WindowTitle(defaultWindowTitle) { closeIconActiveOver: groupCallTitleCloseIconOver; } +groupCallMajorBlobMinRadius: 2px; +groupCallMajorBlobMaxRadius: 2px; + +groupCallMinorBlobMinRadius: 3px; +groupCallMinorBlobMaxRadius: 9px; + +groupCallMajorBlobTopOffset: 0px; +groupCallMinorBlobTopOffset: 6px; + +groupCallBlobWidthAdditional: 40px; + callTopBarMuteCrossLine: CrossLineAnimation { fg: callBarFg; icon: icon {{ "calls/call_record_active", callBarFg }}; diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index a54c94d69..4c51f0804 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_top_bar.h" #include "ui/effects/cross_line.h" +#include "ui/paint/blobs_linear.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/chat/group_call_bar.h" // Ui::GroupCallBarContent. @@ -38,6 +39,43 @@ namespace { constexpr auto kUpdateDebugTimeoutMs = crl::time(500); constexpr auto kSwitchStateDuration = 120; +constexpr auto kMinorBlobAlpha = 76. / 255.; + +constexpr auto kBlobLevelDuration1 = 250; +constexpr auto kBlobLevelDuration2 = 120; + +auto LinearBlobs() -> std::array { + return { { + { + .segmentsCount = 5, + .minScale = 1., + .minRadius = (float)st::groupCallMajorBlobMinRadius, + .maxRadius = (float)st::groupCallMajorBlobMaxRadius, + .speedScale = .3, + .alpha = 1., + .topOffset = st::groupCallMajorBlobTopOffset, + }, + { + .segmentsCount = 7, + .minScale = 1., + .minRadius = (float)st::groupCallMinorBlobMinRadius, + .maxRadius = (float)st::groupCallMinorBlobMaxRadius, + .speedScale = .7, + .alpha = kMinorBlobAlpha, + .topOffset = st::groupCallMinorBlobTopOffset, + }, + { + .segmentsCount = 8, + .minScale = 1., + .minRadius = (float)st::groupCallMinorBlobMinRadius, + .maxRadius = (float)st::groupCallMinorBlobMaxRadius, + .speedScale = .7, + .alpha = kMinorBlobAlpha, + .topOffset = st::groupCallMinorBlobTopOffset, + }, + } }; +} + auto Colors() { using Vector = std::vector; return base::flat_map{ @@ -187,6 +225,12 @@ TopBar::TopBar( , _mute(this, st::callBarMuteToggle) , _info(this) , _hangup(this, st::callBarHangup) +, _blobs(base::make_unique_q(parent)) +, _blobsPaint(std::make_unique( + LinearBlobs() | ranges::to_vector, + kBlobLevelDuration1, + kBlobLevelDuration2, + 1.)) , _gradients(Colors(), QPointF(), QPointF()) { initControls(); resize(width(), st::callBarHeight); @@ -303,6 +347,140 @@ void TopBar::initControls() { }); _updateDurationTimer.setCallback([this] { updateDurationText(); }); updateDurationText(); + + initBlobs(); +} + +void TopBar::initBlobs() { + const auto &hideDuration = kBlobLevelDuration1 * 2; + const auto hideLastTime = _blobs->lifetime().make_state(0); + const auto lastTime = _blobs->lifetime().make_state(0); + const auto blobsRect = + _blobs->lifetime().make_state(_blobs->rect()); + + _blobsAnimation.init([=](crl::time now) { + if (const auto last = *hideLastTime; (last > 0) + && (now - last >= hideDuration)) { + _blobsAnimation.stop(); + return false; + } + _blobsPaint->updateLevel(now - *lastTime); + *lastTime = now; + + _blobs->update(); + return true; + }); + + _groupCall->stateValue( + ) | rpl::start_with_next([=](Calls::GroupCall::State state) { + if (state == Calls::GroupCall::State::HangingUp) { + _blobs->hide(); + } + }, lifetime()); + + auto hideBlobs = rpl::combine( + rpl::single(anim::Disabled()) | rpl::then(anim::Disables()), + Core::App().appDeactivatedValue(), + _groupCall->stateValue( + ) | rpl::map([](Calls::GroupCall::State state) { + using State = Calls::GroupCall::State; + if (state != State::Creating + && state != State::Joining + && state != State::Joined + && state != State::Connecting) { + return true; + } + return false; + }) | rpl::distinct_until_changed() + ) | rpl::map([](bool animDisabled, bool hide, bool isBadState) { + return isBadState || !(!animDisabled && !hide); + }); + + std::move( + hideBlobs + ) | rpl::start_with_next([=](bool hide) { + if (hide) { + _blobsPaint->setLevel(0.); + } + *hideLastTime = hide ? crl::now() : 0; + if (!hide && !_blobsAnimation.animating()) { + _blobsAnimation.start(); + } + + const auto from = hide ? 0. : 1.; + const auto to = hide ? 1. : 0.; + _blobsHideAnimation.start([=](float64 value) { + blobsRect->setHeight(anim::interpolate(0, -20, value)); + }, from, to, hideDuration); + }, lifetime()); + + /// + + const auto parent = static_cast(parentWidget()); + geometryValue( + ) | rpl::start_with_next([=](QRect rect) { + _blobs->resize(rect.width(), rect.height()); + + { + const auto &r = _blobs->rect(); + *blobsRect = QRect( + r.x(), + r.y(), + r.width() + st::groupCallBlobWidthAdditional, + 0); + } + + const auto relativePos = mapTo(parent, rect.topLeft()); + _blobs->moveToLeft(relativePos.x(), relativePos.y() + rect.height()); + }, lifetime()); + + shownValue( + ) | rpl::start_with_next([=](bool shown) { + _blobs->setVisible(shown); + }, lifetime()); + + _blobs->paintRequest( + ) | rpl::start_with_next([=](QRect clip) { + Painter p(_blobs); + + const auto alpha = 1. - _blobsHideAnimation.value(0.); + if (alpha < 1.) { + p.setOpacity(alpha); + } + _blobsPaint->paint(p, _groupBrush, *blobsRect, 0, 0); + }, _blobs->lifetime()); + + rpl::single( + ) | rpl::then( + events( + ) | rpl::filter([](not_null e) { + return e->type() == QEvent::ZOrderChange; + }) | rpl::to_empty + ) | rpl::start_with_next([=] { + crl::on_main(_blobs.get(), [=] { + _blobs->raise(); + }); + }, lifetime()); + + _groupCall->levelUpdates( + ) | rpl::filter([=](const LevelUpdate &update) { + return update.self; + }) | rpl::start_with_next([=](const LevelUpdate &update) { + if (*hideLastTime) { + return; + } + _blobsPaint->setLevel(update.value); + }, _blobs->lifetime()); + + _blobs->setAttribute(Qt::WA_TransparentForMouseEvents); + _blobs->show(); + _blobsAnimation.start(); + + crl::on_main([=] { + const auto r = rect(); + const auto relativePos = mapTo(parent, r.topLeft()); + _blobs->moveToLeft(relativePos.x(), relativePos.y() + r.height()); + }); } void TopBar::subscribeToMembersChanges(not_null call) { diff --git a/Telegram/SourceFiles/calls/calls_top_bar.h b/Telegram/SourceFiles/calls/calls_top_bar.h index db16eea21..ab5f9cc33 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.h +++ b/Telegram/SourceFiles/calls/calls_top_bar.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/weak_ptr.h" #include "base/timer.h" #include "base/object_ptr.h" +#include "base/unique_qptr.h" #include "ui/effects/animations.h" #include "ui/effects/gradient.h" #include "ui/rp_widget.h" @@ -19,6 +20,9 @@ class IconButton; class AbstractButton; class LabelSimple; class FlatLabel; +namespace Paint { +class LinearBlobs; +} // namespace Paint } // namespace Ui namespace Main { @@ -51,6 +55,7 @@ private: const base::weak_ptr &groupCall); void initControls(); + void initBlobs(); void updateInfoLabels(); void setInfoLabels(); void updateDurationText(); @@ -73,11 +78,16 @@ private: object_ptr _mute; object_ptr _info; object_ptr _hangup; + base::unique_qptr _blobs; + std::unique_ptr _blobsPaint; QBrush _groupBrush; anim::linear_gradients _gradients; Ui::Animations::Simple _switchStateAnimation; + Ui::Animations::Simple _blobsHideAnimation; + Ui::Animations::Basic _blobsAnimation; + base::Timer _updateDurationTimer; }; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index dfc0f0b88..a02c8923d 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit dfc0f0b889375c10782a870a377936a19fcac7f3 +Subproject commit a02c8923dc6d00bcb4f4c2b1470cd48e2743903a