mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Moved FloatAnimation->Animation, Animation->BasicAnimation.
This commit is contained in:
parent
06ed7b8eaf
commit
47977009b8
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,6 @@ protected:
|
||||
|
||||
private:
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
void step_good(float64 ms, bool timer);
|
||||
|
||||
ChildWidget<Ui::RoundButton> _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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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(); });
|
||||
|
@ -62,7 +62,7 @@ private:
|
||||
QPixmap _notificationSampleSmall;
|
||||
QPixmap _notificationSampleLarge;
|
||||
ScreenCorner _chosenCorner;
|
||||
std_::vector_of_moveable<FloatAnimation> _sampleOpacities;
|
||||
std_::vector_of_moveable<Animation> _sampleOpacities;
|
||||
|
||||
bool _isOverCorner = false;
|
||||
ScreenCorner _overCorner = ScreenCorner::TopLeft;
|
||||
|
@ -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;
|
||||
|
@ -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<mtpRequestId, QString>;
|
||||
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);
|
||||
|
@ -246,7 +246,7 @@ private:
|
||||
QList<TimeMs> _animStartTimes;
|
||||
TimeMs _aboveShadowFadeStart = 0;
|
||||
anim::value _aboveShadowFadeOpacity;
|
||||
Animation _a_shifting;
|
||||
BasicAnimation _a_shifting;
|
||||
|
||||
base::lambda<void(uint64 setId)> _installSetCallback;
|
||||
|
||||
|
@ -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());
|
||||
|
@ -113,7 +113,7 @@ private:
|
||||
return (_setFlags & MTPDstickerSet::Flag::f_masks);
|
||||
}
|
||||
|
||||
std_::vector_of_moveable<FloatAnimation> _packOvers;
|
||||
std_::vector_of_moveable<Animation> _packOvers;
|
||||
StickerPack _pack;
|
||||
StickersByEmojiMap _emoji;
|
||||
bool _loaded = false;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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] {
|
||||
|
@ -387,7 +387,7 @@ private:
|
||||
ChildWidget<DialogsInner> _inner;
|
||||
ChildWidget<Ui::FlatButton> _updateTelegram = { nullptr };
|
||||
|
||||
FloatAnimation _a_show;
|
||||
Animation _a_show;
|
||||
Window::SlideDirection _showDirection;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
|
||||
typedef QMap<History*, TimeMs> TypingHistories; // when typing in this history started
|
||||
TypingHistories typing;
|
||||
Animation _a_typings;
|
||||
BasicAnimation _a_typings;
|
||||
|
||||
int unreadBadge() const;
|
||||
int unreadMutedCount() const {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<HistoryWidget*>(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();
|
||||
}
|
||||
|
@ -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<void(const QMimeData *data)> _droppedCallback;
|
||||
|
||||
anim::value a_opacity;
|
||||
anim::value a_colorDrop;
|
||||
Animation _a_appearance;
|
||||
Animation _a_opacity;
|
||||
Animation _a_in;
|
||||
|
||||
Ui::RectShadow _shadow;
|
||||
|
||||
|
@ -372,7 +372,7 @@ private:
|
||||
ButtonRows _rows;
|
||||
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
BasicAnimation _a_selected;
|
||||
|
||||
StylePtr _st;
|
||||
|
||||
|
@ -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<HistoryFileMedia*>(this), &HistoryFileMedia::step_thumbOver),
|
||||
animation(const_cast<HistoryFileMedia*>(this), &HistoryFileMedia::step_radial));
|
||||
_animation = std_::make_unique<AnimationData>(animation(const_cast<HistoryFileMedia*>(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)
|
||||
|
@ -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<AnimationData> _animation;
|
||||
|
||||
};
|
||||
|
||||
@ -307,7 +304,7 @@ struct HistoryDocumentVoicePlayback {
|
||||
|
||||
int32 _position;
|
||||
anim::value a_progress;
|
||||
Animation _a_progress;
|
||||
BasicAnimation _a_progress;
|
||||
};
|
||||
struct HistoryDocumentVoice : public RuntimeComponent<HistoryDocumentVoice> {
|
||||
HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) {
|
||||
|
@ -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();
|
||||
|
@ -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<Ui::RoundButton> _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<QUrl> nonLocalUrls;
|
||||
@ -1088,7 +1089,9 @@ private:
|
||||
TimeMs _lastScrolled = 0;
|
||||
QTimer _updateHistoryItems;
|
||||
|
||||
ChildWidget<Ui::HistoryDownButton> _historyToEnd;
|
||||
Animation _historyDownShown;
|
||||
bool _historyDownIsShown = false;
|
||||
ChildWidget<Ui::HistoryDownButton> _historyDown;
|
||||
|
||||
ChildWidget<FieldAutocomplete> _fieldAutocomplete;
|
||||
|
||||
@ -1122,19 +1125,22 @@ private:
|
||||
ChildWidget<SilentToggle> _silent;
|
||||
bool _cmdStartShown = false;
|
||||
ChildWidget<MessageField> _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<Ui::RippleAnimation> _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;
|
||||
|
||||
|
@ -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<File*>(this), &File::step_thumbOver),
|
||||
animation(const_cast<File*>(this), &File::step_radial)));
|
||||
_animation.reset(new AnimationData(animation(const_cast<File*>(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +107,11 @@ private:
|
||||
, radial(std_::move(callbacks)) {
|
||||
}
|
||||
bool over;
|
||||
FloatAnimation _a_over;
|
||||
Animation _a_over;
|
||||
Ui::RadialAnimation radial;
|
||||
};
|
||||
mutable std_::unique_ptr<AnimationData> _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<AnimationData> _animation;
|
||||
|
@ -198,7 +198,7 @@ public:
|
||||
QString _errorText;
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::FlatLabel>> _error = { nullptr };
|
||||
|
||||
FloatAnimation _a_show;
|
||||
Animation _a_show;
|
||||
CoverAnimation _coverAnimation;
|
||||
std_::unique_ptr<Ui::SlideAnimation> _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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -157,7 +157,7 @@ private:
|
||||
void fillEmojiString();
|
||||
void resetGifAndCache();
|
||||
|
||||
FloatAnimation _a_shown;
|
||||
Animation _a_shown;
|
||||
bool _hiding = false;
|
||||
DocumentData *_document = nullptr;
|
||||
PhotoData *_photo = nullptr;
|
||||
|
@ -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();
|
||||
|
@ -586,7 +586,7 @@ private:
|
||||
base::Observable<PeerData*> _searchInPeerChanged;
|
||||
base::Observable<PeerData*> _historyPeerChanged;
|
||||
|
||||
FloatAnimation _a_show;
|
||||
Animation _a_show;
|
||||
bool _showBack = false;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
|
||||
|
@ -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<void()> &&callback)
|
||||
: _st(st)
|
||||
, _callback(std_::move(callback)) {
|
||||
}
|
||||
|
@ -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<void()> &&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<void()> _callback;
|
||||
|
||||
};
|
||||
|
||||
|
@ -100,7 +100,7 @@ private:
|
||||
bool _hiding = false;
|
||||
|
||||
QPixmap _cache;
|
||||
FloatAnimation _a_appearance;
|
||||
Animation _a_appearance;
|
||||
|
||||
bool _ignoringEnterEvents = false;
|
||||
|
||||
|
@ -82,7 +82,7 @@ private:
|
||||
bool _hiding = false;
|
||||
|
||||
QPixmap _cache;
|
||||
FloatAnimation _a_appearance;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer, _showTimer;
|
||||
|
||||
|
@ -50,7 +50,7 @@ private:
|
||||
int _downCoord = -1; // < 0 means mouse is not pressed
|
||||
|
||||
bool _over = false;
|
||||
FloatAnimation _a_over;
|
||||
Animation _a_over;
|
||||
|
||||
};
|
||||
|
||||
|
@ -296,7 +296,7 @@ private:
|
||||
QPoint _lastAction, _lastMouseMovePos;
|
||||
bool _ignoringDropdown = false;
|
||||
|
||||
Animation _a_state;
|
||||
BasicAnimation _a_state;
|
||||
|
||||
enum ControlsState {
|
||||
ControlsShowing,
|
||||
|
@ -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<quint64> >("QVector<quint64>");
|
||||
qRegisterMetaType<QVector<quint64> >("QVector<quint64>");
|
||||
}
|
||||
|
||||
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<quint64> 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<MTPint128>();
|
||||
_authKeyData = std_::make_unique<ConnectionPrivate::AuthKeyCreateData>();
|
||||
_authKeyStrings = std_::make_unique<ConnectionPrivate::AuthKeyCreateStrings>();
|
||||
_authKeyData->req_num = 0;
|
||||
_authKeyData->nonce = rand_value<MTPint128>();
|
||||
|
||||
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<MTPint256>();
|
||||
p_q_inner_data.vnew_nonce = authKeyData->new_nonce;
|
||||
_authKeyData->new_nonce = rand_value<MTPint256>();
|
||||
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);
|
||||
|
||||
|
@ -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<MTPlong> &ids, const std::string &states, QVector<MTPlong> &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<MTPlong> ackRequestData, resendRequestData;
|
||||
|
||||
@ -200,9 +208,10 @@ private:
|
||||
// remove msgs with such ids from sessionData->haveSent, add to sessionData->wereAcked
|
||||
void requestsAcked(const QVector<MTPlong> &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 <typename TResponse>
|
||||
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<AuthKeyCreateData> _authKeyData;
|
||||
std_::unique_ptr<AuthKeyCreateStrings> _authKeyStrings;
|
||||
|
||||
void dhClientParamsSend();
|
||||
void authKeyCreated();
|
||||
|
@ -141,35 +141,6 @@ public:
|
||||
typedef QMap<mtpRequestId, mtpRequest> mtpPreRequestMap;
|
||||
typedef QMap<mtpMsgId, mtpRequest> mtpRequestMap;
|
||||
typedef QMap<mtpMsgId, bool> mtpMsgIdsSet;
|
||||
class mtpMsgIdsMap : public QMap<mtpMsgId, bool> {
|
||||
public:
|
||||
typedef QMap<mtpMsgId, bool> 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<mtpMsgId, mtpRequestId> {
|
||||
public:
|
||||
|
@ -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<mtpMsgId, bool> _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
|
||||
|
@ -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<RadialProgressItem*>(this), &RadialProgressItem::step_radial));
|
||||
_radial = std_::make_unique<Ui::RadialAnimation>(animation(const_cast<RadialProgressItem*>(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<void()> _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());
|
||||
|
||||
|
@ -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<DocumentOpenClickHandler>(document), std_::move(save), MakeShared<DocumentCancelClickHandler>(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<Ui::RadialAnimation> _radial;
|
||||
Animation _a_iconOver;
|
||||
|
||||
};
|
||||
|
@ -362,7 +362,7 @@ private:
|
||||
|
||||
QString _header;
|
||||
|
||||
FloatAnimation _a_show;
|
||||
Animation _a_show;
|
||||
Window::SlideDirection _showDirection;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
|
||||
|
@ -51,7 +51,7 @@ private:
|
||||
void showAll();
|
||||
void hideAll();
|
||||
|
||||
FloatAnimation _a_show;
|
||||
Animation _a_show;
|
||||
bool _showBack = false;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
|
||||
|
@ -65,7 +65,7 @@ void ChannelMembersWidget::addButton(const QString &text, ChildWidget<Ui::LeftOu
|
||||
} else if (*button) {
|
||||
(*button)->setText(text);
|
||||
} else {
|
||||
(*button) = new Ui::LeftOutlineButton(this, text, st::defaultLeftOutlineButton);
|
||||
button->create(this, text, st::defaultLeftOutlineButton);
|
||||
(*button)->show();
|
||||
connect(*button, SIGNAL(clicked()), this, slot);
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ private:
|
||||
Item *computeItem(PeerData *group);
|
||||
QMap<PeerData*, Item*> _dataMap;
|
||||
|
||||
FloatAnimation _height;
|
||||
Animation _height;
|
||||
|
||||
int32 _preloadGroupId = 0;
|
||||
mtpRequestId _preloadRequestId = 0;
|
||||
|
@ -84,7 +84,7 @@ private:
|
||||
ChildWidget<Ui::FlatLabel> _username = { nullptr };
|
||||
ChildWidget<Ui::LeftOutlineButton> _commonGroups = { nullptr };
|
||||
|
||||
FloatAnimation _height;
|
||||
Animation _height;
|
||||
bool _showFinished = false;
|
||||
|
||||
bool _forceHiddenCommonGroups = false;
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ private:
|
||||
int _titleWidth, _subtitleWidth;
|
||||
|
||||
QPixmap _cache;
|
||||
FloatAnimation _a_appearance;
|
||||
Animation _a_appearance;
|
||||
bool _hiding = false;
|
||||
HideFinishCallback _hideFinishCallback;
|
||||
|
||||
|
@ -54,7 +54,7 @@ private:
|
||||
PeerData *_peer;
|
||||
bool _waiting = false;
|
||||
QPixmap _userpic, _oldUserpic;
|
||||
FloatAnimation _a_appearance;
|
||||
Animation _a_appearance;
|
||||
|
||||
};
|
||||
|
||||
|
@ -80,7 +80,7 @@ private:
|
||||
void createChildRow(ChildWidget<Ui::WidgetSlideWrap<Widget>> &child, style::margins &margin, const style::margins &padding, Args&&... args) {
|
||||
ChildWidget<Widget> plainChild = { nullptr };
|
||||
createChildRow(plainChild, margin, std_::forward<Args>(args)...);
|
||||
child = new Ui::WidgetSlideWrap<Widget>(this, plainChild, padding, [this]() {
|
||||
child.create(this, plainChild, padding, [this]() {
|
||||
rowHeightUpdated();
|
||||
});
|
||||
margin.setLeft(margin.left() - padding.left());
|
||||
|
@ -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<EmojiPanel*> &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<EmojiPanel*> &panels) {
|
||||
panels.back()->show();
|
||||
y += st::emojiPanHeader + rows * st::emojiPanSize.height();
|
||||
}
|
||||
_picker.raise();
|
||||
_picker->raise();
|
||||
}
|
||||
|
||||
void EmojiPanInner::refreshPanels(QVector<EmojiPanel*> &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<Ui::RoundButton>(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;
|
||||
|
@ -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<EmojiColorPicker> _picker;
|
||||
QTimer _showPickerTimer;
|
||||
|
||||
};
|
||||
|
||||
struct StickerIcon {
|
||||
@ -368,14 +367,12 @@ private:
|
||||
QTimer _updateInlineItems;
|
||||
bool _inlineWithThumb = false;
|
||||
|
||||
std_::unique_ptr<Ui::RoundButton> _switchPmButton;
|
||||
ChildWidget<Ui::RoundButton> _switchPmButton = { nullptr };
|
||||
QString _switchPmStartToken;
|
||||
|
||||
typedef QVector<InlineItem*> InlineItems;
|
||||
struct InlineRow {
|
||||
InlineRow() : height(0) {
|
||||
}
|
||||
int32 height;
|
||||
int height = 0;
|
||||
InlineItems items;
|
||||
};
|
||||
typedef QVector<InlineRow> InlineRows;
|
||||
@ -629,17 +626,17 @@ private:
|
||||
|
||||
Ui::PanelAnimation::Origin _origin = Ui::PanelAnimation::Origin::BottomRight;
|
||||
std_::unique_ptr<Ui::PanelAnimation> _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> _slideAnimation;
|
||||
FloatAnimation _a_slide;
|
||||
Animation _a_slide;
|
||||
|
||||
ChildWidget<Ui::IconButton> _recent;
|
||||
ChildWidget<Ui::IconButton> _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;
|
||||
|
@ -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()) {
|
||||
|
@ -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<Type, Param>(param, obj, method));
|
||||
}
|
||||
|
||||
template <typename AnimType>
|
||||
class SimpleAnimation {
|
||||
class Animation {
|
||||
public:
|
||||
using ValueType = typename AnimType::ValueType;
|
||||
using Callback = base::lambda<void()>;
|
||||
|
||||
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 <typename Lambda>
|
||||
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<Data>(from, std_::forward<Lambda>(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 <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::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<void()> &updateCallback)
|
||||
Data(float64 from, const base::lambda_copy<void()> &updateCallback)
|
||||
: value(from, from)
|
||||
, a_animation(animation(this, &Data::step))
|
||||
, updateCallback(base::lambda_copy<void()>(updateCallback)) {
|
||||
@ -633,9 +637,9 @@ private:
|
||||
updateCallback();
|
||||
}
|
||||
|
||||
AnimType value;
|
||||
Animation a_animation;
|
||||
Callback updateCallback;
|
||||
anim::value value;
|
||||
BasicAnimation a_animation;
|
||||
base::lambda<void()> updateCallback;
|
||||
float64 duration = 0.;
|
||||
anim::transition transition = anim::linear;
|
||||
MTP::PauseHolder pause;
|
||||
@ -644,16 +648,14 @@ private:
|
||||
|
||||
};
|
||||
|
||||
using FloatAnimation = SimpleAnimation<anim::value>;
|
||||
|
||||
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<Animation*>;
|
||||
using AnimatingObjects = OrderedSet<BasicAnimation*>;
|
||||
AnimatingObjects _objects, _starting, _stopping;
|
||||
QTimer _timer;
|
||||
bool _iterating;
|
||||
|
@ -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)) {
|
||||
|
@ -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) {
|
||||
|
@ -51,7 +51,7 @@ private:
|
||||
float64 _opacity = 0.;
|
||||
anim::value a_arcEnd;
|
||||
anim::value a_arcStart;
|
||||
Animation _animation;
|
||||
BasicAnimation _animation;
|
||||
|
||||
};
|
||||
|
||||
|
@ -46,8 +46,8 @@ private:
|
||||
int _radiusTo = 0;
|
||||
|
||||
bool _hiding = false;
|
||||
FloatAnimation _show;
|
||||
FloatAnimation _hide;
|
||||
Animation _show;
|
||||
Animation _hide;
|
||||
QPixmap _cache;
|
||||
QImage _frame;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
FloatAnimation _animation;
|
||||
Animation _animation;
|
||||
QPixmap _leftSnapshot;
|
||||
QPixmap _rightSnapshot;
|
||||
bool _slideLeft = false;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ private:
|
||||
void updateCallback();
|
||||
|
||||
TWidget *_widget;
|
||||
FloatAnimation _animation;
|
||||
Animation _animation;
|
||||
QPixmap _cache;
|
||||
bool _visible = false;
|
||||
|
||||
|
@ -31,8 +31,7 @@ WidgetSlideWrap<TWidget>::WidgetSlideWrap(QWidget *parent
|
||||
, _entity(entity)
|
||||
, _padding(entityPadding)
|
||||
, _duration(duration)
|
||||
, _updateCallback(std_::move(updateCallback))
|
||||
, _a_height(animation(this, &WidgetSlideWrap<TWidget>::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<TWidget>::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<TWidget>::slideDown() {
|
||||
@ -69,15 +65,14 @@ void WidgetSlideWrap<TWidget>::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<TWidget>::showFast() {
|
||||
show();
|
||||
_a_height.stop();
|
||||
_a_height.finish();
|
||||
_forceHeight = -1;
|
||||
resizeToWidth(_realSize.width());
|
||||
if (_updateCallback) {
|
||||
@ -86,8 +81,7 @@ void WidgetSlideWrap<TWidget>::showFast() {
|
||||
}
|
||||
|
||||
void WidgetSlideWrap<TWidget>::hideFast() {
|
||||
_a_height.stop();
|
||||
a_height = anim::value();
|
||||
_a_height.finish();
|
||||
_forceHeight = 0;
|
||||
resizeToWidth(_realSize.width());
|
||||
hide();
|
||||
@ -135,18 +129,13 @@ int WidgetSlideWrap<TWidget>::resizeGetHeight(int newWidth) {
|
||||
return _realSize.height();
|
||||
}
|
||||
|
||||
void WidgetSlideWrap<TWidget>::step_height(float64 ms, bool timer) {
|
||||
auto dt = ms / _duration;
|
||||
if (dt >= 1) {
|
||||
a_height.finish();
|
||||
_a_height.stop();
|
||||
void WidgetSlideWrap<TWidget>::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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<internal::Widget>(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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.;
|
||||
|
@ -92,7 +92,7 @@ private:
|
||||
|
||||
int _pressed = -1;
|
||||
int _selected = 0;
|
||||
FloatAnimation _a_left;
|
||||
Animation _a_left;
|
||||
|
||||
int _timerId = -1;
|
||||
TimeMs _callbackAfterMs = 0;
|
||||
|
@ -108,11 +108,11 @@ private:
|
||||
|
||||
PanelAnimation::Origin _origin = PanelAnimation::Origin::TopLeft;
|
||||
std_::unique_ptr<PanelAnimation> _showAnimation;
|
||||
FloatAnimation _a_show;
|
||||
Animation _a_show;
|
||||
|
||||
bool _hiding = false;
|
||||
QPixmap _cache;
|
||||
FloatAnimation _a_opacity;
|
||||
Animation _a_opacity;
|
||||
|
||||
QTimer _hideTimer;
|
||||
bool _ignoreShowEvents = false;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -137,7 +137,7 @@ private:
|
||||
QMargins itemPaintMargins() const;
|
||||
|
||||
const style::MultiSelect &_st;
|
||||
FloatAnimation _iconOpacity;
|
||||
Animation _iconOpacity;
|
||||
|
||||
ScrollCallback _scrollCallback;
|
||||
|
||||
@ -157,7 +157,7 @@ private:
|
||||
ChildWidget<Ui::CrossButton> _cancel;
|
||||
|
||||
int _newHeight = 0;
|
||||
FloatAnimation _height;
|
||||
Animation _height;
|
||||
|
||||
base::lambda<void(const QString &query)> _queryChangedCallback;
|
||||
base::lambda<void(bool ctrlShiftEnter)> _submittedCallback;
|
||||
|
@ -119,12 +119,12 @@ private:
|
||||
|
||||
PanelAnimation::Origin _origin = PanelAnimation::Origin::TopLeft;
|
||||
std_::unique_ptr<PanelAnimation> _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;
|
||||
|
@ -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<ScrollArea*>(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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ protected:
|
||||
|
||||
private:
|
||||
const style::color &_color;
|
||||
FloatAnimation _a_opacity;
|
||||
Animation _a_opacity;
|
||||
bool _shown = true;
|
||||
|
||||
};
|
||||
|
@ -64,7 +64,6 @@ FlatButton {
|
||||
|
||||
font: font;
|
||||
overFont: font;
|
||||
duration: int;
|
||||
|
||||
ripple: RippleAnimation;
|
||||
}
|
||||
|
@ -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(); });
|
||||
|
@ -114,7 +114,7 @@ private:
|
||||
using QueuedNotifications = QList<QueuedNotification>;
|
||||
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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -53,7 +53,7 @@ private:
|
||||
SlideDirection _direction = SlideDirection::FromRight;
|
||||
bool _topBarShadowEnabled = false;
|
||||
|
||||
mutable FloatAnimation _animation;
|
||||
mutable Animation _animation;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
|
||||
RepaintCallback _repaintCallback;
|
||||
|
@ -52,7 +52,7 @@ private:
|
||||
void handleTimer();
|
||||
|
||||
bool _hiding = false;
|
||||
FloatAnimation _animation;
|
||||
Animation _animation;
|
||||
QPixmap _cache;
|
||||
QRect _inner, _outer;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user