Use new animations engine for typings.

This commit is contained in:
John Preston 2019-04-01 18:53:18 +04:00
parent 3971f27c66
commit cd3c1c6dc0
15 changed files with 301 additions and 233 deletions

View File

@ -151,7 +151,9 @@ Session::Session(not_null<AuthSession*> session)
Local::cacheBigFilePath(),
Local::cacheBigFileSettings()))
, _selfDestructTimer([=] { checkSelfDestructItems(); })
, _a_sendActions(animation(this, &Session::step_typings))
, _sendActionsAnimation([=](crl::time now) {
return sendActionsAnimationCallback(now);
})
, _groups(this)
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
_cache->open(Local::cacheKey());
@ -241,7 +243,8 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
return data.vid.v;
}));
auto minimal = false;
const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty();
const MTPUserStatus *status = nullptr;
const MTPUserStatus emptyStatus = MTP_userStatusEmpty();
Notify::PeerUpdate update;
using UpdateFlag = Notify::PeerUpdate::Flag;
@ -749,22 +752,20 @@ void Session::registerSendAction(
const auto i = _sendActions.find(history);
if (!_sendActions.contains(history)) {
_sendActions.emplace(history, crl::now());
_a_sendActions.start();
_sendActionsAnimation.start();
}
}
}
void Session::step_typings(crl::time ms, bool timer) {
bool Session::sendActionsAnimationCallback(crl::time now) {
for (auto i = begin(_sendActions); i != end(_sendActions);) {
if (i->first->updateSendActionNeedsAnimating(ms)) {
if (i->first->updateSendActionNeedsAnimating(now)) {
++i;
} else {
i = _sendActions.erase(i);
}
}
if (_sendActions.empty()) {
_a_sendActions.stop();
}
return !_sendActions.empty();
}
Storage::Cache::Database &Session::cache() {

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_notify_settings.h"
#include "history/history_location_manager.h"
#include "base/timer.h"
#include "ui/effects/animations.h"
class Image;
class HistoryItem;
@ -670,7 +671,7 @@ private:
const MTPMessageMedia &media,
TimeId date);
void step_typings(crl::time ms, bool timer);
bool sendActionsAnimationCallback(crl::time now);
void setWallpapers(const QVector<MTPWallPaper> &data, int32 hash);
@ -733,7 +734,7 @@ private:
// When typing in this history started.
base::flat_map<not_null<History*>, crl::time> _sendActions;
BasicAnimation _a_sendActions;
Ui::Animations::Basic _sendActionsAnimation;
std::unordered_map<
PhotoId,

View File

@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text_options.h"
#include "core/crash_reports.h"
#include "styles/style_dialogs.h"
#include <memory>
namespace {
@ -352,45 +353,78 @@ bool History::updateSendActionNeedsAnimating(
return false;
}
auto ms = crl::now();
switch (action.type()) {
case mtpc_sendMessageTypingAction: _typing.insert(user, ms + kStatusShowClientsideTyping); break;
case mtpc_sendMessageRecordVideoAction: _sendActions.insert(user, { Type::RecordVideo, ms + kStatusShowClientsideRecordVideo }); break;
case mtpc_sendMessageUploadVideoAction: _sendActions.insert(user, { Type::UploadVideo, ms + kStatusShowClientsideUploadVideo, action.c_sendMessageUploadVideoAction().vprogress.v }); break;
case mtpc_sendMessageRecordAudioAction: _sendActions.insert(user, { Type::RecordVoice, ms + kStatusShowClientsideRecordVoice }); break;
case mtpc_sendMessageUploadAudioAction: _sendActions.insert(user, { Type::UploadVoice, ms + kStatusShowClientsideUploadVoice, action.c_sendMessageUploadAudioAction().vprogress.v }); break;
case mtpc_sendMessageRecordRoundAction: _sendActions.insert(user, { Type::RecordRound, ms + kStatusShowClientsideRecordRound }); break;
case mtpc_sendMessageUploadRoundAction: _sendActions.insert(user, { Type::UploadRound, ms + kStatusShowClientsideUploadRound }); break;
case mtpc_sendMessageUploadPhotoAction: _sendActions.insert(user, { Type::UploadPhoto, ms + kStatusShowClientsideUploadPhoto, action.c_sendMessageUploadPhotoAction().vprogress.v }); break;
case mtpc_sendMessageUploadDocumentAction: _sendActions.insert(user, { Type::UploadFile, ms + kStatusShowClientsideUploadFile, action.c_sendMessageUploadDocumentAction().vprogress.v }); break;
case mtpc_sendMessageGeoLocationAction: _sendActions.insert(user, { Type::ChooseLocation, ms + kStatusShowClientsideChooseLocation }); break;
case mtpc_sendMessageChooseContactAction: _sendActions.insert(user, { Type::ChooseContact, ms + kStatusShowClientsideChooseContact }); break;
case mtpc_sendMessageGamePlayAction: {
auto it = _sendActions.find(user);
if (it == _sendActions.end() || it->type == Type::PlayGame || it->until <= ms) {
_sendActions.insert(user, { Type::PlayGame, ms + kStatusShowClientsidePlayGame });
const auto now = crl::now();
const auto emplaceAction = [&](
Type type,
crl::time duration,
int progress = 0) {
_sendActions.emplace(user, type, now + duration, progress);
};
action.match([&](const MTPDsendMessageTypingAction &) {
_typing.emplace(user, now + kStatusShowClientsideTyping);
}, [&](const MTPDsendMessageRecordVideoAction &) {
emplaceAction(Type::RecordVideo, kStatusShowClientsideRecordVideo);
}, [&](const MTPDsendMessageRecordAudioAction &) {
emplaceAction(Type::RecordVoice, kStatusShowClientsideRecordVideo);
}, [&](const MTPDsendMessageRecordRoundAction &) {
emplaceAction(Type::RecordRound, kStatusShowClientsideRecordRound);
}, [&](const MTPDsendMessageGeoLocationAction &) {
emplaceAction(Type::ChooseLocation, kStatusShowClientsideChooseLocation);
}, [&](const MTPDsendMessageChooseContactAction &) {
emplaceAction(Type::ChooseContact, kStatusShowClientsideChooseContact);
}, [&](const MTPDsendMessageUploadVideoAction &data) {
emplaceAction(
Type::UploadVideo,
kStatusShowClientsideUploadVideo,
data.vprogress.v);
}, [&](const MTPDsendMessageUploadAudioAction &data) {
emplaceAction(
Type::UploadVoice,
kStatusShowClientsideUploadVoice,
data.vprogress.v);
}, [&](const MTPDsendMessageUploadRoundAction &data) {
emplaceAction(
Type::UploadRound,
kStatusShowClientsideUploadRound,
data.vprogress.v);
}, [&](const MTPDsendMessageUploadPhotoAction &data) {
emplaceAction(
Type::UploadPhoto,
kStatusShowClientsideUploadPhoto,
data.vprogress.v);
}, [&](const MTPDsendMessageUploadDocumentAction &data) {
emplaceAction(
Type::UploadFile,
kStatusShowClientsideUploadFile,
data.vprogress.v);
}, [&](const MTPDsendMessageGamePlayAction &) {
const auto i = _sendActions.find(user);
if ((i == end(_sendActions))
|| (i->second.type == Type::PlayGame)
|| (i->second.until <= now)) {
emplaceAction(Type::PlayGame, kStatusShowClientsidePlayGame);
}
} break;
default: return false;
}
return updateSendActionNeedsAnimating(ms, true);
}, [&](const MTPDsendMessageCancelAction &) {
Unexpected("CancelAction here.");
});
return updateSendActionNeedsAnimating(now, true);
}
bool History::mySendActionUpdated(SendAction::Type type, bool doing) {
auto ms = crl::now();
auto i = _mySendActions.find(type);
const auto now = crl::now();
const auto i = _mySendActions.find(type);
if (doing) {
if (i == _mySendActions.cend()) {
_mySendActions.insert(type, ms + kSetMyActionForMs);
} else if (i.value() > ms + (kSetMyActionForMs / 2)) {
if (i == end(_mySendActions)) {
_mySendActions.emplace(type, now + kSetMyActionForMs);
} else if (i->second > now + (kSetMyActionForMs / 2)) {
return false;
} else {
i.value() = ms + kSetMyActionForMs;
i->second = now + kSetMyActionForMs;
}
} else {
if (i == _mySendActions.cend()) {
if (i == end(_mySendActions)) {
return false;
} else if (i.value() <= ms) {
} else if (i->second <= now) {
return false;
} else {
_mySendActions.erase(i);
@ -425,18 +459,18 @@ bool History::paintSendAction(
return false;
}
bool History::updateSendActionNeedsAnimating(crl::time ms, bool force) {
bool History::updateSendActionNeedsAnimating(crl::time now, bool force) {
auto changed = force;
for (auto i = _typing.begin(), e = _typing.end(); i != e;) {
if (ms >= i.value()) {
for (auto i = begin(_typing); i != end(_typing);) {
if (now >= i->second) {
i = _typing.erase(i);
changed = true;
} else {
++i;
}
}
for (auto i = _sendActions.begin(); i != _sendActions.cend();) {
if (ms >= i.value().until) {
for (auto i = begin(_sendActions); i != end(_sendActions);) {
if (now >= i->second.until) {
i = _sendActions.erase(i);
changed = true;
} else {
@ -449,10 +483,18 @@ bool History::updateSendActionNeedsAnimating(crl::time ms, bool force) {
if (typingCount > 2) {
newTypingString = lng_many_typing(lt_count, typingCount);
} else if (typingCount > 1) {
newTypingString = lng_users_typing(lt_user, _typing.begin().key()->firstName, lt_second_user, (_typing.end() - 1).key()->firstName);
newTypingString = lng_users_typing(
lt_user,
begin(_typing)->first->firstName,
lt_second_user,
(end(_typing) - 1)->first->firstName);
} else if (typingCount) {
newTypingString = peer->isUser() ? lang(lng_typing) : lng_user_typing(lt_user, _typing.begin().key()->firstName);
} else if (!_sendActions.isEmpty()) {
newTypingString = peer->isUser()
? lang(lng_typing)
: lng_user_typing(
lt_user,
begin(_typing)->first->firstName);
} else if (!_sendActions.empty()) {
// Handles all actions except game playing.
using Type = SendAction::Type;
auto sendActionString = [](Type type, const QString &name) -> QString {
@ -471,10 +513,12 @@ bool History::updateSendActionNeedsAnimating(crl::time ms, bool force) {
};
return QString();
};
for (auto i = _sendActions.cbegin(), e = _sendActions.cend(); i != e; ++i) {
newTypingString = sendActionString(i->type, peer->isUser() ? QString() : i.key()->firstName);
for (const auto [user, action] : _sendActions) {
newTypingString = sendActionString(
action.type,
peer->isUser() ? QString() : user->firstName);
if (!newTypingString.isEmpty()) {
_sendActionAnimation.start(i->type);
_sendActionAnimation.start(action.type);
break;
}
}
@ -483,11 +527,21 @@ bool History::updateSendActionNeedsAnimating(crl::time ms, bool force) {
if (newTypingString.isEmpty()) {
int playingCount = _sendActions.size();
if (playingCount > 2) {
newTypingString = lng_many_playing_game(lt_count, playingCount);
newTypingString = lng_many_playing_game(
lt_count,
playingCount);
} else if (playingCount > 1) {
newTypingString = lng_users_playing_game(lt_user, _sendActions.begin().key()->firstName, lt_second_user, (_sendActions.end() - 1).key()->firstName);
newTypingString = lng_users_playing_game(
lt_user,
begin(_sendActions)->first->firstName,
lt_second_user,
(end(_sendActions) - 1)->first->firstName);
} else {
newTypingString = peer->isUser() ? lang(lng_playing_game) : lng_user_playing_game(lt_user, _sendActions.begin().key()->firstName);
newTypingString = peer->isUser()
? lang(lng_playing_game)
: lng_user_playing_game(
lt_user,
begin(_sendActions)->first->firstName);
}
_sendActionAnimation.start(Type::PlayGame);
}
@ -505,7 +559,7 @@ bool History::updateSendActionNeedsAnimating(crl::time ms, bool force) {
Ui::NameTextOptions());
}
}
auto result = (!_typing.isEmpty() || !_sendActions.isEmpty());
const auto result = (!_typing.empty() || !_sendActions.empty());
if (changed || (result && !anim::Disabled())) {
_owner->updateSendActionAnimation({
this,
@ -547,7 +601,7 @@ std::vector<not_null<HistoryItem*>> History::createItems(
for (auto i = data.cend(), e = data.cbegin(); i != e;) {
const auto detachExistingItem = true;
if (const auto item = createItem(*--i, detachExistingItem)) {
result.push_back(item);
result.emplace_back(item);
}
}
return result;
@ -1064,7 +1118,8 @@ void History::applyServiceChanges(
photo->peer = peer;
auto &smallSize = sizes.front();
auto &bigSize = sizes.back();
const MTPFileLocation *smallLoc = 0, *bigLoc = 0;
const MTPFileLocation *smallLoc = nullptr;
const MTPFileLocation *bigLoc = nullptr;
switch (smallSize.type()) {
case mtpc_photoSize: smallLoc = &smallSize.c_photoSize().vlocation; break;
case mtpc_photoCachedSize: smallLoc = &smallSize.c_photoCachedSize().vlocation; break;
@ -1135,12 +1190,12 @@ void History::clearSendAction(not_null<UserData*> from) {
auto i = _typing.find(from);
if (i != _typing.cend()) {
updateAtMs = crl::now();
i.value() = updateAtMs;
i->second = updateAtMs;
}
auto j = _sendActions.find(from);
if (j != _sendActions.cend()) {
if (!updateAtMs) updateAtMs = crl::now();
j.value().until = updateAtMs;
j->second.until = updateAtMs;
}
if (updateAtMs) {
updateSendActionNeedsAnimating(updateAtMs, true);
@ -1977,7 +2032,7 @@ void History::startBuildingFrontBlock(int expectedItemsCount) {
Assert(!isBuildingFrontBlock());
Assert(expectedItemsCount > 0);
_buildingFrontBlock.reset(new BuildingBlock());
_buildingFrontBlock = std::make_unique<BuildingBlock>();
_buildingFrontBlock->expectedItemsCount = expectedItemsCount;
}
@ -2624,10 +2679,9 @@ History *History::migrateFrom() const {
MsgRange History::rangeForDifferenceRequest() const {
auto fromId = MsgId(0);
auto toId = MsgId(0);
for (auto blockIndex = 0, blocksCount = int(blocks.size()); blockIndex < blocksCount; ++blockIndex) {
const auto &block = blocks[blockIndex];
for (auto itemIndex = 0, itemsCount = int(block->messages.size()); itemIndex < itemsCount; ++itemIndex) {
const auto id = block->messages[itemIndex]->data()->id;
for (const auto &block : blocks) {
for (const auto &item : block->messages) {
const auto id = item->data()->id;
if (id > 0) {
fromId = id;
break;

View File

@ -216,10 +216,19 @@ public:
void setHasPendingResizedItems();
bool mySendActionUpdated(SendAction::Type type, bool doing);
bool paintSendAction(Painter &p, int x, int y, int availableWidth, int outerWidth, style::color color, crl::time ms);
bool paintSendAction(
Painter &p,
int x,
int y,
int availableWidth,
int outerWidth,
style::color color,
crl::time now);
// Interface for Histories
bool updateSendActionNeedsAnimating(crl::time ms, bool force = false);
bool updateSendActionNeedsAnimating(
crl::time now,
bool force = false);
bool updateSendActionNeedsAnimating(
not_null<UserData*> user,
const MTPSendMessageAction &action);
@ -490,14 +499,12 @@ private:
TimeId _lastSentDraftTime = 0;
MessageIdsList _forwardDraft;
using TypingUsers = QMap<UserData*, crl::time>;
TypingUsers _typing;
using SendActionUsers = QMap<UserData*, SendAction>;
SendActionUsers _sendActions;
base::flat_map<not_null<UserData*>, crl::time> _typing;
base::flat_map<not_null<UserData*>, SendAction> _sendActions;
QString _sendActionString;
Text _sendActionText;
Ui::SendActionAnimation _sendActionAnimation;
QMap<SendAction::Type, crl::time> _mySendActions;
base::flat_map<SendAction::Type, crl::time> _mySendActions;
std::weak_ptr<AdminLog::LocalIdManager> _adminLogIdManager;

View File

@ -100,20 +100,22 @@ TopBarWidget::TopBarWidget(
if (Adaptive::OneColumn()) {
createUnreadBadge();
}
Auth().data().sendActionAnimationUpdated(
) | rpl::start_with_next([=](
const Data::Session::SendActionAnimationUpdate &update) {
if (update.history == _activeChat.history()) {
this->update();
}
}, lifetime());
{
using AnimationUpdate = Data::Session::SendActionAnimationUpdate;
Auth().data().sendActionAnimationUpdated(
) | rpl::filter([=](const AnimationUpdate &update) {
return (update.history == _activeChat.history());
}) | rpl::start_with_next([=] {
update();
}, lifetime());
}
using UpdateFlag = Notify::PeerUpdate::Flag;
auto flags = UpdateFlag::UserHasCalls
| UpdateFlag::UserOnlineChanged
| UpdateFlag::MembersChanged
| UpdateFlag::UserSupportInfoChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(flags, [this](const Notify::PeerUpdate &update) {
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(flags, [=](const Notify::PeerUpdate &update) {
if (update.flags & UpdateFlag::UserHasCalls) {
if (update.peer->isUser()) {
updateControlsVisibility();

View File

@ -186,7 +186,7 @@ OverlayWidget::OverlayWidget()
, _docCancel(this, lang(lng_cancel), st::mediaviewFileLink)
, _radial(animation(this, &OverlayWidget::step_radial))
, _lastAction(-st::mediaviewDeltaFromLastAction, -st::mediaviewDeltaFromLastAction)
, _a_state([=](float64 now) { step_state(now); })
, _stateAnimation([=](crl::time now) { return stateAnimationCallback(now); })
, _dropdown(this, st::mediaviewDropdownMenu)
, _dropdownShowTimer(this) {
subscribe(Lang::Current().updated(), [this] { refreshLang(); });
@ -651,60 +651,57 @@ auto OverlayWidget::computeOverviewType() const
return std::nullopt;
}
void OverlayWidget::step_state(crl::time now) {
bool OverlayWidget::stateAnimationCallback(crl::time now) {
if (anim::Disabled()) {
now += st::mediaviewShowDuration + st::mediaviewHideDuration;
}
bool result = false;
for (auto i = _animations.begin(); i != _animations.end();) {
crl::time start = i.value();
switch (i.key()) {
case OverLeftNav: update(_leftNav); break;
case OverRightNav: update(_rightNav); break;
case OverName: update(_nameNav); break;
case OverDate: update(_dateNav); break;
case OverHeader: update(_headerNav); break;
case OverClose: update(_closeNav); break;
case OverSave: update(_saveNav); break;
case OverIcon: update(_docIconRect); break;
case OverMore: update(_moreNav); break;
default: break;
}
const auto dt = float64(now - start) / st::mediaviewFadeDuration;
for (auto i = begin(_animations); i != end(_animations);) {
const auto [state, started] = *i;
updateOverRect(state);
const auto dt = float64(now - started) / st::mediaviewFadeDuration;
if (dt >= 1) {
_animOpacities.remove(i.key());
_animationOpacities.erase(state);
i = _animations.erase(i);
} else {
_animOpacities[i.key()].update(dt, anim::linear);
_animationOpacities[state].update(dt, anim::linear);
++i;
}
}
if (_controlsState == ControlsShowing || _controlsState == ControlsHiding) {
float64 dt = float64(now - _controlsAnimStarted) / (_controlsState == ControlsShowing ? st::mediaviewShowDuration : st::mediaviewHideDuration);
if (dt >= 1) {
a_cOpacity.finish();
_controlsState = (_controlsState == ControlsShowing ? ControlsShown : ControlsHidden);
updateCursor();
} else {
a_cOpacity.update(dt, anim::linear);
}
const auto toUpdate = QRegion()
+ (_over == OverLeftNav ? _leftNav : _leftNavIcon)
+ (_over == OverRightNav ? _rightNav : _rightNavIcon)
+ (_over == OverClose ? _closeNav : _closeNavIcon)
+ _saveNavIcon
+ _moreNavIcon
+ _headerNav
+ _nameNav
+ _dateNav
+ _captionRect.marginsAdded(st::mediaviewCaptionPadding)
+ _groupThumbsRect;
update(toUpdate);
if (dt < 1) result = true;
return !_animations.empty() || updateControlsAnimation(now);
}
bool OverlayWidget::updateControlsAnimation(crl::time now) {
if (_controlsState != ControlsShowing
&& _controlsState != ControlsHiding) {
return false;
}
if (!result && _animations.isEmpty()) {
_a_state.stop();
const auto duration = (_controlsState == ControlsShowing)
? st::mediaviewShowDuration
: st::mediaviewHideDuration;
const auto dt = float64(now - _controlsAnimStarted)
/ duration;
if (dt >= 1) {
_controlsOpacity.finish();
_controlsState = (_controlsState == ControlsShowing)
? ControlsShown
: ControlsHidden;
updateCursor();
} else {
_controlsOpacity.update(dt, anim::linear);
}
const auto toUpdate = QRegion()
+ (_over == OverLeftNav ? _leftNav : _leftNavIcon)
+ (_over == OverRightNav ? _rightNav : _rightNavIcon)
+ (_over == OverClose ? _closeNav : _closeNavIcon)
+ _saveNavIcon
+ _moreNavIcon
+ _headerNav
+ _nameNav
+ _dateNav
+ _captionRect.marginsAdded(st::mediaviewCaptionPadding)
+ _groupThumbsRect;
update(toUpdate);
return (dt < 1);
}
void OverlayWidget::step_waiting(crl::time ms, bool timer) {
@ -910,11 +907,13 @@ void OverlayWidget::clearData() {
if (!isHidden()) {
hide();
}
if (!_animations.isEmpty()) {
if (!_animations.empty()) {
_animations.clear();
_a_state.stop();
_stateAnimation.stop();
}
if (!_animationOpacities.empty()) {
_animationOpacities.clear();
}
if (!_animOpacities.isEmpty()) _animOpacities.clear();
clearStreaming();
delete _menu;
_menu = nullptr;
@ -967,8 +966,10 @@ void OverlayWidget::activateControls() {
if (_controlsState == ControlsHiding || _controlsState == ControlsHidden) {
_controlsState = ControlsShowing;
_controlsAnimStarted = crl::now();
a_cOpacity.start(1);
if (!_a_state.animating()) _a_state.start();
_controlsOpacity.start(1);
if (!_stateAnimation.animating()) {
_stateAnimation.start();
}
}
}
@ -991,8 +992,10 @@ void OverlayWidget::onHideControls(bool force) {
_lastMouseMovePos = mapFromGlobal(QCursor::pos());
_controlsState = ControlsHiding;
_controlsAnimStarted = crl::now();
a_cOpacity.start(0);
if (!_a_state.animating()) _a_state.start();
_controlsOpacity.start(0);
if (!_stateAnimation.animating()) {
_stateAnimation.start();
}
}
void OverlayWidget::dropdownHidden() {
@ -1632,6 +1635,22 @@ void OverlayWidget::initGroupThumbs() {
height() - _groupThumbsTop);
}
void OverlayWidget::clearControlsState() {
_saveMsgStarted = 0;
_loadRequest = 0;
_over = _down = OverNone;
_pressed = false;
_dragging = 0;
setCursor(style::cur_default);
if (!_animations.empty()) {
_animations.clear();
_stateAnimation.stop();
}
if (!_animationOpacities.empty()) {
_animationOpacities.clear();
}
}
void OverlayWidget::showPhoto(not_null<PhotoData*> photo, HistoryItem *context) {
if (context) {
setContext(context);
@ -1639,19 +1658,8 @@ void OverlayWidget::showPhoto(not_null<PhotoData*> photo, HistoryItem *context)
setContext(std::nullopt);
}
clearControlsState();
_firstOpenedPeerPhoto = false;
_saveMsgStarted = 0;
_loadRequest = 0;
_over = OverNone;
_pressed = false;
_dragging = 0;
setCursor(style::cur_default);
if (!_animations.isEmpty()) {
_animations.clear();
_a_state.stop();
}
if (!_animOpacities.isEmpty()) _animOpacities.clear();
_photo = photo;
refreshMediaViewer();
@ -1664,17 +1672,8 @@ void OverlayWidget::showPhoto(not_null<PhotoData*> photo, HistoryItem *context)
void OverlayWidget::showPhoto(not_null<PhotoData*> photo, not_null<PeerData*> context) {
setContext(context);
clearControlsState();
_firstOpenedPeerPhoto = true;
_saveMsgStarted = 0;
_loadRequest = 0;
_over = OverNone;
setCursor(style::cur_default);
if (!_animations.isEmpty()) {
_animations.clear();
_a_state.stop();
}
if (!_animOpacities.isEmpty()) _animOpacities.clear();
_photo = photo;
refreshMediaViewer();
@ -1691,18 +1690,8 @@ void OverlayWidget::showDocument(not_null<DocumentData*> document, HistoryItem *
setContext(std::nullopt);
}
clearControlsState();
_photo = nullptr;
_saveMsgStarted = 0;
_loadRequest = 0;
_down = OverNone;
_pressed = false;
_dragging = 0;
setCursor(style::cur_default);
if (!_animations.isEmpty()) {
_animations.clear();
_a_state.stop();
}
if (!_animOpacities.isEmpty()) _animOpacities.clear();
_streamingStartPaused = false;
displayDocument(document, context);
@ -2540,7 +2529,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
}
}
float64 co = _fullScreenVideo ? 0. : a_cOpacity.current();
float64 co = _fullScreenVideo ? 0. : _controlsOpacity.current();
if (co > 0) {
// left nav bar
if (_leftNav.intersects(r) && _leftNavVisible) {
@ -3276,26 +3265,30 @@ bool OverlayWidget::updateOverState(OverState newState) {
updateOverRect(newState);
if (_over != OverNone) {
_animations[_over] = crl::now();
ShowingOpacities::iterator i = _animOpacities.find(_over);
if (i != _animOpacities.end()) {
i->start(0);
const auto i = _animationOpacities.find(_over);
if (i != end(_animationOpacities)) {
i->second.start(0);
} else {
_animOpacities.insert(_over, anim::value(1, 0));
_animationOpacities.emplace(_over, anim::value(1, 0));
}
if (!_stateAnimation.animating()) {
_stateAnimation.start();
}
if (!_a_state.animating()) _a_state.start();
} else {
result = false;
}
_over = newState;
if (newState != OverNone) {
_animations[_over] = crl::now();
ShowingOpacities::iterator i = _animOpacities.find(_over);
if (i != _animOpacities.end()) {
i->start(1);
const auto i = _animationOpacities.find(_over);
if (i != end(_animationOpacities)) {
i->second.start(1);
} else {
_animOpacities.insert(_over, anim::value(0, 1));
_animationOpacities.emplace(_over, anim::value(0, 1));
}
if (!_stateAnimation.animating()) {
_stateAnimation.start();
}
if (!_a_state.animating()) _a_state.start();
}
updateCursor();
}
@ -3428,7 +3421,7 @@ void OverlayWidget::contextMenuEvent(QContextMenuEvent *e) {
if (e->reason() != QContextMenuEvent::Mouse || QRect(_x, _y, _w, _h).contains(e->pos())) {
if (_menu) {
_menu->deleteLater();
_menu = 0;
_menu = nullptr;
}
_menu = new Ui::PopupMenu(this, st::mediaviewPopupMenu);
updateActions();
@ -3574,7 +3567,7 @@ void OverlayWidget::setVisibleHook(bool visible) {
if (_menu) _menu->hideMenu(true);
_controlsHideTimer.stop();
_controlsState = ControlsShown;
a_cOpacity = anim::value(1, 1);
_controlsOpacity = anim::value(1, 1);
_groupThumbs = nullptr;
_groupThumbsRect = QRect();
#ifdef USE_OPENGL_OVERLAY_WIDGET
@ -3615,7 +3608,7 @@ void OverlayWidget::setVisibleHook(bool visible) {
void OverlayWidget::onMenuDestroy(QObject *obj) {
if (_menu == obj) {
_menu = 0;
_menu = nullptr;
activateControls();
}
_receiveMouse = false;
@ -3710,8 +3703,10 @@ void OverlayWidget::updateHeader() {
}
float64 OverlayWidget::overLevel(OverState control) const {
auto i = _animOpacities.constFind(control);
return (i == _animOpacities.cend()) ? (_over == control ? 1 : 0) : i->current();
auto i = _animationOpacities.find(control);
return (i == end(_animationOpacities))
? (_over == control ? 1. : 0.)
: i->second.current();
}
} // namespace View

View File

@ -274,9 +274,11 @@ private:
void updateHeader();
void snapXY();
void step_state(crl::time ms);
void clearControlsState();
bool stateAnimationCallback(crl::time ms);
void step_radial(crl::time ms, bool timer);
void step_waiting(crl::time ms, bool timer);
bool updateControlsAnimation(crl::time now);
void zoomIn();
void zoomOut();
@ -405,7 +407,7 @@ private:
QPoint _lastAction, _lastMouseMovePos;
bool _ignoringDropdown = false;
Ui::Animations::Basic _a_state;
Ui::Animations::Basic _stateAnimation;
enum ControlsState {
ControlsShowing,
@ -416,7 +418,7 @@ private:
ControlsState _controlsState = ControlsShown;
crl::time _controlsAnimStarted = 0;
QTimer _controlsHideTimer;
anim::value a_cOpacity;
anim::value _controlsOpacity;
bool _mousePressed = false;
Ui::PopupMenu *_menu = nullptr;
@ -431,7 +433,9 @@ private:
bool _receiveMouse = true;
bool _touchPress = false, _touchMove = false, _touchRightButton = false;
bool _touchPress = false;
bool _touchMove = false;
bool _touchRightButton = false;
QTimer _touchTimer;
QPoint _touchStart;
QPoint _accumScroll;
@ -443,10 +447,8 @@ private:
QTimer _saveMsgUpdater;
Text _saveMsgText;
typedef QMap<OverState, crl::time> Showing;
Showing _animations;
typedef QMap<OverState, anim::value> ShowingOpacities;
ShowingOpacities _animOpacities;
base::flat_map<OverState, crl::time> _animations;
base::flat_map<OverState, anim::value> _animationOpacities;
int _verticalWheelDelta = 0;

View File

@ -19,8 +19,12 @@ constexpr auto kPlaybackAnimationDurationMs = crl::time(200);
} // namespace
PlaybackProgress::PlaybackProgress()
: _a_value([=](crl::time now) { return valueAnimationCallback(now); })
, _a_receivedTill([=](crl::time now) { return receivedTillAnimationCallback(now); }) {
: _valueAnimation([=](crl::time now) {
return valueAnimationCallback(now);
})
, _receivedTillAnimation([=](crl::time now) {
return receivedTillAnimationCallback(now);
}) {
}
void PlaybackProgress::updateState(const Player::TrackState &state) {
@ -87,10 +91,10 @@ void PlaybackProgress::setValue(float64 value, bool animated) {
if (animated) {
valueAnimationCallback(crl::now());
a_value.start(value);
_a_value.start();
_valueAnimation.start();
} else {
a_value = anim::value(value, value);
_a_value.stop();
_valueAnimation.stop();
}
emitUpdatedValue();
}
@ -100,19 +104,19 @@ void PlaybackProgress::setReceivedTill(float64 value) {
if (value > current && current > 0.) {
receivedTillAnimationCallback(crl::now());
a_receivedTill.start(value);
_a_receivedTill.start();
_receivedTillAnimation.start();
} else if (value > a_value.current()) {
a_receivedTill = anim::value(a_value.current(), value);
_a_receivedTill.start();
_receivedTillAnimation.start();
} else {
a_receivedTill = anim::value(-1., -1.);
_a_receivedTill.stop();
_receivedTillAnimation.stop();
}
emitUpdatedValue();
}
bool PlaybackProgress::valueAnimationCallback(float64 now) {
const auto time = (now - _a_value.started());
const auto time = (now - _valueAnimation.started());
const auto dt = anim::Disabled()
? 1.
: (time / kPlaybackAnimationDurationMs);
@ -126,7 +130,7 @@ bool PlaybackProgress::valueAnimationCallback(float64 now) {
}
bool PlaybackProgress::receivedTillAnimationCallback(float64 now) {
const auto time = now - _a_receivedTill.started();
const auto time = now - _receivedTillAnimation.started();
const auto dt = anim::Disabled()
? 1.
: (time / kPlaybackAnimationDurationMs);

View File

@ -42,7 +42,7 @@ private:
// so it should be a Basic, not a Simple animation, because
// Simple-s pauses mtproto responses/updates handling while playing.
anim::value a_value, a_receivedTill;
Ui::Animations::Basic _a_value, _a_receivedTill;
Ui::Animations::Basic _valueAnimation, _receivedTillAnimation;
Fn<void(float64,float64)> _valueChanged;
bool _inLoadingState = false;

View File

@ -542,14 +542,14 @@ void LeftOutlineButton::paintEvent(QPaintEvent *e) {
CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : RippleButton(parent, st.ripple)
, _st(st)
, _a_loading([=](crl::time duration) { return loadingCallback(duration); }) {
, _loadingAnimation([=](crl::time now) { return loadingCallback(now); }) {
resize(_st.width, _st.height);
setCursor(style::cur_pointer);
setVisible(false);
}
bool CrossButton::loadingCallback(crl::time duration) {
const auto result = !stopLoadingAnimation(duration);
bool CrossButton::loadingCallback(crl::time now) {
const auto result = !stopLoadingAnimation(now);
if (!result || !anim::Disabled()) {
update();
}
@ -563,7 +563,7 @@ void CrossButton::toggle(bool visible, anim::type animated) {
if (isHidden()) {
setVisible(true);
}
_a_show.start(
_showAnimation.start(
[=] { animationCallback(); },
_shown ? 0. : 1.,
_shown ? 1. : 0.,
@ -577,7 +577,7 @@ void CrossButton::toggle(bool visible, anim::type animated) {
void CrossButton::animationCallback() {
update();
if (!_a_show.animating()) {
if (!_showAnimation.animating()) {
setVisible(_shown);
}
}
@ -585,18 +585,17 @@ void CrossButton::animationCallback() {
void CrossButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto ms = crl::now();
auto now = crl::now();
auto over = isOver();
auto shown = _a_show.value(_shown ? 1. : 0.);
auto shown = _showAnimation.value(_shown ? 1. : 0.);
p.setOpacity(shown);
paintRipple(p, _st.crossPosition.x(), _st.crossPosition.y(), ms);
paintRipple(p, _st.crossPosition.x(), _st.crossPosition.y(), now);
auto loading = 0.;
if (_a_loading.animating()) {
const auto duration = (ms - _a_loading.started());
if (stopLoadingAnimation(duration)) {
_a_loading.stop();
if (_loadingAnimation.animating()) {
if (stopLoadingAnimation(now)) {
_loadingAnimation.stop();
} else if (anim::Disabled()) {
CrossAnimation::paintStaticLoading(
p,
@ -608,8 +607,8 @@ void CrossButton::paintEvent(QPaintEvent *e) {
shown);
return;
} else {
loading = (duration % _st.loadingPeriod)
/ float64(_st.loadingPeriod);
loading = ((now - _loadingAnimation.started())
% _st.loadingPeriod) / float64(_st.loadingPeriod);
}
}
CrossAnimation::paint(
@ -623,13 +622,14 @@ void CrossButton::paintEvent(QPaintEvent *e) {
loading);
}
bool CrossButton::stopLoadingAnimation(crl::time duration) {
bool CrossButton::stopLoadingAnimation(crl::time now) {
if (!_loadingStopMs) {
return false;
}
const auto stopPeriod = (_loadingStopMs - _a_loading.started())
const auto stopPeriod = (_loadingStopMs - _loadingAnimation.started())
/ _st.loadingPeriod;
const auto currentPeriod = (now - _loadingAnimation.started())
/ _st.loadingPeriod;
const auto currentPeriod = duration / _st.loadingPeriod;
if (currentPeriod != stopPeriod) {
Assert(currentPeriod > stopPeriod);
return true;
@ -640,13 +640,14 @@ bool CrossButton::stopLoadingAnimation(crl::time duration) {
void CrossButton::setLoadingAnimation(bool enabled) {
if (enabled) {
_loadingStopMs = 0;
if (!_a_loading.animating()) {
_a_loading.start();
if (!_loadingAnimation.animating()) {
_loadingAnimation.start();
}
} else if (_a_loading.animating()) {
} else if (_loadingAnimation.animating()) {
_loadingStopMs = crl::now();
if (!((_loadingStopMs - _a_loading.started()) % _st.loadingPeriod)) {
_a_loading.stop();
if (!((_loadingStopMs - _loadingAnimation.started())
% _st.loadingPeriod)) {
_loadingAnimation.stop();
}
}
if (anim::Disabled()) {

View File

@ -217,7 +217,7 @@ public:
return toggle(false, animated);
}
void finishAnimating() {
_a_show.stop();
_showAnimation.stop();
animationCallback();
}
@ -235,17 +235,17 @@ protected:
QPoint prepareRippleStartPosition() const override;
private:
bool loadingCallback(crl::time duration);
bool stopLoadingAnimation(crl::time duration);
bool loadingCallback(crl::time now);
bool stopLoadingAnimation(crl::time now);
void animationCallback();
const style::CrossButton &_st;
bool _shown = false;
Ui::Animations::Simple _a_show;
Ui::Animations::Simple _showAnimation;
crl::time _loadingStopMs = 0;
Ui::Animations::Basic _a_loading;
Ui::Animations::Basic _loadingAnimation;
};

View File

@ -148,7 +148,7 @@ void ContinuousSlider::setOver(bool over) {
_over = over;
auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
_a_over.start([this] { update(); }, from, to, getOverDuration());
_overAnimation.start([=] { update(); }, from, to, getOverDuration());
}
FilledSlider::FilledSlider(QWidget *parent, const style::FilledSlider &st) : ContinuousSlider(parent)

View File

@ -72,7 +72,7 @@ protected:
return _receivedTill;
}
float64 getCurrentOverFactor() {
return _disabled ? 0. : _a_over.value(_over ? 1. : 0.);
return _disabled ? 0. : _overAnimation.value(_over ? 1. : 0.);
}
Direction getDirection() const {
return _direction;
@ -104,7 +104,7 @@ private:
Fn<void(float64)> _changeFinishedCallback;
bool _over = false;
Ui::Animations::Simple _a_over;
Ui::Animations::Simple _overAnimation;
float64 _value = 0.;
float64 _receivedTill = 0.;

View File

@ -972,7 +972,7 @@ void FlatInput::paintEvent(QPaintEvent *e) {
Painter p(this);
auto ms = crl::now();
auto placeholderFocused = _a_placeholderFocused.value(_focused ? 1. : 0.);
auto placeholderFocused = _placeholderFocusedAnimation.value(_focused ? 1. : 0.);
auto pen = anim::pen(_st.borderColor, _st.borderActive, placeholderFocused);
pen.setWidth(_st.borderWidth);
p.setPen(pen);
@ -986,7 +986,8 @@ void FlatInput::paintEvent(QPaintEvent *e) {
_st.icon.paint(p, 0, 0, width());
}
auto placeholderOpacity = _a_placeholderVisible.value(_placeholderVisible ? 1. : 0.);
const auto placeholderOpacity = _placeholderVisibleAnimation.value(
_placeholderVisible ? 1. : 0.);
if (placeholderOpacity > 0.) {
p.setOpacity(placeholderOpacity);
@ -1006,7 +1007,7 @@ void FlatInput::paintEvent(QPaintEvent *e) {
void FlatInput::focusInEvent(QFocusEvent *e) {
if (!_focused) {
_focused = true;
_a_placeholderFocused.start(
_placeholderFocusedAnimation.start(
[=] { update(); },
0.,
1.,
@ -1020,7 +1021,7 @@ void FlatInput::focusInEvent(QFocusEvent *e) {
void FlatInput::focusOutEvent(QFocusEvent *e) {
if (_focused) {
_focused = false;
_a_placeholderFocused.start(
_placeholderFocusedAnimation.start(
[=] { update(); },
1.,
0.,
@ -1076,7 +1077,7 @@ void FlatInput::updatePlaceholder() {
auto placeholderVisible = !hasText;
if (_placeholderVisible != placeholderVisible) {
_placeholderVisible = placeholderVisible;
_a_placeholderVisible.start(
_placeholderVisibleAnimation.start(
[=] { update(); },
_placeholderVisible ? 0. : 1.,
_placeholderVisible ? 1. : 0.,

View File

@ -111,8 +111,8 @@ private:
bool _focused = false;
bool _placeholderVisible = true;
Animations::Simple _a_placeholderFocused;
Animations::Simple _a_placeholderVisible;
Animations::Simple _placeholderFocusedAnimation;
Animations::Simple _placeholderVisibleAnimation;
bool _lastPreEditTextNotEmpty = false;
const style::FlatInput &_st;