Provide simple spoiler animations manager.

This commit is contained in:
John Preston 2022-09-09 12:41:07 +04:00
parent c732bd874f
commit ff85d2226c
2 changed files with 81 additions and 0 deletions

View file

@ -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<const SpoilerMessCached*> DefaultMask/* = nullptr*/;
std::condition_variable *DefaultMaskSignal/* = nullptr*/;
std::mutex *DefaultMaskMutex/* = nullptr*/;
struct AnimationManager {
Ui::Animations::Basic animation;
base::flat_set<not_null<SpoilerAnimation*>> 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<SpoilerAnimation*> 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<SpoilerAnimation*> 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> SpoilerMessCached::FromSerialized(
header.canvasSize);
}
SpoilerAnimation::SpoilerAnimation(Fn<void()> 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();

View file

@ -62,6 +62,24 @@ private:
};
// Works with default frame duration and default frame count.
class SpoilerAnimation final {
public:
explicit SpoilerAnimation(Fn<void()> repaint);
~SpoilerAnimation();
int index(crl::time now, bool paused);
void repaint();
private:
const Fn<void()> _repaint;
crl::time _accumulated = 0;
crl::time _last = 0;
bool _animating = false;
};
[[nodiscard]] SpoilerMessCached GenerateSpoilerMess(
const SpoilerMessDescriptor &descriptor);