From aa00f9bd3417ed5358c317ff178b7cb4c16d01d6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 11 Mar 2019 11:11:02 +0400 Subject: [PATCH] Fix new animations engine restarts. --- .../SourceFiles/ui/effects/animations.cpp | 56 +++++++++++++------ Telegram/SourceFiles/ui/effects/animations.h | 52 ++++++++++++++++- 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/Telegram/SourceFiles/ui/effects/animations.cpp b/Telegram/SourceFiles/ui/effects/animations.cpp index 389457e68c..ecc9e4c9cf 100644 --- a/Telegram/SourceFiles/ui/effects/animations.cpp +++ b/Telegram/SourceFiles/ui/effects/animations.cpp @@ -20,19 +20,37 @@ constexpr auto kIgnoreUpdatesTimeout = crl::time(4); } // namespace void Basic::start() { - if (!animating()) { + if (animating()) { + restart(); + } else { Core::App().animationManager().start(this); } - _started = crl::now(); } void Basic::stop() { if (animating()) { Core::App().animationManager().stop(this); - _started = -1; } } +void Basic::restart() { + Expects(_started >= 0); + + _started = crl::now(); +} + +void Basic::markStarted() { + Expects(_started < 0); + + _started = crl::now(); +} + +void Basic::markStopped() { + Expects(_started >= 0); + + _started = -1; +} + Manager::Manager() { Core::Sandbox::Instance().widgetUpdateRequests( ) | rpl::start_with_next([=] { @@ -42,28 +60,30 @@ Manager::Manager() { void Manager::start(not_null animation) { if (_updating) { - _starting.push_back(animation); + _starting.emplace_back(animation.get()); } else { if (empty(_active)) { updateQueued(); } - _active.push_back(animation); + _active.emplace_back(animation.get()); } } void Manager::stop(not_null animation) { - if (empty(_active)) { + if (empty(_active) && empty(_starting)) { return; } + const auto value = animation.get(); + const auto proj = &ActiveBasicPointer::get; + auto &list = _updating ? _starting : _active; + list.erase(ranges::remove(list, value, proj), end(list)); + if (_updating) { - const auto i = ranges::find(_active, animation.get()); + const auto i = ranges::find(_active, value, proj); if (i != end(_active)) { *i = nullptr; } - return; - } - _active.erase(ranges::remove(_active, animation.get()), end(_active)); - if (empty(_active)) { + } else if (empty(_active)) { stopTimer(); } } @@ -82,13 +102,17 @@ void Manager::update() { const auto guard = gsl::finally([&] { _updating = false; }); _lastUpdateTime = now; - _active.erase(ranges::remove_if(_active, [&](Basic *element) { - return !element || !element->call(now); - }), end(_active)); + const auto isFinished = [&](const ActiveBasicPointer &element) { + return !element.call(now); + }; + _active.erase(ranges::remove_if(_active, isFinished), end(_active)); if (!empty(_starting)) { - auto starting = std::move(_starting); - _active.insert(end(_active), begin(starting), end(starting)); + _active.insert( + end(_active), + std::make_move_iterator(begin(_starting)), + std::make_move_iterator(end(_starting))); + _starting.clear(); } } diff --git a/Telegram/SourceFiles/ui/effects/animations.h b/Telegram/SourceFiles/ui/effects/animations.h index a65054e04b..5fdcb0bb90 100644 --- a/Telegram/SourceFiles/ui/effects/animations.h +++ b/Telegram/SourceFiles/ui/effects/animations.h @@ -37,6 +37,10 @@ private: [[nodiscard]] static Fn Prepare(Callback &&callback); [[nodiscard]] bool call(crl::time now) const; + void restart(); + + void markStarted(); + void markStopped(); crl::time _started = -1; Fn _callback; @@ -98,6 +102,50 @@ public: void update(); private: + class ActiveBasicPointer { + public: + ActiveBasicPointer(Basic *value = nullptr) : _value(value) { + if (_value) { + _value->markStarted(); + } + } + ActiveBasicPointer(ActiveBasicPointer &&other) + : _value(base::take(other._value)) { + } + ActiveBasicPointer &operator=(ActiveBasicPointer &&other) { + if (_value != other._value) { + if (_value) { + _value->markStopped(); + } + _value = base::take(other._value); + } + return *this; + } + ~ActiveBasicPointer() { + if (_value) { + _value->markStopped(); + } + } + + [[nodiscard]] bool call(crl::time now) const { + return _value && _value->call(now); + } + + friend inline bool operator==( + const ActiveBasicPointer &a, + const ActiveBasicPointer &b) { + return a._value == b._value; + } + + Basic *get() const { + return _value; + } + + private: + Basic *_value = nullptr; + + }; + friend class Basic; void timerEvent(QTimerEvent *e) override; @@ -113,8 +161,8 @@ private: int _timerId = 0; bool _updating = false; bool _scheduled = false; - std::vector _active; - std::vector> _starting; + std::vector _active; + std::vector _starting; rpl::lifetime _lifetime; };