From 47977009b85423b00ae0138d23f4e62af8b06bc3 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 7 Dec 2016 16:32:25 +0300 Subject: [PATCH] Moved FloatAnimation->Animation, Animation->BasicAnimation. --- Telegram/SourceFiles/boxes/addcontactbox.cpp | 34 +- Telegram/SourceFiles/boxes/addcontactbox.h | 4 +- Telegram/SourceFiles/boxes/confirmbox.cpp | 35 +- Telegram/SourceFiles/boxes/confirmbox.h | 6 +- .../SourceFiles/boxes/notifications_box.cpp | 4 +- .../SourceFiles/boxes/notifications_box.h | 2 +- Telegram/SourceFiles/boxes/sharebox.cpp | 12 +- Telegram/SourceFiles/boxes/sharebox.h | 6 +- Telegram/SourceFiles/boxes/stickers_box.h | 2 +- Telegram/SourceFiles/boxes/stickersetbox.cpp | 5 +- Telegram/SourceFiles/boxes/stickersetbox.h | 2 +- Telegram/SourceFiles/dialogs/dialogs.style | 2 - Telegram/SourceFiles/dialogswidget.cpp | 2 +- Telegram/SourceFiles/dialogswidget.h | 2 +- Telegram/SourceFiles/history.h | 2 +- .../history/field_autocomplete.cpp | 41 +- .../SourceFiles/history/field_autocomplete.h | 6 +- Telegram/SourceFiles/history/history.style | 11 +- .../SourceFiles/history/history_drag_area.cpp | 71 ++-- .../SourceFiles/history/history_drag_area.h | 15 +- Telegram/SourceFiles/history/history_item.h | 2 +- .../history/history_media_types.cpp | 38 +- .../SourceFiles/history/history_media_types.h | 23 +- Telegram/SourceFiles/historywidget.cpp | 116 +++--- Telegram/SourceFiles/historywidget.h | 26 +- .../inline_bot_layout_internal.cpp | 38 +- .../inline_bots/inline_bot_layout_internal.h | 24 +- Telegram/SourceFiles/intro/introwidget.h | 6 +- Telegram/SourceFiles/layerwidget.cpp | 8 +- Telegram/SourceFiles/layerwidget.h | 2 +- Telegram/SourceFiles/mainwidget.cpp | 2 +- Telegram/SourceFiles/mainwidget.h | 2 +- .../media/player/media_player_button.cpp | 2 +- .../media/player/media_player_button.h | 7 +- .../media/player/media_player_panel.h | 2 +- .../player/media_player_volume_controller.h | 2 +- .../media/view/media_clip_volume_controller.h | 2 +- Telegram/SourceFiles/mediaview.h | 2 +- Telegram/SourceFiles/mtproto/connection.cpp | 378 +++++++++--------- Telegram/SourceFiles/mtproto/connection.h | 69 ++-- Telegram/SourceFiles/mtproto/core_types.h | 29 -- Telegram/SourceFiles/mtproto/session.h | 82 +++- .../SourceFiles/overview/overview_layout.cpp | 53 +-- .../SourceFiles/overview/overview_layout.h | 9 +- Telegram/SourceFiles/overviewwidget.h | 2 +- Telegram/SourceFiles/passcodewidget.h | 2 +- .../profile/profile_block_channel_members.cpp | 2 +- .../profile/profile_block_common_groups.h | 2 +- .../SourceFiles/profile/profile_block_info.h | 2 +- .../profile/profile_block_invite_link.cpp | 6 +- .../profile/profile_cover_drop_area.h | 2 +- .../profile/profile_userpic_button.h | 2 +- .../settings/settings_block_widget.h | 2 +- Telegram/SourceFiles/stickers/emoji_pan.cpp | 120 +++--- Telegram/SourceFiles/stickers/emoji_pan.h | 25 +- Telegram/SourceFiles/ui/animation.cpp | 8 +- Telegram/SourceFiles/ui/animation.h | 64 +-- .../ui/buttons/history_down_button.cpp | 48 +-- .../ui/buttons/history_down_button.h | 21 +- .../SourceFiles/ui/effects/radial_animation.h | 2 +- .../ui/effects/ripple_animation.cpp | 4 +- .../SourceFiles/ui/effects/round_checkbox.h | 6 +- .../SourceFiles/ui/effects/slide_animation.h | 2 +- .../ui/effects/widget_fade_wrap.cpp | 2 +- .../SourceFiles/ui/effects/widget_fade_wrap.h | 2 +- .../ui/effects/widget_slide_wrap.cpp | 31 +- .../ui/effects/widget_slide_wrap.h | 3 +- Telegram/SourceFiles/ui/toast/toast.cpp | 41 +- Telegram/SourceFiles/ui/toast/toast.h | 7 +- Telegram/SourceFiles/ui/widgets/buttons.cpp | 51 +-- Telegram/SourceFiles/ui/widgets/buttons.h | 14 +- Telegram/SourceFiles/ui/widgets/checkbox.h | 4 +- .../ui/widgets/continuous_sliders.h | 6 +- .../SourceFiles/ui/widgets/discrete_sliders.h | 2 +- .../SourceFiles/ui/widgets/inner_dropdown.h | 4 +- .../SourceFiles/ui/widgets/input_fields.cpp | 9 - .../SourceFiles/ui/widgets/input_fields.h | 26 +- .../SourceFiles/ui/widgets/multi_select.cpp | 6 +- .../SourceFiles/ui/widgets/multi_select.h | 4 +- Telegram/SourceFiles/ui/widgets/popup_menu.h | 4 +- .../SourceFiles/ui/widgets/scroll_area.cpp | 169 ++++---- Telegram/SourceFiles/ui/widgets/scroll_area.h | 45 ++- Telegram/SourceFiles/ui/widgets/shadow.h | 2 +- Telegram/SourceFiles/ui/widgets/widgets.style | 1 - .../window/notifications_manager_default.cpp | 36 +- .../window/notifications_manager_default.h | 11 +- Telegram/SourceFiles/window/window.style | 7 +- .../window/window_slide_animation.cpp | 3 +- .../window/window_slide_animation.h | 2 +- .../SourceFiles/window/window_theme_warning.h | 2 +- 90 files changed, 865 insertions(+), 1139 deletions(-) diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 26775ab7ed..988375ac1d 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -436,9 +436,7 @@ SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : Abstract , _link(this, st::defaultInputField, QString(), channel->username, true) , _linkOver(false) , _save(this, lang(lng_settings_save), st::defaultBoxButton) -, _skip(this, lang(existing ? lng_cancel : lng_create_group_skip), st::cancelBoxButton) -, a_goodOpacity(0, 0) -, _a_goodFade(animation(this, &SetupChannelBox::step_goodFade)) { +, _skip(this, lang(existing ? lng_cancel : lng_create_group_skip), st::cancelBoxButton) { setMouseTracking(true); _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail)); @@ -515,12 +513,15 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont); p.setPen(st::defaultLinkButton.color); p.drawText(_invitationLink, _channel->inviteLink(), option); - if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { - p.setOpacity(a_goodOpacity.current()); - p.setPen(st::boxTextFgGood); - p.setFont(st::boxTextFont); - p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink); - p.setOpacity(1); + if (!_goodTextLink.isEmpty()) { + auto opacity = _a_goodOpacity.current(getms(), 0.); + if (opacity > 0.) { + p.setOpacity(opacity); + p.setPen(st::boxTextFgGood); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxPadding.right(), _link->y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink); + p.setOpacity(1); + } } } } else { @@ -557,8 +558,8 @@ void SetupChannelBox::mousePressEvent(QMouseEvent *e) { if (_linkOver) { Application::clipboard()->setText(_channel->inviteLink()); _goodTextLink = lang(lng_create_channel_link_copied); - a_goodOpacity = anim::value(1, 0); - _a_goodFade.start(); + _a_goodOpacity.finish(); + _a_goodOpacity.start([this] { update(); }, 1., 0., st::newGroupLinkFadeDuration); } } @@ -577,17 +578,6 @@ void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) { } } -void SetupChannelBox::step_goodFade(float64 ms, bool timer) { - float dt = ms / st::newGroupLinkFadeDuration; - if (dt >= 1) { - _a_goodFade.stop(); - a_goodOpacity.finish(); - } else { - a_goodOpacity.update(dt, anim::linear); - } - if (timer) update(); -} - void SetupChannelBox::closePressed() { if (!_existing) { Ui::showLayer(new ContactsBox(_channel)); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h index 4129218e27..8cea13eeb1 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.h +++ b/Telegram/SourceFiles/boxes/addcontactbox.h @@ -154,7 +154,6 @@ protected: private: void updateSelected(const QPoint &cursorGlobalPosition); - void step_goodFade(float64 ms, bool timer); void onUpdateDone(const MTPBool &result); bool onUpdateFail(const RPCError &error); @@ -190,8 +189,7 @@ private: QString _sentUsername, _checkUsername, _errorText, _goodText; QString _goodTextLink; - anim::value a_goodOpacity; - Animation _a_goodFade; + Animation _a_goodOpacity; QTimer _checkTimer; diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index 2fd8124690..1b39928df3 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -204,10 +204,7 @@ void ConfirmBotGameBox::onOpenLink() { MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth) , _close(this, lang(lng_box_ok), st::defaultBoxButton) , _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) -, _link(link) -, _linkOver(false) -, a_goodOpacity(0, 0) -, _a_good(animation(this, &MaxInviteBox::step_good)) { +, _link(link) { setMouseTracking(true); _textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); @@ -226,8 +223,8 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) { if (_linkOver) { Application::clipboard()->setText(_link); _goodTextLink = lang(lng_create_channel_link_copied); - a_goodOpacity = anim::value(1, 0); - _a_good.start(); + _a_goodOpacity.finish(); + _a_goodOpacity.start([this] { update(); }, 1., 0., st::newGroupLinkFadeDuration); } } @@ -246,17 +243,6 @@ void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) { } } -void MaxInviteBox::step_good(float64 ms, bool timer) { - float dt = ms / st::newGroupLinkFadeDuration; - if (dt >= 1) { - _a_good.stop(); - a_goodOpacity.finish(); - } else { - a_goodOpacity.update(dt, anim::linear); - } - if (timer) update(); -} - void MaxInviteBox::paintEvent(QPaintEvent *e) { AbstractBox::paintEvent(e); @@ -271,12 +257,15 @@ void MaxInviteBox::paintEvent(QPaintEvent *e) { p.setFont(_linkOver ? st::defaultInputField.font->underline() : st::defaultInputField.font); p.setPen(st::defaultLinkButton.color); p.drawText(_invitationLink, _link, option); - if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { - p.setOpacity(a_goodOpacity.current()); - p.setPen(st::boxTextFgGood); - p.setFont(st::boxTextFont); - p.drawTextLeft(st::boxPadding.left(), height() - st::boxButtonPadding.bottom() - _close->height() + st::defaultBoxButton.textTop + st::defaultBoxButton.font->ascent - st::boxTextFont->ascent, width(), _goodTextLink); - p.setOpacity(1); + if (!_goodTextLink.isEmpty()) { + auto opacity = _a_goodOpacity.current(getms(), 0.); + if (opacity > 0.) { + p.setOpacity(opacity); + p.setPen(st::boxTextFgGood); + p.setFont(st::boxTextFont); + p.drawTextLeft(st::boxPadding.left(), height() - st::boxButtonPadding.bottom() - _close->height() + st::defaultBoxButton.textTop + st::defaultBoxButton.font->ascent - st::boxTextFont->ascent, width(), _goodTextLink); + p.setOpacity(1); + } } } diff --git a/Telegram/SourceFiles/boxes/confirmbox.h b/Telegram/SourceFiles/boxes/confirmbox.h index 5e42b5a94c..f926a81aa9 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.h +++ b/Telegram/SourceFiles/boxes/confirmbox.h @@ -164,7 +164,6 @@ protected: private: void updateSelected(const QPoint &cursorGlobalPosition); - void step_good(float64 ms, bool timer); ChildWidget _close; @@ -173,13 +172,12 @@ private: QString _link; QRect _invitationLink; - bool _linkOver; + bool _linkOver = false; QPoint _lastMousePos; QString _goodTextLink; - anim::value a_goodOpacity; - Animation _a_good; + Animation _a_goodOpacity; }; diff --git a/Telegram/SourceFiles/boxes/notifications_box.cpp b/Telegram/SourceFiles/boxes/notifications_box.cpp index 1708903c34..bd21d9e8b2 100644 --- a/Telegram/SourceFiles/boxes/notifications_box.cpp +++ b/Telegram/SourceFiles/boxes/notifications_box.cpp @@ -102,7 +102,7 @@ private: NotificationsBox *_owner; QPixmap _cache; - FloatAnimation _opacity; + Animation _opacity; bool _hiding = false; bool _deleted = false; @@ -116,7 +116,7 @@ NotificationsBox::NotificationsBox() : AbstractBox() _sampleOpacities.reserve(kMaxNotificationsCount); for (int i = 0; i != kMaxNotificationsCount; ++i) { _countSlider->addSection(QString::number(i + 1)); - _sampleOpacities.push_back(FloatAnimation()); + _sampleOpacities.push_back(Animation()); } _countSlider->setActiveSectionFast(_oldCount - 1); _countSlider->setSectionActivatedCallback([this] { countChanged(); }); diff --git a/Telegram/SourceFiles/boxes/notifications_box.h b/Telegram/SourceFiles/boxes/notifications_box.h index 14d8ecc8ae..58259011d0 100644 --- a/Telegram/SourceFiles/boxes/notifications_box.h +++ b/Telegram/SourceFiles/boxes/notifications_box.h @@ -62,7 +62,7 @@ private: QPixmap _notificationSampleSmall; QPixmap _notificationSampleLarge; ScreenCorner _chosenCorner; - std_::vector_of_moveable _sampleOpacities; + std_::vector_of_moveable _sampleOpacities; bool _isOverCorner = false; ScreenCorner _overCorner = ScreenCorner::TopLeft; diff --git a/Telegram/SourceFiles/boxes/sharebox.cpp b/Telegram/SourceFiles/boxes/sharebox.cpp index 734a814d8f..3a53d8647e 100644 --- a/Telegram/SourceFiles/boxes/sharebox.cpp +++ b/Telegram/SourceFiles/boxes/sharebox.cpp @@ -273,12 +273,15 @@ void ShareBox::onMustScrollTo(int top, int bottom) { to = bottom - (scrollBottom - scrollTop); } if (from != to) { - _scrollAnimation.start([this]() { - scrollArea()->scrollToY(qRound(_scrollAnimation.current(scrollArea()->scrollTop()))); - }, from, to, st::shareScrollDuration, anim::sineInOut); + _scrollAnimation.start([this]() { scrollAnimationCallback(); }, from, to, st::shareScrollDuration, anim::sineInOut); } } +void ShareBox::scrollAnimationCallback() { + auto scrollTop = qRound(_scrollAnimation.current(scrollArea()->scrollTop())); + scrollArea()->scrollToY(scrollTop); +} + void ShareBox::onScroll() { auto scroll = scrollArea(); auto scrollTop = scroll->scrollTop(); @@ -505,7 +508,8 @@ void ShareBox::Inner::paintChat(Painter &p, TimeMs ms, Chat *chat, int index) { auto photoTop = st::sharePhotoTop; chat->checkbox.paint(p, ms, x + photoLeft, y + photoTop, outerWidth); - p.setPen(anim::pen(st::shareNameFg, st::shareNameActiveFg, chat->nameActive.current((index == _active) ? 1. : 0.))); + auto nameActive = chat->nameActive.current(ms, (index == _active) ? 1. : 0.); + p.setPen(anim::pen(st::shareNameFg, st::shareNameActiveFg, nameActive)); auto nameWidth = (_rowWidth - st::shareColumnSkip); auto nameLeft = st::shareColumnSkip / 2; diff --git a/Telegram/SourceFiles/boxes/sharebox.h b/Telegram/SourceFiles/boxes/sharebox.h index ec284510f2..214ae25057 100644 --- a/Telegram/SourceFiles/boxes/sharebox.h +++ b/Telegram/SourceFiles/boxes/sharebox.h @@ -69,6 +69,8 @@ protected: void doSetInnerFocus() override; private: + void scrollAnimationCallback(); + void onFilterUpdate(const QString &query); void onSelectedChanged(); void moveButtons(); @@ -107,7 +109,7 @@ private: using PeopleQueries = QMap; PeopleQueries _peopleQueries; - FloatAnimation _scrollAnimation; + Animation _scrollAnimation; }; @@ -161,7 +163,7 @@ private: PeerData *peer; Ui::RoundImageCheckbox checkbox; Text name; - FloatAnimation nameActive; + Animation nameActive; }; void paintChat(Painter &p, TimeMs ms, Chat *chat, int index); void updateChat(PeerData *peer); diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index 8b97c3333d..46dca70151 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -246,7 +246,7 @@ private: QList _animStartTimes; TimeMs _aboveShadowFadeStart = 0; anim::value _aboveShadowFadeOpacity; - Animation _a_shifting; + BasicAnimation _a_shifting; base::lambda _installSetCallback; diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 92dbf50a4f..c60d8e7e4f 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -177,7 +177,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) { if (!doc || !doc->sticker()) continue; _pack.push_back(doc); - _packOvers.push_back(FloatAnimation()); + _packOvers.push_back(Animation()); } auto &packs(d.vpacks.c_vector().v); for (int i = 0, l = packs.size(); i < l; ++i) { @@ -389,6 +389,7 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) { if (_pack.isEmpty()) return; + auto ms = getms(); int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0); int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1; @@ -401,7 +402,7 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) { DocumentData *doc = _pack.at(index); QPoint pos(st::stickersPadding.left() + j * st::stickersSize.width(), st::stickersPadding.top() + i * st::stickersSize.height()); - if (auto over = _packOvers[index].current((index == _selected) ? 1. : 0.)) { + if (auto over = _packOvers[index].current(ms, (index == _selected) ? 1. : 0.)) { p.setOpacity(over); QPoint tl(pos); if (rtl()) tl.setX(width() - tl.x() - st::stickersSize.width()); diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 36d2da5106..b780e588cd 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -113,7 +113,7 @@ private: return (_setFlags & MTPDstickerSet::Flag::f_masks); } - std_::vector_of_moveable _packOvers; + std_::vector_of_moveable _packOvers; StickerPack _pack; StickersByEmojiMap _emoji; bool _loaded = false; diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index e93fc4537a..f56f64f070 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -172,8 +172,6 @@ historyViewsSendingIcon: icon {{ "dialogs_sending", #a0adb5, point(3px, 0px) }}; historyViewsSendingInvertedIcon: icon {{ "dialogs_sending", #ffffffc8, point(3px, 0px) }}; dialogsUpdateButton: FlatButton { - duration: 0; - color: activeButtonFg; overColor: activeButtonFgOver; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 18a65942d2..f7ebd587f6 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -477,7 +477,7 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) { setHashtagPressed(_hashtagSelected); _hashtagDeletePressed = _hashtagDeleteSelected; setFilteredPressed(_filteredSelected); - setPeerSearchPressed(_peerSearchPressed); + setPeerSearchPressed(_peerSearchSelected); setSearchedPressed(_searchedSelected); if (_importantSwitchPressed) { _importantSwitch->row.addRipple(e->pos(), QSize(getFullWidth(), st::dialogsImportantBarHeight), [this] { diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h index e3cce1c172..072a952937 100644 --- a/Telegram/SourceFiles/dialogswidget.h +++ b/Telegram/SourceFiles/dialogswidget.h @@ -387,7 +387,7 @@ private: ChildWidget _inner; ChildWidget _updateTelegram = { nullptr }; - FloatAnimation _a_show; + Animation _a_show; Window::SlideDirection _showDirection; QPixmap _cacheUnder, _cacheOver; diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index b330516119..30da42bcac 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -61,7 +61,7 @@ public: typedef QMap TypingHistories; // when typing in this history started TypingHistories typing; - Animation _a_typings; + BasicAnimation _a_typings; int unreadBadge() const; int unreadMutedCount() const { diff --git a/Telegram/SourceFiles/history/field_autocomplete.cpp b/Telegram/SourceFiles/history/field_autocomplete.cpp index 236a2df47a..21ddbc3537 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.cpp +++ b/Telegram/SourceFiles/history/field_autocomplete.cpp @@ -31,9 +31,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent) , _scroll(this, st::mentionScroll) -, _inner(this, &_mrows, &_hrows, &_brows, &_srows) -, a_opacity(0) -, _a_appearance(animation(this, &FieldAutocomplete::step_appearance)) { +, _inner(this, &_mrows, &_hrows, &_brows, &_srows) { connect(_inner, SIGNAL(mentionChosen(UserData*,FieldAutocomplete::ChooseMethod)), this, SIGNAL(mentionChosen(UserData*,FieldAutocomplete::ChooseMethod))); connect(_inner, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod))); connect(_inner, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)), this, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod))); @@ -47,15 +45,22 @@ FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent) _scroll->show(); _inner->show(); + hide(); + connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged())); } void FieldAutocomplete::paintEvent(QPaintEvent *e) { Painter p(this); - if (_a_appearance.animating()) { - p.setOpacity(a_opacity.current()); - p.drawPixmap(0, 0, _cache); + auto opacity = _a_opacity.current(getms(), _hiding ? 0. : 1.); + if (opacity < 1.) { + if (opacity > 0.) { + p.setOpacity(opacity); + p.drawPixmap(0, 0, _cache); + } else if (_hiding) { + + } return; } @@ -392,10 +397,7 @@ void FieldAutocomplete::recount(bool resetScroll) { } void FieldAutocomplete::hideFast() { - if (_a_appearance.animating()) { - _a_appearance.stop(); - } - a_opacity = anim::value(); + _a_opacity.finish(); hideFinish(); } @@ -410,9 +412,8 @@ void FieldAutocomplete::hideAnimated() { } _scroll->hide(); _hiding = true; - a_opacity.start(0); + _a_opacity.start([this] { animationCallback(); }, 1., 0., st::defaultDropdownDuration); setAttribute(Qt::WA_OpaquePaintEvent, false); - _a_appearance.start(); } void FieldAutocomplete::hideFinish() { @@ -423,7 +424,7 @@ void FieldAutocomplete::hideFinish() { } void FieldAutocomplete::showAnimated() { - if (!isHidden() && a_opacity.current() == 1 && !_hiding) { + if (!isHidden() && !_hiding) { return; } if (_cache.isNull()) { @@ -433,16 +434,13 @@ void FieldAutocomplete::showAnimated() { _scroll->hide(); _hiding = false; show(); - a_opacity.start(1); + _a_opacity.start([this] { animationCallback(); }, 0., 1., st::defaultDropdownDuration); setAttribute(Qt::WA_OpaquePaintEvent, false); - _a_appearance.start(); } -void FieldAutocomplete::step_appearance(float64 ms, bool timer) { - float64 dt = ms / st::defaultDropdownDuration; - if (dt >= 1) { - _a_appearance.stop(); - a_opacity.finish(); +void FieldAutocomplete::animationCallback() { + update(); + if (!_a_opacity.animating()) { _cache = QPixmap(); setAttribute(Qt::WA_OpaquePaintEvent); if (_hiding) { @@ -451,10 +449,7 @@ void FieldAutocomplete::step_appearance(float64 ms, bool timer) { _scroll->show(); _inner->clearSel(); } - } else { - a_opacity.update(dt, anim::linear); } - if (timer) update(); } const QString &FieldAutocomplete::filter() const { diff --git a/Telegram/SourceFiles/history/field_autocomplete.h b/Telegram/SourceFiles/history/field_autocomplete.h index ba8df4f928..0a05d5f0a0 100644 --- a/Telegram/SourceFiles/history/field_autocomplete.h +++ b/Telegram/SourceFiles/history/field_autocomplete.h @@ -48,8 +48,6 @@ public: void showStickers(EmojiPtr emoji); void setBoundings(QRect boundings); - void step_appearance(float64 ms, bool timer); - const QString &filter() const; ChatData *chat() const; ChannelData *channel() const; @@ -97,6 +95,7 @@ protected: void paintEvent(QPaintEvent *e) override; private: + void animationCallback(); void hideFinish(); void updateFiltered(bool resetScroll = false); @@ -131,8 +130,7 @@ private: int32 _width, _height; bool _hiding = false; - anim::value a_opacity; - Animation _a_appearance; + Animation _a_opacity; friend class internal::FieldAutocompleteInner; diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style index 146100c8a9..b64e72ba1d 100644 --- a/Telegram/SourceFiles/history/history.style +++ b/Telegram/SourceFiles/history/history.style @@ -189,8 +189,6 @@ historySendPadding: 9px; historySendRight: 2px; historyComposeButton: FlatButton { - duration: 200; - color: windowActiveTextFg; overColor: windowActiveTextFg; @@ -214,12 +212,14 @@ historyUnblock: FlatButton(historyComposeButton) { overColor: #d15948; } +historySendIcon: icon {{ "send_control_send", historySendIconFg }}; +historySendIconOver: icon {{ "send_control_send", historySendIconFgOver }}; historySend: IconButton { width: 46px; height: 46px; - icon: icon {{ "send_control_send", historySendIconFg }}; - iconOver: icon {{ "send_control_send", historySendIconFgOver }}; + icon: historySendIcon; + iconOver: historySendIconOver; iconPosition: point(11px, 11px); } historyEditSaveIcon: icon {{ "send_control_save", historySendIconFg, point(3px, 7px) }}; @@ -265,6 +265,7 @@ historyBotCommandStart: IconButton(historyAttach) { historyRecordVoiceFg: historyComposeIconFg; historyRecordVoiceFgOver: historyComposeIconFgOver; historyRecordVoiceFgActive: windowBgActive; +historyRecordVoiceDuration: 200; historyRecordVoice: icon {{ "send_control_record", historyRecordVoiceFg }}; historyRecordVoiceOver: icon {{ "send_control_record", historyRecordVoiceFgOver }}; historyRecordVoiceActive: icon {{ "send_control_record", historyRecordVoiceFgActive }}; @@ -315,8 +316,6 @@ historyInlineBotCancel: IconButton(historyReplyCancel) { } reportSpamHide: FlatButton { - duration: 200; - color: windowActiveTextFg; overColor: windowActiveTextFg; diff --git a/Telegram/SourceFiles/history/history_drag_area.cpp b/Telegram/SourceFiles/history/history_drag_area.cpp index f14df11e75..f4a588838a 100644 --- a/Telegram/SourceFiles/history/history_drag_area.cpp +++ b/Telegram/SourceFiles/history/history_drag_area.cpp @@ -38,9 +38,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org DragArea::DragArea(QWidget *parent) : TWidget(parent) , _hiding(false) , _in(false) -, a_opacity(0) -, a_colorDrop(0) -, _a_appearance(animation(this, &DragArea::step_appearance)) , _shadow(st::boxShadow) { setMouseTracking(true); setAcceptDrops(true); @@ -49,28 +46,24 @@ DragArea::DragArea(QWidget *parent) : TWidget(parent) void DragArea::mouseMoveEvent(QMouseEvent *e) { if (_hiding) return; - bool newIn = QRect(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()).contains(e->pos()); - if (newIn != _in) { - _in = newIn; - a_opacity.start(1); - a_colorDrop.start(_in ? 1. : 0.); - _a_appearance.start(); - } + auto in = QRect(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()).contains(e->pos()); + setIn(in); } void DragArea::dragMoveEvent(QDragMoveEvent *e) { QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()); - bool newIn = r.contains(e->pos()); - if (newIn != _in) { - _in = newIn; - a_opacity.start(1); - a_colorDrop.start(_in ? 1. : 0.); - _a_appearance.start(); - } + setIn(r.contains(e->pos())); e->setDropAction(_in ? Qt::CopyAction : Qt::IgnoreAction); e->accept(); } +void DragArea::setIn(bool in) { + if (_in != in) { + _in = in; + _a_in.start([this] { update(); }, _in ? 0. : 1., _in ? 1. : 0., st::defaultDropdownDuration); + } +} + void DragArea::setText(const QString &text, const QString &subtext) { _text = text; _subtext = subtext; @@ -80,9 +73,12 @@ void DragArea::setText(const QString &text, const QString &subtext) { void DragArea::paintEvent(QPaintEvent *e) { Painter p(this); - if (_a_appearance.animating()) { - p.setOpacity(a_opacity.current()); + auto ms = getms(); + auto opacity = _a_opacity.current(ms, _hiding ? 0. : 1.); + if (!_a_opacity.animating() && _hiding) { + return; } + p.setOpacity(opacity); QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()); @@ -91,7 +87,7 @@ void DragArea::paintEvent(QPaintEvent *e) { p.fillRect(r, st::dragBg); - p.setPen(anim::pen(st::dragColor, st::dragDropColor, a_colorDrop.current())); + p.setPen(anim::pen(st::dragColor, st::dragDropColor, _a_in.current(ms, _in ? 1. : 0.))); p.setFont(st::dragFont); p.drawText(QRect(0, (height() - st::dragHeight) / 2, width(), st::dragFont->height), _text, QTextOption(style::al_top)); @@ -108,10 +104,7 @@ void DragArea::dragEnterEvent(QDragEnterEvent *e) { void DragArea::dragLeaveEvent(QDragLeaveEvent *e) { static_cast(parentWidget())->dragLeaveEvent(e); - _in = false; - a_opacity.start(_hiding ? 0 : 1); - a_colorDrop.start(_in ? 1. : 0.); - _a_appearance.start(); + setIn(false); } void DragArea::dropEvent(QDropEvent *e) { @@ -130,47 +123,33 @@ void DragArea::otherLeave() { } void DragArea::hideFast() { - if (_a_appearance.animating()) { - _a_appearance.stop(); - } - a_opacity = anim::value(); + _a_opacity.finish(); hide(); } void DragArea::hideStart() { _hiding = true; - _in = false; - a_opacity.start(0.); - a_colorDrop.start(_in ? 1. : 0.); - _a_appearance.start(); + setIn(false); + _a_opacity.start([this] { opacityAnimationCallback(); }, 1., 0., st::defaultDropdownDuration); } void DragArea::hideFinish() { hide(); _in = false; - a_colorDrop = anim::value(); + _a_in.finish(); } void DragArea::showStart() { _hiding = false; show(); - a_opacity.start(1); - a_colorDrop.start(_in ? 1. : 0.); - _a_appearance.start(); + _a_opacity.start([this] { opacityAnimationCallback(); }, 0., 1., st::defaultDropdownDuration); } -void DragArea::step_appearance(float64 ms, bool timer) { - float64 dt = ms / st::defaultDropdownDuration; - if (dt >= 1) { - a_opacity.finish(); - a_colorDrop.finish(); +void DragArea::opacityAnimationCallback() { + update(); + if (!_a_opacity.animating()) { if (_hiding) { hideFinish(); } - _a_appearance.stop(); - } else { - a_opacity.update(dt, anim::linear); - a_colorDrop.update(dt, anim::linear); } - if (timer) update(); } diff --git a/Telegram/SourceFiles/history/history_drag_area.h b/Telegram/SourceFiles/history/history_drag_area.h index ff4706566c..ef5ee9be4a 100644 --- a/Telegram/SourceFiles/history/history_drag_area.h +++ b/Telegram/SourceFiles/history/history_drag_area.h @@ -34,10 +34,8 @@ public: void otherEnter(); void otherLeave(); - void step_appearance(float64 ms, bool timer); - bool overlaps(const QRect &globalRect) { - if (isHidden() || _a_appearance.animating()) return false; + if (isHidden() || _a_opacity.animating()) return false; return QRect(st::dragPadding.left(), st::dragPadding.top(), @@ -67,12 +65,15 @@ public slots: void showStart(); private: - bool _hiding, _in; + void setIn(bool in); + void opacityAnimationCallback(); + + bool _hiding = false; + bool _in = false; base::lambda _droppedCallback; - anim::value a_opacity; - anim::value a_colorDrop; - Animation _a_appearance; + Animation _a_opacity; + Animation _a_in; Ui::RectShadow _shadow; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 23835375f7..644343d594 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -372,7 +372,7 @@ private: ButtonRows _rows; Animations _animations; - Animation _a_selected; + BasicAnimation _a_selected; StylePtr _st; diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index d74135ca64..fc396e637a 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -155,15 +155,18 @@ void HistoryFileMedia::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool if (p == _savel || p == _cancell) { if (active && !dataLoaded()) { ensureAnimation(); - _animation->a_thumbOver.start(1); - _animation->_a_thumbOver.start(); + _animation->a_thumbOver.start([this] { thumbAnimationCallback(); }, 0., 1., st::msgFileOverDuration); } else if (!active && _animation) { - _animation->a_thumbOver.start(0); - _animation->_a_thumbOver.start(); + _animation->a_thumbOver.start([this] { thumbAnimationCallback(); }, 1., 0., st::msgFileOverDuration); } } } +void HistoryFileMedia::thumbAnimationCallback() { + Ui::repaintHistoryItem(_parent); + checkAnimationFinished(); +} + void HistoryFileMedia::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { Ui::repaintHistoryItem(_parent); } @@ -189,20 +192,6 @@ void HistoryFileMedia::setStatusSize(int32 newSize, int32 fullSize, int32 durati } } -void HistoryFileMedia::step_thumbOver(float64 ms, bool timer) { - float64 dt = ms / st::msgFileOverDuration; - if (dt >= 1) { - _animation->a_thumbOver.finish(); - _animation->_a_thumbOver.stop(); - checkAnimationFinished(); - } else if (!timer) { - _animation->a_thumbOver.update(dt, anim::linear); - } - if (timer) { - Ui::repaintHistoryItem(_parent); - } -} - void HistoryFileMedia::step_radial(TimeMs ms, bool timer) { if (timer) { Ui::repaintHistoryItem(_parent); @@ -216,24 +205,19 @@ void HistoryFileMedia::step_radial(TimeMs ms, bool timer) { void HistoryFileMedia::ensureAnimation() const { if (!_animation) { - _animation = new AnimationData( - animation(const_cast(this), &HistoryFileMedia::step_thumbOver), - animation(const_cast(this), &HistoryFileMedia::step_radial)); + _animation = std_::make_unique(animation(const_cast(this), &HistoryFileMedia::step_radial)); } } void HistoryFileMedia::checkAnimationFinished() { - if (_animation && !_animation->_a_thumbOver.animating() && !_animation->radial.animating()) { + if (_animation && !_animation->a_thumbOver.animating() && !_animation->radial.animating()) { if (dataLoaded()) { - delete _animation; - _animation = 0; + _animation.reset(); } } } -HistoryFileMedia::~HistoryFileMedia() { - delete base::take(_animation); -} +HistoryFileMedia::~HistoryFileMedia() = default; HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption) : HistoryFileMedia(parent) , _data(photo) diff --git a/Telegram/SourceFiles/history/history_media_types.h b/Telegram/SourceFiles/history/history_media_types.h index a7340ace90..b9c905a996 100644 --- a/Telegram/SourceFiles/history/history_media_types.h +++ b/Telegram/SourceFiles/history/history_media_types.h @@ -71,8 +71,8 @@ protected: // duration = -1 - no duration, duration = -2 - "GIF" duration void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const; - void step_thumbOver(float64 ms, bool timer); void step_radial(TimeMs ms, bool timer); + void thumbAnimationCallback(); void ensureAnimation() const; void checkAnimationFinished(); @@ -84,10 +84,10 @@ protected: return _animation && _animation->radial.animating(); } bool isThumbAnimation(TimeMs ms) const { - if (!_animation || !_animation->_a_thumbOver.animating()) return false; - - _animation->_a_thumbOver.step(ms); - return _animation && _animation->_a_thumbOver.animating(); + if (_animation) { + return _animation->a_thumbOver.animating(ms); + } + return false; } virtual float64 dataProgress() const = 0; @@ -95,16 +95,13 @@ protected: virtual bool dataLoaded() const = 0; struct AnimationData { - AnimationData(AnimationCallbacks &&thumbOverCallbacks, AnimationCallbacks &&radialCallbacks) : a_thumbOver(0, 0) - , _a_thumbOver(std_::move(thumbOverCallbacks)) - , radial(std_::move(radialCallbacks)) { + AnimationData(AnimationCallbacks &&radialCallbacks) + : radial(std_::move(radialCallbacks)) { } - anim::value a_thumbOver; - Animation _a_thumbOver; - + Animation a_thumbOver; Ui::RadialAnimation radial; }; - mutable AnimationData *_animation = nullptr; + mutable std_::unique_ptr _animation; }; @@ -307,7 +304,7 @@ struct HistoryDocumentVoicePlayback { int32 _position; anim::value a_progress; - Animation _a_progress; + BasicAnimation _a_progress; }; struct HistoryDocumentVoice : public RuntimeComponent { HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 81c3a44f62..6a3bdab90e 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -2676,8 +2676,6 @@ HistoryHider::HistoryHider(MainWidget *parent, bool forwardSelected) : TWidget(p , _forwardSelected(forwardSelected) , _send(this, lang(lng_forward_send), st::defaultBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton) -, a_opacity(0, 1) -, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _shadow(st::boxShadow) { init(); } @@ -2686,8 +2684,6 @@ HistoryHider::HistoryHider(MainWidget *parent, UserData *sharedContact) : TWidge , _sharedContact(sharedContact) , _send(this, lang(lng_forward_send), st::defaultBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton) -, a_opacity(0, 1) -, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _shadow(st::boxShadow) { init(); } @@ -2696,8 +2692,6 @@ HistoryHider::HistoryHider(MainWidget *parent) : TWidget(parent) , _sendPath(true) , _send(this, lang(lng_forward_send), st::defaultBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton) -, a_opacity(0, 1) -, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _shadow(st::boxShadow) { init(); } @@ -2706,8 +2700,6 @@ HistoryHider::HistoryHider(MainWidget *parent, const QString &botAndQuery) : TWi , _botAndQuery(botAndQuery) , _send(this, lang(lng_forward_send), st::defaultBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton) -, a_opacity(0, 1) -, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _shadow(st::boxShadow) { init(); } @@ -2717,8 +2709,6 @@ HistoryHider::HistoryHider(MainWidget *parent, const QString &url, const QString , _shareText(text) , _send(this, lang(lng_forward_send), st::defaultBoxButton) , _cancel(this, lang(lng_cancel), st::cancelBoxButton) -, a_opacity(0, 1) -, _a_appearance(animation(this, &HistoryHider::step_appearance)) , _shadow(st::boxShadow) { init(); } @@ -2731,21 +2721,7 @@ void HistoryHider::init() { _chooseWidth = st::forwardFont->width(lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose)); resizeEvent(0); - _a_appearance.start(); -} - -void HistoryHider::step_appearance(float64 ms, bool timer) { - float64 dt = ms / 200; - if (dt >= 1) { - _a_appearance.stop(); - a_opacity.finish(); - if (_hiding) { - QTimer::singleShot(0, this, SLOT(deleteLater())); - } - } else { - a_opacity.update(dt, anim::linear); - } - if (timer) update(); + _a_opacity.start([this] { update(); }, 0., 1., st::boxDuration); } bool HistoryHider::withConfirm() const { @@ -2754,7 +2730,15 @@ bool HistoryHider::withConfirm() const { void HistoryHider::paintEvent(QPaintEvent *e) { Painter p(this); - p.setOpacity(a_opacity.current()); + auto opacity = _a_opacity.current(getms(), _hiding ? 0. : 1.); + if (opacity == 0.) { + if (_hiding) { + QTimer::singleShot(0, this, SLOT(deleteLater())); + } + return; + } + + p.setOpacity(opacity); if (!_hiding || !_cacheForAnim.isNull() || !_offered) { p.fillRect(rect(), st::layerBg); } @@ -2813,10 +2797,16 @@ void HistoryHider::startHide() { } else { if (_offered) _cacheForAnim = myGrab(this, _box); if (_forwardRequest) MTP::cancel(_forwardRequest); - a_opacity.start(0); _send->hide(); _cancel->hide(); - _a_appearance.start(); + _a_opacity.start([this] { animationCallback(); }, 1., 0., st::boxDuration); + } +} + +void HistoryHider::animationCallback() { + update(); + if (!_a_opacity.animating() && _hiding) { + QTimer::singleShot(0, this, SLOT(deleteLater())); } } @@ -3037,7 +3027,7 @@ TextWithTags::Tags textTagsFromEntities(const EntitiesInText &entities) { HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) , _fieldBarCancel(this, st::historyReplyCancel) , _scroll(this, st::historyScroll, false) -, _historyToEnd(this, st::historyToDown) +, _historyDown(_scroll, st::historyToDown) , _fieldAutocomplete(this) , _reportSpamPanel(this) , _send(this, st::historySend) @@ -3052,8 +3042,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) , _botCommandStart(this, st::historyBotCommandStart) , _silent(this) , _field(this, st::historyComposeField, lang(lng_message_ph)) -, _a_recording(animation(this, &HistoryWidget::step_recording)) , _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel))) +, _a_recording(animation(this, &HistoryWidget::step_recording)) , _kbScroll(this, st::botKbScroll) , _keyboard(this) , _emojiPan(this) @@ -3068,7 +3058,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) connect(_reportSpamPanel, SIGNAL(reportClicked()), this, SLOT(onReportSpamClicked())); connect(_reportSpamPanel, SIGNAL(hideClicked()), this, SLOT(onReportSpamHide())); connect(_reportSpamPanel, SIGNAL(clearClicked()), this, SLOT(onReportSpamClear())); - connect(_historyToEnd, SIGNAL(clicked()), this, SLOT(onHistoryToEnd())); + connect(_historyDown, SIGNAL(clicked()), this, SLOT(onHistoryToEnd())); connect(_fieldBarCancel, SIGNAL(clicked()), this, SLOT(onFieldBarCancel())); connect(_send, SIGNAL(clicked()), this, SLOT(onSend())); connect(_unblock, SIGNAL(clicked()), this, SLOT(onUnblock())); @@ -3138,7 +3128,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) updateScrollColors(); - _historyToEnd->installEventFilter(this); + _historyDown->installEventFilter(this); _fieldAutocomplete->hide(); connect(_fieldAutocomplete, SIGNAL(mentionChosen(UserData*,FieldAutocomplete::ChooseMethod)), this, SLOT(onMentionInsert(UserData*))); @@ -4346,7 +4336,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re if (wasHistory) _peer->asUser()->botInfo->inlineReturnPeerId = wasHistory->peer->id; onBotStart(); } - unreadCountChanged(_history); // set _historyToEnd badge. + unreadCountChanged(_history); // set _historyDown badge. } else { clearFieldText(); doneShow(); @@ -4523,7 +4513,7 @@ void HistoryWidget::updateControlsVisibility() { if (!_a_show.animating()) { _topShadow->setVisible(_peer ? true : false); } - updateToEndVisibility(); + updateHistoryDownVisibility(); if (!_history || _a_show.animating()) { _reportSpamPanel->hide(); _scroll->hide(); @@ -4540,7 +4530,7 @@ void HistoryWidget::updateControlsVisibility() { _attachToggle->hide(); _attachEmoji->hide(); _silent->hide(); - _historyToEnd->hide(); + _historyDown->hide(); _botKeyboardShow->hide(); _botKeyboardHide->hide(); _botCommandStart->hide(); @@ -4781,9 +4771,9 @@ void HistoryWidget::historyWasRead(ReadServerHistoryChecks checks) { void HistoryWidget::unreadCountChanged(History *history) { if (history == _history || history == _migrated) { - updateToEndVisibility(); - if (_historyToEnd) { - _historyToEnd->setUnreadCount(_history->unreadCount() + (_migrated ? _migrated->unreadCount() : 0)); + updateHistoryDownVisibility(); + if (_historyDown) { + _historyDown->setUnreadCount(_history->unreadCount() + (_migrated ? _migrated->unreadCount() : 0)); } } } @@ -5118,7 +5108,7 @@ void HistoryWidget::visibleAreaUpdated() { void HistoryWidget::preloadHistoryIfNeeded() { if (_firstLoadRequest || _scroll->isHidden() || !_peer) return; - updateToEndVisibility(); + updateHistoryDownVisibility(); int st = _scroll->scrollTop(), stm = _scroll->scrollTopMax(), sh = _scroll->height(); if (st + PreloadHeightsCount * sh > stm) { @@ -5456,7 +5446,7 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window: _cacheUnder = params.oldContentCache; show(); _topShadow->setVisible(params.withTopBarShadow ? false : true); - _historyToEnd->finishAnimation(); + historyDownAnimationFinish(); _cacheOver = App::main()->grabForShowAnimation(params); App::main()->topBar()->startAnim(); _topShadow->setVisible(params.withTopBarShadow ? true : false); @@ -5464,7 +5454,7 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window: _scroll->hide(); _kbScroll->hide(); _reportSpamPanel->hide(); - _historyToEnd->hide(); + _historyDown->hide(); _attachToggle->hide(); _attachEmoji->hide(); _fieldAutocomplete->hide(); @@ -5500,7 +5490,7 @@ void HistoryWidget::animationCallback() { App::main()->topBar()->update(); if (!_a_show.animating()) { _topShadow->setVisible(_peer ? true : false); - _historyToEnd->finishAnimation(); + historyDownAnimationFinish(); _cacheUnder = _cacheOver = QPixmap(); App::main()->topBar()->stopAnim(); @@ -5528,7 +5518,12 @@ void HistoryWidget::finishAnimation() { if (!_a_show.animating()) return; _a_show.finish(); _topShadow->setVisible(_peer ? true : false); - _historyToEnd->finishAnimation(); + historyDownAnimationFinish(); +} + +void HistoryWidget::historyDownAnimationFinish() { + _historyDownShown.finish(); + updateHistoryDownPosition(); } void HistoryWidget::recordActiveCallback() { @@ -5634,7 +5629,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) { } if (inField != _inField && _recording) { _inField = inField; - _a_recordActive.start([this] { recordActiveCallback(); }, _inField ? 0. : 1., _inField ? 1. : 0., st::historyComposeButton.duration); + _a_recordActive.start([this] { recordActiveCallback(); }, _inField ? 0. : 1., _inField ? 1. : 0., st::historyRecordVoiceDuration); } _inReplyEdit = inReplyEdit; _inPinnedMsg = inPinnedMsg; @@ -5680,7 +5675,7 @@ void HistoryWidget::stopRecording(bool send) { updateField(); if (_inField) { - _a_recordActive.start([this] { recordActiveCallback(); }, 1., 0., st::historyComposeButton.duration); + _a_recordActive.start([this] { recordActiveCallback(); }, 1., 0., st::historyRecordVoiceDuration); } if (_recordRipple) { @@ -5873,7 +5868,7 @@ bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) { } bool HistoryWidget::eventFilter(QObject *obj, QEvent *e) { - if (obj == _historyToEnd && e->type() == QEvent::Wheel) { + if (obj == _historyDown && e->type() == QEvent::Wheel) { return _scroll->viewportEvent(e); } return TWidget::eventFilter(obj, e); @@ -7096,7 +7091,7 @@ void HistoryWidget::updateControlsGeometry() { updateFieldSize(); - _historyToEnd->moveToRight(st::historyToDownPosition.x(), _scroll->y() + _scroll->height() - _historyToEnd->height() - st::historyToDownPosition.y()); + updateHistoryDownPosition(); _emojiPan->setMaxHeight(height() - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom() - _attachEmoji->height()); if (_membersDropdown) { @@ -7196,7 +7191,7 @@ void HistoryWidget::updateListSize(bool initial, bool loadedDown, const ScrollCh } _fieldAutocomplete->setBoundings(_scroll->geometry()); - _historyToEnd->moveToRight(st::historyToDownPosition.x(), _scroll->y() + _scroll->height() - _historyToEnd->height() - st::historyToDownPosition.y()); + _historyDown->moveToRight(st::historyToDownPosition.x(), _scroll->y() + _scroll->height() - _historyDown->height() - st::historyToDownPosition.y()); } _list->recountHeight(); @@ -7439,7 +7434,16 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) { update(); } -void HistoryWidget::updateToEndVisibility() { +void HistoryWidget::updateHistoryDownPosition() { + auto top = anim::interpolate(0, _historyDown->height() + st::historyToDownPosition.y(), _historyDownShown.current(_historyDownIsShown ? 1. : 0.)); + _historyDown->moveToRight(st::historyToDownPosition.x(), _scroll->height() - top); + auto shouldBeHidden = !_historyDownIsShown && !_historyDownShown.animating(); + if (shouldBeHidden != _historyDown->isHidden()) { + _historyDown->setVisible(!shouldBeHidden); + } +} + +void HistoryWidget::updateHistoryDownVisibility() { if (_a_show.animating()) return; auto haveUnreadBelowBottom = [this](History *history) { @@ -7451,7 +7455,7 @@ void HistoryWidget::updateToEndVisibility() { } return (_list->itemTop(history->showFrom) >= _scroll->scrollTop() + _scroll->height()); }; - auto isToEndVisible = [this, &haveUnreadBelowBottom]() { + auto historyDownIsVisible = [this, &haveUnreadBelowBottom]() { if (!_history || _firstLoadRequest) { return false; } @@ -7466,11 +7470,10 @@ void HistoryWidget::updateToEndVisibility() { } return false; }; - bool toEndVisible = isToEndVisible(); - if (toEndVisible && _historyToEnd->hidden()) { - _historyToEnd->showAnimated(); - } else if (!toEndVisible && !_historyToEnd->hidden()) { - _historyToEnd->hideAnimated(); + auto historyDownIsShown = historyDownIsVisible(); + if (_historyDownIsShown != historyDownIsShown) { + _historyDownIsShown = historyDownIsShown; + _historyDownShown.start([this] { updateHistoryDownPosition(); }, _historyDownIsShown ? 0. : 1., _historyDownIsShown ? 1. : 0., st::historyToDownDuration); } } @@ -7487,7 +7490,7 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { updateField(); - _a_recordActive.start([this] { recordActiveCallback(); }, 0., 1., st::historyComposeButton.duration); + _a_recordActive.start([this] { recordActiveCallback(); }, 0., 1., st::historyRecordVoiceDuration); if (!_recordRipple) { auto mask = Ui::RippleAnimation::ellipseMask(QSize(st::historyAttachEmoji.rippleAreaSize, st::historyAttachEmoji.rippleAreaSize)); @@ -8797,6 +8800,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { bool hasTopBar = !App::main()->topBar()->isHidden(); auto ms = getms(); + _historyDownShown.step(ms); auto progress = _a_show.current(ms, 1.); if (_a_show.animating()) { auto retina = cIntRetinaFactor(); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 14e381b8ac..f7a5be999d 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -274,7 +274,7 @@ private: int _visibleAreaBottom = 0; bool _scrollDateShown = false; - FloatAnimation _scrollDateOpacity; + Animation _scrollDateOpacity; SingleDelayedCall _scrollDateCheck = { this, "onScrollDateCheck" }; SingleTimer _scrollDateHideTimer; HistoryItem *_scrollDateLastItem = nullptr; @@ -467,7 +467,6 @@ public: HistoryHider(MainWidget *parent, const QString &url, const QString &text); // share url HistoryHider(MainWidget *parent, const QString &botAndQuery); // inline switch button handler - void step_appearance(float64 ms, bool timer); bool withConfirm() const; bool offerPeer(PeerId peer); @@ -496,6 +495,7 @@ signals: void forwarded(); private: + void animationCallback(); void init(); MainWidget *parent(); @@ -510,8 +510,7 @@ private: ChildWidget _cancel; PeerData *_offered = nullptr; - anim::value a_opacity; - Animation _a_appearance; + Animation _a_opacity; QRect _box; bool _hiding = false; @@ -677,7 +676,8 @@ public: void applyCloudDraft(History *history); void contactsReceived(); - void updateToEndVisibility(); + void updateHistoryDownPosition(); + void updateHistoryDownVisibility(); void updateAfterDrag(); void updateFieldSubmitSettings(); @@ -850,6 +850,7 @@ private: void animationCallback(); void recordActiveCallback(); void chooseAttach(); + void historyDownAnimationFinish(); void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update); struct SendingFilesLists { QList nonLocalUrls; @@ -1088,7 +1089,9 @@ private: TimeMs _lastScrolled = 0; QTimer _updateHistoryItems; - ChildWidget _historyToEnd; + Animation _historyDownShown; + bool _historyDownIsShown = false; + ChildWidget _historyDown; ChildWidget _fieldAutocomplete; @@ -1122,19 +1125,22 @@ private: ChildWidget _silent; bool _cmdStartShown = false; ChildWidget _field; - Animation _a_recording; bool _recording = false; bool _inRecord = false; bool _inField = false; bool _inReplyEdit = false; bool _inPinnedMsg = false; bool _inClickable = false; - anim::value a_recordingLevel; int _recordingSamples = 0; - FloatAnimation _a_recordActive; + Animation _a_recordActive; std_::unique_ptr _recordRipple; int _recordCancelWidth; + // This can animate for a very long time (like in music playing), + // so it should be a BasicAnimation, not an Animation. + BasicAnimation _a_recording; + anim::value a_recordingLevel; + FileDialog::QueryId _attachFilesQueryId = 0; bool kbWasHidden() const; @@ -1163,7 +1169,7 @@ private: bool _titlePeerTextOnline = false; int _titlePeerTextWidth = 0; - FloatAnimation _a_show; + Animation _a_show; Window::SlideDirection _showDirection; QPixmap _cacheUnder, _cacheOver; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 26f724b211..4932714dbd 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -383,7 +383,7 @@ void Sticker::preload() const { void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const { bool loaded = getShownDocument()->loaded(); - auto over = _a_over.current(_active ? 1. : 0.); + auto over = _a_over.current(context->ms, _active ? 1. : 0.); if (over > 0) { p.setOpacity(over); App::roundRect(p, QRect(QPoint(0, 0), st::stickerPanSize), st::emojiPanHover, StickerHoverCorners); @@ -780,17 +780,8 @@ void File::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, in void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { if (p == _open || p == _cancel) { - if (active) { - ensureAnimation(); - _animation->a_thumbOver.start(1); - } else { - if (!_animation) { - ensureAnimation(); - _animation->a_thumbOver = anim::value(1, 1); - } - _animation->a_thumbOver.start(0); - } - _animation->_a_thumbOver.start(); + ensureAnimation(); + _animation->a_thumbOver.start([this] { thumbAnimationCallback(); }, active ? 0. : 1., active ? 1. : 0., st::msgFileOverDuration); } } @@ -798,18 +789,9 @@ File::~File() { unregDocumentItem(getShownDocument(), this); } -void File::step_thumbOver(float64 ms, bool timer) { - float64 dt = ms / st::msgFileOverDuration; - if (dt >= 1) { - _animation->a_thumbOver.finish(); - _animation->_a_thumbOver.stop(); - checkAnimationFinished(); - } else if (!timer) { - _animation->a_thumbOver.update(dt, anim::linear); - } - if (timer) { - Ui::repaintInlineItem(this); - } +void File::thumbAnimationCallback() { + Ui::repaintInlineItem(this); + checkAnimationFinished(); } void File::step_radial(TimeMs ms, bool timer) { @@ -826,16 +808,14 @@ void File::step_radial(TimeMs ms, bool timer) { void File::ensureAnimation() const { if (!_animation) { - _animation.reset(new AnimationData( - animation(const_cast(this), &File::step_thumbOver), - animation(const_cast(this), &File::step_radial))); + _animation.reset(new AnimationData(animation(const_cast(this), &File::step_radial))); } } void File::checkAnimationFinished() { - if (_animation && !_animation->_a_thumbOver.animating() && !_animation->radial.animating()) { + if (_animation && !_animation->a_thumbOver.animating() && !_animation->radial.animating()) { if (getShownDocument()->loaded()) { - _animation = nullptr; + _animation.reset(); } } } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index c04c4ee76f..b98f14435c 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -107,11 +107,11 @@ private: , radial(std_::move(callbacks)) { } bool over; - FloatAnimation _a_over; + Animation _a_over; Ui::RadialAnimation radial; }; mutable std_::unique_ptr _animation; - mutable FloatAnimation _a_deleteOver; + mutable Animation _a_deleteOver; }; @@ -170,7 +170,7 @@ private: QSize getThumbSize() const; - mutable FloatAnimation _a_over; + mutable Animation _a_over; mutable bool _active = false; mutable QPixmap _thumb; @@ -242,7 +242,7 @@ public: ~File(); private: - void step_thumbOver(float64 ms, bool timer); + void thumbAnimationCallback(); void step_radial(TimeMs ms, bool timer); void ensureAnimation() const; @@ -256,20 +256,16 @@ private: return _animation && _animation->radial.animating(); } bool isThumbAnimation(TimeMs ms) const { - if (!_animation || !_animation->_a_thumbOver.animating()) return false; - - _animation->_a_thumbOver.step(ms); - return _animation && _animation->_a_thumbOver.animating(); + if (_animation) { + return _animation->a_thumbOver.animating(ms); + } + return false; } struct AnimationData { - AnimationData(AnimationCallbacks &&thumbOverCallbacks, AnimationCallbacks &&radialCallbacks) : a_thumbOver(0, 0) - , _a_thumbOver(std_::move(thumbOverCallbacks)) - , radial(std_::move(radialCallbacks)) { + AnimationData(AnimationCallbacks &&radialCallbacks) : radial(std_::move(radialCallbacks)) { } - anim::value a_thumbOver; - Animation _a_thumbOver; - + Animation a_thumbOver; Ui::RadialAnimation radial; }; mutable std_::unique_ptr _animation; diff --git a/Telegram/SourceFiles/intro/introwidget.h b/Telegram/SourceFiles/intro/introwidget.h index 0baddc61f5..9deaaed94d 100644 --- a/Telegram/SourceFiles/intro/introwidget.h +++ b/Telegram/SourceFiles/intro/introwidget.h @@ -198,7 +198,7 @@ public: QString _errorText; ChildWidget> _error = { nullptr }; - FloatAnimation _a_show; + Animation _a_show; CoverAnimation _coverAnimation; std_::unique_ptr _slideAnimation; QPixmap _coverMask; @@ -226,7 +226,7 @@ private: void resetDone(const MTPBool &result); bool resetFail(const RPCError &error); - FloatAnimation _a_show; + Animation _a_show; bool _showBack = false; QPixmap _cacheUnder, _cacheOver; @@ -243,7 +243,7 @@ private: Data _data; - FloatAnimation _coverShownAnimation; + Animation _coverShownAnimation; int _nextTopFrom = 0; int _controlsTopFrom = 0; diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 5c71b328a3..d9cc061c76 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -79,10 +79,10 @@ private: bool _wasAnimating = false; bool _inPaintEvent = false; - FloatAnimation _a_shown; - FloatAnimation _a_mainMenuShown; - FloatAnimation _a_specialLayerShown; - FloatAnimation _a_layerShown; + Animation _a_shown; + Animation _a_mainMenuShown; + Animation _a_specialLayerShown; + Animation _a_layerShown; Ui::RectShadow _shadow; diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index 498608974c..b42773d27a 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -157,7 +157,7 @@ private: void fillEmojiString(); void resetGifAndCache(); - FloatAnimation _a_shown; + Animation _a_shown; bool _hiding = false; DocumentData *_document = nullptr; PhotoData *_photo = nullptr; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4909737d3a..6c9d2bd23b 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -3139,7 +3139,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } if (_history->peer() == channel) { - _history->updateToEndVisibility(); + _history->updateHistoryDownVisibility(); _history->preloadHistoryIfNeeded(); } h->asChannelHistory()->getRangeDifference(); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index cc0c757283..abefb88558 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -586,7 +586,7 @@ private: base::Observable _searchInPeerChanged; base::Observable _historyPeerChanged; - FloatAnimation _a_show; + Animation _a_show; bool _showBack = false; QPixmap _cacheUnder, _cacheOver; diff --git a/Telegram/SourceFiles/media/player/media_player_button.cpp b/Telegram/SourceFiles/media/player/media_player_button.cpp index e79ec7974e..bdacc5c5bf 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.cpp +++ b/Telegram/SourceFiles/media/player/media_player_button.cpp @@ -45,7 +45,7 @@ QPainterPath interpolatePaths(QPointF (&from)[N], QPointF (&to)[N], float64 k) { } // namespace -PlayButtonLayout::PlayButtonLayout(const style::MediaPlayerButton &st, UpdateCallback &&callback) +PlayButtonLayout::PlayButtonLayout(const style::MediaPlayerButton &st, base::lambda &&callback) : _st(st) , _callback(std_::move(callback)) { } diff --git a/Telegram/SourceFiles/media/player/media_player_button.h b/Telegram/SourceFiles/media/player/media_player_button.h index aabf46968b..02557b056d 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.h +++ b/Telegram/SourceFiles/media/player/media_player_button.h @@ -33,8 +33,7 @@ public: Pause, Cancel, }; - using UpdateCallback = FloatAnimation::Callback; - PlayButtonLayout(const style::MediaPlayerButton &st, UpdateCallback &&callback); + PlayButtonLayout(const style::MediaPlayerButton &st, base::lambda &&callback); void setState(State state); void finishTransform(); @@ -54,10 +53,10 @@ private: State _state = State::Play; State _oldState = State::Play; State _nextState = State::Play; - FloatAnimation _transformProgress; + Animation _transformProgress; bool _transformBackward = false; - UpdateCallback _callback; + base::lambda _callback; }; diff --git a/Telegram/SourceFiles/media/player/media_player_panel.h b/Telegram/SourceFiles/media/player/media_player_panel.h index b6fce0b300..87071cbbaa 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.h +++ b/Telegram/SourceFiles/media/player/media_player_panel.h @@ -100,7 +100,7 @@ private: bool _hiding = false; QPixmap _cache; - FloatAnimation _a_appearance; + Animation _a_appearance; bool _ignoringEnterEvents = false; diff --git a/Telegram/SourceFiles/media/player/media_player_volume_controller.h b/Telegram/SourceFiles/media/player/media_player_volume_controller.h index 3056549950..14dc4796a9 100644 --- a/Telegram/SourceFiles/media/player/media_player_volume_controller.h +++ b/Telegram/SourceFiles/media/player/media_player_volume_controller.h @@ -82,7 +82,7 @@ private: bool _hiding = false; QPixmap _cache; - FloatAnimation _a_appearance; + Animation _a_appearance; QTimer _hideTimer, _showTimer; diff --git a/Telegram/SourceFiles/media/view/media_clip_volume_controller.h b/Telegram/SourceFiles/media/view/media_clip_volume_controller.h index 69389eeab9..cfe84d80d6 100644 --- a/Telegram/SourceFiles/media/view/media_clip_volume_controller.h +++ b/Telegram/SourceFiles/media/view/media_clip_volume_controller.h @@ -50,7 +50,7 @@ private: int _downCoord = -1; // < 0 means mouse is not pressed bool _over = false; - FloatAnimation _a_over; + Animation _a_over; }; diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index 3fd288f913..958bd1d412 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -296,7 +296,7 @@ private: QPoint _lastAction, _lastMouseMovePos; bool _ignoringDropdown = false; - Animation _a_state; + BasicAnimation _a_state; enum ControlsState { ControlsShowing, diff --git a/Telegram/SourceFiles/mtproto/connection.cpp b/Telegram/SourceFiles/mtproto/connection.cpp index 149e4a7e1e..98188ac580 100644 --- a/Telegram/SourceFiles/mtproto/connection.cpp +++ b/Telegram/SourceFiles/mtproto/connection.cpp @@ -105,20 +105,30 @@ public: return false; } + // check g_b > 2^{2048 - 8} and get the value of g_b + if (BN_is_negative(&bnResult)) { + LOG(("BigNum Error: bad g_b - negative")); + return false; + } uint32 resultLen = BN_num_bytes(&bnResult); if (resultLen != 64 * sizeof(uint32)) { - DEBUG_LOG(("BigNum Error: bad gResult len (%1)").arg(resultLen)); + LOG(("BigNum Error: bad g_b len (%1)").arg(resultLen)); return false; } resultLen = BN_bn2bin(&bnResult, (uchar*)gResult); if (resultLen != 64 * sizeof(uint32)) { - DEBUG_LOG(("BigNum Error: bad gResult export len (%1)").arg(resultLen)); + LOG(("BigNum Error: bad g_b export len (%1)").arg(resultLen)); return false; } - BN_add_word(&bnResult, 1); // check g_b < dh_prime - 1 - if (BN_cmp(&bnResult, &bnModul) >= 0) { - DEBUG_LOG(("BigNum Error: bad g_b >= dh_prime - 1")); + // check g_b < dh_prime - 2^{2048 - 8} + BN_sub(&bnTemp, &bnModul, &bnResult); + if (BN_is_negative(&bnTemp)) { + DEBUG_LOG(("BigNum Error: bad g_b > dh_prime")); + return false; + } + if (BN_num_bytes(&bnTemp) != 64 * sizeof(uint32)) { + DEBUG_LOG(("BigNum Error: bad g_b > dh_prime - 2^{2048 - 8}")); return false; } @@ -140,9 +150,25 @@ public: return false; } - BN_add_word(&bn_g_a, 1); // check g_a < dh_prime - 1 - if (BN_cmp(&bn_g_a, &bnModul) >= 0) { - DEBUG_LOG(("BigNum Error: bad g_a >= dh_prime - 1")); + // check g_a > 2^{2048 - 8} + if (BN_is_negative(&bn_g_a)) { + LOG(("BigNum Error: bad g_a - negative")); + return false; + } + resultLen = BN_num_bytes(&bn_g_a); + if (resultLen != 64 * sizeof(uint32)) { + LOG(("BigNum Error: bad g_a len (%1)").arg(resultLen)); + return false; + } + + // check g_a < dh_prime - 2^{2048 - 8} + BN_sub(&bnTemp, &bnModul, &bn_g_a); + if (BN_is_negative(&bnTemp)) { + LOG(("BigNum Error: bad g_b > dh_prime")); + return false; + } + if (BN_num_bytes(&bnTemp) != 64 * sizeof(uint32)) { + LOG(("BigNum Error: bad g_b > dh_prime - 2^{2048 - 8}")); return false; } @@ -155,6 +181,7 @@ public: BN_init(&bn_g); BN_init(&bn_g_a); BN_init(&bnResult); + BN_init(&bnTemp); } ~BigNumCounter() { BN_CTX_free(ctx); @@ -163,11 +190,13 @@ public: BN_clear_free(&bn_g); BN_clear_free(&bn_g_a); BN_clear_free(&bnResult); + BN_clear_free(&bnTemp); } private: - BIGNUM bnPower, bnModul, bn_g, bn_g_a, bnResult; + BIGNUM bnPower, bnModul, bn_g, bn_g_a, bnResult, bnTemp; BN_CTX *ctx; + }; // Miller-Rabin primality test @@ -409,29 +438,12 @@ void ConnectionPrivate::destroyConn(AbstractConnection **conn) { ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, SessionData *data, uint32 _dc) : QObject(nullptr) , _state(DisconnectedState) -, _needSessionReset(false) , dc(_dc) , _owner(owner) -, _conn(nullptr) -, _conn4(nullptr) -, _conn6(nullptr) -, retryTimeout(1) -, oldConnection(true) , _waitForReceived(MTPMinReceiveDelay) , _waitForConnected(MTPMinConnectDelay) -, firstSentAt(-1) -, _pingId(0) -, _pingIdToSend(0) -, _pingSendAt(0) -, _pingMsgId(0) -, restarted(false) -, _finished(false) -, keyId(0) // , sessionDataMutex(QReadWriteLock::Recursive) -, sessionData(data) -, myKeyLock(false) -, authKeyData(0) -, authKeyStrings(0) { +, sessionData(data) { oldConnectionTimer.moveToThread(thread); _waitForConnectedTimer.moveToThread(thread); _waitForReceivedTimer.moveToThread(thread); @@ -474,7 +486,7 @@ ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, Session static bool _registered = false; if (!_registered) { _registered = true; - qRegisterMetaType >("QVector"); + qRegisterMetaType >("QVector"); } connect(this, SIGNAL(needToSendAsync()), sessionData->owner(), SLOT(needToResumeAndSend()), Qt::QueuedConnection); @@ -1459,7 +1471,7 @@ void ConnectionPrivate::handleReceived() { if (needAck) ackRequestData.push_back(MTP_long(msgId)); - int32 res = 1; // if no need to handle, then succeed + auto res = HandleResult::Success; // if no need to handle, then succeed end = data + 8 + (msgLen >> 2); const mtpPrime *sfrom(data + 4); MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end)); @@ -1467,19 +1479,14 @@ void ConnectionPrivate::handleReceived() { bool needToHandle = false; { QWriteLocker lock(sessionData->receivedIdsMutex()); - mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet()); - needToHandle = receivedIds.insert(msgId, needAck); + needToHandle = sessionData->receivedIdsSet().registerMsgId(msgId, needAck); } if (needToHandle) { res = handleOneReceived(from, end, msgId, serverTime, serverSalt, badTime); } { QWriteLocker lock(sessionData->receivedIdsMutex()); - mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet()); - uint32 receivedIdsSize = receivedIds.size(); - while (receivedIdsSize-- > MTPIdsBufferSize) { - receivedIds.erase(receivedIds.begin()); - } + sessionData->receivedIdsSet().shrink(); } // send acks @@ -1502,8 +1509,8 @@ void ConnectionPrivate::handleReceived() { emit needToReceive(); } - if (res < 0) { - _needSessionReset = (res < -1); + if (res != HandleResult::Success && res != HandleResult::Ignored) { + _needSessionReset = (res == HandleResult::ResetSession); lockFinished.unlock(); return restart(); @@ -1526,7 +1533,7 @@ void ConnectionPrivate::handleReceived() { } } -int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime) { +ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime) { mtpTypeId cons = *from; try { @@ -1536,7 +1543,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime DEBUG_LOG(("Message Info: gzip container")); mtpBuffer response = ungzip(++from, end); if (!response.size()) { - return -1; + return HandleResult::RestartConnection; } return handleOneReceived(response.data(), response.data() + response.size(), msgId, serverTime, serverSalt, badTime); } @@ -1555,14 +1562,14 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime bool isReply = ((inMsgId.v & 0x03) == 1); if (!isReply && ((inMsgId.v & 0x03) != 3)) { LOG(("Message Error: bad msg_id %1 in contained message received").arg(inMsgId.v)); - return -1; + return HandleResult::RestartConnection; } MTPint inSeqNo(from, otherEnd); MTPint bytes(from, otherEnd); if ((bytes.v & 0x03) || bytes.v < 4) { LOG(("Message Error: bad length %1 of contained message received").arg(bytes.v)); - return -1; + return HandleResult::RestartConnection; } bool needAck = (inSeqNo.v & 0x01); @@ -1576,21 +1583,20 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime bool needToHandle = false; { QWriteLocker lock(sessionData->receivedIdsMutex()); - mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet()); - needToHandle = receivedIds.insert(inMsgId.v, needAck); + needToHandle = sessionData->receivedIdsSet().registerMsgId(inMsgId.v, needAck); } - int32 res = 1; // if no need to handle, then succeed + auto res = HandleResult::Success; // if no need to handle, then succeed if (needToHandle) { res = handleOneReceived(from, otherEnd, inMsgId.v, serverTime, serverSalt, badTime); badTime = false; } - if (res <= 0) { + if (res != HandleResult::Success) { return res; } from = otherEnd; } - } return 1; + } return HandleResult::Success; case mtpc_msgs_ack: { MTPMsgsAck msg(from, end); @@ -1598,17 +1604,17 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime uint32 idsCount = ids.size(); DEBUG_LOG(("Message Info: acks received, ids: %1").arg(Logs::vector(ids))); - if (!idsCount) return (badTime ? 0 : 1); + if (!idsCount) return (badTime ? HandleResult::Ignored : HandleResult::Success); if (badTime) { if (requestsFixTimeSalt(ids, serverTime, serverSalt)) { badTime = false; } else { - return 0; + return HandleResult::Ignored; } } requestsAcked(ids); - } return 1; + } return HandleResult::Success; case mtpc_bad_msg_notification: { MTPBadMsgNotification msg(from, end); @@ -1654,7 +1660,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime if (!wasSent(resendId)) { DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); - return (badTime ? 0 : 1); + return (badTime ? HandleResult::Ignored : HandleResult::Success); } if (needResend) { // bad msg_id @@ -1671,7 +1677,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime badTime = false; } LOG(("Message Info: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(errorCode)); - return -2; + return HandleResult::ResetSession; } } else { // fatal (except 48, but it must not get here) mtpMsgId resendId = data.vbad_msg_id.v; @@ -1682,9 +1688,9 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime } else { DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); } - return (badTime ? 0 : 1); + return (badTime ? HandleResult::Ignored : HandleResult::Success); } - } return 1; + } return HandleResult::Success; case mtpc_bad_server_salt: { MTPBadMsgNotification msg(from, end); @@ -1696,7 +1702,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime _pingId = 0; } else if (!wasSent(resendId)) { DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId)); - return (badTime ? 0 : 1); + return (badTime ? HandleResult::Ignored : HandleResult::Success); } uint64 serverSalt = data.vnew_server_salt.v; @@ -1714,25 +1720,25 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime DEBUG_LOG(("Message Info: unixtime updated, now %1, server_salt updated, now %2, resending...").arg(serverTime).arg(serverSalt)); resend(resendId); - } return 1; + } return HandleResult::Success; case mtpc_msgs_state_req: { if (badTime) { DEBUG_LOG(("Message Info: skipping with bad time...")); - return 0; + return HandleResult::Ignored; } MTPMsgsStateReq msg(from, end); const auto &ids(msg.c_msgs_state_req().vmsg_ids.c_vector().v); uint32 idsCount = ids.size(); DEBUG_LOG(("Message Info: msgs_state_req received, ids: %1").arg(Logs::vector(ids))); - if (!idsCount) return 1; + if (!idsCount) return HandleResult::Success; QByteArray info(idsCount, Qt::Uninitialized); { QReadLocker lock(sessionData->receivedIdsMutex()); - const mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet()); - mtpMsgIdsMap::const_iterator receivedIdsEnd(receivedIds.cend()); - uint64 minRecv = receivedIds.min(), maxRecv = receivedIds.max(); + auto &receivedIds = sessionData->receivedIdsSet(); + auto minRecv = receivedIds.min(); + auto maxRecv = receivedIds.max(); QReadLocker locker(sessionData->wereAckedMutex()); const mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); @@ -1746,15 +1752,15 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime } else if (reqMsgId > maxRecv) { state |= 0x03; } else { - mtpMsgIdsMap::const_iterator recv = receivedIds.constFind(reqMsgId); - if (recv == receivedIdsEnd) { + auto msgIdState = receivedIds.lookup(reqMsgId); + if (msgIdState == ReceivedMsgIds::State::NotFound) { state |= 0x02; } else { state |= 0x04; if (wereAcked.constFind(reqMsgId) != wereAckedEnd) { state |= 0x80; // we know, that server knows, that we received request } - if (recv.value()) { // need ack, so we sent ack + if (msgIdState == ReceivedMsgIds::State::NeedsAck) { // need ack, so we sent ack state |= 0x08; } else { state |= 0x10; @@ -1765,7 +1771,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime } } emit sendMsgsStateInfoAsync(msgId, info); - } return 1; + } return HandleResult::Success; case mtpc_msgs_state_info: { MTPMsgsStateInfo msg(from, end); @@ -1782,7 +1788,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime mtpRequestMap::const_iterator replyTo = haveSent.constFind(reqMsgId); if (replyTo == haveSent.cend()) { // do not look in toResend, because we do not resend msgs_state_req requests DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(reqMsgId)); - return (badTime ? 0 : 1); + return (badTime ? HandleResult::Ignored : HandleResult::Success); } if (badTime) { if (serverSalt) sessionData->setSalt(serverSalt); // requestsFixTimeSalt with no lookup @@ -1799,7 +1805,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime if (requestBuffer->size() < 9) { LOG(("Message Error: bad request %1 found in requestMap, size: %2").arg(reqMsgId).arg(requestBuffer->size())); - return -1; + return HandleResult::RestartConnection; } try { const mtpPrime *rFrom = requestBuffer->constData() + 8, *rEnd = requestBuffer->constData() + requestBuffer->size(); @@ -1816,12 +1822,12 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime } requestsAcked(toAck); - } return 1; + } return HandleResult::Success; case mtpc_msgs_all_info: { if (badTime) { DEBUG_LOG(("Message Info: skipping with bad time...")); - return 0; + return HandleResult::Ignored; } MTPMsgsAllInfo msg(from, end); @@ -1835,7 +1841,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime handleMsgsStates(ids, states, toAck); requestsAcked(toAck); - } return 1; + } return HandleResult::Success; case mtpc_msg_detailed_info: { MTPMsgDetailedInfo msg(from, end); @@ -1849,7 +1855,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime badTime = false; } else { DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(data.vmsg_id.v)); - return 0; + return HandleResult::Ignored; } } requestsAcked(ids); @@ -1858,8 +1864,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime MTPlong resMsgId = data.vanswer_msg_id; { QReadLocker lock(sessionData->receivedIdsMutex()); - const mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet()); - received = (receivedIds.find(resMsgId.v) != receivedIds.cend()) && (receivedIds.min() < resMsgId.v); + received = (sessionData->receivedIdsSet().lookup(resMsgId.v) != ReceivedMsgIds::State::NotFound); } if (received) { ackRequestData.push_back(resMsgId); @@ -1867,12 +1872,12 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime DEBUG_LOG(("Message Info: answer message %1 was not received, requesting...").arg(resMsgId.v)); resendRequestData.push_back(resMsgId); } - } return 1; + } return HandleResult::Success; case mtpc_msg_new_detailed_info: { if (badTime) { DEBUG_LOG(("Message Info: skipping msg_new_detailed_info with bad time...")); - return 0; + return HandleResult::Ignored; } MTPMsgDetailedInfo msg(from, end); const auto &data(msg.c_msg_new_detailed_info()); @@ -1883,8 +1888,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime MTPlong resMsgId = data.vanswer_msg_id; { QReadLocker lock(sessionData->receivedIdsMutex()); - const mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet()); - received = (receivedIds.find(resMsgId.v) != receivedIds.cend()) && (receivedIds.min() < resMsgId.v); + received = (sessionData->receivedIdsSet().lookup(resMsgId.v) != ReceivedMsgIds::State::NotFound); } if (received) { ackRequestData.push_back(resMsgId); @@ -1892,7 +1896,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime DEBUG_LOG(("Message Info: answer message %1 was not received, requesting...").arg(resMsgId.v)); resendRequestData.push_back(resMsgId); } - } return 1; + } return HandleResult::Success; case mtpc_msg_resend_req: { MTPMsgResendReq msg(from, end); @@ -1900,14 +1904,14 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime uint32 idsCount = ids.size(); DEBUG_LOG(("Message Info: resend of msgs requested, ids: %1").arg(Logs::vector(ids))); - if (!idsCount) return (badTime ? 0 : 1); + if (!idsCount) return (badTime ? HandleResult::Ignored : HandleResult::Success); QVector toResend(ids.size()); for (int32 i = 0, l = ids.size(); i < l; ++i) { toResend[i] = ids.at(i).v; } resendMany(toResend, 0, false, true); - } return 1; + } return HandleResult::Success; case mtpc_rpc_result: { if (from + 3 > end) throw mtpErrorInsufficient(); @@ -1924,7 +1928,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime badTime = false; } else { DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(reqMsgId.v)); - return 0; + return HandleResult::Ignored; } } requestsAcked(ids, true); @@ -1933,7 +1937,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime DEBUG_LOG(("RPC Info: gzip container")); response = ungzip(++from, end); if (!response.size()) { - return -1; + return HandleResult::RestartConnection; } typeId = response[0]; } else { @@ -1952,7 +1956,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime } else { DEBUG_LOG(("RPC Info: requestId not found for msgId %1").arg(reqMsgId.v)); } - } return 1; + } return HandleResult::Success; case mtpc_new_session_created: { const mtpPrime *start = from; @@ -1964,7 +1968,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime badTime = false; } else { DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(data.vfirst_msg_id.v)); - return 0; + return HandleResult::Ignored; } } @@ -1991,16 +1995,16 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime mtpResponseMap &haveReceived(sessionData->haveReceivedMap()); mtpRequestId fakeRequestId = sessionData->nextFakeRequestId(); haveReceived.insert(fakeRequestId, mtpResponse(update)); // notify main process about new session - need to get difference - } return 1; + } return HandleResult::Success; case mtpc_ping: { - if (badTime) return 0; + if (badTime) return HandleResult::Ignored; MTPPing msg(from, end); DEBUG_LOG(("Message Info: ping received, ping_id: %1, sending pong...").arg(msg.vping_id.v)); emit sendPongAsync(msgId, msg.vping_id.v); - } return 1; + } return HandleResult::Success; case mtpc_pong: { MTPPong msg(from, end); @@ -2009,7 +2013,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime if (!wasSent(data.vmsg_id.v)) { DEBUG_LOG(("Message Error: such msg_id %1 ping_id %2 was not sent recently").arg(data.vmsg_id.v).arg(data.vping_id.v)); - return 0; + return HandleResult::Ignored; } if (data.vping_id.v == _pingId) { _pingId = 0; @@ -2022,21 +2026,21 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime if (requestsFixTimeSalt(ids, serverTime, serverSalt)) { badTime = false; } else { - return 0; + return HandleResult::Ignored; } } requestsAcked(ids, true); - } return 1; + } return HandleResult::Success; } } catch (Exception &) { - return -1; + return HandleResult::RestartConnection; } if (badTime) { DEBUG_LOG(("Message Error: bad time in updates cons, must create new session")); - return -2; + return HandleResult::ResetSession; } mtpBuffer update(end - from); @@ -2051,7 +2055,7 @@ int32 ConnectionPrivate::handleOneReceived(const mtpPrime *from, const mtpPrime LOG(("Message Error: unknown constructor %1").arg(cons)); // maybe new api?.. } - return 1; + return HandleResult::Success; } mtpBuffer ConnectionPrivate::ungzip(const mtpPrime *from, const mtpPrime *end) const { @@ -2377,13 +2381,13 @@ void ConnectionPrivate::updateAuthKey() { return authKeyCreated(); } - authKeyData = new ConnectionPrivate::AuthKeyCreateData(); - authKeyStrings = new ConnectionPrivate::AuthKeyCreateStrings(); - authKeyData->req_num = 0; - authKeyData->nonce = rand_value(); + _authKeyData = std_::make_unique(); + _authKeyStrings = std_::make_unique(); + _authKeyData->req_num = 0; + _authKeyData->nonce = rand_value(); MTPReq_pq req_pq; - req_pq.vnonce = authKeyData->nonce; + req_pq.vnonce = _authKeyData->nonce; connect(_conn, SIGNAL(receivedData()), this, SLOT(pqAnswered())); @@ -2408,9 +2412,9 @@ void ConnectionPrivate::pqAnswered() { } const auto &res_pq_data(res_pq.c_resPQ()); - if (res_pq_data.vnonce != authKeyData->nonce) { + if (res_pq_data.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in res_pq)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&res_pq_data.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&res_pq_data.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); return restart(); } @@ -2436,12 +2440,12 @@ void ConnectionPrivate::pqAnswered() { return restart(); } - authKeyData->server_nonce = res_pq_data.vserver_nonce; + _authKeyData->server_nonce = res_pq_data.vserver_nonce; MTPP_Q_inner_data p_q_inner; MTPDp_q_inner_data &p_q_inner_data(p_q_inner._p_q_inner_data()); - p_q_inner_data.vnonce = authKeyData->nonce; - p_q_inner_data.vserver_nonce = authKeyData->server_nonce; + p_q_inner_data.vnonce = _authKeyData->nonce; + p_q_inner_data.vserver_nonce = _authKeyData->server_nonce; p_q_inner_data.vpq = res_pq_data.vpq; const string &pq(res_pq_data.vpq.c_string().v); @@ -2453,12 +2457,12 @@ void ConnectionPrivate::pqAnswered() { return restart(); } - authKeyData->new_nonce = rand_value(); - p_q_inner_data.vnew_nonce = authKeyData->new_nonce; + _authKeyData->new_nonce = rand_value(); + p_q_inner_data.vnew_nonce = _authKeyData->new_nonce; MTPReq_DH_params req_DH_params; - req_DH_params.vnonce = authKeyData->nonce; - req_DH_params.vserver_nonce = authKeyData->server_nonce; + req_DH_params.vnonce = _authKeyData->nonce; + req_DH_params.vserver_nonce = _authKeyData->server_nonce; req_DH_params.vpublic_key_fingerprint = MTP_long(rsaKey->getFingerPrint()); req_DH_params.vp = p_q_inner_data.vp; req_DH_params.vq = p_q_inner_data.vq; @@ -2508,14 +2512,14 @@ void ConnectionPrivate::dhParamsAnswered() { switch (res_DH_params.type()) { case mtpc_server_DH_params_ok: { const auto &encDH(res_DH_params.c_server_DH_params_ok()); - if (encDH.vnonce != authKeyData->nonce) { + if (encDH.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in server_DH_params_ok)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&encDH.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&encDH.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); return restart(); } - if (encDH.vserver_nonce != authKeyData->server_nonce) { + if (encDH.vserver_nonce != _authKeyData->server_nonce) { LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_ok)!")); - DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&encDH.vserver_nonce, 16).str()).arg(Logs::mb(&authKeyData->server_nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&encDH.vserver_nonce, 16).str()).arg(Logs::mb(&_authKeyData->server_nonce, 16).str())); return restart(); } @@ -2527,12 +2531,12 @@ void ConnectionPrivate::dhParamsAnswered() { return restart(); } - uint32 nlen = authKeyData->new_nonce.innerLength(), slen = authKeyData->server_nonce.innerLength(); + uint32 nlen = _authKeyData->new_nonce.innerLength(), slen = _authKeyData->server_nonce.innerLength(); uchar tmp_aes[1024], sha1ns[20], sha1sn[20], sha1nn[20]; - memcpy(tmp_aes, &authKeyData->new_nonce, nlen); - memcpy(tmp_aes + nlen, &authKeyData->server_nonce, slen); - memcpy(tmp_aes + nlen + slen, &authKeyData->new_nonce, nlen); - memcpy(tmp_aes + nlen + slen + nlen, &authKeyData->new_nonce, nlen); + memcpy(tmp_aes, &_authKeyData->new_nonce, nlen); + memcpy(tmp_aes + nlen, &_authKeyData->server_nonce, slen); + memcpy(tmp_aes + nlen + slen, &_authKeyData->new_nonce, nlen); + memcpy(tmp_aes + nlen + slen + nlen, &_authKeyData->new_nonce, nlen); hashSha1(tmp_aes, nlen + slen, sha1ns); hashSha1(tmp_aes + nlen, nlen + slen, sha1sn); hashSha1(tmp_aes + nlen + slen, nlen + nlen, sha1nn); @@ -2540,31 +2544,31 @@ void ConnectionPrivate::dhParamsAnswered() { mtpBuffer decBuffer; decBuffer.resize(encDHBufLen); - memcpy(authKeyData->aesKey, sha1ns, 20); - memcpy(authKeyData->aesKey + 20, sha1sn, 12); - memcpy(authKeyData->aesIV, sha1sn + 12, 8); - memcpy(authKeyData->aesIV + 8, sha1nn, 20); - memcpy(authKeyData->aesIV + 28, &authKeyData->new_nonce, 4); + memcpy(_authKeyData->aesKey, sha1ns, 20); + memcpy(_authKeyData->aesKey + 20, sha1sn, 12); + memcpy(_authKeyData->aesIV, sha1sn + 12, 8); + memcpy(_authKeyData->aesIV + 8, sha1nn, 20); + memcpy(_authKeyData->aesIV + 28, &_authKeyData->new_nonce, 4); - aesIgeDecrypt(&encDHStr[0], &decBuffer[0], encDHLen, authKeyData->aesKey, authKeyData->aesIV); + aesIgeDecrypt(&encDHStr[0], &decBuffer[0], encDHLen, _authKeyData->aesKey, _authKeyData->aesIV); const mtpPrime *from(&decBuffer[5]), *to(from), *end(from + (encDHBufLen - 5)); MTPServer_DH_inner_data dh_inner(to, end); const auto &dh_inner_data(dh_inner.c_server_DH_inner_data()); - if (dh_inner_data.vnonce != authKeyData->nonce) { + if (dh_inner_data.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in server_DH_inner_data)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&dh_inner_data.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&dh_inner_data.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); return restart(); } - if (dh_inner_data.vserver_nonce != authKeyData->server_nonce) { + if (dh_inner_data.vserver_nonce != _authKeyData->server_nonce) { LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_inner_data)!")); - DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&dh_inner_data.vserver_nonce, 16).str()).arg(Logs::mb(&authKeyData->server_nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&dh_inner_data.vserver_nonce, 16).str()).arg(Logs::mb(&_authKeyData->server_nonce, 16).str())); return restart(); } uchar sha1Buffer[20]; if (memcmp(&decBuffer[0], hashSha1(&decBuffer[5], (to - from) * sizeof(mtpPrime), sha1Buffer), 20)) { LOG(("AuthKey Error: sha1 hash of encrypted part did not match!")); - DEBUG_LOG(("AuthKey Error: sha1 did not match, server_nonce: %1, new_nonce %2, encrypted data %3").arg(Logs::mb(&authKeyData->server_nonce, 16).str()).arg(Logs::mb(&authKeyData->new_nonce, 16).str()).arg(Logs::mb(&encDHStr[0], encDHLen).str())); + DEBUG_LOG(("AuthKey Error: sha1 did not match, server_nonce: %1, new_nonce %2, encrypted data %3").arg(Logs::mb(&_authKeyData->server_nonce, 16).str()).arg(Logs::mb(&_authKeyData->new_nonce, 16).str()).arg(Logs::mb(&encDHStr[0], encDHLen).str())); return restart(); } unixtimeSet(dh_inner_data.vserver_time.v); @@ -2584,29 +2588,29 @@ void ConnectionPrivate::dhParamsAnswered() { return restart(); } - authKeyStrings->dh_prime = QByteArray(dhPrime.data(), dhPrime.size()); - authKeyData->g = dh_inner_data.vg.v; - authKeyStrings->g_a = QByteArray(g_a.data(), g_a.size()); - authKeyData->retry_id = MTP_long(0); - authKeyData->retries = 0; + _authKeyStrings->dh_prime = QByteArray(dhPrime.data(), dhPrime.size()); + _authKeyData->g = dh_inner_data.vg.v; + _authKeyStrings->g_a = QByteArray(g_a.data(), g_a.size()); + _authKeyData->retry_id = MTP_long(0); + _authKeyData->retries = 0; } return dhClientParamsSend(); case mtpc_server_DH_params_fail: { const auto &encDH(res_DH_params.c_server_DH_params_fail()); - if (encDH.vnonce != authKeyData->nonce) { + if (encDH.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in server_DH_params_fail)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&encDH.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&encDH.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); return restart(); } - if (encDH.vserver_nonce != authKeyData->server_nonce) { + if (encDH.vserver_nonce != _authKeyData->server_nonce) { LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in server_DH_params_fail)!")); - DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&encDH.vserver_nonce, 16).str()).arg(Logs::mb(&authKeyData->server_nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&encDH.vserver_nonce, 16).str()).arg(Logs::mb(&_authKeyData->server_nonce, 16).str())); return restart(); } uchar sha1Buffer[20]; - if (encDH.vnew_nonce_hash != *(MTPint128*)(hashSha1(&authKeyData->new_nonce, 32, sha1Buffer) + 1)) { + if (encDH.vnew_nonce_hash != *(MTPint128*)(hashSha1(&_authKeyData->new_nonce, 32, sha1Buffer) + 1)) { LOG(("AuthKey Error: received new_nonce_hash did not match!")); - DEBUG_LOG(("AuthKey Error: received new_nonce_hash: %1, new_nonce: %2").arg(Logs::mb(&encDH.vnew_nonce_hash, 16).str()).arg(Logs::mb(&authKeyData->new_nonce, 32).str())); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash: %1, new_nonce: %2").arg(Logs::mb(&encDH.vnew_nonce_hash, 16).str()).arg(Logs::mb(&_authKeyData->new_nonce, 32).str())); return restart(); } LOG(("AuthKey Error: server_DH_params_fail received!")); @@ -2618,16 +2622,16 @@ void ConnectionPrivate::dhParamsAnswered() { } void ConnectionPrivate::dhClientParamsSend() { - if (++authKeyData->retries > 5) { - LOG(("AuthKey Error: could not create auth_key for %1 retries").arg(authKeyData->retries - 1)); + if (++_authKeyData->retries > 5) { + LOG(("AuthKey Error: could not create auth_key for %1 retries").arg(_authKeyData->retries - 1)); return restart(); } MTPClient_DH_Inner_Data client_dh_inner; MTPDclient_DH_inner_data &client_dh_inner_data(client_dh_inner._client_DH_inner_data()); - client_dh_inner_data.vnonce = authKeyData->nonce; - client_dh_inner_data.vserver_nonce = authKeyData->server_nonce; - client_dh_inner_data.vretry_id = authKeyData->retry_id; + client_dh_inner_data.vnonce = _authKeyData->nonce; + client_dh_inner_data.vserver_nonce = _authKeyData->server_nonce; + client_dh_inner_data.vretry_id = _authKeyData->retry_id; client_dh_inner_data.vg_b._string().v.resize(256); // gen rand 'b' @@ -2636,19 +2640,19 @@ void ConnectionPrivate::dhClientParamsSend() { // count g_b and auth_key using openssl BIGNUM methods MTP::internal::BigNumCounter bnCounter; - if (!bnCounter.count(b, authKeyStrings->dh_prime.constData(), authKeyData->g, g_b, authKeyStrings->g_a.constData(), authKeyData->auth_key)) { + if (!bnCounter.count(b, _authKeyStrings->dh_prime.constData(), _authKeyData->g, g_b, _authKeyStrings->g_a.constData(), _authKeyData->auth_key)) { return dhClientParamsSend(); } // count auth_key hashes - parts of sha1(auth_key) uchar sha1Buffer[20]; - int32 *auth_key_sha = hashSha1(authKeyData->auth_key, 256, sha1Buffer); - memcpy(&authKeyData->auth_key_aux_hash, auth_key_sha, 8); - memcpy(&authKeyData->auth_key_hash, auth_key_sha + 3, 8); + int32 *auth_key_sha = hashSha1(_authKeyData->auth_key, 256, sha1Buffer); + memcpy(&_authKeyData->auth_key_aux_hash, auth_key_sha, 8); + memcpy(&_authKeyData->auth_key_hash, auth_key_sha + 3, 8); MTPSet_client_DH_params req_client_DH_params; - req_client_DH_params.vnonce = authKeyData->nonce; - req_client_DH_params.vserver_nonce = authKeyData->server_nonce; + req_client_DH_params.vnonce = _authKeyData->nonce; + req_client_DH_params.vserver_nonce = _authKeyData->server_nonce; string &sdhEncString(req_client_DH_params.vencrypted_data._string().v); @@ -2670,7 +2674,7 @@ void ConnectionPrivate::dhClientParamsSend() { sdhEncString.resize(encFullSize * 4); - aesIgeEncrypt(&encBuffer[0], &sdhEncString[0], encFullSize * sizeof(mtpPrime), authKeyData->aesKey, authKeyData->aesIV); + aesIgeEncrypt(&encBuffer[0], &sdhEncString[0], encFullSize * sizeof(mtpPrime), _authKeyData->aesKey, _authKeyData->aesIV); connect(_conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered())); @@ -2694,38 +2698,38 @@ void ConnectionPrivate::dhClientParamsAnswered() { switch (res_client_DH_params.type()) { case mtpc_dh_gen_ok: { const auto &resDH(res_client_DH_params.c_dh_gen_ok()); - if (resDH.vnonce != authKeyData->nonce) { + if (resDH.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in dh_gen_ok)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&resDH.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&resDH.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); lockFinished.unlock(); return restart(); } - if (resDH.vserver_nonce != authKeyData->server_nonce) { + if (resDH.vserver_nonce != _authKeyData->server_nonce) { LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_ok)!")); - DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&resDH.vserver_nonce, 16).str()).arg(Logs::mb(&authKeyData->server_nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&resDH.vserver_nonce, 16).str()).arg(Logs::mb(&_authKeyData->server_nonce, 16).str())); lockFinished.unlock(); return restart(); } - authKeyData->new_nonce_buf[32] = 1; + _authKeyData->new_nonce_buf[32] = 1; uchar sha1Buffer[20]; - if (resDH.vnew_nonce_hash1 != *(MTPint128*)(hashSha1(authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { + if (resDH.vnew_nonce_hash1 != *(MTPint128*)(hashSha1(_authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { LOG(("AuthKey Error: received new_nonce_hash1 did not match!")); - DEBUG_LOG(("AuthKey Error: received new_nonce_hash1: %1, new_nonce_buf: %2").arg(Logs::mb(&resDH.vnew_nonce_hash1, 16).str()).arg(Logs::mb(authKeyData->new_nonce_buf, 41).str())); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash1: %1, new_nonce_buf: %2").arg(Logs::mb(&resDH.vnew_nonce_hash1, 16).str()).arg(Logs::mb(_authKeyData->new_nonce_buf, 41).str())); lockFinished.unlock(); return restart(); } - uint64 salt1 = authKeyData->new_nonce.l.l, salt2 = authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2; + uint64 salt1 = _authKeyData->new_nonce.l.l, salt2 = _authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2; sessionData->setSalt(serverSalt); AuthKeyPtr authKey(new AuthKey()); - authKey->setKey(authKeyData->auth_key); + authKey->setKey(_authKeyData->auth_key); authKey->setDC(bareDcId(dc)); - DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3").arg(authKey->keyId()).arg(serverSalt).arg(Logs::mb(authKeyData->auth_key, 256).str())); + DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3").arg(authKey->keyId()).arg(serverSalt).arg(Logs::mb(_authKeyData->auth_key, 256).str())); sessionData->owner()->notifyKeyCreated(authKey); // slot will call authKeyCreated() sessionData->clear(); @@ -2734,53 +2738,53 @@ void ConnectionPrivate::dhClientParamsAnswered() { case mtpc_dh_gen_retry: { const auto &resDH(res_client_DH_params.c_dh_gen_retry()); - if (resDH.vnonce != authKeyData->nonce) { + if (resDH.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in dh_gen_retry)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&resDH.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&resDH.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); lockFinished.unlock(); return restart(); } - if (resDH.vserver_nonce != authKeyData->server_nonce) { + if (resDH.vserver_nonce != _authKeyData->server_nonce) { LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_retry)!")); - DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&resDH.vserver_nonce, 16).str()).arg(Logs::mb(&authKeyData->server_nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&resDH.vserver_nonce, 16).str()).arg(Logs::mb(&_authKeyData->server_nonce, 16).str())); lockFinished.unlock(); return restart(); } - authKeyData->new_nonce_buf[32] = 2; + _authKeyData->new_nonce_buf[32] = 2; uchar sha1Buffer[20]; - if (resDH.vnew_nonce_hash2 != *(MTPint128*)(hashSha1(authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { + if (resDH.vnew_nonce_hash2 != *(MTPint128*)(hashSha1(_authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { LOG(("AuthKey Error: received new_nonce_hash2 did not match!")); - DEBUG_LOG(("AuthKey Error: received new_nonce_hash2: %1, new_nonce_buf: %2").arg(Logs::mb(&resDH.vnew_nonce_hash2, 16).str()).arg(Logs::mb(authKeyData->new_nonce_buf, 41).str())); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash2: %1, new_nonce_buf: %2").arg(Logs::mb(&resDH.vnew_nonce_hash2, 16).str()).arg(Logs::mb(_authKeyData->new_nonce_buf, 41).str())); lockFinished.unlock(); return restart(); } - authKeyData->retry_id = authKeyData->auth_key_aux_hash; + _authKeyData->retry_id = _authKeyData->auth_key_aux_hash; } return dhClientParamsSend(); case mtpc_dh_gen_fail: { const auto &resDH(res_client_DH_params.c_dh_gen_fail()); - if (resDH.vnonce != authKeyData->nonce) { + if (resDH.vnonce != _authKeyData->nonce) { LOG(("AuthKey Error: received nonce <> sent nonce (in dh_gen_fail)!")); - DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&resDH.vnonce, 16).str()).arg(Logs::mb(&authKeyData->nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received nonce: %1, sent nonce: %2").arg(Logs::mb(&resDH.vnonce, 16).str()).arg(Logs::mb(&_authKeyData->nonce, 16).str())); lockFinished.unlock(); return restart(); } - if (resDH.vserver_nonce != authKeyData->server_nonce) { + if (resDH.vserver_nonce != _authKeyData->server_nonce) { LOG(("AuthKey Error: received server_nonce <> sent server_nonce (in dh_gen_fail)!")); - DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&resDH.vserver_nonce, 16).str()).arg(Logs::mb(&authKeyData->server_nonce, 16).str())); + DEBUG_LOG(("AuthKey Error: received server_nonce: %1, sent server_nonce: %2").arg(Logs::mb(&resDH.vserver_nonce, 16).str()).arg(Logs::mb(&_authKeyData->server_nonce, 16).str())); lockFinished.unlock(); return restart(); } - authKeyData->new_nonce_buf[32] = 3; + _authKeyData->new_nonce_buf[32] = 3; uchar sha1Buffer[20]; - if (resDH.vnew_nonce_hash3 != *(MTPint128*)(hashSha1(authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { + if (resDH.vnew_nonce_hash3 != *(MTPint128*)(hashSha1(_authKeyData->new_nonce_buf, 41, sha1Buffer) + 1)) { LOG(("AuthKey Error: received new_nonce_hash3 did not match!")); - DEBUG_LOG(("AuthKey Error: received new_nonce_hash3: %1, new_nonce_buf: %2").arg(Logs::mb(&resDH.vnew_nonce_hash3, 16).str()).arg(Logs::mb(authKeyData->new_nonce_buf, 41).str())); + DEBUG_LOG(("AuthKey Error: received new_nonce_hash3: %1, new_nonce_buf: %2").arg(Logs::mb(&resDH.vnew_nonce_hash3, 16).str()).arg(Logs::mb(_authKeyData->new_nonce_buf, 41).str())); lockFinished.unlock(); return restart(); @@ -2817,20 +2821,18 @@ void ConnectionPrivate::authKeyCreated() { } void ConnectionPrivate::clearAuthKeyData() { - if (authKeyData) { + if (_authKeyData) { #ifdef Q_OS_WIN - SecureZeroMemory(authKeyData, sizeof(AuthKeyCreateData)); - if (!authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(authKeyStrings->dh_prime.data(), authKeyStrings->dh_prime.size()); - if (!authKeyStrings->g_a.isEmpty()) SecureZeroMemory(authKeyStrings->g_a.data(), authKeyStrings->g_a.size()); + SecureZeroMemory(_authKeyData.get(), sizeof(AuthKeyCreateData)); + if (!_authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(_authKeyStrings->dh_prime.data(), _authKeyStrings->dh_prime.size()); + if (!_authKeyStrings->g_a.isEmpty()) SecureZeroMemory(_authKeyStrings->g_a.data(), _authKeyStrings->g_a.size()); #else memset(authKeyData, 0, sizeof(AuthKeyCreateData)); - if (!authKeyStrings->dh_prime.isEmpty()) memset(authKeyStrings->dh_prime.data(), 0, authKeyStrings->dh_prime.size()); - if (!authKeyStrings->g_a.isEmpty()) memset(authKeyStrings->g_a.data(), 0, authKeyStrings->g_a.size()); + if (!_authKeyStrings->dh_prime.isEmpty()) memset(_authKeyStrings->dh_prime.data(), 0, _authKeyStrings->dh_prime.size()); + if (!_authKeyStrings->g_a.isEmpty()) memset(_authKeyStrings->g_a.data(), 0, _authKeyStrings->g_a.size()); #endif - delete authKeyData; - authKeyData = 0; - delete authKeyStrings; - authKeyStrings = 0; + _authKeyData.reset(); + _authKeyStrings.reset(); } } @@ -2877,14 +2879,14 @@ void ConnectionPrivate::sendRequestNotSecure(const TRequest &request) { buffer.push_back(0); // tcp packet num buffer.push_back(0); buffer.push_back(0); - buffer.push_back(authKeyData->req_num); + buffer.push_back(_authKeyData->req_num); buffer.push_back(unixtime()); buffer.push_back(requestSize * 4); request.write(buffer); buffer.push_back(0); // tcp crc32 hash - ++authKeyData->msgs_sent; + ++_authKeyData->msgs_sent; - DEBUG_LOG(("AuthKey Info: sending request, size: %1, num: %2, time: %3").arg(requestSize).arg(authKeyData->req_num).arg(buffer[5])); + DEBUG_LOG(("AuthKey Info: sending request, size: %1, num: %2, time: %3").arg(requestSize).arg(_authKeyData->req_num).arg(buffer[5])); _conn->sendData(buffer); diff --git a/Telegram/SourceFiles/mtproto/connection.h b/Telegram/SourceFiles/mtproto/connection.h index 2eeacc4820..c1c2f63d04 100644 --- a/Telegram/SourceFiles/mtproto/connection.h +++ b/Telegram/SourceFiles/mtproto/connection.h @@ -164,7 +164,13 @@ private: bool sendRequest(mtpRequest &request, bool needAnyResponse, QReadLocker &lockFinished); mtpRequestId wasSent(mtpMsgId msgId) const; - int32 handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime); + enum class HandleResult { + Success, + Ignored, + RestartConnection, + ResetSession, + }; + HandleResult handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime); mtpBuffer ungzip(const mtpPrime *from, const mtpPrime *end) const; void handleMsgsStates(const QVector &ids, const std::string &states, QVector &acked); @@ -174,23 +180,25 @@ private: mutable QReadWriteLock stateConnMutex; int32 _state; - bool _needSessionReset; + bool _needSessionReset = false; void resetSession(); - ShiftedDcId dc; - Connection *_owner; - AbstractConnection *_conn, *_conn4, *_conn6; + ShiftedDcId dc = 0; + Connection *_owner = nullptr; + AbstractConnection *_conn = nullptr; + AbstractConnection *_conn4 = nullptr; + AbstractConnection *_conn6 = nullptr;; SingleTimer retryTimer; // exp retry timer - int retryTimeout; + int retryTimeout = 1; qint64 retryWillFinish; SingleTimer oldConnectionTimer; - bool oldConnection; + bool oldConnection = true; SingleTimer _waitForConnectedTimer, _waitForReceivedTimer, _waitForIPv4Timer; uint32 _waitForReceived, _waitForConnected; - TimeMs firstSentAt; + TimeMs firstSentAt = -1; QVector ackRequestData, resendRequestData; @@ -200,9 +208,10 @@ private: // remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked void requestsAcked(const QVector &ids, bool byResponse = false); - mtpPingId _pingId, _pingIdToSend; - TimeMs _pingSendAt; - mtpMsgId _pingMsgId; + mtpPingId _pingId = 0; + mtpPingId _pingIdToSend = 0; + TimeMs _pingSendAt = 0; + mtpMsgId _pingMsgId = 0; SingleTimer _pingSender; void resend(quint64 msgId, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); @@ -214,13 +223,14 @@ private: template bool readResponseNotSecure(TResponse &response); - bool restarted, _finished; + bool restarted = false; + bool _finished = false; - uint64 keyId; + uint64 keyId = 0; QReadWriteLock sessionDataMutex; - SessionData *sessionData; + SessionData *sessionData = nullptr; - bool myKeyLock; + bool myKeyLock = false; void lockKey(); void unlockKey(); @@ -228,39 +238,32 @@ private: struct AuthKeyCreateData { AuthKeyCreateData() : new_nonce(*(MTPint256*)((uchar*)new_nonce_buf)) - , auth_key_aux_hash(*(MTPlong*)((uchar*)new_nonce_buf + 33)) - , retries(0) - , g(0) - , req_num(0) - , msgs_sent(0) { - memset(new_nonce_buf, 0, sizeof(new_nonce_buf)); - memset(aesKey, 0, sizeof(aesKey)); - memset(aesIV, 0, sizeof(aesIV)); - memset(auth_key, 0, sizeof(auth_key)); + , auth_key_aux_hash(*(MTPlong*)((uchar*)new_nonce_buf + 33)) { } MTPint128 nonce, server_nonce; - uchar new_nonce_buf[41]; // 32 bytes new_nonce + 1 check byte + 8 bytes of auth_key_aux_hash + uchar new_nonce_buf[41] = { 0 }; // 32 bytes new_nonce + 1 check byte + 8 bytes of auth_key_aux_hash MTPint256 &new_nonce; MTPlong &auth_key_aux_hash; - uint32 retries; + uint32 retries = 0; MTPlong retry_id; - int32 g; + int32 g = 0; - uchar aesKey[32], aesIV[32]; - uint32 auth_key[64]; + uchar aesKey[32] = { 0 }; + uchar aesIV[32] = { 0 }; + uint32 auth_key[64] = { 0 }; MTPlong auth_key_hash; - uint32 req_num; // sent not encrypted request number - uint32 msgs_sent; + uint32 req_num = 0; // sent not encrypted request number + uint32 msgs_sent = 0; }; struct AuthKeyCreateStrings { QByteArray dh_prime; QByteArray g_a; }; - AuthKeyCreateData *authKeyData; - AuthKeyCreateStrings *authKeyStrings; + std_::unique_ptr _authKeyData; + std_::unique_ptr _authKeyStrings; void dhClientParamsSend(); void authKeyCreated(); diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index bab6da418f..821f822f6e 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -141,35 +141,6 @@ public: typedef QMap mtpPreRequestMap; typedef QMap mtpRequestMap; typedef QMap mtpMsgIdsSet; -class mtpMsgIdsMap : public QMap { -public: - typedef QMap ParentType; - - bool insert(const mtpMsgId &k, bool v) { - ParentType::const_iterator i = constFind(k); - if (i == cend()) { - if (size() >= MTPIdsBufferSize && k < min()) { - MTP_LOG(-1, ("No need to handle - %1 < min = %2").arg(k).arg(min())); - return false; - } else { - ParentType::insert(k, v); - return true; - } - } else { - MTP_LOG(-1, ("No need to handle - %1 already is in map").arg(k)); - return false; - } - } - - mtpMsgId min() const { - return isEmpty() ? 0 : cbegin().key(); - } - - mtpMsgId max() const { - ParentType::const_iterator e(cend()); - return isEmpty() ? 0 : (--e).key(); - } -}; class mtpRequestIdsMap : public QMap { public: diff --git a/Telegram/SourceFiles/mtproto/session.h b/Telegram/SourceFiles/mtproto/session.h index 204876b646..9c0bec0a8c 100644 --- a/Telegram/SourceFiles/mtproto/session.h +++ b/Telegram/SourceFiles/mtproto/session.h @@ -28,18 +28,64 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace MTP { namespace internal { -class Session; +class ReceivedMsgIds { +public: + bool registerMsgId(mtpMsgId msgId, bool needAck) { + auto i = _idsNeedAck.constFind(msgId); + if (i == _idsNeedAck.cend()) { + if (_idsNeedAck.size() < MTPIdsBufferSize || msgId > min()) { + _idsNeedAck.insert(msgId, needAck); + return true; + } + MTP_LOG(-1, ("No need to handle - %1 < min = %2").arg(msgId).arg(min())); + } else { + MTP_LOG(-1, ("No need to handle - %1 already is in map").arg(msgId)); + } + return false; + } + mtpMsgId min() const { + return _idsNeedAck.isEmpty() ? 0 : _idsNeedAck.cbegin().key(); + } + + mtpMsgId max() const { + auto end = _idsNeedAck.cend(); + return _idsNeedAck.isEmpty() ? 0 : (--end).key(); + } + + void shrink() { + auto size = _idsNeedAck.size(); + while (size-- > MTPIdsBufferSize) { + _idsNeedAck.erase(_idsNeedAck.begin()); + } + } + + enum class State { + NotFound, + NeedsAck, + NoAckNeeded, + }; + State lookup(mtpMsgId msgId) const { + auto i = _idsNeedAck.constFind(msgId); + if (i == _idsNeedAck.cend()) { + return State::NotFound; + } + return i.value() ? State::NeedsAck : State::NoAckNeeded; + } + + void clear() { + _idsNeedAck.clear(); + } + +private: + QMap _idsNeedAck; + +}; + +class Session; class SessionData { public: - SessionData(Session *creator) - : _session(0) - , _salt(0) - , _messagesSent(0) - , _fakeRequestId(-2000000000) - , _owner(creator) - , _keyChecked(false) - , _layerInited(false) { + SessionData(Session *creator) : _owner(creator) { } void setSession(uint64 session) { @@ -142,10 +188,10 @@ public: const mtpRequestIdsMap &toResendMap() const { return toResend; } - mtpMsgIdsMap &receivedIdsSet() { + ReceivedMsgIds &receivedIdsSet() { return receivedIds; } - const mtpMsgIdsMap &receivedIdsSet() const { + const ReceivedMsgIds &receivedIdsSet() const { return receivedIds; } mtpRequestIdsMap &wereAckedMap() { @@ -193,20 +239,22 @@ public: void clear(); private: - uint64 _session, _salt; + uint64 _session = 0; + uint64 _salt = 0; - uint32 _messagesSent; - mtpRequestId _fakeRequestId; + uint32 _messagesSent = 0; + mtpRequestId _fakeRequestId = -2000000000; - Session *_owner; + Session *_owner = nullptr; AuthKeyPtr _authKey; - bool _keyChecked, _layerInited; + bool _keyChecked = false; + bool _layerInited = false; mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent mtpRequestMap haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers mtpRequestIdsMap toResend; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent - mtpMsgIdsMap receivedIds; // set of received msg_id's, for checking new msg_ids + ReceivedMsgIds receivedIds; // set of received msg_id's, for checking new msg_ids mtpRequestIdsMap wereAcked; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack mtpResponseMap haveReceived; // map of request_id -> response, that should be processed in other thread mtpMsgIdsSet stateRequest; // set of msg_id's, whose state should be requested diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 1e21ef8099..9de617bf64 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -62,8 +62,9 @@ void ItemBase::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { if (p == _openl || p == _savel || p == _cancell) { - a_iconOver.start(active ? 1 : 0); - _a_iconOver.start(); + if (iconAnimated()) { + _a_iconOver.start([this] { Ui::repaintHistoryItem(_parent); }, active ? 0. : 1., active ? 1. : 0., st::msgFileOverDuration); + } } ItemBase::clickHandlerActiveChanged(p, active); } @@ -78,19 +79,6 @@ void RadialProgressItem::setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&sav _cancell = std_::move(cancell); } -void RadialProgressItem::step_iconOver(float64 ms, bool timer) { - float64 dt = ms / st::msgFileOverDuration; - if (dt >= 1) { - a_iconOver.finish(); - _a_iconOver.stop(); - } else if (!timer) { - a_iconOver.update(dt, anim::linear); - } - if (timer && iconAnimated()) { - Ui::repaintHistoryItem(_parent); - } -} - void RadialProgressItem::step_radial(TimeMs ms, bool timer) { if (timer) { Ui::repaintHistoryItem(_parent); @@ -104,20 +92,17 @@ void RadialProgressItem::step_radial(TimeMs ms, bool timer) { void RadialProgressItem::ensureRadial() { if (!_radial) { - _radial = new Ui::RadialAnimation(animation(const_cast(this), &RadialProgressItem::step_radial)); + _radial = std_::make_unique(animation(const_cast(this), &RadialProgressItem::step_radial)); } } void RadialProgressItem::checkRadialFinished() { if (_radial && !_radial->animating() && dataLoaded()) { - delete _radial; - _radial = nullptr; + _radial.reset(); } } -RadialProgressItem::~RadialProgressItem() { - delete base::take(_radial); -} +RadialProgressItem::~RadialProgressItem() = default; void StatusText::update(int newSize, int fullSize, int duration, TimeMs realDuration) { setSize(newSize); @@ -174,7 +159,7 @@ private: base::lambda_copy _updateCallback; Ui::RoundCheckbox _check; - FloatAnimation _pression; + Animation _pression; bool _active = false; bool _pressed = false; @@ -393,13 +378,9 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const p.setPen(Qt::NoPen); if (selected) { p.setBrush(st::msgDateImgBgSelected); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - auto over = a_iconOver.current(); - p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, over)); } else { auto over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _savel)); - p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); + p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, _a_iconOver.current(context->ms, over ? 1. : 0.))); } { @@ -541,13 +522,9 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const p.setPen(Qt::NoPen); if (selected) { p.setBrush(st::msgFileInBgSelected); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - auto over = a_iconOver.current(); - p.setBrush(anim::brush(st::msgFileInBg, st::msgFileInBgOver, over)); } else { auto over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl)); - p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); + p.setBrush(anim::brush(st::msgFileInBg, st::msgFileInBgOver, _a_iconOver.current(context->ms, over ? 1. : 0.))); } { @@ -752,13 +729,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con p.setPen(Qt::NoPen); if (selected) { p.setBrush(st::msgFileInBgSelected); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - auto over = a_iconOver.current(); - p.setBrush(anim::brush(_st.songIconBg, _st.songOverBg, over)); } else { auto over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl)); - p.setBrush(over ? _st.songOverBg : _st.songIconBg); + p.setBrush(anim::brush(_st.songIconBg, _st.songOverBg, _a_iconOver.current(context->ms, over ? 1. : 0.))); } { @@ -828,13 +801,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con p.setPen(Qt::NoPen); if (selected) { p.setBrush(wthumb ? st::msgDateImgBgSelected : documentSelectedColor(_colorIndex)); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - auto over = a_iconOver.current(); - p.setBrush(anim::brush(wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex), wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex), over)); } else { auto over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(over ? (wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex)) : (wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex))); + p.setBrush(anim::brush(wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex), wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex), _a_iconOver.current(context->ms, over ? 1. : 0.))); } p.setOpacity(radialOpacity * p.opacity()); diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index ca6a7857c5..8e23bb7155 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -86,10 +86,7 @@ protected: class RadialProgressItem : public ItemBase { public: - RadialProgressItem(HistoryItem *parent) : ItemBase(parent) - , _radial(0) - , a_iconOver(0, 0) - , _a_iconOver(animation(this, &RadialProgressItem::step_iconOver)) { + RadialProgressItem(HistoryItem *parent) : ItemBase(parent) { } RadialProgressItem(const RadialProgressItem &other) = delete; @@ -111,7 +108,6 @@ protected: setLinks(MakeShared(document), std_::move(save), MakeShared(document)); } - void step_iconOver(float64 ms, bool timer); void step_radial(TimeMs ms, bool timer); void ensureRadial(); @@ -131,8 +127,7 @@ protected: return false; } - Ui::RadialAnimation *_radial; - anim::value a_iconOver; + std_::unique_ptr _radial; Animation _a_iconOver; }; diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 79f272c6cb..5d6988c6b0 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -362,7 +362,7 @@ private: QString _header; - FloatAnimation _a_show; + Animation _a_show; Window::SlideDirection _showDirection; QPixmap _cacheUnder, _cacheOver; diff --git a/Telegram/SourceFiles/passcodewidget.h b/Telegram/SourceFiles/passcodewidget.h index aca9921b75..bb19963323 100644 --- a/Telegram/SourceFiles/passcodewidget.h +++ b/Telegram/SourceFiles/passcodewidget.h @@ -51,7 +51,7 @@ private: void showAll(); void hideAll(); - FloatAnimation _a_show; + Animation _a_show; bool _showBack = false; QPixmap _cacheUnder, _cacheOver; diff --git a/Telegram/SourceFiles/profile/profile_block_channel_members.cpp b/Telegram/SourceFiles/profile/profile_block_channel_members.cpp index b51c33f93d..d8475f9084 100644 --- a/Telegram/SourceFiles/profile/profile_block_channel_members.cpp +++ b/Telegram/SourceFiles/profile/profile_block_channel_members.cpp @@ -65,7 +65,7 @@ void ChannelMembersWidget::addButton(const QString &text, ChildWidgetsetText(text); } else { - (*button) = new Ui::LeftOutlineButton(this, text, st::defaultLeftOutlineButton); + button->create(this, text, st::defaultLeftOutlineButton); (*button)->show(); connect(*button, SIGNAL(clicked()), this, slot); } diff --git a/Telegram/SourceFiles/profile/profile_block_common_groups.h b/Telegram/SourceFiles/profile/profile_block_common_groups.h index 55d8d54a94..b005668ca3 100644 --- a/Telegram/SourceFiles/profile/profile_block_common_groups.h +++ b/Telegram/SourceFiles/profile/profile_block_common_groups.h @@ -65,7 +65,7 @@ private: Item *computeItem(PeerData *group); QMap _dataMap; - FloatAnimation _height; + Animation _height; int32 _preloadGroupId = 0; mtpRequestId _preloadRequestId = 0; diff --git a/Telegram/SourceFiles/profile/profile_block_info.h b/Telegram/SourceFiles/profile/profile_block_info.h index 04bee1181f..8736395f85 100644 --- a/Telegram/SourceFiles/profile/profile_block_info.h +++ b/Telegram/SourceFiles/profile/profile_block_info.h @@ -84,7 +84,7 @@ private: ChildWidget _username = { nullptr }; ChildWidget _commonGroups = { nullptr }; - FloatAnimation _height; + Animation _height; bool _showFinished = false; bool _forceHiddenCommonGroups = false; diff --git a/Telegram/SourceFiles/profile/profile_block_invite_link.cpp b/Telegram/SourceFiles/profile/profile_block_invite_link.cpp index b4355e9cfb..58edf35c78 100644 --- a/Telegram/SourceFiles/profile/profile_block_invite_link.cpp +++ b/Telegram/SourceFiles/profile/profile_block_invite_link.cpp @@ -23,8 +23,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_profile.h" #include "ui/widgets/labels.h" +#include "ui/toast/toast.h" #include "boxes/confirmbox.h" #include "observer_peer.h" +#include "mainwindow.h" #include "lang.h" namespace Profile { @@ -108,7 +110,9 @@ void InviteLinkWidget::refreshLink() { } QApplication::clipboard()->setText(link); - Ui::showLayer(new InformBox(lang(lng_group_invite_copied))); + Ui::Toast::Config toast; + toast.text = lang(lng_group_invite_copied); + Ui::Toast::Show(App::wnd(), toast); return false; }); } diff --git a/Telegram/SourceFiles/profile/profile_cover_drop_area.h b/Telegram/SourceFiles/profile/profile_cover_drop_area.h index c70d4f25e7..6825537a7b 100644 --- a/Telegram/SourceFiles/profile/profile_cover_drop_area.h +++ b/Telegram/SourceFiles/profile/profile_cover_drop_area.h @@ -45,7 +45,7 @@ private: int _titleWidth, _subtitleWidth; QPixmap _cache; - FloatAnimation _a_appearance; + Animation _a_appearance; bool _hiding = false; HideFinishCallback _hideFinishCallback; diff --git a/Telegram/SourceFiles/profile/profile_userpic_button.h b/Telegram/SourceFiles/profile/profile_userpic_button.h index f5bc9a00ff..5700aa0c82 100644 --- a/Telegram/SourceFiles/profile/profile_userpic_button.h +++ b/Telegram/SourceFiles/profile/profile_userpic_button.h @@ -54,7 +54,7 @@ private: PeerData *_peer; bool _waiting = false; QPixmap _userpic, _oldUserpic; - FloatAnimation _a_appearance; + Animation _a_appearance; }; diff --git a/Telegram/SourceFiles/settings/settings_block_widget.h b/Telegram/SourceFiles/settings/settings_block_widget.h index 8d651f827f..fcc55fc3c9 100644 --- a/Telegram/SourceFiles/settings/settings_block_widget.h +++ b/Telegram/SourceFiles/settings/settings_block_widget.h @@ -80,7 +80,7 @@ private: void createChildRow(ChildWidget> &child, style::margins &margin, const style::margins &padding, Args&&... args) { ChildWidget plainChild = { nullptr }; createChildRow(plainChild, margin, std_::forward(args)...); - child = new Ui::WidgetSlideWrap(this, plainChild, padding, [this]() { + child.create(this, plainChild, padding, [this]() { rowHeightUpdated(); }); margin.setLeft(margin.left() - padding.left()); diff --git a/Telegram/SourceFiles/stickers/emoji_pan.cpp b/Telegram/SourceFiles/stickers/emoji_pan.cpp index fe3a17ce82..aaae3e6f95 100644 --- a/Telegram/SourceFiles/stickers/emoji_pan.cpp +++ b/Telegram/SourceFiles/stickers/emoji_pan.cpp @@ -41,9 +41,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace internal { -EmojiColorPicker::EmojiColorPicker() : TWidget() -, a_opacity(0) -, _a_appearance(animation(this, &EmojiColorPicker::step_appearance)) +EmojiColorPicker::EmojiColorPicker(QWidget *parent) : TWidget(parent) , _shadow(st::defaultDropdownShadow) { memset(_variants, 0, sizeof(_variants)); @@ -78,15 +76,21 @@ void EmojiColorPicker::showEmoji(uint32 code) { void EmojiColorPicker::paintEvent(QPaintEvent *e) { Painter p(this); - if (!_cache.isNull()) { - p.setOpacity(a_opacity.current()); + auto opacity = _a_opacity.current(getms(), _hiding ? 0. : 1.); + if (opacity < 1.) { + if (opacity > 0.) { + p.setOpacity(opacity); + } else { + return; + } } if (e->rect() != rect()) { p.setClipRect(e->rect()); } - int32 w = st::defaultDropdownShadow.width(), h = st::defaultDropdownShadow.height(); - QRect r = QRect(w, h, width() - 2 * w, height() - 2 * h); + auto w = st::defaultDropdownShadow.width(); + auto h = st::defaultDropdownShadow.height(); + auto r = QRect(w, h, width() - 2 * w, height() - 2 * h); _shadow.paint(p, r, st::defaultDropdownShadowShift); if (_cache.isNull()) { @@ -151,14 +155,9 @@ void EmojiColorPicker::mouseMoveEvent(QMouseEvent *e) { handleMouseMove(e->globalPos()); } -void EmojiColorPicker::step_appearance(float64 ms, bool timer) { - if (_cache.isNull()) { - _a_appearance.stop(); - return; - } - float64 dt = ms / st::defaultDropdownDuration; - if (dt >= 1) { - a_opacity.finish(); +void EmojiColorPicker::animationCallback() { + update(); + if (!_a_opacity.animating()) { _cache = QPixmap(); if (_hiding) { hide(); @@ -167,17 +166,12 @@ void EmojiColorPicker::step_appearance(float64 ms, bool timer) { _lastMousePos = QCursor::pos(); updateSelected(); } - _a_appearance.stop(); - } else { - a_opacity.update(dt, anim::linear); } - if (timer) update(); } void EmojiColorPicker::hideFast() { clearSelection(); - if (_a_appearance.animating()) _a_appearance.stop(); - a_opacity = anim::value(); + _a_opacity.finish(); _cache = QPixmap(); hide(); emit hidden(); @@ -190,29 +184,23 @@ void EmojiColorPicker::hideAnimated() { clearSelection(); } _hiding = true; - a_opacity.start(0); - _a_appearance.start(); + _a_opacity.start([this] { animationCallback(); }, 1., 0., st::defaultDropdownDuration); } void EmojiColorPicker::showAnimated() { if (_ignoreShow) return; - _hiding = false; - if (!isHidden() && a_opacity.current() == 1) { - if (_a_appearance.animating()) { - _a_appearance.stop(); - _cache = QPixmap(); - } + if (!isHidden() && !_hiding) { return; } + _hiding = false; if (_cache.isNull()) { auto w = st::defaultDropdownShadow.width(), h = st::defaultDropdownShadow.height(); _cache = myGrab(this, QRect(w, h, width() - 2 * w, height() - 2 * h)); clearSelection(); } show(); - a_opacity.start(1); - _a_appearance.start(); + _a_opacity.start([this] { animationCallback(); }, 0., 1., st::defaultDropdownDuration); } void EmojiColorPicker::clearSelection() { @@ -266,13 +254,14 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) { } EmojiPanInner::EmojiPanInner(QWidget *parent) : TWidget(parent) -, _maxHeight(int(st::emojiPanMaxHeight) - st::emojiCategory.height) { +, _maxHeight(int(st::emojiPanMaxHeight) - st::emojiCategory.height) +, _picker(this) { resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight()); setMouseTracking(true); setAttribute(Qt::WA_OpaquePaintEvent); - _picker.hide(); + _picker->hide(); _esize = EmojiSizes[EIndex + 1]; @@ -282,8 +271,8 @@ EmojiPanInner::EmojiPanInner(QWidget *parent) : TWidget(parent) _showPickerTimer.setSingleShot(true); connect(&_showPickerTimer, SIGNAL(timeout()), this, SLOT(onShowPicker())); - connect(&_picker, SIGNAL(emojiSelected(EmojiPtr)), this, SLOT(onColorSelected(EmojiPtr))); - connect(&_picker, SIGNAL(hidden()), this, SLOT(onPickerHidden())); + connect(_picker, SIGNAL(emojiSelected(EmojiPtr)), this, SLOT(onColorSelected(EmojiPtr))); + connect(_picker, SIGNAL(hidden()), this, SLOT(onPickerHidden())); } void EmojiPanInner::setMaxHeight(int32 h) { @@ -357,7 +346,7 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) { int32 index = i * EmojiPanPerRow + j; if (index >= size) break; - auto selected = (!_picker.isHidden() && c * MatrixRowShift + index == _pickerSel) || (c * MatrixRowShift + index == _selected); + auto selected = (!_picker->isHidden() && c * MatrixRowShift + index == _pickerSel) || (c * MatrixRowShift + index == _selected); QPoint w(st::emojiPanPadding + j * st::emojiPanSize.width(), y + i * st::emojiPanSize.height()); if (selected) { @@ -372,8 +361,8 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) { } bool EmojiPanInner::checkPickerHide() { - if (!_picker.isHidden() && _pickerSel >= 0) { - _picker.hideAnimated(); + if (!_picker->isHidden() && _pickerSel >= 0) { + _picker->hideAnimated(); _pickerSel = -1; updateSelected(); return true; @@ -408,14 +397,14 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) { _pressedSel = -1; _lastMousePos = e->globalPos(); - if (!_picker.isHidden()) { - if (_picker.rect().contains(_picker.mapFromGlobal(_lastMousePos))) { - return _picker.handleMouseRelease(QCursor::pos()); + if (!_picker->isHidden()) { + if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) { + return _picker->handleMouseRelease(QCursor::pos()); } else if (_pickerSel >= 0) { int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift; if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) { if (cEmojiVariants().constFind(_emojis[tab][sel]->code) != cEmojiVariants().cend()) { - _picker.hideAnimated(); + _picker->hideAnimated(); _pickerSel = -1; } } @@ -426,7 +415,7 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) { if (_showPickerTimer.isActive()) { _showPickerTimer.stop(); _pickerSel = -1; - _picker.hide(); + _picker->hide(); } if (_selected < 0 || _selected != pressed) return; @@ -438,7 +427,7 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) { int tab = (_selected / MatrixRowShift), sel = _selected % MatrixRowShift; if (sel < _emojis[tab].size()) { EmojiPtr emoji(_emojis[tab][sel]); - if (emoji->color && !_picker.isHidden()) return; + if (emoji->color && !_picker->isHidden()) return; selectEmoji(emoji); } @@ -493,16 +482,16 @@ void EmojiPanInner::onShowPicker() { int32 size = (c == tab) ? (sel - (sel % EmojiPanPerRow)) : _counts[c], rows = (size / EmojiPanPerRow) + ((size % EmojiPanPerRow) ? 1 : 0); y += st::emojiPanHeader + (rows * st::emojiPanSize.height()); } - y -= _picker.height() - st::buttonRadius + _visibleTop; + y -= _picker->height() - st::buttonRadius + _visibleTop; if (y < 0) { - y += _picker.height() - st::buttonRadius + st::emojiPanSize.height() - st::buttonRadius; + y += _picker->height() - st::buttonRadius + st::emojiPanSize.height() - st::buttonRadius; } - int xmax = width() - _picker.width(); + int xmax = width() - _picker->width(); float64 coef = float64(sel % EmojiPanPerRow) / float64(EmojiPanPerRow - 1); if (rtl()) coef = 1. - coef; - _picker.move(qRound(xmax * coef), y); + _picker->move(qRound(xmax * coef), y); - _picker.showEmoji(_emojis[tab][sel]->code); + _picker->showEmoji(_emojis[tab][sel]->code); emit disableScroll(true); } } @@ -545,16 +534,16 @@ void EmojiPanInner::onColorSelected(EmojiPtr emoji) { } } selectEmoji(emoji); - _picker.hideAnimated(); + _picker->hideAnimated(); } void EmojiPanInner::mouseMoveEvent(QMouseEvent *e) { _lastMousePos = e->globalPos(); - if (!_picker.isHidden()) { - if (_picker.rect().contains(_picker.mapFromGlobal(_lastMousePos))) { - return _picker.handleMouseMove(QCursor::pos()); + if (!_picker->isHidden()) { + if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) { + return _picker->handleMouseMove(QCursor::pos()); } else { - _picker.clearSelection(); + _picker->clearSelection(); } } updateSelected(); @@ -593,8 +582,8 @@ DBIEmojiTab EmojiPanInner::currentTab(int yOffset) const { } void EmojiPanInner::hideFinish() { - if (!_picker.isHidden()) { - _picker.hideFast(); + if (!_picker->isHidden()) { + _picker->hideFast(); _pickerSel = -1; clearSelection(); } @@ -612,8 +601,8 @@ void EmojiPanInner::refreshRecent() { } void EmojiPanInner::fillPanels(QVector &panels) { - if (_picker.parentWidget() != parentWidget()) { - _picker.setParent(parentWidget()); + if (_picker->parentWidget() != parentWidget()) { + _picker->setParent(parentWidget()); } for (int32 i = 0; i < panels.size(); ++i) { panels.at(i)->hide(); @@ -630,7 +619,7 @@ void EmojiPanInner::fillPanels(QVector &panels) { panels.back()->show(); y += st::emojiPanHeader + rows * st::emojiPanSize.height(); } - _picker.raise(); + _picker->raise(); } void EmojiPanInner::refreshPanels(QVector &panels) { @@ -684,11 +673,11 @@ void EmojiPanInner::setSelected(int newSelected) { updateSelected(); setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default); - if (_selected >= 0 && !_picker.isHidden()) { + if (_selected >= 0 && !_picker->isHidden()) { if (_selected != _pickerSel) { - _picker.hideAnimated(); + _picker->hideAnimated(); } else { - _picker.showAnimated(); + _picker->showAnimated(); } } } @@ -1633,14 +1622,15 @@ void StickerPanInner::clearInlineRowsPanel() { void StickerPanInner::refreshSwitchPmButton(const InlineCacheEntry *entry) { if (!entry || entry->switchPmText.isEmpty()) { - _switchPmButton.reset(); + _switchPmButton.destroy(); _switchPmStartToken.clear(); } else { if (!_switchPmButton) { - _switchPmButton = std_::make_unique(this, QString(), st::switchPmButton); + _switchPmButton.create(this, QString(), st::switchPmButton); _switchPmButton->show(); _switchPmButton->move(st::inlineResultsLeft - st::buttonRadius, st::emojiPanHeader); - connect(_switchPmButton.get(), SIGNAL(clicked()), this, SLOT(onSwitchPm())); + _switchPmButton->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); + connect(_switchPmButton, SIGNAL(clicked()), this, SLOT(onSwitchPm())); } _switchPmButton->setText(entry->switchPmText); // doesn't perform text.toUpper() _switchPmStartToken = entry->switchPmStartToken; diff --git a/Telegram/SourceFiles/stickers/emoji_pan.h b/Telegram/SourceFiles/stickers/emoji_pan.h index 463f43faba..d4126d483d 100644 --- a/Telegram/SourceFiles/stickers/emoji_pan.h +++ b/Telegram/SourceFiles/stickers/emoji_pan.h @@ -63,7 +63,7 @@ class EmojiColorPicker : public TWidget { Q_OBJECT public: - EmojiColorPicker(); + EmojiColorPicker(QWidget *parent); void showEmoji(uint32 code); @@ -90,7 +90,7 @@ protected: void mouseMoveEvent(QMouseEvent *e) override; private: - void step_appearance(float64 ms, bool timer); + void animationCallback(); void drawVariant(Painter &p, int variant); @@ -107,9 +107,7 @@ private: bool _hiding = false; QPixmap _cache; - - anim::value a_opacity; - Animation _a_appearance; + Animation _a_opacity; QTimer _hideTimer; @@ -192,8 +190,9 @@ private: int _pickerSel = -1; QPoint _lastMousePos; - EmojiColorPicker _picker; + ChildWidget _picker; QTimer _showPickerTimer; + }; struct StickerIcon { @@ -368,14 +367,12 @@ private: QTimer _updateInlineItems; bool _inlineWithThumb = false; - std_::unique_ptr _switchPmButton; + ChildWidget _switchPmButton = { nullptr }; QString _switchPmStartToken; typedef QVector InlineItems; struct InlineRow { - InlineRow() : height(0) { - } - int32 height; + int height = 0; InlineItems items; }; typedef QVector InlineRows; @@ -629,17 +626,17 @@ private: Ui::PanelAnimation::Origin _origin = Ui::PanelAnimation::Origin::BottomRight; std_::unique_ptr _showAnimation; - FloatAnimation _a_show; + Animation _a_show; bool _hiding = false; QPixmap _cache; - FloatAnimation _a_opacity; + Animation _a_opacity; QTimer _hideTimer; bool _inPanelGrab = false; class SlideAnimation; std_::unique_ptr _slideAnimation; - FloatAnimation _a_slide; + Animation _a_slide; ChildWidget _recent; ChildWidget _people; @@ -655,7 +652,7 @@ private: int _iconSel = 0; int _iconDown = -1; bool _iconsDragging = false; - Animation _a_icons; + BasicAnimation _a_icons; QPoint _iconsMousePos, _iconsMouseDown; int _iconsLeft = 0; int _iconsTop = 0; diff --git a/Telegram/SourceFiles/ui/animation.cpp b/Telegram/SourceFiles/ui/animation.cpp index b6ad772070..b0f29b7d3b 100644 --- a/Telegram/SourceFiles/ui/animation.cpp +++ b/Telegram/SourceFiles/ui/animation.cpp @@ -112,7 +112,7 @@ void registerClipManager(Media::Clip::Manager *manager) { } // anim -void Animation::start() { +void BasicAnimation::start() { if (!_manager) return; _callbacks.start(); @@ -120,7 +120,7 @@ void Animation::start() { _animating = true; } -void Animation::stop() { +void BasicAnimation::stop() { if (!_manager) return; _animating = false; @@ -132,7 +132,7 @@ AnimationManager::AnimationManager() : _timer(this), _iterating(false) { connect(&_timer, SIGNAL(timeout()), this, SLOT(timeout())); } -void AnimationManager::start(Animation *obj) { +void AnimationManager::start(BasicAnimation *obj) { if (_iterating) { _starting.insert(obj); if (!_stopping.isEmpty()) { @@ -146,7 +146,7 @@ void AnimationManager::start(Animation *obj) { } } -void AnimationManager::stop(Animation *obj) { +void AnimationManager::stop(BasicAnimation *obj) { if (_iterating) { _stopping.insert(obj); if (!_starting.isEmpty()) { diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 0c7c2ac97b..5086891201 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -383,12 +383,12 @@ FORCE_INLINE QBrush brush(const style::color &a, const style::color &b, float64 }; -class Animation; +class BasicAnimation; class AnimationImplementation { public: virtual void start() {} - virtual void step(Animation *a, TimeMs ms, bool timer) = 0; + virtual void step(BasicAnimation *a, TimeMs ms, bool timer) = 0; virtual ~AnimationImplementation() {} }; @@ -407,7 +407,7 @@ public: } void start() { _implementation->start(); } - void step(Animation *a, TimeMs ms, bool timer) { _implementation->step(a, ms, timer); } + void step(BasicAnimation *a, TimeMs ms, bool timer) { _implementation->step(a, ms, timer); } ~AnimationCallbacks() { delete base::take(_implementation); } private: @@ -415,9 +415,9 @@ private: }; -class Animation { +class BasicAnimation { public: - Animation(AnimationCallbacks &&callbacks) + BasicAnimation(AnimationCallbacks &&callbacks) : _callbacks(std_::move(callbacks)) , _animating(false) { } @@ -437,7 +437,7 @@ public: return _animating; } - ~Animation() { + ~BasicAnimation() { if (_animating) stop(); } @@ -459,7 +459,7 @@ public: _started = float64(getms()); } - void step(Animation *a, TimeMs ms, bool timer) { + void step(BasicAnimation *a, TimeMs ms, bool timer) { (_obj->*_method)(ms - _started, timer); } @@ -482,7 +482,7 @@ public: AnimationCallbacksAbsolute(Type *obj, Method method) : _obj(obj), _method(method) { } - void step(Animation *a, TimeMs ms, bool timer) { + void step(BasicAnimation *a, TimeMs ms, bool timer) { (_obj->*_method)(ms, timer); } @@ -508,7 +508,7 @@ public: _started = float64(getms()); } - void step(Animation *a, TimeMs ms, bool timer) { + void step(BasicAnimation *a, TimeMs ms, bool timer) { (_obj->*_method)(_param, ms - _started, timer); } @@ -532,7 +532,7 @@ public: AnimationCallbacksAbsoluteWithParam(Param param, Type *obj, Method method) : _param(param), _obj(obj), _method(method) { } - void step(Animation *a, TimeMs ms, bool timer) { + void step(BasicAnimation *a, TimeMs ms, bool timer) { (_obj->*_method)(_param, ms, timer); } @@ -547,12 +547,8 @@ AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacks return AnimationCallbacks(new AnimationCallbacksAbsoluteWithParam(param, obj, method)); } -template -class SimpleAnimation { +class Animation { public: - using ValueType = typename AnimType::ValueType; - using Callback = base::lambda; - void step(TimeMs ms) { if (_data) { _data->a_animation.step(ms); @@ -576,24 +572,32 @@ public: return animating(); } - ValueType current() const { + float64 current() const { t_assert(_data != nullptr); return _data->value.current(); } - ValueType current(const ValueType &def) const { - return _data ? current() : def; + float64 current(float64 def) const { + return animating() ? current() : def; } - ValueType current(TimeMs ms, const ValueType &def) { + float64 current(TimeMs ms, float64 def) { return animating(ms) ? current() : def; } + static constexpr auto kLongAnimationDuration = 1000; + template - void start(Lambda &&updateCallback, const ValueType &from, const ValueType &to, float64 duration, const anim::transition &transition = anim::linear) { + void start(Lambda &&updateCallback, float64 from, float64 to, float64 duration, const anim::transition &transition = anim::linear) { + auto isLong = (duration >= kLongAnimationDuration); if (_data) { - _data->pause.restart(); + if (!isLong) { + _data->pause.restart(); + } } else { _data = std_::make_unique(from, std_::forward(updateCallback)); } + if (isLong) { + _data->pause.release(); + } _data->value.start(to); _data->duration = duration; _data->transition = transition; @@ -611,12 +615,12 @@ public: private: struct Data { template ::value>> - Data(const ValueType &from, Lambda &&updateCallback) + Data(float64 from, Lambda &&updateCallback) : value(from, from) , a_animation(animation(this, &Data::step)) , updateCallback(std_::move(updateCallback)) { } - Data(const ValueType &from, const base::lambda_copy &updateCallback) + Data(float64 from, const base::lambda_copy &updateCallback) : value(from, from) , a_animation(animation(this, &Data::step)) , updateCallback(base::lambda_copy(updateCallback)) { @@ -633,9 +637,9 @@ private: updateCallback(); } - AnimType value; - Animation a_animation; - Callback updateCallback; + anim::value value; + BasicAnimation a_animation; + base::lambda updateCallback; float64 duration = 0.; anim::transition transition = anim::linear; MTP::PauseHolder pause; @@ -644,16 +648,14 @@ private: }; -using FloatAnimation = SimpleAnimation; - class AnimationManager : public QObject { Q_OBJECT public: AnimationManager(); - void start(Animation *obj); - void stop(Animation *obj); + void start(BasicAnimation *obj); + void stop(BasicAnimation *obj); public slots: void timeout(); @@ -661,7 +663,7 @@ public slots: void clipCallback(Media::Clip::Reader *reader, qint32 threadIndex, qint32 notification); private: - using AnimatingObjects = OrderedSet; + using AnimatingObjects = OrderedSet; AnimatingObjects _objects, _starting, _stopping; QTimer _timer; bool _iterating; diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp index 1706d1b8df..b4b1535c29 100644 --- a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp +++ b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp @@ -28,9 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Ui { HistoryDownButton::HistoryDownButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple) -, _st(st) -//, a_arrowOpacity(st::historyAttachEmoji.opacity, st::historyAttachEmoji.opacity) -, _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) { +, _st(st) { resize(_st.width, _st.height); setCursor(style::cur_pointer); @@ -49,12 +47,6 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) { Painter p(this); auto ms = getms(); - auto opacity = _a_show.current(ms, _shown ? 1. : 0.); - if (opacity == 0.) { - if (!_shown) hide(); - return; - } - p.setOpacity(opacity); auto over = isOver(); auto down = isDown(); ((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width()); @@ -80,44 +72,6 @@ void HistoryDownButton::setUnreadCount(int unreadCount) { update(); } -bool HistoryDownButton::hidden() const { - return !_shown; -} - -void HistoryDownButton::showAnimated() { - if (_shown) return; - - if (isHidden()) show(); - toggleAnimated(); -} - -void HistoryDownButton::hideAnimated() { - if (!_shown) return; - toggleAnimated(); -} - -void HistoryDownButton::toggleAnimated() { - _shown = !_shown; - float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.; - _a_show.start([this] { update(); }, from, to, st::historyToDownDuration); -} - -void HistoryDownButton::finishAnimation() { - _a_show.finish(); - setVisible(_shown); -} - -void HistoryDownButton::step_arrowOver(float64 ms, bool timer) { - float64 dt = ms / st::historyAttachEmoji.duration; - if (dt >= 1) { - _a_arrowOver.stop(); - a_arrowOpacity.finish(); - } else { - a_arrowOpacity.update(dt, anim::linear); - } - if (timer) update(); -} - EmojiButton::EmojiButton(QWidget *parent, const style::IconButton &st) : RippleButton(parent, st.ripple) , _st(st) , _a_loading(animation(this, &EmojiButton::step_loading)) { diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.h b/Telegram/SourceFiles/ui/buttons/history_down_button.h index ab009c1d13..d19dce1766 100644 --- a/Telegram/SourceFiles/ui/buttons/history_down_button.h +++ b/Telegram/SourceFiles/ui/buttons/history_down_button.h @@ -34,13 +34,6 @@ public: return _unreadCount; } - bool hidden() const; - - void showAnimated(); - void hideAnimated(); - - void finishAnimation(); - protected: void paintEvent(QPaintEvent *e) override; @@ -48,18 +41,8 @@ protected: QPoint prepareRippleStartPosition() const override; private: - void toggleAnimated(); - void step_arrowOver(float64 ms, bool timer); - const style::TwoIconButton &_st; - bool _shown = false; - - anim::value a_arrowOpacity; - Animation _a_arrowOver; - - FloatAnimation _a_show; - int _unreadCount = 0; }; @@ -81,8 +64,8 @@ private: const style::IconButton &_st; bool _loading = false; - FloatAnimation a_loading; - Animation _a_loading; + Animation a_loading; + BasicAnimation _a_loading; void step_loading(TimeMs ms, bool timer) { if (timer) { diff --git a/Telegram/SourceFiles/ui/effects/radial_animation.h b/Telegram/SourceFiles/ui/effects/radial_animation.h index c648f01bbd..addf336982 100644 --- a/Telegram/SourceFiles/ui/effects/radial_animation.h +++ b/Telegram/SourceFiles/ui/effects/radial_animation.h @@ -51,7 +51,7 @@ private: float64 _opacity = 0.; anim::value a_arcEnd; anim::value a_arcStart; - Animation _animation; + BasicAnimation _animation; }; diff --git a/Telegram/SourceFiles/ui/effects/ripple_animation.cpp b/Telegram/SourceFiles/ui/effects/ripple_animation.cpp index e77e8b71be..eb88bd22d5 100644 --- a/Telegram/SourceFiles/ui/effects/ripple_animation.cpp +++ b/Telegram/SourceFiles/ui/effects/ripple_animation.cpp @@ -46,8 +46,8 @@ private: int _radiusTo = 0; bool _hiding = false; - FloatAnimation _show; - FloatAnimation _hide; + Animation _show; + Animation _hide; QPixmap _cache; QImage _frame; diff --git a/Telegram/SourceFiles/ui/effects/round_checkbox.h b/Telegram/SourceFiles/ui/effects/round_checkbox.h index f0769186f7..4d11bff91a 100644 --- a/Telegram/SourceFiles/ui/effects/round_checkbox.h +++ b/Telegram/SourceFiles/ui/effects/round_checkbox.h @@ -42,8 +42,8 @@ public: private: struct Icon { - FloatAnimation fadeIn; - FloatAnimation fadeOut; + Animation fadeIn; + Animation fadeOut; QPixmap wideCheckCache; }; void removeFadeOutedIcons(); @@ -87,7 +87,7 @@ private: PaintRoundImage _paintRoundImage; QPixmap _wideCache; - FloatAnimation _selection; + Animation _selection; RoundCheckbox _check; diff --git a/Telegram/SourceFiles/ui/effects/slide_animation.h b/Telegram/SourceFiles/ui/effects/slide_animation.h index 241e6569ba..b168e8335c 100644 --- a/Telegram/SourceFiles/ui/effects/slide_animation.h +++ b/Telegram/SourceFiles/ui/effects/slide_animation.h @@ -40,7 +40,7 @@ public: } private: - FloatAnimation _animation; + Animation _animation; QPixmap _leftSnapshot; QPixmap _rightSnapshot; bool _slideLeft = false; diff --git a/Telegram/SourceFiles/ui/effects/widget_fade_wrap.cpp b/Telegram/SourceFiles/ui/effects/widget_fade_wrap.cpp index 6dfb34f2a8..aa0678c5bc 100644 --- a/Telegram/SourceFiles/ui/effects/widget_fade_wrap.cpp +++ b/Telegram/SourceFiles/ui/effects/widget_fade_wrap.cpp @@ -29,7 +29,7 @@ FadeAnimation::FadeAnimation(TWidget *widget) : _widget(widget) { bool FadeAnimation::paint(Painter &p) { if (_cache.isNull()) return false; - p.setOpacity(_animation.current(_visible ? 1. : 0.)); + p.setOpacity(_animation.current(getms(), _visible ? 1. : 0.)); p.drawPixmap(0, 0, _cache); return true; } diff --git a/Telegram/SourceFiles/ui/effects/widget_fade_wrap.h b/Telegram/SourceFiles/ui/effects/widget_fade_wrap.h index 52f2f5b507..fb21cc2964 100644 --- a/Telegram/SourceFiles/ui/effects/widget_fade_wrap.h +++ b/Telegram/SourceFiles/ui/effects/widget_fade_wrap.h @@ -52,7 +52,7 @@ private: void updateCallback(); TWidget *_widget; - FloatAnimation _animation; + Animation _animation; QPixmap _cache; bool _visible = false; diff --git a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp index 353636c8e5..690b401c24 100644 --- a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp +++ b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.cpp @@ -31,8 +31,7 @@ WidgetSlideWrap::WidgetSlideWrap(QWidget *parent , _entity(entity) , _padding(entityPadding) , _duration(duration) -, _updateCallback(std_::move(updateCallback)) -, _a_height(animation(this, &WidgetSlideWrap::step_height)) { +, _updateCallback(std_::move(updateCallback)) { _entity->setParent(this); auto margins = getMargins(); _entity->moveToLeft(margins.left() + _padding.left(), margins.top() + _padding.top()); @@ -50,12 +49,9 @@ void WidgetSlideWrap::slideUp() { } if (_a_height.animating()) { if (_hiding) return; - } else { - a_height = anim::value(_realSize.height()); } - a_height.start(0.); _hiding = true; - _a_height.start(); + _a_height.start([this] { animationCallback(); }, _realSize.height(), 0., _duration); } void WidgetSlideWrap::slideDown() { @@ -69,15 +65,14 @@ void WidgetSlideWrap::slideDown() { if (_a_height.animating()) { if (!_hiding) return; } - a_height.start(_realSize.height()); - _forceHeight = qRound(a_height.current()); _hiding = false; - _a_height.start(); + _forceHeight = qRound(_a_height.current(0.)); + _a_height.start([this] { animationCallback(); }, 0., _realSize.height(), _duration); } void WidgetSlideWrap::showFast() { show(); - _a_height.stop(); + _a_height.finish(); _forceHeight = -1; resizeToWidth(_realSize.width()); if (_updateCallback) { @@ -86,8 +81,7 @@ void WidgetSlideWrap::showFast() { } void WidgetSlideWrap::hideFast() { - _a_height.stop(); - a_height = anim::value(); + _a_height.finish(); _forceHeight = 0; resizeToWidth(_realSize.width()); hide(); @@ -135,18 +129,13 @@ int WidgetSlideWrap::resizeGetHeight(int newWidth) { return _realSize.height(); } -void WidgetSlideWrap::step_height(float64 ms, bool timer) { - auto dt = ms / _duration; - if (dt >= 1) { - a_height.finish(); - _a_height.stop(); +void WidgetSlideWrap::animationCallback() { + _forceHeight = qRound(_a_height.current(_hiding ? 0 : -1)); + resizeToWidth(_realSize.width()); + if (!_a_height.animating()) { _forceHeight = _hiding ? 0 : -1; if (_hiding) hide(); - } else { - a_height.update(dt, anim::linear); - _forceHeight = qRound(a_height.current()); } - resizeToWidth(_realSize.width()); if (_updateCallback) { _updateCallback(); } diff --git a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h index dbbe697d2b..8d0c3bd320 100644 --- a/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h +++ b/Telegram/SourceFiles/ui/effects/widget_slide_wrap.h @@ -56,7 +56,7 @@ protected: int resizeGetHeight(int newWidth) override; private: - void step_height(float64 ms, bool timer); + void animationCallback(); TWidget *_entity; bool _inResizeToWidth = false; @@ -66,7 +66,6 @@ private: style::size _realSize; int _forceHeight = -1; - anim::value a_height; Animation _a_height; bool _hiding = false; diff --git a/Telegram/SourceFiles/ui/toast/toast.cpp b/Telegram/SourceFiles/ui/toast/toast.cpp index 02d67e92a9..715ef19136 100644 --- a/Telegram/SourceFiles/ui/toast/toast.cpp +++ b/Telegram/SourceFiles/ui/toast/toast.cpp @@ -28,10 +28,9 @@ namespace Ui { namespace Toast { Instance::Instance(const Config &config, QWidget *widgetParent, const Private &) -: _a_fade(animation(this, &Instance::step_fade)) -, _hideAtMs(getms(true) + config.durationMs) { +: _hideAtMs(getms(true) + config.durationMs) { _widget = std_::make_unique(widgetParent, config); - _a_fade.start(); + _a_opacity.start([this] { opacityAnimationCallback(); }, 0., 1., st::toastFadeInDuration); } void Show(QWidget *parent, const Config &config) { @@ -41,9 +40,19 @@ void Show(QWidget *parent, const Config &config) { } } +void Instance::opacityAnimationCallback() { + _widget->setShownLevel(_a_opacity.current(_hiding ? 0. : 1.)); + _widget->update(); + if (!_a_opacity.animating()) { + if (_hiding) { + hide(); + } + } +} + void Instance::fadeOut() { - _fadingOut = true; - _a_fade.start(); + _hiding = true; + _a_opacity.start([this] { opacityAnimationCallback(); }, 1., 0., st::toastFadeOutDuration); } void Instance::hide() { @@ -51,27 +60,5 @@ void Instance::hide() { _widget->deleteLater(); } -void Instance::step_fade(float64 ms, bool timer) { - if (timer) { - _widget->update(); - } - if (_fadingOut) { - if (ms >= st::toastFadeOutDuration) { - hide(); - } else { - float64 dt = ms / st::toastFadeOutDuration; - _widget->setShownLevel(1. - dt); - } - } else { - if (ms >= st::toastFadeInDuration) { - _widget->setShownLevel(1.); - _a_fade.stop(); - } else { - float64 dt = ms / st::toastFadeInDuration; - _widget->setShownLevel(dt); - } - } -} - } // namespace Toast } // namespace Ui diff --git a/Telegram/SourceFiles/ui/toast/toast.h b/Telegram/SourceFiles/ui/toast/toast.h index 16a4aa33c6..8e7b137614 100644 --- a/Telegram/SourceFiles/ui/toast/toast.h +++ b/Telegram/SourceFiles/ui/toast/toast.h @@ -49,9 +49,10 @@ public: void hide(); private: - void step_fade(float64 ms, bool timer); - bool _fadingOut = false; - Animation _a_fade; + void opacityAnimationCallback(); + + bool _hiding = false; + Animation _a_opacity; const TimeMs _hideAtMs; diff --git a/Telegram/SourceFiles/ui/widgets/buttons.cpp b/Telegram/SourceFiles/ui/widgets/buttons.cpp index 5c77c8bdc6..f55bb7d338 100644 --- a/Telegram/SourceFiles/ui/widgets/buttons.cpp +++ b/Telegram/SourceFiles/ui/widgets/buttons.cpp @@ -135,9 +135,7 @@ RippleButton::~RippleButton() = default; FlatButton::FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st) : RippleButton(parent, st.ripple) , _text(text) -, _st(st) -, a_over(0) -, _a_appearance(animation(this, &FlatButton::step_appearance)) { +, _st(st) { if (_st.width < 0) { _width = textWidth() - _st.width; } else if (!_st.width) { @@ -148,15 +146,6 @@ FlatButton::FlatButton(QWidget *parent, const QString &text, const style::FlatBu resize(_width, _st.height); } -void FlatButton::setOpacity(float64 o) { - _opacity = o; - update(); -} - -float64 FlatButton::opacity() const { - return _opacity; -} - void FlatButton::setText(const QString &text) { _text = text; update(); @@ -176,44 +165,22 @@ int32 FlatButton::textWidth() const { return _st.font->width(_text); } -void FlatButton::step_appearance(float64 ms, bool timer) { - float64 dt = ms / _st.duration; - if (dt >= 1) { - _a_appearance.stop(); - a_over.finish(); - } else { - a_over.update(dt, anim::linear); - } - if (timer) update(); -} - void FlatButton::onStateChanged(State was, StateChangeSource source) { RippleButton::onStateChanged(was, source); - - a_over.start(isOver() ? 1. : 0.); - if (source == StateChangeSource::ByUser || source == StateChangeSource::ByPress) { - _a_appearance.stop(); - a_over.finish(); - update(); - } else { - _a_appearance.start(); - } + update(); } void FlatButton::paintEvent(QPaintEvent *e) { QPainter p(this); QRect r(0, height() - _st.height, width(), _st.height); + p.fillRect(r, isOver() ? _st.overBgColor : _st.bgColor); - p.setOpacity(_opacity); - p.fillRect(r, anim::brush(_st.bgColor, _st.overBgColor, a_over.current())); - - auto ms = getms(); - paintRipple(p, 0, 0, ms); + paintRipple(p, 0, 0, getms()); p.setFont(isOver() ? _st.overFont : _st.font); p.setRenderHint(QPainter::TextAntialiasing); - p.setPen(anim::pen(_st.color, _st.overColor, a_over.current())); + p.setPen(isOver() ? _st.overColor : _st.color); r.setTop(_st.textTop); p.drawText(r, _text, style::al_top); @@ -269,8 +236,12 @@ void RoundButton::resizeToText() { resize(innerWidth - _st.width + _st.padding.left() + _st.padding.right(), _st.height + _st.padding.top() + _st.padding.bottom()); } else { if (_st.width < innerWidth + (_st.height - _st.font->height)) { - _text = _st.font->elided(_fullText, qMax(_st.width - (_st.height - _st.font->height), 1)); - innerWidth = _st.font->width(_text); + auto fullText = _fullText; + if (_transform == TextTransform::ToUpper) { + fullText = std_::move(fullText).toUpper(); + } + _text = _st.font->elided(fullText, qMax(_st.width - (_st.height - _st.font->height), 1)); + _textWidth = _st.font->width(_text); } resize(_st.width + _st.padding.left() + _st.padding.right(), _st.height + _st.padding.top() + _st.padding.bottom()); } diff --git a/Telegram/SourceFiles/ui/widgets/buttons.h b/Telegram/SourceFiles/ui/widgets/buttons.h index 43f6a5199f..2c4629e2ce 100644 --- a/Telegram/SourceFiles/ui/widgets/buttons.h +++ b/Telegram/SourceFiles/ui/widgets/buttons.h @@ -90,8 +90,6 @@ class FlatButton : public RippleButton { public: FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st); - void step_appearance(float64 ms, bool timer); - void setText(const QString &text); void setWidth(int32 w); @@ -103,19 +101,11 @@ protected: void onStateChanged(State was, StateChangeSource source) override; private: - void setOpacity(float64 o); - float64 opacity() const; - QString _text, _textForAutoSize; int _width; const style::FlatButton &_st; - anim::value a_over; - Animation _a_appearance; - - float64 _opacity = 1.; - }; class RoundButton : public RippleButton { @@ -181,7 +171,7 @@ private: const style::icon *_iconOverrideOver = nullptr; const style::color *_rippleColorOverride = nullptr; - FloatAnimation _a_over; + Animation _a_over; }; @@ -231,7 +221,7 @@ private: const style::CrossButton &_st; bool _shown = false; - FloatAnimation _a_show; + Animation _a_show; }; diff --git a/Telegram/SourceFiles/ui/widgets/checkbox.h b/Telegram/SourceFiles/ui/widgets/checkbox.h index ccc4c41a17..14969278c4 100644 --- a/Telegram/SourceFiles/ui/widgets/checkbox.h +++ b/Telegram/SourceFiles/ui/widgets/checkbox.h @@ -68,7 +68,7 @@ private: QRect _checkRect; bool _checked; - FloatAnimation _a_checked; + Animation _a_checked; }; @@ -117,7 +117,7 @@ private: QRect _checkRect; bool _checked; - FloatAnimation _a_checked; + Animation _a_checked; void *_group; int32 _value; diff --git a/Telegram/SourceFiles/ui/widgets/continuous_sliders.h b/Telegram/SourceFiles/ui/widgets/continuous_sliders.h index 0bb4af4bba..2c253b2661 100644 --- a/Telegram/SourceFiles/ui/widgets/continuous_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/continuous_sliders.h @@ -105,10 +105,12 @@ private: Callback _changeFinishedCallback; bool _over = false; - FloatAnimation _a_over; + Animation _a_over; + // This can animate for a very long time (like in music playing), + // so it should be a BasicAnimation, not an Animation. anim::value a_value; - Animation _a_value; + BasicAnimation _a_value; bool _mouseDown = false; float64 _downValue = 0.; diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h index 9a3f545b80..b0d600e37f 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h @@ -92,7 +92,7 @@ private: int _pressed = -1; int _selected = 0; - FloatAnimation _a_left; + Animation _a_left; int _timerId = -1; TimeMs _callbackAfterMs = 0; diff --git a/Telegram/SourceFiles/ui/widgets/inner_dropdown.h b/Telegram/SourceFiles/ui/widgets/inner_dropdown.h index bf7c08e33d..a3683238eb 100644 --- a/Telegram/SourceFiles/ui/widgets/inner_dropdown.h +++ b/Telegram/SourceFiles/ui/widgets/inner_dropdown.h @@ -108,11 +108,11 @@ private: PanelAnimation::Origin _origin = PanelAnimation::Origin::TopLeft; std_::unique_ptr _showAnimation; - FloatAnimation _a_show; + Animation _a_show; bool _hiding = false; QPixmap _cache; - FloatAnimation _a_opacity; + Animation _a_opacity; QTimer _hideTimer; bool _ignoreShowEvents = false; diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.cpp b/Telegram/SourceFiles/ui/widgets/input_fields.cpp index e8c7508813..45e5cc9efa 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.cpp +++ b/Telegram/SourceFiles/ui/widgets/input_fields.cpp @@ -1717,9 +1717,6 @@ InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString , _placeholderFull(ph) , _placeholderVisible(val.isEmpty()) -, a_borderOpacityActive(0) -, a_borderFgActive(0) -, a_borderFgError(0) , _a_border(animation(this, &InputArea::step_border)) , _focused(false) @@ -2412,9 +2409,6 @@ InputField::InputField(QWidget *parent, const style::InputField &st, const QStri , _placeholderFull(ph) , _placeholderVisible(val.isEmpty()) -, a_borderOpacityActive(0) -, a_borderFgActive(0) -, a_borderFgError(0) , _a_border(animation(this, &InputField::step_border)) , _focused(false) @@ -3125,9 +3119,6 @@ MaskedInputField::MaskedInputField(QWidget *parent, const style::InputField &st, , _placeholderVisible(val.isEmpty()) , _placeholderFast(false) -, a_borderOpacityActive(0) -, a_borderFgActive(0) -, a_borderFgError(0) , _a_border(animation(this, &MaskedInputField::step_border)) , _focused(false) diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.h b/Telegram/SourceFiles/ui/widgets/input_fields.h index bbede945c7..7e5f3a1a7b 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.h +++ b/Telegram/SourceFiles/ui/widgets/input_fields.h @@ -190,8 +190,8 @@ private: QString _ph, _phelided; int _phAfter = 0; bool _placeholderVisible = true; - FloatAnimation _a_placeholderFocused; - FloatAnimation _a_placeholderVisible; + Animation _a_placeholderFocused; + Animation _a_placeholderVisible; TextWithTags _lastTextWithTags; @@ -314,8 +314,8 @@ private: bool _customUpDown = false; bool _placeholderVisible = true; - FloatAnimation _a_placeholderFocused; - FloatAnimation _a_placeholderVisible; + Animation _a_placeholderFocused; + Animation _a_placeholderVisible; const style::FlatInput &_st; @@ -468,13 +468,13 @@ private: QString _placeholder, _placeholderFull; bool _placeholderVisible; - FloatAnimation _a_placeholderFocused; - FloatAnimation _a_placeholderVisible; + Animation _a_placeholderFocused; + Animation _a_placeholderVisible; anim::value a_borderOpacityActive; anim::value a_borderFgActive; anim::value a_borderFgError; - Animation _a_border; + BasicAnimation _a_border; bool _focused, _error; @@ -634,13 +634,13 @@ private: QString _placeholder, _placeholderFull; bool _placeholderVisible; - FloatAnimation _a_placeholderFocused; - FloatAnimation _a_placeholderVisible; + Animation _a_placeholderFocused; + Animation _a_placeholderVisible; anim::value a_borderOpacityActive; anim::value a_borderFgActive; anim::value a_borderFgError; - Animation _a_border; + BasicAnimation _a_border; bool _focused, _error; @@ -754,13 +754,13 @@ private: QString _placeholder, _placeholderFull; bool _placeholderVisible, _placeholderFast; - FloatAnimation _a_placeholderFocused; - FloatAnimation _a_placeholderVisible; + Animation _a_placeholderFocused; + Animation _a_placeholderVisible; anim::value a_borderOpacityActive; anim::value a_borderFgActive; anim::value a_borderFgError; - Animation _a_border; + BasicAnimation _a_border; bool _focused, _error; diff --git a/Telegram/SourceFiles/ui/widgets/multi_select.cpp b/Telegram/SourceFiles/ui/widgets/multi_select.cpp index c5a49273a8..accc210fcc 100644 --- a/Telegram/SourceFiles/ui/widgets/multi_select.cpp +++ b/Telegram/SourceFiles/ui/widgets/multi_select.cpp @@ -95,7 +95,7 @@ private: , y(y) { x.start(updateCallback, fromX, toX, duration); } - FloatAnimation x; + Animation x; int fromX, toX; int y; }; @@ -107,8 +107,8 @@ private: const style::color &_color; bool _over = false; QPixmap _cache; - FloatAnimation _visibility; - FloatAnimation _overOpacity; + Animation _visibility; + Animation _overOpacity; bool _overDelete = false; bool _active = false; PaintRoundImage _paintRoundImage; diff --git a/Telegram/SourceFiles/ui/widgets/multi_select.h b/Telegram/SourceFiles/ui/widgets/multi_select.h index b535c141e9..41a57bce90 100644 --- a/Telegram/SourceFiles/ui/widgets/multi_select.h +++ b/Telegram/SourceFiles/ui/widgets/multi_select.h @@ -137,7 +137,7 @@ private: QMargins itemPaintMargins() const; const style::MultiSelect &_st; - FloatAnimation _iconOpacity; + Animation _iconOpacity; ScrollCallback _scrollCallback; @@ -157,7 +157,7 @@ private: ChildWidget _cancel; int _newHeight = 0; - FloatAnimation _height; + Animation _height; base::lambda _queryChangedCallback; base::lambda _submittedCallback; diff --git a/Telegram/SourceFiles/ui/widgets/popup_menu.h b/Telegram/SourceFiles/ui/widgets/popup_menu.h index 0ab90a8e0c..7428fd5a5a 100644 --- a/Telegram/SourceFiles/ui/widgets/popup_menu.h +++ b/Telegram/SourceFiles/ui/widgets/popup_menu.h @@ -119,12 +119,12 @@ private: PanelAnimation::Origin _origin = PanelAnimation::Origin::TopLeft; std_::unique_ptr _showAnimation; - FloatAnimation _a_show; + Animation _a_show; bool _useTransparency = true; bool _hiding = false; QPixmap _cache; - FloatAnimation _a_opacity; + Animation _a_opacity; bool _deleteOnHide = true; bool _triggering = false; diff --git a/Telegram/SourceFiles/ui/widgets/scroll_area.cpp b/Telegram/SourceFiles/ui/widgets/scroll_area.cpp index 6c152bcc9c..d0af59c9d8 100644 --- a/Telegram/SourceFiles/ui/widgets/scroll_area.cpp +++ b/Telegram/SourceFiles/ui/widgets/scroll_area.cpp @@ -41,18 +41,9 @@ void ScrollShadow::changeVisibility(bool shown) { ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::FlatScroll *st) : QWidget(parent) , _st(st) , _vertical(vert) -, _over(false) -, _overbar(false) -, _moving(false) -, _topSh(false) -, _bottomSh(false) +, _hiding(_st->hiding != 0) , _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar()) -, _scrollMax(_connected->maximum()) -, _hideIn(-1) -, a_bgOver(0.) -, a_barOver(0.) -, a_fullOpacity(_st->hiding ? 0. : 1.) -, _a_appearance(animation(this, &ScrollBar::step_appearance)) { +, _scrollMax(_connected->maximum()) { recountSize(); _hideTimer.setSingleShot(true); @@ -121,32 +112,78 @@ void ScrollBar::updateBar(bool force) { } void ScrollBar::onHideTimer() { - _hideIn = -1; - a_fullOpacity.start(0.); - a_bgOver.restart(); - a_barOver.restart(); - _a_appearance.start(); + if (!_hiding) { + _hiding = true; + _a_opacity.start([this] { update(); }, 1., 0., _st->duration); + } } ScrollArea *ScrollBar::area() { return static_cast(parentWidget()); } +void ScrollBar::setOver(bool over) { + if (_over != over) { + auto wasOver = (_over || _moving); + _over = over; + auto nowOver = (_over || _moving); + if (wasOver != nowOver) { + _a_over.start([this] { update(); }, nowOver ? 0. : 1., nowOver ? 1. : 0., _st->duration); + } + if (nowOver && _hiding) { + _hiding = false; + _a_opacity.start([this] { update(); }, 0., 1., _st->duration); + } + } +} + +void ScrollBar::setOverBar(bool overbar) { + if (_overbar != overbar) { + auto wasBarOver = (_overbar || _moving); + _overbar = overbar; + auto nowBarOver = (_overbar || _moving); + if (wasBarOver != nowBarOver) { + _a_barOver.start([this] { update(); }, nowBarOver ? 0. : 1., nowBarOver ? 1. : 0., _st->duration); + } + } +} + +void ScrollBar::setMoving(bool moving) { + if (_moving != moving) { + auto wasOver = (_over || _moving); + auto wasBarOver = (_overbar || _moving); + _moving = moving; + auto nowBarOver = (_overbar || _moving); + if (wasBarOver != nowBarOver) { + _a_barOver.start([this] { update(); }, nowBarOver ? 0. : 1., nowBarOver ? 1. : 0., _st->duration); + } + auto nowOver = (_over || _moving); + if (wasOver != nowOver) { + _a_over.start([this] { update(); }, nowOver ? 0. : 1., nowOver ? 1. : 0., _st->duration); + } + if (!nowOver && _st->hiding && !_hiding) { + _hideTimer.start(_hideIn); + } + } +} + void ScrollBar::paintEvent(QPaintEvent *e) { if (!_bar.width() && !_bar.height()) { hide(); return; } - if (a_fullOpacity.current() == 0.) return; + auto ms = getms(); + auto opacity = _a_opacity.current(ms, _hiding ? 0. : 1.); + if (opacity == 0.) return; Painter p(this); auto deltal = _vertical ? _st->deltax : 0, deltar = _vertical ? _st->deltax : 0; auto deltat = _vertical ? 0 : _st->deltax, deltab = _vertical ? 0 : _st->deltax; p.setPen(Qt::NoPen); - auto bg = anim::color(_st->bgColor, _st->bgOverColor, a_bgOver.current()); - bg.setAlpha(anim::interpolate(0, bg.alpha(), a_fullOpacity.current())); - auto bar = anim::color(_st->barColor, _st->barOverColor, a_barOver.current()); - bar.setAlpha(anim::interpolate(0, bar.alpha(), a_fullOpacity.current())); + auto bg = anim::color(_st->bgColor, _st->bgOverColor, _a_over.current(ms, (_over || _moving) ? 1. : 0.)); + bg.setAlpha(anim::interpolate(0, bg.alpha(), opacity)); + auto bar = anim::color(_st->barColor, _st->barOverColor, _a_barOver.current(ms, (_overbar || _moving) ? 1. : 0.)); + bar.setAlpha(anim::interpolate(0, bar.alpha(), opacity)); if (_st->round) { PainterHighQualityEnabler hq(p); p.setBrush(bg); @@ -159,30 +196,13 @@ void ScrollBar::paintEvent(QPaintEvent *e) { } } -void ScrollBar::step_appearance(float64 ms, bool timer) { - float64 dt = ms / _st->duration; - if (dt >= 1) { - _a_appearance.stop(); - a_bgOver.finish(); - a_barOver.finish(); - a_fullOpacity.finish(); - } else { - a_bgOver.update(dt, anim::linear); - a_barOver.update(dt, anim::linear); - a_fullOpacity.update(dt, anim::linear); - } - if (timer) update(); -} - void ScrollBar::hideTimeout(TimeMs dt) { - if (_hideIn < 0) { - a_bgOver.start(_over ? 1. : 0.); - a_barOver.start(_over ? 1. : 0.); - a_fullOpacity.start(1.); - _a_appearance.start(); + if (_hiding && dt > 0) { + _hiding = false; + _a_opacity.start([this] { update(); }, 0., 1., _st->duration); } _hideIn = dt; - if (!_moving && _hideIn >= 0) { + if (!_moving) { _hideTimer.start(_hideIn); } } @@ -190,40 +210,22 @@ void ScrollBar::hideTimeout(TimeMs dt) { void ScrollBar::enterEvent(QEvent *e) { _hideTimer.stop(); setMouseTracking(true); - _over = true; - a_bgOver.start(1.); - a_barOver.start(1.); - a_fullOpacity.start(1.); - _a_appearance.start(); + setOver(true); } void ScrollBar::leaveEvent(QEvent *e) { if (!_moving) { setMouseTracking(false); - a_bgOver.start(0.); - a_barOver.start(0.); - a_fullOpacity.start(1.); - _a_appearance.start(); - if (_hideIn >= 0) { - _hideTimer.start(_hideIn); - } else if (_st->hiding) { - hideTimeout(_st->hiding); - } } - _over = _overbar = false; + setOver(false); + setOverBar(false); + if (_st->hiding && !_hiding) { + _hideTimer.start(_hideIn); + } } void ScrollBar::mouseMoveEvent(QMouseEvent *e) { - bool newOverBar = _bar.contains(e->pos()); - if (_overbar != newOverBar) { - _overbar = newOverBar; - if (!_moving) { - a_barOver.start(newOverBar ? 1. : 0.); - a_bgOver.start(1.); - a_fullOpacity.start(1.); - _a_appearance.start(); - } - } + setOverBar(_bar.contains(e->pos())); if (_moving) { int delta = 0, barDelta = _vertical ? (area()->height() - _bar.height()) : (area()->width() - _bar.width()); if (barDelta > 0) { @@ -238,7 +240,7 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) { if (!width() || !height()) return; _dragStart = e->globalPos(); - _moving = true; + setMoving(true); if (_overbar) { _startFrom = _connected->value(); } else { @@ -247,13 +249,7 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) { div = (div <= _st->deltat + _st->deltab) ? 1 : (div - _st->deltat - _st->deltab); _startFrom = _vertical ? int32((val * int64(area()->scrollTopMax())) / div) : ((val * int64(area()->scrollLeftMax())) / div); _connected->setValue(_startFrom); - if (!_overbar) { - _overbar = true; - a_barOver.start(1.); - a_bgOver.start(1.); - a_fullOpacity.start(1.); - _a_appearance.start(); - } + setOverBar(true); } area()->setMovingByScrollBar(true); @@ -262,28 +258,7 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) { void ScrollBar::mouseReleaseEvent(QMouseEvent *e) { if (_moving) { - _moving = false; - bool a = false; - if (!_overbar) { - if (!_over || _hideIn) { - a_bgOver.restart(); - a_barOver.start(0.); - a_fullOpacity.start(1.); - a = true; - } - } - if (!_over) { - if (_hideIn) { - a_barOver.restart(); - a_bgOver.start(0.); - a_fullOpacity.start(1.); - a = true; - } - if (_hideIn >= 0) { - _hideTimer.start(_hideIn); - } - } - if (a) _a_appearance.start(); + setMoving(false); area()->setMovingByScrollBar(false); emit area()->scrollFinished(); diff --git a/Telegram/SourceFiles/ui/widgets/scroll_area.h b/Telegram/SourceFiles/ui/widgets/scroll_area.h index 16e25ef60d..c2463b7961 100644 --- a/Telegram/SourceFiles/ui/widgets/scroll_area.h +++ b/Telegram/SourceFiles/ui/widgets/scroll_area.h @@ -55,53 +55,58 @@ class ScrollBar : public QWidget { Q_OBJECT public: - ScrollBar(ScrollArea *parent, bool vertical, const style::FlatScroll *st); void recountSize(); - void paintEvent(QPaintEvent *e); - void enterEvent(QEvent *e); - void leaveEvent(QEvent *e); - void mouseMoveEvent(QMouseEvent *e); - void mousePressEvent(QMouseEvent *e); - void mouseReleaseEvent(QMouseEvent *e); - void resizeEvent(QResizeEvent *e); - - void step_appearance(float64 ms, bool timer); - void hideTimeout(TimeMs dt); public slots: - void onValueChanged(); void updateBar(bool force = false); void onHideTimer(); signals: - void topShadowVisibility(bool); void bottomShadowVisibility(bool); -private: +protected: + void paintEvent(QPaintEvent *e) override; + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void resizeEvent(QResizeEvent *e) override; +private: ScrollArea *area(); + + void setOver(bool over); + void setOverBar(bool overbar); + void setMoving(bool moving); + const style::FlatScroll *_st; - bool _vertical; - bool _over, _overbar, _moving; - bool _topSh, _bottomSh; + bool _vertical = true; + bool _hiding = false; + bool _over = false; + bool _overbar = false; + bool _moving = false; + bool _topSh = false; + bool _bottomSh = false; QPoint _dragStart; QScrollBar *_connected; int32 _startFrom, _scrollMax; - TimeMs _hideIn; + TimeMs _hideIn = 0; QTimer _hideTimer; - anim::value a_bgOver, a_barOver, a_fullOpacity; - Animation _a_appearance; + Animation _a_over; + Animation _a_barOver; + Animation _a_opacity; QRect _bar; }; diff --git a/Telegram/SourceFiles/ui/widgets/shadow.h b/Telegram/SourceFiles/ui/widgets/shadow.h index 0f559bd24c..f09fc51299 100644 --- a/Telegram/SourceFiles/ui/widgets/shadow.h +++ b/Telegram/SourceFiles/ui/widgets/shadow.h @@ -58,7 +58,7 @@ protected: private: const style::color &_color; - FloatAnimation _a_opacity; + Animation _a_opacity; bool _shown = true; }; diff --git a/Telegram/SourceFiles/ui/widgets/widgets.style b/Telegram/SourceFiles/ui/widgets/widgets.style index 2b3b0c013e..084c813b07 100644 --- a/Telegram/SourceFiles/ui/widgets/widgets.style +++ b/Telegram/SourceFiles/ui/widgets/widgets.style @@ -64,7 +64,6 @@ FlatButton { font: font; overFont: font; - duration: int; ripple: RippleAnimation; } diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index 2ce657b27a..3951334465 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -346,10 +346,6 @@ Manager::~Manager() { namespace internal { Widget::Widget(QPoint startPosition, int shift, Direction shiftDirection) : TWidget(nullptr) -, _opacityDuration(st::notifyFastAnim) -, a_opacity(0, 1) -, a_func(anim::linear) -, _a_opacity(animation(this, &Widget::step_opacity)) , _startPosition(startPosition) , _direction(shiftDirection) , a_shift(shift) @@ -360,7 +356,7 @@ Widget::Widget(QPoint startPosition, int shift, Direction shiftDirection) : TWid setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_MacAlwaysShowToolWindow); - _a_opacity.start(); + _a_opacity.start([this] { opacityAnimationCallback(); }, 0., 1., st::notifyFastAnim); } void Widget::destroyDelayed() { @@ -376,19 +372,12 @@ void Widget::destroyDelayed() { #endif // Q_OS_LINUX32 || Q_OS_LINUX64 } -void Widget::step_opacity(float64 ms, bool timer) { - float64 dt = ms / float64(_opacityDuration); - if (dt >= 1) { - a_opacity.finish(); - _a_opacity.stop(); - if (_hiding) { - destroyDelayed(); - } - } else { - a_opacity.update(dt, a_func); - } +void Widget::opacityAnimationCallback() { updateOpacity(); update(); + if (!_a_opacity.animating() && _hiding) { + destroyDelayed(); + } } void Widget::step_shift(float64 ms, bool timer) { @@ -411,25 +400,19 @@ void Widget::hideFast() { void Widget::hideStop() { if (_hiding) { - _opacityDuration = st::notifyFastAnim; - a_func = anim::linear; - a_opacity.start(1); _hiding = false; - _a_opacity.start(); + _a_opacity.start([this] { opacityAnimationCallback(); }, 0., 1., st::notifyFastAnim); } } void Widget::hideAnimated(float64 duration, const anim::transition &func) { - _opacityDuration = duration; - a_func = func; - a_opacity.start(0); _hiding = true; - _a_opacity.start(); + _a_opacity.start([this] { opacityAnimationCallback(); }, 1., 0., duration, func); } void Widget::updateOpacity() { if (auto manager = ManagerInstance.data()) { - setWindowOpacity(a_opacity.current() * manager->demoMasterOpacity()); + setWindowOpacity(_a_opacity.current(_hiding ? 1. : 0.) * manager->demoMasterOpacity()); } } @@ -724,6 +707,7 @@ void Notification::toggleActionButtons(bool visible) { if (_actionsVisible != visible) { _actionsVisible = visible; a_actionsOpacity.start([this] { actionsOpacityCallback(); }, _actionsVisible ? 0. : 1., _actionsVisible ? 1. : 0., st::notifyActionsDuration); + _reply->clearState(); _reply->hide(); } } @@ -755,7 +739,7 @@ void Notification::showReplyField() { connect(_replyArea, SIGNAL(submitted(bool)), this, SLOT(onReplySubmit(bool))); connect(_replyArea, SIGNAL(cancelled()), this, SLOT(onReplyCancel())); - _replySend = new Ui::IconButton(this, st::notifySendReply); + _replySend.create(this, st::notifySendReply); _replySend->moveToRight(st::notifyBorderWidth, st::notifyMinHeight); _replySend->show(); _replySend->setClickedCallback([this] { sendReply(); }); diff --git a/Telegram/SourceFiles/window/notifications_manager_default.h b/Telegram/SourceFiles/window/notifications_manager_default.h index 170dc4b529..84f1e85319 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.h +++ b/Telegram/SourceFiles/window/notifications_manager_default.h @@ -114,7 +114,7 @@ private: using QueuedNotifications = QList; QueuedNotifications _queuedNotifications; - FloatAnimation _demoMasterOpacity; + Animation _demoMasterOpacity; }; @@ -150,23 +150,20 @@ protected: virtual void updateGeometry(int x, int y, int width, int height); private: + void opacityAnimationCallback(); void destroyDelayed(); void moveByShift(); void hideAnimated(float64 duration, const anim::transition &func); - void step_opacity(float64 ms, bool timer); void step_shift(float64 ms, bool timer); bool _hiding = false; bool _deleted = false; - float64 _opacityDuration; - anim::value a_opacity; - anim::transition a_func; Animation _a_opacity; QPoint _startPosition; Direction _direction; anim::value a_shift; - Animation _a_shift; + BasicAnimation _a_shift; }; @@ -234,7 +231,7 @@ private: bool _hideReplyButton = false; bool _actionsVisible = false; - FloatAnimation a_actionsOpacity; + Animation a_actionsOpacity; QPixmap _buttonsCache; #if defined Q_OS_WIN && !defined Q_OS_WINRT diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index d08c7e3a74..1160b21e35 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org using "basic.style"; using "ui/widgets/widgets.style"; +using "history/history.style"; windowMinWidth: 380px; windowMinHeight: 480px; @@ -76,12 +77,10 @@ notifyReplyArea: InputArea(defaultInputArea) { borderActive: 0px; borderError: 0px; } -notifySendReply: IconButton { +notifySendReply: IconButton(historySend) { width: 36px; height: 36px; - - icon: icon {{ "notification_send", lightButtonFg, point(3px, 9px) }}; - iconPosition: point(0px, 0px); + iconPosition: point(6px, 6px); } titleUnreadCounterTop: 5px; diff --git a/Telegram/SourceFiles/window/window_slide_animation.cpp b/Telegram/SourceFiles/window/window_slide_animation.cpp index 6510908cf7..6e4323c01e 100644 --- a/Telegram/SourceFiles/window/window_slide_animation.cpp +++ b/Telegram/SourceFiles/window/window_slide_animation.cpp @@ -28,7 +28,8 @@ namespace Window { void SlideAnimation::paintContents(Painter &p, const QRect &update) const { int retina = cIntRetinaFactor(); - auto progress = _animation.current(getms()); + // Animation callback can destroy "this", so we don't pass "ms". + auto progress = _animation.current((_direction == SlideDirection::FromLeft) ? 0. : 1.); auto coordUnder = anim::interpolate(0, -st::slideShift, progress); auto coordOver = anim::interpolate(_cacheOver.width() / cIntRetinaFactor(), 0, progress); if (coordOver) { diff --git a/Telegram/SourceFiles/window/window_slide_animation.h b/Telegram/SourceFiles/window/window_slide_animation.h index 2f0a072c39..c7285f92ad 100644 --- a/Telegram/SourceFiles/window/window_slide_animation.h +++ b/Telegram/SourceFiles/window/window_slide_animation.h @@ -53,7 +53,7 @@ private: SlideDirection _direction = SlideDirection::FromRight; bool _topBarShadowEnabled = false; - mutable FloatAnimation _animation; + mutable Animation _animation; QPixmap _cacheUnder, _cacheOver; RepaintCallback _repaintCallback; diff --git a/Telegram/SourceFiles/window/window_theme_warning.h b/Telegram/SourceFiles/window/window_theme_warning.h index 91a1ca3659..a5ee31a6cb 100644 --- a/Telegram/SourceFiles/window/window_theme_warning.h +++ b/Telegram/SourceFiles/window/window_theme_warning.h @@ -52,7 +52,7 @@ private: void handleTimer(); bool _hiding = false; - FloatAnimation _animation; + Animation _animation; QPixmap _cache; QRect _inner, _outer;