From ff85d2226cd33bd20e273b3b2576cebc73b4116d Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 9 Sep 2022 12:41:07 +0400 Subject: [PATCH] Provide simple spoiler animations manager. --- ui/effects/spoiler_mess.cpp | 63 +++++++++++++++++++++++++++++++++++++ ui/effects/spoiler_mess.h | 18 +++++++++++ 2 files changed, 81 insertions(+) diff --git a/ui/effects/spoiler_mess.cpp b/ui/effects/spoiler_mess.cpp index e246306..0c608a9 100644 --- a/ui/effects/spoiler_mess.cpp +++ b/ui/effects/spoiler_mess.cpp @@ -6,6 +6,7 @@ // #include "ui/effects/spoiler_mess.h" +#include "ui/effects/animations.h" #include "ui/painter.h" #include "ui/integration.h" #include "base/random.h" @@ -32,6 +33,13 @@ std::atomic DefaultMask/* = nullptr*/; std::condition_variable *DefaultMaskSignal/* = nullptr*/; std::mutex *DefaultMaskMutex/* = nullptr*/; +struct AnimationManager { + Ui::Animations::Basic animation; + base::flat_set> list; +}; + +AnimationManager *DefaultAnimationManager/* = nullptr*/; + struct Header { uint32 version = 0; uint32 dataLength = 0; @@ -124,6 +132,28 @@ void WriteDefaultMask(const SpoilerMessCached &mask) { } } +void Register(not_null animation) { + if (!DefaultAnimationManager) { + DefaultAnimationManager = new AnimationManager(); + DefaultAnimationManager->animation.init([] { + for (const auto &animation : DefaultAnimationManager->list) { + animation->repaint(); + } + }); + DefaultAnimationManager->animation.start(); + } + DefaultAnimationManager->list.emplace(animation); +} + +void Unregister(not_null animation) { + Expects(DefaultAnimationManager != nullptr); + + DefaultAnimationManager->list.remove(animation); + if (DefaultAnimationManager->list.empty()) { + delete base::take(DefaultAnimationManager); + } +} + } // namespace SpoilerMessCached GenerateSpoilerMess( @@ -372,6 +402,39 @@ std::optional SpoilerMessCached::FromSerialized( header.canvasSize); } +SpoilerAnimation::SpoilerAnimation(Fn repaint) +: _repaint(std::move(repaint)) { + Expects(_repaint != nullptr); +} + +SpoilerAnimation::~SpoilerAnimation() { + if (_animating) { + _animating = false; + Unregister(this); + } +} + +int SpoilerAnimation::index(crl::time now, bool paused) { + const auto add = std::min(now - _last, kDefaultFrameDuration); + if (!paused || _last) { + _accumulated += add; + _last = paused ? 0 : now; + } + const auto absolute = (_accumulated / kDefaultFrameDuration); + if (!paused && !_animating) { + _animating = true; + Register(this); + } else if (paused && _animating) { + _animating = false; + Unregister(this); + } + return absolute % kDefaultFramesCount; +} + +void SpoilerAnimation::repaint() { + _repaint(); +} + void PrepareDefaultSpoilerMess() { DefaultMaskSignal = new std::condition_variable(); DefaultMaskMutex = new std::mutex(); diff --git a/ui/effects/spoiler_mess.h b/ui/effects/spoiler_mess.h index 93ae0f1..2a1f80a 100644 --- a/ui/effects/spoiler_mess.h +++ b/ui/effects/spoiler_mess.h @@ -62,6 +62,24 @@ private: }; +// Works with default frame duration and default frame count. +class SpoilerAnimation final { +public: + explicit SpoilerAnimation(Fn repaint); + ~SpoilerAnimation(); + + int index(crl::time now, bool paused); + + void repaint(); + +private: + const Fn _repaint; + crl::time _accumulated = 0; + crl::time _last = 0; + bool _animating = false; + +}; + [[nodiscard]] SpoilerMessCached GenerateSpoilerMess( const SpoilerMessDescriptor &descriptor);