init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
212
Telegram/lib_ui/ui/effects/animations.cpp
Normal file
212
Telegram/lib_ui/ui/effects/animations.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "ui/effects/animations.h"
|
||||
|
||||
#include "base/invoke_queued.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "styles/style_basic.h"
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
#include <crl/crl_on_main.h>
|
||||
#include <crl/crl.h>
|
||||
#include <rpl/filter.h>
|
||||
#include <range/v3/algorithm/remove_if.hpp>
|
||||
#include <range/v3/algorithm/remove.hpp>
|
||||
#include <range/v3/algorithm/find.hpp>
|
||||
|
||||
namespace Ui {
|
||||
namespace Animations {
|
||||
namespace {
|
||||
|
||||
constexpr auto kAnimationTick = crl::time(1000) / st::universalDuration;
|
||||
constexpr auto kIgnoreUpdatesTimeout = crl::time(4);
|
||||
|
||||
Manager *ManagerInstance = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
void Basic::start() {
|
||||
Expects(ManagerInstance != nullptr);
|
||||
|
||||
if (animating()) {
|
||||
restart();
|
||||
} else {
|
||||
ManagerInstance->start(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Basic::stop() {
|
||||
Expects(ManagerInstance != nullptr);
|
||||
|
||||
if (animating()) {
|
||||
ManagerInstance->stop(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Basic::restart() {
|
||||
Expects(_started >= 0);
|
||||
|
||||
_started = crl::now();
|
||||
|
||||
Ensures(_started >= 0);
|
||||
}
|
||||
|
||||
void Basic::markStarted() {
|
||||
Expects(_started < 0);
|
||||
|
||||
_started = crl::now();
|
||||
|
||||
Ensures(_started >= 0);
|
||||
}
|
||||
|
||||
void Basic::markStopped() {
|
||||
Expects(_started >= 0);
|
||||
|
||||
_started = -1;
|
||||
}
|
||||
|
||||
Manager::Manager() {
|
||||
Expects(ManagerInstance == nullptr);
|
||||
|
||||
ManagerInstance = this;
|
||||
|
||||
crl::on_main_update_requests(
|
||||
) | rpl::filter([=] {
|
||||
return (_lastUpdateTime + kIgnoreUpdatesTimeout < crl::now());
|
||||
}) | rpl::on_next([=] {
|
||||
update();
|
||||
}, _lifetime);
|
||||
}
|
||||
|
||||
Manager::~Manager() {
|
||||
Expects(ManagerInstance == this);
|
||||
Expects(_active.empty());
|
||||
Expects(_starting.empty());
|
||||
|
||||
ManagerInstance = nullptr;
|
||||
}
|
||||
|
||||
void Manager::start(not_null<Basic*> animation) {
|
||||
_forceImmediateUpdate = true;
|
||||
if (_updating) {
|
||||
_starting.emplace_back(animation.get());
|
||||
} else {
|
||||
schedule();
|
||||
_active.emplace_back(animation.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::stop(not_null<Basic*> animation) {
|
||||
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, value, proj);
|
||||
if (i != end(_active)) {
|
||||
*i = nullptr;
|
||||
_removedWhileUpdating = true;
|
||||
}
|
||||
} else if (empty(_active)) {
|
||||
stopTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::update() {
|
||||
if (_active.empty() || _updating || _scheduled) {
|
||||
return;
|
||||
}
|
||||
const auto now = crl::now();
|
||||
if (_forceImmediateUpdate) {
|
||||
_forceImmediateUpdate = false;
|
||||
}
|
||||
schedule();
|
||||
|
||||
_updating = true;
|
||||
const auto guard = gsl::finally([&] { _updating = false; });
|
||||
|
||||
_lastUpdateTime = now;
|
||||
const auto isFinished = [&](const ActiveBasicPointer &element) {
|
||||
return !element.call(now);
|
||||
};
|
||||
_active.erase(ranges::remove_if(_active, isFinished), end(_active));
|
||||
|
||||
if (_removedWhileUpdating) {
|
||||
_removedWhileUpdating = false;
|
||||
const auto proj = &ActiveBasicPointer::get;
|
||||
_active.erase(ranges::remove(_active, nullptr, proj), end(_active));
|
||||
}
|
||||
|
||||
if (!empty(_starting)) {
|
||||
_active.insert(
|
||||
end(_active),
|
||||
std::make_move_iterator(begin(_starting)),
|
||||
std::make_move_iterator(end(_starting)));
|
||||
_starting.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::updateQueued() {
|
||||
Expects(_timerId == 0);
|
||||
|
||||
_timerId = -1;
|
||||
InvokeQueued(delayedCallGuard(), [=] {
|
||||
Expects(_timerId < 0);
|
||||
|
||||
_timerId = 0;
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
void Manager::schedule() {
|
||||
if (_scheduled || _timerId < 0) {
|
||||
return;
|
||||
}
|
||||
stopTimer();
|
||||
|
||||
_scheduled = true;
|
||||
PostponeCall(delayedCallGuard(), [=] {
|
||||
_scheduled = false;
|
||||
if (_active.empty()) {
|
||||
return;
|
||||
}
|
||||
if (_forceImmediateUpdate) {
|
||||
_forceImmediateUpdate = false;
|
||||
updateQueued();
|
||||
} else {
|
||||
const auto next = _lastUpdateTime + kAnimationTick;
|
||||
const auto now = crl::now();
|
||||
if (now < next) {
|
||||
_timerId = startTimer(next - now, Qt::PreciseTimer);
|
||||
} else {
|
||||
updateQueued();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
not_null<const QObject*> Manager::delayedCallGuard() const {
|
||||
return static_cast<const QObject*>(this);
|
||||
}
|
||||
|
||||
void Manager::stopTimer() {
|
||||
if (_timerId > 0) {
|
||||
killTimer(base::take(_timerId));
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::timerEvent(QTimerEvent *e) {
|
||||
update();
|
||||
}
|
||||
|
||||
} // namespace Animations
|
||||
} // namespace Ui
|
||||
Reference in New Issue
Block a user