Intro redesign done.
|
@ -125,8 +125,10 @@ notificationSampleTextFg: #d7d7d7 | windowSubTextFg;
|
||||||
notificationSampleNameFg: #939393 | windowSubTextFg;
|
notificationSampleNameFg: #939393 | windowSubTextFg;
|
||||||
|
|
||||||
// intro
|
// intro
|
||||||
introHeaderFg: windowFg;
|
introBg: windowBg;
|
||||||
introErrorFg: windowFg;
|
introTitleFg: windowBoldFg;
|
||||||
|
introDescriptionFg: windowSubTextFg;
|
||||||
|
introErrorFg: windowSubTextFg;
|
||||||
|
|
||||||
// dialogs
|
// dialogs
|
||||||
dialogsMenuIconFg: menuIconFg;
|
dialogsMenuIconFg: menuIconFg;
|
||||||
|
|
After Width: | Height: | Size: 159 B |
After Width: | Height: | Size: 203 B |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 1020 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 17 KiB |
|
@ -138,7 +138,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
"lng_pinned_unpin" = "Unpin";
|
"lng_pinned_unpin" = "Unpin";
|
||||||
"lng_pinned_notify" = "Notify all members";
|
"lng_pinned_notify" = "Notify all members";
|
||||||
|
|
||||||
"lng_intro" = "Welcome to the official [a href=\"https://telegram.org/\"]Telegram[/a] desktop app.\nIt's [b]fast[/b] and [b]secure[/b].";
|
"lng_intro_about" = "Welcome to the official Telegram Desktop app.\nIt's fast and secure.";
|
||||||
"lng_start_msgs" = "START MESSAGING";
|
"lng_start_msgs" = "START MESSAGING";
|
||||||
|
|
||||||
"lng_intro_next" = "NEXT";
|
"lng_intro_next" = "NEXT";
|
||||||
|
@ -150,7 +150,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
"lng_phone_ph" = "Your phone number";
|
"lng_phone_ph" = "Your phone number";
|
||||||
"lng_phone_title" = "Your Phone";
|
"lng_phone_title" = "Your Phone";
|
||||||
"lng_phone_desc" = "Please confirm your country code and\nenter your phone number.";
|
"lng_phone_desc" = "Please confirm your country code and\nenter your phone number.";
|
||||||
"lng_phone_notreg" = "Note: if you don't have a Telegram account yet,\nplease [b]sign up[/b] with your [a href=\"https://telegram.org/\"]iOS / Android[/a] or {signup_start}here »{signup_end}";
|
"lng_phone_notreg" = "If you don't have a Telegram account yet,\nplease [b]sign up[/b] with {link_start}Android / iPhone{link_end} or {signup_start}here{signup_end}";
|
||||||
"lng_country_code" = "Country Code";
|
"lng_country_code" = "Country Code";
|
||||||
"lng_bad_country_code" = "Invalid Country Code";
|
"lng_bad_country_code" = "Invalid Country Code";
|
||||||
"lng_country_ph" = "Search";
|
"lng_country_ph" = "Search";
|
||||||
|
@ -160,7 +160,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
"lng_code_ph" = "Your code";
|
"lng_code_ph" = "Your code";
|
||||||
"lng_code_desc" = "We have sent you a message with activation\ncode to your phone. Please enter it below.";
|
"lng_code_desc" = "We have sent you a message with activation\ncode to your phone. Please enter it below.";
|
||||||
"lng_code_telegram" = "Please enter the code you've just\nreceived in your previous [b]Telegram[/b] app.";
|
"lng_code_telegram" = "Please enter the code you've just received\nin your previous [b]Telegram[/b] app.";
|
||||||
"lng_code_no_telegram" = "Send code via SMS";
|
"lng_code_no_telegram" = "Send code via SMS";
|
||||||
"lng_code_call" = "Telegram will dial your number in {minutes}:{seconds}";
|
"lng_code_call" = "Telegram will dial your number in {minutes}:{seconds}";
|
||||||
"lng_code_calling" = "Requesting a call from Telegram...";
|
"lng_code_calling" = "Requesting a call from Telegram...";
|
||||||
|
@ -174,7 +174,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
"lng_signin_title" = "Cloud password check";
|
"lng_signin_title" = "Cloud password check";
|
||||||
"lng_signin_desc" = "Please enter your cloud password.";
|
"lng_signin_desc" = "Please enter your cloud password.";
|
||||||
"lng_signin_recover_desc" = "Please enter the code from the e-mail.";
|
"lng_signin_recover_desc" = "Please enter the code from the e-mail\n{email}";
|
||||||
"lng_signin_password" = "Your cloud password";
|
"lng_signin_password" = "Your cloud password";
|
||||||
"lng_signin_code" = "Code from e-mail";
|
"lng_signin_code" = "Code from e-mail";
|
||||||
"lng_signin_recover" = "Forgot password?";
|
"lng_signin_recover" = "Forgot password?";
|
||||||
|
@ -196,7 +196,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
"lng_signin_reset_in_minutes" = "{count_minutes:0 minutes|# minute|# minutes}";
|
"lng_signin_reset_in_minutes" = "{count_minutes:0 minutes|# minute|# minutes}";
|
||||||
"lng_signin_reset_cancelled" = "Your recent attempts to reset this account have been cancelled by its active user. Please try again in 7 days.";
|
"lng_signin_reset_cancelled" = "Your recent attempts to reset this account have been cancelled by its active user. Please try again in 7 days.";
|
||||||
|
|
||||||
"lng_signup_title" = "Information and photo";
|
"lng_signup_title" = "Your Info";
|
||||||
"lng_signup_desc" = "Please enter your name and\nupload a photo.";
|
"lng_signup_desc" = "Please enter your name and\nupload a photo.";
|
||||||
|
|
||||||
"lng_signup_firstname" = "First Name";
|
"lng_signup_firstname" = "First Name";
|
||||||
|
|
|
@ -102,8 +102,10 @@ notificationSampleUserpicFg: windowBgActive;
|
||||||
notificationSampleCloseFg: #d7d7d7; // windowSubTextFg;
|
notificationSampleCloseFg: #d7d7d7; // windowSubTextFg;
|
||||||
notificationSampleTextFg: #d7d7d7; // windowSubTextFg;
|
notificationSampleTextFg: #d7d7d7; // windowSubTextFg;
|
||||||
notificationSampleNameFg: #939393; // windowSubTextFg;
|
notificationSampleNameFg: #939393; // windowSubTextFg;
|
||||||
introHeaderFg: windowFg;
|
introBg: windowBg;
|
||||||
introErrorFg: windowFg;
|
introTitleFg: windowBoldFg;
|
||||||
|
introDescriptionFg: windowSubTextFg;
|
||||||
|
introErrorFg: windowSubTextFg;
|
||||||
dialogsMenuIconFg: menuIconFg;
|
dialogsMenuIconFg: menuIconFg;
|
||||||
dialogsMenuIconFgOver: menuIconFgOver;
|
dialogsMenuIconFgOver: menuIconFgOver;
|
||||||
dialogsBg: windowBg;
|
dialogsBg: windowBg;
|
||||||
|
|
|
@ -2546,7 +2546,7 @@ namespace {
|
||||||
|
|
||||||
QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) {
|
QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) {
|
||||||
QFile f(file);
|
QFile f(file);
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
if (f.size() > MediaViewImageSizeLimit || !f.open(QIODevice::ReadOnly)) {
|
||||||
if (animated) *animated = false;
|
if (animated) *animated = false;
|
||||||
return QImage();
|
return QImage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ void AddContactBox::onRetry() {
|
||||||
|
|
||||||
GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : AbstractBox()
|
GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : AbstractBox()
|
||||||
, _creating(creating)
|
, _creating(creating)
|
||||||
, _photo(this, st::newGroupPhotoSize)
|
, _photo(this, st::newGroupPhotoSize, st::newGroupPhotoIconPosition)
|
||||||
, _title(this, st::defaultInputField, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name))
|
, _title(this, st::defaultInputField, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name))
|
||||||
, _description(this, st::newGroupDescription, lang(lng_create_group_description))
|
, _description(this, st::newGroupDescription, lang(lng_create_group_description))
|
||||||
, _next(this, lang(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), st::defaultBoxButton)
|
, _next(this, lang(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), st::defaultBoxButton)
|
||||||
|
@ -276,15 +276,14 @@ GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : Ab
|
||||||
connect(_next, SIGNAL(clicked()), this, SLOT(onNext()));
|
connect(_next, SIGNAL(clicked()), this, SLOT(onNext()));
|
||||||
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||||
|
|
||||||
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
|
||||||
notifyFileQueryUpdated(update);
|
|
||||||
});
|
|
||||||
|
|
||||||
_photo->setClickedCallback([this] {
|
_photo->setClickedCallback([this] {
|
||||||
auto imgExtensions = cImgExtensions();
|
auto imgExtensions = cImgExtensions();
|
||||||
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
||||||
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
_setPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
||||||
});
|
});
|
||||||
|
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
||||||
|
notifyFileQueryUpdated(update);
|
||||||
|
});
|
||||||
|
|
||||||
prepare();
|
prepare();
|
||||||
}
|
}
|
||||||
|
@ -418,7 +417,7 @@ void GroupInfoBox::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update)
|
||||||
if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
|
if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PhotoCropBox *box = new PhotoCropBox(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0));
|
auto box = new PhotoCropBox(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0));
|
||||||
connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&)));
|
connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&)));
|
||||||
Ui::showLayer(box, KeepOtherLayers);
|
Ui::showLayer(box, KeepOtherLayers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,8 +401,7 @@ sessionTerminateAllButton: LinkButton(boxLinkButton) {
|
||||||
|
|
||||||
passcodeHeaderFont: font(19px);
|
passcodeHeaderFont: font(19px);
|
||||||
passcodeHeaderHeight: 80px;
|
passcodeHeaderHeight: 80px;
|
||||||
passcodeInput: FlatInput(introPhone) {
|
passcodeInput: introPhone;
|
||||||
}
|
|
||||||
passcodeSubmit: RoundButton(introNextButton) {
|
passcodeSubmit: RoundButton(introNextButton) {
|
||||||
width: 225px;
|
width: 225px;
|
||||||
}
|
}
|
||||||
|
@ -420,8 +419,6 @@ newGroupLinkTop: 3px;
|
||||||
newGroupLinkFont: font(16px);
|
newGroupLinkFont: font(16px);
|
||||||
|
|
||||||
newGroupPhotoSize: 76px;
|
newGroupPhotoSize: 76px;
|
||||||
newGroupPhotoBg: #4eb5f0;
|
|
||||||
newGroupPhotoBgOver: #3fa9e7;
|
|
||||||
newGroupPhotoIcon: icon {{ "new_chat_photo", #ffffff }};
|
newGroupPhotoIcon: icon {{ "new_chat_photo", #ffffff }};
|
||||||
newGroupPhotoIconPosition: point(23px, 25px);
|
newGroupPhotoIconPosition: point(23px, 25px);
|
||||||
newGroupPhotoDuration: 150;
|
newGroupPhotoDuration: 150;
|
||||||
|
|
|
@ -65,6 +65,10 @@ void PhotoCropBox::init(const QImage &img, PeerData *peer) {
|
||||||
int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||||
_thumb = App::pixmapFromImageInPlace(img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
_thumb = App::pixmapFromImageInPlace(img.scaled(s * cIntRetinaFactor(), s * cIntRetinaFactor(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
_mask = QImage(_thumb.size(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
_mask.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
_fade = QImage(_thumb.size(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
_fade.setDevicePixelRatio(cRetinaFactor());
|
||||||
_thumbw = _thumb.width() / cIntRetinaFactor();
|
_thumbw = _thumb.width() / cIntRetinaFactor();
|
||||||
_thumbh = _thumb.height() / cIntRetinaFactor();
|
_thumbh = _thumb.height() / cIntRetinaFactor();
|
||||||
if (_thumbw > _thumbh) {
|
if (_thumbw > _thumbh) {
|
||||||
|
@ -238,18 +242,16 @@ void PhotoCropBox::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
p.translate(_thumbx, _thumby);
|
p.translate(_thumbx, _thumby);
|
||||||
p.drawPixmap(0, 0, _thumb);
|
p.drawPixmap(0, 0, _thumb);
|
||||||
if (_cropy > 0) {
|
_mask.fill(Qt::white);
|
||||||
p.fillRect(QRect(0, 0, _cropx + _cropw, _cropy), st::photoCropFadeBg);
|
{
|
||||||
}
|
Painter p(&_mask);
|
||||||
if (_cropx + _cropw < _thumbw) {
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
p.fillRect(QRect(_cropx + _cropw, 0, _thumbw - _cropx - _cropw, _cropy + _cropw), st::photoCropFadeBg);
|
p.setPen(Qt::NoPen);
|
||||||
}
|
p.setBrush(Qt::black);
|
||||||
if (_cropy + _cropw < _thumbh) {
|
p.drawEllipse(_cropx, _cropy, _cropw, _cropw);
|
||||||
p.fillRect(QRect(_cropx, _cropy + _cropw, _thumbw - _cropx, _thumbh - _cropy - _cropw), st::photoCropFadeBg);
|
|
||||||
}
|
|
||||||
if (_cropx > 0) {
|
|
||||||
p.fillRect(QRect(0, _cropy, _cropx, _thumbh - _cropy), st::photoCropFadeBg);
|
|
||||||
}
|
}
|
||||||
|
style::colorizeImage(_mask, st::photoCropFadeBg->c, &_fade);
|
||||||
|
p.drawImage(0, 0, _fade);
|
||||||
|
|
||||||
int delta = st::cropPointSize;
|
int delta = st::cropPointSize;
|
||||||
int mdelta = -delta / 2;
|
int mdelta = -delta / 2;
|
||||||
|
|
|
@ -62,6 +62,7 @@ private:
|
||||||
ChildWidget<Ui::RoundButton> _cancel;
|
ChildWidget<Ui::RoundButton> _cancel;
|
||||||
QImage _img;
|
QImage _img;
|
||||||
QPixmap _thumb;
|
QPixmap _thumb;
|
||||||
|
QImage _mask, _fade;
|
||||||
PeerId _peerId;
|
PeerId _peerId;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,6 +34,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/effects/slide_animation.h"
|
||||||
#include "ui/widgets/discrete_sliders.h"
|
#include "ui/widgets/discrete_sliders.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -338,37 +339,12 @@ void StickersBox::paintEvent(QPaintEvent *e) {
|
||||||
_about.draw(p, st::stickersReorderPadding.top(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
|
_about.draw(p, st::stickersReorderPadding.top(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_leftCache.isNull()) {
|
if (_slideAnimation) {
|
||||||
auto slide = _a_slide.current(getms(), _slideLeft ? 0. : 1.);
|
_slideAnimation->paintFrame(p, scrollArea()->x(), scrollArea()->y() - titleHeight(), width(), getms());
|
||||||
if (!_a_slide.animating()) {
|
if (!_slideAnimation->animating()) {
|
||||||
_leftCache = _rightCache = QPixmap();
|
_slideAnimation.reset();
|
||||||
scrollArea()->show();
|
scrollArea()->show();
|
||||||
update();
|
update();
|
||||||
} else {
|
|
||||||
auto easeOut = anim::easeOutCirc(1., slide);
|
|
||||||
auto easeIn = anim::easeInCirc(1., slide);
|
|
||||||
auto cacheWidth = (_leftCache.width() / cIntRetinaFactor());
|
|
||||||
auto arrivingCoord = anim::interpolate(cacheWidth, 0, easeOut);
|
|
||||||
auto departingCoord = anim::interpolate(0, cacheWidth, easeIn);
|
|
||||||
auto arrivingAlpha = easeIn;
|
|
||||||
auto departingAlpha = 1. - easeOut;
|
|
||||||
auto leftCoord = (_slideLeft ? arrivingCoord : departingCoord) * -1;
|
|
||||||
auto leftAlpha = (_slideLeft ? arrivingAlpha : departingAlpha);
|
|
||||||
auto rightCoord = (_slideLeft ? departingCoord : arrivingCoord);
|
|
||||||
auto rightAlpha = (_slideLeft ? departingAlpha : arrivingAlpha);
|
|
||||||
|
|
||||||
auto x = scrollArea()->x();
|
|
||||||
auto y = scrollArea()->y() - titleHeight();
|
|
||||||
auto leftWidth = (cacheWidth + leftCoord);
|
|
||||||
if (leftWidth > 0) {
|
|
||||||
p.setOpacity(leftAlpha);
|
|
||||||
p.drawPixmap(x, y, leftWidth, _leftCache.height() / cIntRetinaFactor(), _leftCache, (_leftCache.width() - leftWidth * cIntRetinaFactor()), 0, leftWidth * cIntRetinaFactor(), _leftCache.height());
|
|
||||||
}
|
|
||||||
auto rightWidth = cacheWidth - rightCoord;
|
|
||||||
if (rightWidth > 0) {
|
|
||||||
p.setOpacity(rightAlpha);
|
|
||||||
p.drawPixmap(x + rightCoord, y, _rightCache, 0, 0, rightWidth * cIntRetinaFactor(), _rightCache.height());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,14 +406,11 @@ void StickersBox::switchTab() {
|
||||||
auto nowCache = grabContentCache();
|
auto nowCache = grabContentCache();
|
||||||
auto nowIndex = _tab->index;
|
auto nowIndex = _tab->index;
|
||||||
|
|
||||||
_leftCache = std_::move(wasCache);
|
_slideAnimation = std_::make_unique<Ui::SlideAnimation>();
|
||||||
_rightCache = std_::move(nowCache);
|
_slideAnimation->setSnapshots(std_::move(wasCache), std_::move(nowCache));
|
||||||
_slideLeft = (wasIndex > nowIndex);
|
auto slideLeft = wasIndex > nowIndex;
|
||||||
if (_slideLeft) {
|
_slideAnimation->start(slideLeft, [this] { update(); }, st::slideDuration);
|
||||||
std_::swap_moveable(_leftCache, _rightCache);
|
|
||||||
}
|
|
||||||
scrollArea()->hide();
|
scrollArea()->hide();
|
||||||
_a_slide.start([this] { update(); }, 0., 1., st::slideDuration);
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -602,6 +575,8 @@ void StickersBox::closePressed() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StickersBox::~StickersBox() = default;
|
||||||
|
|
||||||
StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent)
|
StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent)
|
||||||
, _section(section)
|
, _section(section)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
|
|
|
@ -33,6 +33,7 @@ class PlainShadow;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
class RippleAnimation;
|
class RippleAnimation;
|
||||||
class SettingsSlider;
|
class SettingsSlider;
|
||||||
|
class SlideAnimation;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class StickersBox : public ItemListBox, public RPCSender {
|
class StickersBox : public ItemListBox, public RPCSender {
|
||||||
|
@ -48,6 +49,8 @@ public:
|
||||||
StickersBox(Section section = Section::Installed);
|
StickersBox(Section section = Section::Installed);
|
||||||
StickersBox(const Stickers::Order &archivedIds);
|
StickersBox(const Stickers::Order &archivedIds);
|
||||||
|
|
||||||
|
~StickersBox();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onStickersUpdated();
|
void onStickersUpdated();
|
||||||
|
|
||||||
|
@ -111,9 +114,7 @@ private:
|
||||||
ChildWidget<Ui::RoundButton> _done = { nullptr };
|
ChildWidget<Ui::RoundButton> _done = { nullptr };
|
||||||
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
|
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
|
||||||
|
|
||||||
FloatAnimation _a_slide;
|
std_::unique_ptr<Ui::SlideAnimation> _slideAnimation;
|
||||||
bool _slideLeft = false;
|
|
||||||
QPixmap _leftCache, _rightCache;
|
|
||||||
|
|
||||||
QTimer _scrollTimer;
|
QTimer _scrollTimer;
|
||||||
int32 _scrollDelta = 0;
|
int32 _scrollDelta = 0;
|
||||||
|
|
|
@ -516,8 +516,8 @@ void start() {
|
||||||
|
|
||||||
SandboxData->LangSystemISO = psCurrentLanguage();
|
SandboxData->LangSystemISO = psCurrentLanguage();
|
||||||
if (SandboxData->LangSystemISO.isEmpty()) SandboxData->LangSystemISO = qstr("en");
|
if (SandboxData->LangSystemISO.isEmpty()) SandboxData->LangSystemISO = qstr("en");
|
||||||
QByteArray l = LangSystemISO().toLatin1();
|
auto l = LangSystemISO().toLatin1();
|
||||||
for (int32 i = 0; i < languageCount; ++i) {
|
for (auto i = 0; i < languageCount; ++i) {
|
||||||
if (l.at(0) == LanguageCodes[i][0] && l.at(1) == LanguageCodes[i][1]) {
|
if (l.at(0) == LanguageCodes[i][0] && l.at(1) == LanguageCodes[i][1]) {
|
||||||
SandboxData->LangSystem = i;
|
SandboxData->LangSystem = i;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,119 +21,135 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
using "basic.style";
|
using "basic.style";
|
||||||
using "ui/widgets/widgets.style";
|
using "ui/widgets/widgets.style";
|
||||||
|
|
||||||
countryInput {
|
introCoverHeight: 208px;
|
||||||
width: pixels;
|
introCoverTopBg: #0f89d0;
|
||||||
height: pixels;
|
introCoverBottomBg: #39b0f0;
|
||||||
top: pixels;
|
introCoverIconsFg: #5ec6ff;
|
||||||
bgColor: color;
|
introCoverMaxWidth: 880px;
|
||||||
ptrSize: size;
|
introCoverIconsMinSkip: 120px;
|
||||||
textMrg: margins;
|
introCoverLeft: icon {{ "intro_left", introCoverIconsFg }};
|
||||||
font: font;
|
introCoverRight: icon {{ "intro_right", introCoverIconsFg }};
|
||||||
align: align;
|
introCoverIcon: icon {
|
||||||
}
|
{ "intro_plane_trace", #5ec6ff69 },
|
||||||
|
{ "intro_plane_inner", #c6d8e8 },
|
||||||
|
{ "intro_plane_outer", #a1bed4 },
|
||||||
|
{ "intro_plane_top", #ffffff },
|
||||||
|
};
|
||||||
|
introCoverIconLeft: 50px;
|
||||||
|
introCoverIconTop: 46px;
|
||||||
|
|
||||||
introCountry: countryInput {
|
introSettingsSkip: 10px;
|
||||||
width: 300px;
|
|
||||||
height: 41px;
|
|
||||||
top: 33px;
|
|
||||||
bgColor: windowBgOver;
|
|
||||||
ptrSize: size(15px, 8px);
|
|
||||||
textMrg: margins(16px, 5px, 16px, 15px);
|
|
||||||
font: defaultInputFont;
|
|
||||||
align: align(left);
|
|
||||||
}
|
|
||||||
|
|
||||||
introIcon: icon {{ "intro_logo", #008ed5 }};
|
introPhotoSize: 76px;
|
||||||
|
introPhotoIconPosition: point(23px, 25px);
|
||||||
|
introPhotoTop: 10px;
|
||||||
|
|
||||||
introResetLink: LinkButton(defaultLinkButton) {
|
introCoverTitle: FlatLabel(defaultFlatLabel) {
|
||||||
color: #d15948;
|
font: font(22px semibold);
|
||||||
overColor: #d15948;
|
textFg: introTitleFg;
|
||||||
downColor: #db6352;
|
|
||||||
}
|
|
||||||
|
|
||||||
introBtnTop: 288px;
|
|
||||||
introSkip: 25px;
|
|
||||||
introFinishSkip: 15px;
|
|
||||||
introPhotoSize: 98px;
|
|
||||||
introHeaderFont: font(24px);
|
|
||||||
introHeaderSkip: 14px;
|
|
||||||
introIconSkip: 50px;
|
|
||||||
introFont: font(16px);
|
|
||||||
introLink: LinkButton(defaultLinkButton) {
|
|
||||||
font: introFont;
|
|
||||||
overFont: font(16px underline);
|
|
||||||
}
|
|
||||||
introLabel: FlatLabel(defaultFlatLabel) {
|
|
||||||
font: introFont;
|
|
||||||
align: align(center);
|
align: align(center);
|
||||||
}
|
}
|
||||||
|
introCoverTitleTop: 126px;
|
||||||
|
introCoverDescription: FlatLabel(defaultFlatLabel) {
|
||||||
|
font: font(15px);
|
||||||
|
textFg: introDescriptionFg;
|
||||||
|
align: align(center);
|
||||||
|
}
|
||||||
|
introCoverDescriptionTextStyle: TextStyle(defaultTextStyle) {
|
||||||
|
lineHeight: 24px;
|
||||||
|
}
|
||||||
|
introCoverDescriptionTop: 164px;
|
||||||
|
introTitle: FlatLabel(defaultFlatLabel) {
|
||||||
|
font: font(17px semibold);
|
||||||
|
textFg: introTitleFg;
|
||||||
|
}
|
||||||
|
introTitleTop: 11px;
|
||||||
|
introDescription: FlatLabel(defaultFlatLabel) {
|
||||||
|
font: normalFont;
|
||||||
|
textFg: introDescriptionFg;
|
||||||
|
}
|
||||||
|
introDescriptionTextStyle: TextStyle(defaultTextStyle) {
|
||||||
|
lineHeight: 20px;
|
||||||
|
}
|
||||||
|
introDescriptionTop: 44px;
|
||||||
|
|
||||||
introStepSize: size(400px, 200px);
|
introLink: defaultLinkButton;
|
||||||
introSize: size(400px, 460px);
|
|
||||||
introSlideShift: 500px; // intro hiding animation
|
introPlaneWidth: 48px;
|
||||||
|
introPlaneHeight: 38px;
|
||||||
|
introHeight: 396px;
|
||||||
|
introStepTopMin: 86px;
|
||||||
|
introStepWidth: 380px;
|
||||||
|
introStepHeight: 256px;
|
||||||
|
introStepHeightAdd: 30px;
|
||||||
|
introStepHeightFull: 580px;
|
||||||
introSlideDuration: 200;
|
introSlideDuration: 200;
|
||||||
introSlideDelta: 0; // between hide start and show start
|
introCoverDuration: 200;
|
||||||
introTextTop: 22px;
|
|
||||||
introTextSize: size(400px, 93px);
|
|
||||||
introCallSkip: 15px;
|
|
||||||
introPwdTextSize: size(400px, 73px);
|
|
||||||
|
|
||||||
introNextButton: RoundButton(defaultActiveButton) {
|
introNextButton: RoundButton(defaultActiveButton) {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
|
|
||||||
textTop: 16px;
|
textTop: 17px;
|
||||||
|
font: font(17px semibold);
|
||||||
font: font(17px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
introPhoneTop: 8px;
|
introStepFieldTop: 116px;
|
||||||
introCountryCode: FlatInput(defaultFlatInput) {
|
introPhoneTop: 16px;
|
||||||
width: 70px;
|
introLinkTop: 21px;
|
||||||
|
introCountry: InputField(defaultInputField) {
|
||||||
|
textMargins: margins(3px, 7px, 3px, 6px);
|
||||||
|
font: font(16px);
|
||||||
|
width: 300px;
|
||||||
height: 41px;
|
height: 41px;
|
||||||
align: align(center);
|
|
||||||
}
|
}
|
||||||
introPhone: FlatInput(defaultFlatInput) {
|
introCountryCode: InputField(introCountry) {
|
||||||
textMrg: margins(12px, 5px, 12px, 6px);
|
width: 64px;
|
||||||
|
height: 41px;
|
||||||
|
textAlign: align(top);
|
||||||
|
}
|
||||||
|
introPhone: InputField(introCountry) {
|
||||||
|
textMargins: margins(12px, 7px, 12px, 6px);
|
||||||
width: 225px;
|
width: 225px;
|
||||||
height: 41px;
|
height: 41px;
|
||||||
}
|
}
|
||||||
introCode: FlatInput(defaultFlatInput) {
|
introCode: introCountry;
|
||||||
textMrg: margins(12px, 5px, 12px, 6px);
|
introName: introCountry;
|
||||||
width: 106px;
|
introPassword: introCountry;
|
||||||
height: 41px;
|
introPasswordTop: 94px;
|
||||||
align: align(center);
|
introPasswordHintTop: 146px;
|
||||||
|
|
||||||
phPos: point(0px, 0px);
|
introPasswordHint: FlatLabel(introDescription) {
|
||||||
phAlign: align(center);
|
textFg: windowFg;
|
||||||
phShift: 0px;
|
|
||||||
}
|
}
|
||||||
introName: FlatInput(introPhone) {
|
introPasswordHintTextStyle: introDescriptionTextStyle;
|
||||||
width: 192px;
|
|
||||||
}
|
introResetButton: RoundButton(defaultLightButton) {
|
||||||
introPassword: FlatInput(introPhone) {
|
textFg: attentionButtonFg;
|
||||||
width: 300px;
|
textFgOver: attentionButtonFgOver;
|
||||||
|
textBgOver: attentionButtonBgOver;
|
||||||
|
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: attentionButtonBgRipple;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
introResetBottom: 20px;
|
||||||
|
|
||||||
|
introCountryIcon: icon {{ "intro_country_dropdown", menuIconFg }};
|
||||||
|
introCountryIconPosition: point(8px, 17px);
|
||||||
|
|
||||||
introSelectDelta: 30px;
|
introSelectDelta: 30px;
|
||||||
|
|
||||||
introErrorWidth: 450px;
|
introErrorTop: 225px;
|
||||||
|
introErrorBelowLinkTop: 213px;
|
||||||
introErrorDuration: 200;
|
introErrorDuration: 200;
|
||||||
introErrorTop: 15px;
|
|
||||||
introErrorHeight: 40px;
|
|
||||||
introErrorFont: font(16px);
|
|
||||||
|
|
||||||
introLabelTextStyle: TextStyle(defaultTextStyle) {
|
introError: introDescription;
|
||||||
lineHeight: 30px;
|
introErrorCentered: FlatLabel(introError) {
|
||||||
}
|
|
||||||
introErrorLabelTextStyle: TextStyle(defaultTextStyle) {
|
|
||||||
lineHeight: 27px;
|
|
||||||
}
|
|
||||||
|
|
||||||
introErrorLabel: FlatLabel(defaultFlatLabel) {
|
|
||||||
font: introErrorFont;
|
|
||||||
align: align(center);
|
align: align(center);
|
||||||
}
|
}
|
||||||
|
introErrorTextStyle: introDescriptionTextStyle;
|
||||||
|
|
||||||
introBackButton: IconButton(defaultIconButton) {
|
introBackButton: IconButton(defaultIconButton) {
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
|
|
|
@ -26,21 +26,28 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "intro/introsignup.h"
|
#include "intro/introsignup.h"
|
||||||
#include "intro/intropwdcheck.h"
|
#include "intro/intropwdcheck.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
#include "styles/style_intro.h"
|
#include "styles/style_intro.h"
|
||||||
|
|
||||||
CodeInput::CodeInput(QWidget *parent, const style::FlatInput &st, const QString &ph) : Ui::FlatInput(parent, st, ph) {
|
namespace Intro {
|
||||||
|
|
||||||
|
CodeInput::CodeInput(QWidget *parent, const style::InputField &st, const QString &ph) : Ui::MaskedInputField(parent, st, ph) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeInput::correctValue(const QString &was, QString &now) {
|
void CodeInput::setDigitsCountMax(int digitsCount) {
|
||||||
|
_digitsCountMax = digitsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeInput::correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) {
|
||||||
QString newText;
|
QString newText;
|
||||||
int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), digitCount = 0;
|
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), digitCount = 0;
|
||||||
for (int i = 0; i < oldLen; ++i) {
|
for (int i = 0; i < oldLen; ++i) {
|
||||||
if (now[i].isDigit()) {
|
if (now[i].isDigit()) {
|
||||||
++digitCount;
|
++digitCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (digitCount > 5) digitCount = 5;
|
accumulate_min(digitCount, _digitsCountMax);
|
||||||
bool strict = (digitCount == 5);
|
auto strict = (digitCount == _digitsCountMax);
|
||||||
|
|
||||||
newText.reserve(oldLen);
|
newText.reserve(oldLen);
|
||||||
for (int i = 0; i < oldLen; ++i) {
|
for (int i = 0; i < oldLen; ++i) {
|
||||||
|
@ -58,177 +65,131 @@ void CodeInput::correctValue(const QString &was, QString &now) {
|
||||||
newPos = newText.length();
|
newPos = newText.length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newPos < 0) {
|
if (newPos < 0 || newPos > newText.size()) {
|
||||||
newPos = newText.length();
|
newPos = newText.size();
|
||||||
}
|
}
|
||||||
if (newText != now) {
|
if (newText != now) {
|
||||||
now = newText;
|
now = newText;
|
||||||
setText(now);
|
setText(now);
|
||||||
updatePlaceholder();
|
updatePlaceholder();
|
||||||
if (newPos != oldPos) {
|
}
|
||||||
setCursorPosition(newPos);
|
if (newPos != nowCursor) {
|
||||||
}
|
nowCursor = newPos;
|
||||||
|
setCursorPosition(nowCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strict) emit codeEntered();
|
if (strict) emit codeEntered();
|
||||||
}
|
}
|
||||||
|
|
||||||
IntroCode::IntroCode(IntroWidget *parent) : IntroStep(parent)
|
CodeWidget::CodeWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||||
, a_errorAlpha(0)
|
|
||||||
, _a_error(animation(this, &IntroCode::step_error))
|
|
||||||
, _next(this, lang(lng_intro_next), st::introNextButton)
|
|
||||||
, _desc(st::introTextSize.width())
|
|
||||||
, _noTelegramCode(this, lang(lng_code_no_telegram), st::introLink)
|
, _noTelegramCode(this, lang(lng_code_no_telegram), st::introLink)
|
||||||
, _noTelegramCodeRequestId(0)
|
|
||||||
, _code(this, st::introCode, lang(lng_code_ph))
|
, _code(this, st::introCode, lang(lng_code_ph))
|
||||||
, _callTimer(this)
|
, _callTimer(this)
|
||||||
, _callStatus(intro()->getCallStatus())
|
, _callStatus(getData()->callStatus)
|
||||||
|
, _callTimeout(getData()->callTimeout)
|
||||||
|
, _callLabel(this, st::introDescription, st::introDescriptionTextStyle)
|
||||||
, _checkRequest(this) {
|
, _checkRequest(this) {
|
||||||
setGeometry(parent->innerRect());
|
|
||||||
|
|
||||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitCode()));
|
|
||||||
connect(_code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
connect(_code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||||
connect(_callTimer, SIGNAL(timeout()), this, SLOT(onSendCall()));
|
connect(_callTimer, SIGNAL(timeout()), this, SLOT(onSendCall()));
|
||||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||||
connect(_noTelegramCode, SIGNAL(clicked()), this, SLOT(onNoTelegramCode()));
|
connect(_noTelegramCode, SIGNAL(clicked()), this, SLOT(onNoTelegramCode()));
|
||||||
|
|
||||||
updateDescText();
|
_code->setDigitsCountMax(getData()->codeLength);
|
||||||
|
setErrorBelowLink(true);
|
||||||
|
|
||||||
if (!intro()->codeByTelegram()) {
|
setTitleText(App::formatPhone(getData()->phone));
|
||||||
if (_callStatus.type == IntroWidget::CallWaiting) {
|
updateDescText();
|
||||||
_callTimer->start(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::updateDescText() {
|
void CodeWidget::updateDescText() {
|
||||||
_desc.setRichText(st::introFont, lang(intro()->codeByTelegram() ? lng_code_telegram : lng_code_desc));
|
setDescriptionText(lang(getData()->codeByTelegram ? lng_code_telegram : lng_code_desc));
|
||||||
if (intro()->codeByTelegram()) {
|
if (getData()->codeByTelegram) {
|
||||||
_noTelegramCode->show();
|
_noTelegramCode->show();
|
||||||
_callTimer->stop();
|
_callTimer->stop();
|
||||||
} else {
|
} else {
|
||||||
_noTelegramCode->hide();
|
_noTelegramCode->hide();
|
||||||
_callStatus = intro()->getCallStatus();
|
_callStatus = getData()->callStatus;
|
||||||
if (_callStatus.type == IntroWidget::CallWaiting && !_callTimer->isActive()) {
|
_callTimeout = getData()->callTimeout;
|
||||||
|
if (_callStatus == Widget::Data::CallStatus::Waiting && !_callTimer->isActive()) {
|
||||||
_callTimer->start(1000);
|
_callTimer->start(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update();
|
updateCallText();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::paintEvent(QPaintEvent *e) {
|
void CodeWidget::updateCallText() {
|
||||||
bool trivial = (rect() == e->rect());
|
auto text = ([this]() -> QString {
|
||||||
|
if (getData()->codeByTelegram) {
|
||||||
QPainter p(this);
|
return QString();
|
||||||
if (!trivial) {
|
}
|
||||||
p.setClipRect(e->rect());
|
switch (_callStatus) {
|
||||||
}
|
case Widget::Data::CallStatus::Waiting: {
|
||||||
bool codeByTelegram = intro()->codeByTelegram();
|
if (_callTimeout >= 3600) {
|
||||||
if (trivial || e->rect().intersects(_textRect)) {
|
return lng_code_call(lt_minutes, qsl("%1:%2").arg(_callTimeout / 3600).arg((_callTimeout / 60) % 60, 2, 10, QChar('0')), lt_seconds, qsl("%1").arg(_callTimeout % 60, 2, 10, QChar('0')));
|
||||||
p.setFont(st::introHeaderFont->f);
|
|
||||||
p.drawText(_textRect, intro()->getPhone(), style::al_top);
|
|
||||||
p.setFont(st::introFont->f);
|
|
||||||
_desc.draw(p, _textRect.x(), _textRect.y() + _textRect.height() - 2 * st::introFont->height, _textRect.width(), style::al_top);
|
|
||||||
}
|
|
||||||
if (codeByTelegram) {
|
|
||||||
} else {
|
|
||||||
QString callText;
|
|
||||||
switch (_callStatus.type) {
|
|
||||||
case IntroWidget::CallWaiting: {
|
|
||||||
if (_callStatus.timeout >= 3600) {
|
|
||||||
callText = lng_code_call(lt_minutes, qsl("%1:%2").arg(_callStatus.timeout / 3600).arg((_callStatus.timeout / 60) % 60, 2, 10, QChar('0')), lt_seconds, qsl("%1").arg(_callStatus.timeout % 60, 2, 10, QChar('0')));
|
|
||||||
} else {
|
} else {
|
||||||
callText = lng_code_call(lt_minutes, QString::number(_callStatus.timeout / 60), lt_seconds, qsl("%1").arg(_callStatus.timeout % 60, 2, 10, QChar('0')));
|
return lng_code_call(lt_minutes, QString::number(_callTimeout / 60), lt_seconds, qsl("%1").arg(_callTimeout % 60, 2, 10, QChar('0')));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case Widget::Data::CallStatus::Calling: return lang(lng_code_calling);
|
||||||
case IntroWidget::CallCalling: {
|
case Widget::Data::CallStatus::Called: return lang(lng_code_called);
|
||||||
callText = lang(lng_code_calling);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case IntroWidget::CallCalled: {
|
|
||||||
callText = lang(lng_code_called);
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
if (!callText.isEmpty()) {
|
return QString();
|
||||||
p.drawText(QRect(_textRect.left(), _code->y() + _code->height() + st::introCallSkip, st::introTextSize.width(), st::introErrorHeight), callText, style::al_center);
|
})();
|
||||||
}
|
_callLabel->setText(text);
|
||||||
}
|
_callLabel->setVisible(!text.isEmpty() && !animating());
|
||||||
if (_a_error.animating() || _error.length()) {
|
|
||||||
p.setOpacity(a_errorAlpha.current());
|
|
||||||
p.setFont(st::introErrorFont);
|
|
||||||
p.setPen(st::introErrorFg);
|
|
||||||
p.drawText(QRect(_textRect.left(), _next->y() + _next->height() + st::introErrorTop, st::introTextSize.width(), st::introErrorHeight), _error, style::al_center);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::resizeEvent(QResizeEvent *e) {
|
void CodeWidget::resizeEvent(QResizeEvent *e) {
|
||||||
if (e->oldSize().width() != width()) {
|
Step::resizeEvent(e);
|
||||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
_code->moveToLeft(contentLeft(), contentTop() + st::introStepFieldTop);
|
||||||
_code->move((width() - _code->width()) / 2, st::introTextTop + st::introTextSize.height() + st::introCountry.top);
|
auto linkTop = _code->y() + _code->height() + st::introLinkTop;
|
||||||
}
|
_noTelegramCode->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||||
_textRect = QRect((width() - st::introTextSize.width()) / 2, st::introTextTop, st::introTextSize.width(), st::introTextSize.height());
|
_callLabel->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||||
_noTelegramCode->move(_textRect.left() + (st::introTextSize.width() - _noTelegramCode->width()) / 2, _code->y() + _code->height() + st::introCallSkip + (st::introErrorHeight - _noTelegramCode->height()) / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::showError(const QString &error) {
|
void CodeWidget::showCodeError(const QString &text) {
|
||||||
if (!error.isEmpty()) _code->notaBene();
|
if (!text.isEmpty()) _code->showError();
|
||||||
if (!_a_error.animating() && error == _error) return;
|
showError(text);
|
||||||
|
|
||||||
if (error.length()) {
|
|
||||||
_error = error;
|
|
||||||
a_errorAlpha.start(1);
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.start(0);
|
|
||||||
}
|
|
||||||
_a_error.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::step_error(float64 ms, bool timer) {
|
void CodeWidget::setInnerFocus() {
|
||||||
float64 dt = ms / st::introErrorDuration;
|
|
||||||
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_error.stop();
|
|
||||||
a_errorAlpha.finish();
|
|
||||||
if (!a_errorAlpha.current()) {
|
|
||||||
_error.clear();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroCode::activate() {
|
|
||||||
IntroStep::activate();
|
|
||||||
_code->setFocus();
|
_code->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::finished() {
|
void CodeWidget::activate() {
|
||||||
IntroStep::finished();
|
Step::activate();
|
||||||
_error.clear();
|
_code->show();
|
||||||
a_errorAlpha = anim::fvalue(0);
|
if (getData()->codeByTelegram) {
|
||||||
|
_noTelegramCode->show();
|
||||||
_sentCode.clear();
|
} else {
|
||||||
_code->setDisabled(false);
|
_callLabel->show();
|
||||||
|
|
||||||
_callTimer->stop();
|
|
||||||
_code->setText(QString());
|
|
||||||
rpcClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroCode::cancelled() {
|
|
||||||
if (_sentRequest) {
|
|
||||||
MTP::cancel(base::take(_sentRequest));
|
|
||||||
}
|
}
|
||||||
MTP::send(MTPauth_CancelCode(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash())));
|
setInnerFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::stopCheck() {
|
void CodeWidget::finished() {
|
||||||
|
Step::finished();
|
||||||
|
_checkRequest->stop();
|
||||||
|
_callTimer->stop();
|
||||||
|
rpcClear();
|
||||||
|
|
||||||
|
cancelled();
|
||||||
|
_sentCode.clear();
|
||||||
|
_code->setText(QString());
|
||||||
|
_code->setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeWidget::cancelled() {
|
||||||
|
MTP::cancel(base::take(_sentRequest));
|
||||||
|
MTP::cancel(base::take(_callRequestId));
|
||||||
|
MTP::send(MTPauth_CancelCode(MTP_string(getData()->phone), MTP_string(getData()->phoneHash)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeWidget::stopCheck() {
|
||||||
_checkRequest->stop();
|
_checkRequest->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::onCheckRequest() {
|
void CodeWidget::onCheckRequest() {
|
||||||
int32 status = MTP::state(_sentRequest);
|
int32 status = MTP::state(_sentRequest);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
int32 leftms = -status;
|
int32 leftms = -status;
|
||||||
|
@ -248,26 +209,25 @@ void IntroCode::onCheckRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::codeSubmitDone(const MTPauth_Authorization &result) {
|
void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
_code->setDisabled(false);
|
_code->setDisabled(false);
|
||||||
const auto &d(result.c_auth_authorization());
|
auto &d = result.c_auth_authorization();
|
||||||
if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf?
|
if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf?
|
||||||
showError(lang(lng_server_error));
|
showCodeError(lang(lng_server_error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cSetLoggedPhoneNumber(intro()->getPhone());
|
cSetLoggedPhoneNumber(getData()->phone);
|
||||||
intro()->finish(d.vuser);
|
finish(d.vuser);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroCode::codeSubmitFail(const RPCError &error) {
|
bool CodeWidget::codeSubmitFail(const RPCError &error) {
|
||||||
if (MTP::isFloodError(error)) {
|
if (MTP::isFloodError(error)) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
showError(lang(lng_flood_error));
|
|
||||||
_code->setDisabled(false);
|
_code->setDisabled(false);
|
||||||
_code->setFocus();
|
showCodeError(lang(lng_flood_error));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (MTP::isDefaultHandledError(error)) return false;
|
if (MTP::isDefaultHandledError(error)) return false;
|
||||||
|
@ -277,138 +237,138 @@ bool IntroCode::codeSubmitFail(const RPCError &error) {
|
||||||
_code->setDisabled(false);
|
_code->setDisabled(false);
|
||||||
const QString &err = error.type();
|
const QString &err = error.type();
|
||||||
if (err == qstr("PHONE_NUMBER_INVALID") || err == qstr("PHONE_CODE_EXPIRED")) { // show error
|
if (err == qstr("PHONE_NUMBER_INVALID") || err == qstr("PHONE_CODE_EXPIRED")) { // show error
|
||||||
intro()->onBack();
|
goBack();
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID")) {
|
} else if (err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID")) {
|
||||||
showError(lang(lng_bad_code));
|
showCodeError(lang(lng_bad_code));
|
||||||
_code->notaBene();
|
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("PHONE_NUMBER_UNOCCUPIED")) { // success, need to signUp
|
} else if (err == qstr("PHONE_NUMBER_UNOCCUPIED")) { // success, need to signUp
|
||||||
intro()->setCode(_sentCode);
|
getData()->code = _sentCode;
|
||||||
intro()->replaceStep(new IntroSignup(intro()));
|
goReplace(new Intro::SignupWidget(parentWidget(), getData()));
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("SESSION_PASSWORD_NEEDED")) {
|
} else if (err == qstr("SESSION_PASSWORD_NEEDED")) {
|
||||||
intro()->setCode(_sentCode);
|
getData()->code = _sentCode;
|
||||||
_code->setDisabled(false);
|
_code->setDisabled(false);
|
||||||
_checkRequest->start(1000);
|
_checkRequest->start(1000);
|
||||||
_sentRequest = MTP::send(MTPaccount_GetPassword(), rpcDone(&IntroCode::gotPassword), rpcFail(&IntroCode::codeSubmitFail));
|
_sentRequest = MTP::send(MTPaccount_GetPassword(), rpcDone(&CodeWidget::gotPassword), rpcFail(&CodeWidget::codeSubmitFail));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (cDebug()) { // internal server error
|
if (cDebug()) { // internal server error
|
||||||
showError(err + ": " + error.description());
|
showCodeError(err + ": " + error.description());
|
||||||
} else {
|
} else {
|
||||||
showError(lang(lng_server_error));
|
showCodeError(lang(lng_server_error));
|
||||||
}
|
}
|
||||||
_code->setFocus();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::onInputChange() {
|
void CodeWidget::onInputChange() {
|
||||||
showError(QString());
|
hideError();
|
||||||
if (_code->text().length() == 5) onSubmitCode();
|
if (_code->getLastText().length() == getData()->codeLength) {
|
||||||
|
submit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::onSendCall() {
|
void CodeWidget::onSendCall() {
|
||||||
if (_callStatus.type == IntroWidget::CallWaiting) {
|
if (_callStatus == Widget::Data::CallStatus::Waiting) {
|
||||||
if (--_callStatus.timeout <= 0) {
|
if (--_callTimeout <= 0) {
|
||||||
_callStatus.type = IntroWidget::CallCalling;
|
_callStatus = Widget::Data::CallStatus::Calling;
|
||||||
_callTimer->stop();
|
_callTimer->stop();
|
||||||
MTP::send(MTPauth_ResendCode(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash())), rpcDone(&IntroCode::callDone));
|
_callRequestId = MTP::send(MTPauth_ResendCode(MTP_string(getData()->phone), MTP_string(getData()->phoneHash)), rpcDone(&CodeWidget::callDone));
|
||||||
} else {
|
} else {
|
||||||
intro()->setCallStatus(_callStatus);
|
getData()->callStatus = _callStatus;
|
||||||
|
getData()->callTimeout = _callTimeout;
|
||||||
}
|
}
|
||||||
}
|
updateCallText();
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroCode::callDone(const MTPauth_SentCode &v) {
|
|
||||||
if (_callStatus.type == IntroWidget::CallCalling) {
|
|
||||||
_callStatus.type = IntroWidget::CallCalled;
|
|
||||||
intro()->setCallStatus(_callStatus);
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::gotPassword(const MTPaccount_Password &result) {
|
void CodeWidget::callDone(const MTPauth_SentCode &v) {
|
||||||
|
if (v.type() == mtpc_auth_sentCode) {
|
||||||
|
fillSentCodeData(v.c_auth_sentCode().vtype);
|
||||||
|
_code->setDigitsCountMax(getData()->codeLength);
|
||||||
|
}
|
||||||
|
if (_callStatus == Widget::Data::CallStatus::Calling) {
|
||||||
|
_callStatus = Widget::Data::CallStatus::Called;
|
||||||
|
getData()->callStatus = _callStatus;
|
||||||
|
getData()->callTimeout = _callTimeout;
|
||||||
|
updateCallText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeWidget::gotPassword(const MTPaccount_Password &result) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
_code->setDisabled(false);
|
_code->setDisabled(false);
|
||||||
switch (result.type()) {
|
switch (result.type()) {
|
||||||
case mtpc_account_noPassword: // should not happen
|
case mtpc_account_noPassword: { // should not happen
|
||||||
_code->setFocus();
|
_code->setFocus();
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
case mtpc_account_password: {
|
case mtpc_account_password: {
|
||||||
const auto &d(result.c_account_password());
|
auto &d = result.c_account_password();
|
||||||
intro()->setPwdSalt(qba(d.vcurrent_salt));
|
getData()->pwdSalt = qba(d.vcurrent_salt);
|
||||||
intro()->setHasRecovery(mtpIsTrue(d.vhas_recovery));
|
getData()->hasRecovery = mtpIsTrue(d.vhas_recovery);
|
||||||
intro()->setPwdHint(qs(d.vhint));
|
getData()->pwdHint = qs(d.vhint);
|
||||||
intro()->replaceStep(new IntroPwdCheck(intro()));
|
goReplace(new Intro::PwdCheckWidget(parentWidget(), getData()));
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::onSubmitCode() {
|
void CodeWidget::submit() {
|
||||||
if (_sentRequest) return;
|
if (_sentRequest) return;
|
||||||
|
|
||||||
_code->setDisabled(true);
|
_code->setDisabled(true);
|
||||||
setFocus();
|
setFocus();
|
||||||
|
|
||||||
showError(QString());
|
hideError();
|
||||||
|
|
||||||
_checkRequest->start(1000);
|
_checkRequest->start(1000);
|
||||||
|
|
||||||
_sentCode = _code->text();
|
_sentCode = _code->getLastText();
|
||||||
intro()->setPwdSalt(QByteArray());
|
getData()->pwdSalt = QByteArray();
|
||||||
intro()->setHasRecovery(false);
|
getData()->hasRecovery = false;
|
||||||
intro()->setPwdHint(QString());
|
getData()->pwdHint = QString();
|
||||||
_sentRequest = MTP::send(MTPauth_SignIn(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash()), MTP_string(_sentCode)), rpcDone(&IntroCode::codeSubmitDone), rpcFail(&IntroCode::codeSubmitFail));
|
_sentRequest = MTP::send(MTPauth_SignIn(MTP_string(getData()->phone), MTP_string(getData()->phoneHash), MTP_string(_sentCode)), rpcDone(&CodeWidget::codeSubmitDone), rpcFail(&CodeWidget::codeSubmitFail));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::onNoTelegramCode() {
|
void CodeWidget::onNoTelegramCode() {
|
||||||
if (_noTelegramCodeRequestId) return;
|
if (_noTelegramCodeRequestId) return;
|
||||||
_noTelegramCodeRequestId = MTP::send(MTPauth_ResendCode(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash())), rpcDone(&IntroCode::noTelegramCodeDone), rpcFail(&IntroCode::noTelegramCodeFail));
|
_noTelegramCodeRequestId = MTP::send(MTPauth_ResendCode(MTP_string(getData()->phone), MTP_string(getData()->phoneHash)), rpcDone(&CodeWidget::noTelegramCodeDone), rpcFail(&CodeWidget::noTelegramCodeFail));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::noTelegramCodeDone(const MTPauth_SentCode &result) {
|
void CodeWidget::noTelegramCodeDone(const MTPauth_SentCode &result) {
|
||||||
if (result.type() != mtpc_auth_sentCode) {
|
if (result.type() != mtpc_auth_sentCode) {
|
||||||
showError(lang(lng_server_error));
|
showCodeError(lang(lng_server_error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &d(result.c_auth_sentCode());
|
auto &d = result.c_auth_sentCode();
|
||||||
switch (d.vtype.type()) {
|
fillSentCodeData(d.vtype);
|
||||||
case mtpc_auth_sentCodeTypeApp: intro()->setCodeByTelegram(true);
|
_code->setDigitsCountMax(getData()->codeLength);
|
||||||
case mtpc_auth_sentCodeTypeSms:
|
|
||||||
case mtpc_auth_sentCodeTypeCall: intro()->setCodeByTelegram(false);
|
|
||||||
case mtpc_auth_sentCodeTypeFlashCall: LOG(("Error: should not be flashcall!")); break;
|
|
||||||
}
|
|
||||||
if (d.has_next_type() && d.vnext_type.type() == mtpc_auth_codeTypeCall) {
|
if (d.has_next_type() && d.vnext_type.type() == mtpc_auth_codeTypeCall) {
|
||||||
intro()->setCallStatus({ IntroWidget::CallWaiting, d.has_timeout() ? d.vtimeout.v : 60 });
|
getData()->callStatus = Widget::Data::CallStatus::Waiting;
|
||||||
|
getData()->callTimeout = d.has_timeout() ? d.vtimeout.v : 60;
|
||||||
} else {
|
} else {
|
||||||
intro()->setCallStatus({ IntroWidget::CallDisabled, 0 });
|
getData()->callStatus = Widget::Data::CallStatus::Disabled;
|
||||||
|
getData()->callTimeout = 0;
|
||||||
}
|
}
|
||||||
intro()->setCodeByTelegram(false);
|
getData()->codeByTelegram = false;
|
||||||
updateDescText();
|
updateDescText();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroCode::noTelegramCodeFail(const RPCError &error) {
|
bool CodeWidget::noTelegramCodeFail(const RPCError &error) {
|
||||||
if (MTP::isFloodError(error)) {
|
if (MTP::isFloodError(error)) {
|
||||||
showError(lang(lng_flood_error));
|
showCodeError(lang(lng_flood_error));
|
||||||
_code->setFocus();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (MTP::isDefaultHandledError(error)) return false;
|
if (MTP::isDefaultHandledError(error)) return false;
|
||||||
|
|
||||||
if (cDebug()) { // internal server error
|
if (cDebug()) { // internal server error
|
||||||
showError(error.type() + ": " + error.description());
|
showCodeError(error.type() + ": " + error.description());
|
||||||
} else {
|
} else {
|
||||||
showError(lang(lng_server_error));
|
showCodeError(lang(lng_server_error));
|
||||||
}
|
}
|
||||||
_code->setFocus();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroCode::onSubmit() {
|
} // namespace Intro
|
||||||
onSubmitCode();
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,55 +26,63 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
|
class FlatLabel;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class CodeInput final : public Ui::FlatInput {
|
namespace Intro {
|
||||||
|
|
||||||
|
class CodeInput final : public Ui::MaskedInputField {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CodeInput(QWidget *parent, const style::FlatInput &st, const QString &ph);
|
CodeInput(QWidget *parent, const style::InputField &st, const QString &ph);
|
||||||
|
|
||||||
|
void setDigitsCountMax(int digitsCount);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void codeEntered();
|
void codeEntered();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void correctValue(const QString &was, QString &now);
|
void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _digitsCountMax = 5;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IntroCode final : public IntroStep {
|
class CodeWidget : public Widget::Step {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntroCode(IntroWidget *parent);
|
CodeWidget(QWidget *parent, Widget::Data *data);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
|
|
||||||
void step_error(float64 ms, bool timer);
|
|
||||||
|
|
||||||
bool hasBack() const override {
|
bool hasBack() const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
void setInnerFocus() override;
|
||||||
void activate() override;
|
void activate() override;
|
||||||
void finished() override;
|
void finished() override;
|
||||||
void cancelled() override;
|
void cancelled() override;
|
||||||
void onSubmit() override;
|
void submit() override;
|
||||||
|
|
||||||
void codeSubmitDone(const MTPauth_Authorization &result);
|
|
||||||
bool codeSubmitFail(const RPCError &error);
|
|
||||||
|
|
||||||
void updateDescText();
|
void updateDescText();
|
||||||
|
|
||||||
public slots:
|
protected:
|
||||||
void onSubmitCode();
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
void onNoTelegramCode();
|
void onNoTelegramCode();
|
||||||
void onInputChange();
|
void onInputChange();
|
||||||
void onSendCall();
|
void onSendCall();
|
||||||
void onCheckRequest();
|
void onCheckRequest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void showError(const QString &err);
|
void updateCallText();
|
||||||
|
|
||||||
|
void codeSubmitDone(const MTPauth_Authorization &result);
|
||||||
|
bool codeSubmitFail(const RPCError &error);
|
||||||
|
|
||||||
|
void showCodeError(const QString &text);
|
||||||
void callDone(const MTPauth_SentCode &v);
|
void callDone(const MTPauth_SentCode &v);
|
||||||
void gotPassword(const MTPaccount_Password &result);
|
void gotPassword(const MTPaccount_Password &result);
|
||||||
|
|
||||||
|
@ -83,23 +91,21 @@ private:
|
||||||
|
|
||||||
void stopCheck();
|
void stopCheck();
|
||||||
|
|
||||||
QString _error;
|
|
||||||
anim::fvalue a_errorAlpha;
|
|
||||||
Animation _a_error;
|
|
||||||
|
|
||||||
ChildWidget<Ui::RoundButton> _next;
|
|
||||||
|
|
||||||
Text _desc;
|
|
||||||
ChildWidget<Ui::LinkButton> _noTelegramCode;
|
ChildWidget<Ui::LinkButton> _noTelegramCode;
|
||||||
mtpRequestId _noTelegramCodeRequestId;
|
mtpRequestId _noTelegramCodeRequestId = 0;
|
||||||
QRect _textRect;
|
|
||||||
|
|
||||||
ChildWidget<CodeInput> _code;
|
ChildWidget<CodeInput> _code;
|
||||||
QString _sentCode;
|
QString _sentCode;
|
||||||
mtpRequestId _sentRequest = 0;
|
mtpRequestId _sentRequest = 0;
|
||||||
|
|
||||||
ChildObject<QTimer> _callTimer;
|
ChildObject<QTimer> _callTimer;
|
||||||
IntroWidget::CallStatus _callStatus;
|
Widget::Data::CallStatus _callStatus;
|
||||||
|
int _callTimeout;
|
||||||
|
mtpRequestId _callRequestId = 0;
|
||||||
|
ChildWidget<Ui::FlatLabel> _callLabel;
|
||||||
|
|
||||||
ChildObject<QTimer> _checkRequest;
|
ChildObject<QTimer> _checkRequest;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -27,20 +27,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_intro.h"
|
#include "styles/style_intro.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
|
#include "ui/effects/widget_fade_wrap.h"
|
||||||
|
#include "core/click_handler_types.h"
|
||||||
|
|
||||||
IntroPhone::IntroPhone(IntroWidget *parent) : IntroStep(parent)
|
namespace Intro {
|
||||||
, a_errorAlpha(0)
|
|
||||||
, _a_error(animation(this, &IntroPhone::step_error))
|
PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||||
, _next(this, lang(lng_intro_next), st::introNextButton)
|
|
||||||
, _country(this, st::introCountry)
|
, _country(this, st::introCountry)
|
||||||
, _phone(this, st::introPhone)
|
|
||||||
, _code(this, st::introCountryCode)
|
, _code(this, st::introCountryCode)
|
||||||
, _signup(this, lng_phone_notreg(lt_signup_start, textcmdStartLink(1), lt_signup_end, textcmdStopLink()), Ui::FlatLabel::InitType::Rich, st::introErrorLabel, st::introErrorLabelTextStyle)
|
, _phone(this, st::introPhone)
|
||||||
, _checkRequest(this) {
|
, _checkRequest(this) {
|
||||||
setVisible(false);
|
|
||||||
setGeometry(parent->innerRect());
|
|
||||||
|
|
||||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitPhone()));
|
|
||||||
connect(_phone, SIGNAL(voidBackspace(QKeyEvent*)), _code, SLOT(startErasing(QKeyEvent*)));
|
connect(_phone, SIGNAL(voidBackspace(QKeyEvent*)), _code, SLOT(startErasing(QKeyEvent*)));
|
||||||
connect(_country, SIGNAL(codeChanged(const QString &)), _code, SLOT(codeSelected(const QString &)));
|
connect(_country, SIGNAL(codeChanged(const QString &)), _code, SLOT(codeSelected(const QString &)));
|
||||||
connect(_code, SIGNAL(codeChanged(const QString &)), _country, SLOT(onChooseCode(const QString &)));
|
connect(_code, SIGNAL(codeChanged(const QString &)), _country, SLOT(onChooseCode(const QString &)));
|
||||||
|
@ -49,146 +45,112 @@ IntroPhone::IntroPhone(IntroWidget *parent) : IntroStep(parent)
|
||||||
connect(_code, SIGNAL(addedToNumber(const QString &)), _phone, SLOT(addedToNumber(const QString &)));
|
connect(_code, SIGNAL(addedToNumber(const QString &)), _phone, SLOT(addedToNumber(const QString &)));
|
||||||
connect(_phone, SIGNAL(changed()), this, SLOT(onInputChange()));
|
connect(_phone, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||||
connect(_code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
connect(_code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||||
connect(intro(), SIGNAL(countryChanged()), this, SLOT(countryChanged()));
|
|
||||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||||
|
|
||||||
_signup->setLink(1, MakeShared<LambdaClickHandler>([this] {
|
setTitleText(lang(lng_phone_title));
|
||||||
toSignUp();
|
setDescriptionText(lang(lng_phone_desc));
|
||||||
}));
|
subscribe(getData()->updated, [this] { countryChanged(); });
|
||||||
_signup->hide();
|
setErrorCentered(true);
|
||||||
|
|
||||||
_signupCache = myGrab(_signup);
|
if (!_country->onChooseCountry(getData()->country)) {
|
||||||
|
|
||||||
if (!_country->onChooseCountry(intro()->currentCountry())) {
|
|
||||||
_country->onChooseCountry(qsl("US"));
|
_country->onChooseCountry(qsl("US"));
|
||||||
}
|
}
|
||||||
_changed = false;
|
_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::paintEvent(QPaintEvent *e) {
|
void PhoneWidget::resizeEvent(QResizeEvent *e) {
|
||||||
bool trivial = (rect() == e->rect());
|
Step::resizeEvent(e);
|
||||||
|
_country->moveToLeft(contentLeft(), contentTop() + st::introStepFieldTop);
|
||||||
|
auto phoneTop = _country->y() + _country->height() + st::introPhoneTop;
|
||||||
|
_code->moveToLeft(contentLeft(), phoneTop);
|
||||||
|
_phone->moveToLeft(contentLeft() + _country->width() - st::introPhone.width, phoneTop);
|
||||||
|
updateSignupGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
QPainter p(this);
|
void PhoneWidget::updateSignupGeometry() {
|
||||||
if (!trivial) {
|
if (_signup) {
|
||||||
p.setClipRect(e->rect());
|
_signup->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introDescriptionTop);
|
||||||
}
|
|
||||||
if (trivial || e->rect().intersects(_textRect)) {
|
|
||||||
p.setFont(st::introHeaderFont->f);
|
|
||||||
p.drawText(_textRect, lang(lng_phone_title), style::al_top);
|
|
||||||
p.setFont(st::introFont->f);
|
|
||||||
p.drawText(_textRect, lang(lng_phone_desc), style::al_bottom);
|
|
||||||
}
|
|
||||||
if (_a_error.animating() || _error.length()) {
|
|
||||||
int32 errorY = _showSignup ? ((_phone->y() + _phone->height() + _next->y() - st::introErrorFont->height) / 2) : (_next->y() + _next->height() + st::introErrorTop);
|
|
||||||
p.setOpacity(a_errorAlpha.current());
|
|
||||||
p.setFont(st::introErrorFont);
|
|
||||||
p.setPen(st::introErrorFg);
|
|
||||||
p.drawText(QRect(_textRect.x(), errorY, _textRect.width(), st::introErrorFont->height), _error, style::al_top);
|
|
||||||
|
|
||||||
if (_signup->isHidden() && _showSignup) {
|
|
||||||
p.drawPixmap(_signup->x(), _signup->y(), _signupCache);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::resizeEvent(QResizeEvent *e) {
|
void PhoneWidget::showPhoneError(const QString &text) {
|
||||||
if (e->oldSize().width() != width()) {
|
_phone->showError();
|
||||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
showError(text);
|
||||||
_country->move((width() - _country->width()) / 2, st::introTextTop + st::introTextSize.height() + st::introCountry.top);
|
|
||||||
int phoneTop = _country->y() + _country->height() + st::introPhoneTop;
|
|
||||||
_phone->move((width() - _country->width()) / 2 + _country->width() - st::introPhone.width, phoneTop);
|
|
||||||
_code->move((width() - _country->width()) / 2, phoneTop);
|
|
||||||
}
|
|
||||||
_signup->move((width() - _signup->width()) / 2, _next->y() + _next->height() + st::introErrorTop - ((st::introErrorLabelTextStyle.lineHeight - st::introErrorFont->height) / 2));
|
|
||||||
_textRect = QRect((width() - st::introTextSize.width()) / 2, st::introTextTop, st::introTextSize.width(), st::introTextSize.height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::showError(const QString &error, bool signUp) {
|
void PhoneWidget::hidePhoneError() {
|
||||||
if (!error.isEmpty()) {
|
hideError();
|
||||||
_phone->notaBene();
|
if (_signup) {
|
||||||
_showSignup = signUp;
|
_signup->fadeOut();
|
||||||
|
showDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_a_error.animating() && error == _error) return;
|
|
||||||
|
|
||||||
if (error.length()) {
|
|
||||||
_error = error;
|
|
||||||
a_errorAlpha.start(1);
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.start(0);
|
|
||||||
}
|
|
||||||
_signup->hide();
|
|
||||||
_a_error.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::step_error(float64 ms, bool timer) {
|
void PhoneWidget::showSignup() {
|
||||||
float64 dt = ms / st::introErrorDuration;
|
showPhoneError(lang(lng_bad_phone_noreg));
|
||||||
|
if (!_signup) {
|
||||||
if (dt >= 1) {
|
auto signupText = lng_phone_notreg(lt_link_start, textcmdStartLink(1), lt_link_end, textcmdStopLink(), lt_signup_start, textcmdStartLink(2), lt_signup_end, textcmdStopLink());
|
||||||
_a_error.stop();
|
auto inner = new Ui::FlatLabel(this, signupText, Ui::FlatLabel::InitType::Rich, st::introDescription, st::introDescriptionTextStyle);
|
||||||
a_errorAlpha.finish();
|
_signup.create(this, inner, base::lambda<void()>(), st::introErrorDuration);
|
||||||
if (!a_errorAlpha.current()) {
|
_signup->entity()->setLink(1, MakeShared<UrlClickHandler>(qsl("https://telegram.org"), false));
|
||||||
_error.clear();
|
_signup->entity()->setLink(2, MakeShared<LambdaClickHandler>([this] {
|
||||||
_signup->hide();
|
toSignUp();
|
||||||
} else if (!_error.isEmpty() && _showSignup) {
|
}));
|
||||||
_signup->show();
|
_signup->hideFast();
|
||||||
}
|
updateSignupGeometry();
|
||||||
} else {
|
|
||||||
a_errorAlpha.update(dt, anim::linear);
|
|
||||||
}
|
}
|
||||||
if (timer) update();
|
_signup->fadeIn();
|
||||||
|
hideDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::countryChanged() {
|
void PhoneWidget::countryChanged() {
|
||||||
if (!_changed) {
|
if (!_changed) {
|
||||||
selectCountry(intro()->currentCountry());
|
selectCountry(getData()->country);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::onInputChange() {
|
void PhoneWidget::onInputChange() {
|
||||||
_changed = true;
|
_changed = true;
|
||||||
showError(QString());
|
hidePhoneError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::disableAll() {
|
void PhoneWidget::disableAll() {
|
||||||
_next->setDisabled(true);
|
|
||||||
_phone->setDisabled(true);
|
_phone->setDisabled(true);
|
||||||
_country->setDisabled(true);
|
_country->setDisabled(true);
|
||||||
_code->setDisabled(true);
|
_code->setDisabled(true);
|
||||||
setFocus();
|
setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::enableAll(bool failed) {
|
void PhoneWidget::enableAll(bool failed) {
|
||||||
_next->setDisabled(false);
|
|
||||||
_phone->setDisabled(false);
|
_phone->setDisabled(false);
|
||||||
_country->setDisabled(false);
|
_country->setDisabled(false);
|
||||||
_code->setDisabled(false);
|
_code->setDisabled(false);
|
||||||
if (failed) _phone->setFocus();
|
if (failed) _phone->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::onSubmitPhone() {
|
void PhoneWidget::submit() {
|
||||||
if (_sentRequest || isHidden()) return;
|
if (_sentRequest || isHidden()) return;
|
||||||
|
|
||||||
if (!App::isValidPhone(fullNumber())) {
|
if (!App::isValidPhone(fullNumber())) {
|
||||||
showError(lang(lng_bad_phone));
|
showPhoneError(lang(lng_bad_phone));
|
||||||
_phone->setFocus();
|
_phone->setFocus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
disableAll();
|
disableAll();
|
||||||
showError(QString());
|
hidePhoneError();
|
||||||
|
|
||||||
_checkRequest->start(1000);
|
_checkRequest->start(1000);
|
||||||
|
|
||||||
_sentPhone = fullNumber();
|
_sentPhone = fullNumber();
|
||||||
_sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(_sentPhone)), rpcDone(&IntroPhone::phoneCheckDone), rpcFail(&IntroPhone::phoneSubmitFail));
|
_sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(_sentPhone)), rpcDone(&PhoneWidget::phoneCheckDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::stopCheck() {
|
void PhoneWidget::stopCheck() {
|
||||||
_checkRequest->stop();
|
_checkRequest->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::onCheckRequest() {
|
void PhoneWidget::onCheckRequest() {
|
||||||
int32 status = MTP::state(_sentRequest);
|
int32 status = MTP::state(_sentRequest);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
int32 leftms = -status;
|
int32 leftms = -status;
|
||||||
|
@ -202,66 +164,65 @@ void IntroPhone::onCheckRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::phoneCheckDone(const MTPauth_CheckedPhone &result) {
|
void PhoneWidget::phoneCheckDone(const MTPauth_CheckedPhone &result) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
|
|
||||||
const auto &d(result.c_auth_checkedPhone());
|
auto &d = result.c_auth_checkedPhone();
|
||||||
if (mtpIsTrue(d.vphone_registered)) {
|
if (mtpIsTrue(d.vphone_registered)) {
|
||||||
disableAll();
|
disableAll();
|
||||||
showError(QString());
|
hidePhoneError();
|
||||||
|
|
||||||
_checkRequest->start(1000);
|
_checkRequest->start(1000);
|
||||||
|
|
||||||
MTPauth_SendCode::Flags flags = 0;
|
MTPauth_SendCode::Flags flags = 0;
|
||||||
_sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(flags), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&IntroPhone::phoneSubmitDone), rpcFail(&IntroPhone::phoneSubmitFail));
|
_sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(flags), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&PhoneWidget::phoneSubmitDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||||
} else {
|
} else {
|
||||||
showError(lang(lng_bad_phone_noreg), true);
|
showSignup();
|
||||||
enableAll(true);
|
enableAll(true);
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::phoneSubmitDone(const MTPauth_SentCode &result) {
|
void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
enableAll(true);
|
enableAll(true);
|
||||||
|
|
||||||
if (result.type() != mtpc_auth_sentCode) {
|
if (result.type() != mtpc_auth_sentCode) {
|
||||||
showError(lang(lng_server_error));
|
showPhoneError(lang(lng_server_error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &d(result.c_auth_sentCode());
|
auto &d = result.c_auth_sentCode();
|
||||||
switch (d.vtype.type()) {
|
fillSentCodeData(d.vtype);
|
||||||
case mtpc_auth_sentCodeTypeApp: intro()->setCodeByTelegram(true); break;
|
getData()->phone = _sentPhone;
|
||||||
case mtpc_auth_sentCodeTypeSms:
|
getData()->phoneHash = d.vphone_code_hash.c_string().v.c_str();
|
||||||
case mtpc_auth_sentCodeTypeCall: intro()->setCodeByTelegram(false); break;
|
getData()->phoneIsRegistered = d.is_phone_registered();
|
||||||
case mtpc_auth_sentCodeTypeFlashCall: LOG(("Error: should not be flashcall!")); break;
|
|
||||||
}
|
|
||||||
intro()->setPhone(_sentPhone, d.vphone_code_hash.c_string().v.c_str(), d.is_phone_registered());
|
|
||||||
if (d.has_next_type() && d.vnext_type.type() == mtpc_auth_codeTypeCall) {
|
if (d.has_next_type() && d.vnext_type.type() == mtpc_auth_codeTypeCall) {
|
||||||
intro()->setCallStatus({ IntroWidget::CallWaiting, d.has_timeout() ? d.vtimeout.v : 60 });
|
getData()->callStatus = Widget::Data::CallStatus::Waiting;
|
||||||
|
getData()->callTimeout = d.has_timeout() ? d.vtimeout.v : 60;
|
||||||
} else {
|
} else {
|
||||||
intro()->setCallStatus({ IntroWidget::CallDisabled, 0 });
|
getData()->callStatus = Widget::Data::CallStatus::Disabled;
|
||||||
|
getData()->callTimeout = 0;
|
||||||
}
|
}
|
||||||
intro()->nextStep(new IntroCode(intro()));
|
goNext(new Intro::CodeWidget(parentWidget(), getData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::toSignUp() {
|
void PhoneWidget::toSignUp() {
|
||||||
disableAll();
|
disableAll();
|
||||||
showError(QString());
|
hideError(); // Hide error, but leave the signup label visible.
|
||||||
|
|
||||||
_checkRequest->start(1000);
|
_checkRequest->start(1000);
|
||||||
|
|
||||||
MTPauth_SendCode::Flags flags = 0;
|
MTPauth_SendCode::Flags flags = 0;
|
||||||
_sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(flags), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&IntroPhone::phoneSubmitDone), rpcFail(&IntroPhone::phoneSubmitFail));
|
_sentRequest = MTP::send(MTPauth_SendCode(MTP_flags(flags), MTP_string(_sentPhone), MTPBool(), MTP_int(ApiId), MTP_string(ApiHash)), rpcDone(&PhoneWidget::phoneSubmitDone), rpcFail(&PhoneWidget::phoneSubmitFail));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroPhone::phoneSubmitFail(const RPCError &error) {
|
bool PhoneWidget::phoneSubmitFail(const RPCError &error) {
|
||||||
if (MTP::isFloodError(error)) {
|
if (MTP::isFloodError(error)) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
showError(lang(lng_flood_error));
|
showPhoneError(lang(lng_flood_error));
|
||||||
enableAll(true);
|
enableAll(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -271,48 +232,50 @@ bool IntroPhone::phoneSubmitFail(const RPCError &error) {
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
const QString &err = error.type();
|
const QString &err = error.type();
|
||||||
if (err == qstr("PHONE_NUMBER_INVALID")) { // show error
|
if (err == qstr("PHONE_NUMBER_INVALID")) { // show error
|
||||||
showError(lang(lng_bad_phone));
|
showPhoneError(lang(lng_bad_phone));
|
||||||
enableAll(true);
|
enableAll(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (cDebug()) { // internal server error
|
if (cDebug()) { // internal server error
|
||||||
showError(err + ": " + error.description());
|
showPhoneError(err + ": " + error.description());
|
||||||
} else {
|
} else {
|
||||||
showError(lang(lng_server_error));
|
showPhoneError(lang(lng_server_error));
|
||||||
}
|
}
|
||||||
enableAll(true);
|
enableAll(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString IntroPhone::fullNumber() const {
|
QString PhoneWidget::fullNumber() const {
|
||||||
return _code->text() + _phone->text();
|
return _code->getLastText() + _phone->getLastText();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::selectCountry(const QString &c) {
|
void PhoneWidget::selectCountry(const QString &c) {
|
||||||
_country->onChooseCountry(c);
|
_country->onChooseCountry(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::activate() {
|
void PhoneWidget::setInnerFocus() {
|
||||||
IntroStep::activate();
|
|
||||||
_phone->setFocus();
|
_phone->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::finished() {
|
void PhoneWidget::activate() {
|
||||||
IntroStep::finished();
|
Step::activate();
|
||||||
|
_country->show();
|
||||||
|
_phone->show();
|
||||||
|
_code->show();
|
||||||
|
setInnerFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneWidget::finished() {
|
||||||
|
Step::finished();
|
||||||
_checkRequest->stop();
|
_checkRequest->stop();
|
||||||
rpcClear();
|
rpcClear();
|
||||||
|
|
||||||
_error.clear();
|
cancelled();
|
||||||
a_errorAlpha = anim::fvalue(0);
|
|
||||||
enableAll(true);
|
enableAll(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::cancelled() {
|
void PhoneWidget::cancelled() {
|
||||||
if (_sentRequest) {
|
MTP::cancel(base::take(_sentRequest));
|
||||||
MTP::cancel(base::take(_sentRequest));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPhone::onSubmit() {
|
} // namespace Intro
|
||||||
onSubmitPhone();
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,35 +30,41 @@ class RoundButton;
|
||||||
class FlatLabel;
|
class FlatLabel;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class IntroPhone final : public IntroStep {
|
namespace Intro {
|
||||||
|
|
||||||
|
class PhoneWidget : public Widget::Step, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntroPhone(IntroWidget *parent);
|
PhoneWidget(QWidget *parent, Widget::Data *data);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
|
|
||||||
void step_error(float64 ms, bool timer);
|
|
||||||
|
|
||||||
void selectCountry(const QString &country);
|
void selectCountry(const QString &country);
|
||||||
|
|
||||||
|
void setInnerFocus() override;
|
||||||
void activate() override;
|
void activate() override;
|
||||||
void finished() override;
|
void finished() override;
|
||||||
void cancelled() override;
|
void cancelled() override;
|
||||||
void onSubmit() override;
|
void submit() override;
|
||||||
|
|
||||||
|
bool hasBack() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onInputChange();
|
||||||
|
void onCheckRequest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateSignupGeometry();
|
||||||
|
void countryChanged();
|
||||||
|
|
||||||
void phoneCheckDone(const MTPauth_CheckedPhone &result);
|
void phoneCheckDone(const MTPauth_CheckedPhone &result);
|
||||||
void phoneSubmitDone(const MTPauth_SentCode &result);
|
void phoneSubmitDone(const MTPauth_SentCode &result);
|
||||||
bool phoneSubmitFail(const RPCError &error);
|
bool phoneSubmitFail(const RPCError &error);
|
||||||
|
|
||||||
public slots:
|
|
||||||
void countryChanged();
|
|
||||||
void onInputChange();
|
|
||||||
void onSubmitPhone();
|
|
||||||
void onCheckRequest();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void toSignUp();
|
void toSignUp();
|
||||||
|
|
||||||
QString fullNumber() const;
|
QString fullNumber() const;
|
||||||
|
@ -66,24 +72,17 @@ private:
|
||||||
void enableAll(bool failed);
|
void enableAll(bool failed);
|
||||||
void stopCheck();
|
void stopCheck();
|
||||||
|
|
||||||
void showError(const QString &err, bool signUp = false);
|
void showPhoneError(const QString &text);
|
||||||
|
void hidePhoneError();
|
||||||
QString _error;
|
void showSignup();
|
||||||
anim::fvalue a_errorAlpha;
|
|
||||||
Animation _a_error;
|
|
||||||
|
|
||||||
bool _changed = false;
|
bool _changed = false;
|
||||||
ChildWidget<Ui::RoundButton> _next;
|
|
||||||
|
|
||||||
QRect _textRect;
|
|
||||||
|
|
||||||
ChildWidget<CountryInput> _country;
|
ChildWidget<CountryInput> _country;
|
||||||
ChildWidget<Ui::PhonePartInput> _phone;
|
|
||||||
ChildWidget<Ui::CountryCodeInput> _code;
|
ChildWidget<Ui::CountryCodeInput> _code;
|
||||||
|
ChildWidget<Ui::PhonePartInput> _phone;
|
||||||
|
|
||||||
ChildWidget<Ui::FlatLabel> _signup;
|
ChildWidget<Ui::WidgetFadeWrap<Ui::FlatLabel>> _signup = { nullptr };
|
||||||
QPixmap _signupCache;
|
|
||||||
bool _showSignup = false;
|
|
||||||
|
|
||||||
QString _sentPhone;
|
QString _sentPhone;
|
||||||
mtpRequestId _sentRequest = 0;
|
mtpRequestId _sentRequest = 0;
|
||||||
|
@ -91,3 +90,5 @@ private:
|
||||||
ChildObject<QTimer> _checkRequest;
|
ChildObject<QTimer> _checkRequest;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -30,117 +30,52 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "intro/introsignup.h"
|
#include "intro/introsignup.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
|
|
||||||
IntroPwdCheck::IntroPwdCheck(IntroWidget *parent) : IntroStep(parent)
|
namespace Intro {
|
||||||
, a_errorAlpha(0)
|
|
||||||
, _a_error(animation(this, &IntroPwdCheck::step_error))
|
PwdCheckWidget::PwdCheckWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||||
, _next(this, lang(lng_intro_submit), st::introNextButton)
|
, _salt(getData()->pwdSalt)
|
||||||
, _salt(parent->getPwdSalt())
|
, _hasRecovery(getData()->hasRecovery)
|
||||||
, _hasRecovery(parent->getHasRecovery())
|
, _hint(getData()->pwdHint)
|
||||||
, _hint(parent->getPwdHint())
|
|
||||||
, _pwdField(this, st::introPassword, lang(lng_signin_password))
|
, _pwdField(this, st::introPassword, lang(lng_signin_password))
|
||||||
|
, _pwdHint(this, st::introPasswordHint, st::introPasswordHintTextStyle)
|
||||||
, _codeField(this, st::introPassword, lang(lng_signin_code))
|
, _codeField(this, st::introPassword, lang(lng_signin_code))
|
||||||
, _toRecover(this, lang(lng_signin_recover))
|
, _toRecover(this, lang(lng_signin_recover))
|
||||||
, _toPassword(this, lang(lng_signin_try_password))
|
, _toPassword(this, lang(lng_signin_try_password))
|
||||||
, _reset(this, lang(lng_signin_reset_account), st::introResetLink)
|
|
||||||
, _checkRequest(this) {
|
, _checkRequest(this) {
|
||||||
setVisible(false);
|
|
||||||
setGeometry(parent->innerRect());
|
|
||||||
|
|
||||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitPwd()));
|
|
||||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||||
connect(_toRecover, SIGNAL(clicked()), this, SLOT(onToRecover()));
|
connect(_toRecover, SIGNAL(clicked()), this, SLOT(onToRecover()));
|
||||||
connect(_toPassword, SIGNAL(clicked()), this, SLOT(onToPassword()));
|
connect(_toPassword, SIGNAL(clicked()), this, SLOT(onToPassword()));
|
||||||
connect(_pwdField, SIGNAL(changed()), this, SLOT(onInputChange()));
|
connect(_pwdField, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||||
connect(_codeField, SIGNAL(changed()), this, SLOT(onInputChange()));
|
connect(_codeField, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||||
connect(_reset, SIGNAL(clicked()), this, SLOT(onReset()));
|
|
||||||
|
|
||||||
_pwdField->setEchoMode(QLineEdit::Password);
|
setTitleText(lang(lng_signin_title));
|
||||||
|
updateDescriptionText();
|
||||||
|
setErrorBelowLink(true);
|
||||||
|
|
||||||
if (!_hint.isEmpty()) {
|
if (_hint.isEmpty()) {
|
||||||
_hintText.setText(st::introFont, lng_signin_hint(lt_password_hint, _hint));
|
_pwdHint->hide();
|
||||||
|
} else {
|
||||||
|
_pwdHint->setText(lng_signin_hint(lt_password_hint, _hint));
|
||||||
}
|
}
|
||||||
_codeField->hide();
|
_codeField->hide();
|
||||||
_toPassword->hide();
|
_toPassword->hide();
|
||||||
_toRecover->show();
|
|
||||||
_reset->hide();
|
|
||||||
|
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::paintEvent(QPaintEvent *e) {
|
void PwdCheckWidget::resizeEvent(QResizeEvent *e) {
|
||||||
bool trivial = (rect() == e->rect());
|
Step::resizeEvent(e);
|
||||||
|
_pwdField->moveToLeft(contentLeft(), contentTop() + st::introPasswordTop);
|
||||||
QPainter p(this);
|
_pwdHint->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introPasswordHintTop);
|
||||||
if (!trivial) {
|
_codeField->moveToLeft(contentLeft(), contentTop() + st::introStepFieldTop);
|
||||||
p.setClipRect(e->rect());
|
auto linkTop = _codeField->y() + _codeField->height() + st::introLinkTop;
|
||||||
}
|
_toRecover->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||||
if (trivial || e->rect().intersects(_textRect)) {
|
_toPassword->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||||
p.setFont(st::introHeaderFont->f);
|
|
||||||
p.drawText(_textRect, lang(lng_signin_title), style::al_top);
|
|
||||||
p.setFont(st::introFont->f);
|
|
||||||
p.drawText(_textRect, lang(_pwdField->isHidden() ? lng_signin_recover_desc : lng_signin_desc), style::al_bottom);
|
|
||||||
}
|
|
||||||
if (_pwdField->isHidden()) {
|
|
||||||
if (!_emailPattern.isEmpty()) {
|
|
||||||
p.drawText(QRect(_textRect.x(), _pwdField->y() + _pwdField->height() + st::introFinishSkip, _textRect.width(), st::introFont->height), _emailPattern, style::al_top);
|
|
||||||
}
|
|
||||||
} else if (!_hint.isEmpty()) {
|
|
||||||
_hintText.drawElided(p, _pwdField->x(), _pwdField->y() + _pwdField->height() + st::introFinishSkip, _pwdField->width(), 1, style::al_top);
|
|
||||||
}
|
|
||||||
if (_a_error.animating() || _error.length()) {
|
|
||||||
p.setOpacity(a_errorAlpha.current());
|
|
||||||
|
|
||||||
QRect errRect((width() - st::introErrorWidth) / 2, (_pwdField->y() + _pwdField->height() + st::introFinishSkip + st::introFont->height + _next->y() - st::introErrorHeight) / 2, st::introErrorWidth, st::introErrorHeight);
|
|
||||||
p.setFont(st::introErrorFont);
|
|
||||||
p.setPen(st::introErrorFg);
|
|
||||||
p.drawText(errRect, _error, QTextOption(style::al_center));
|
|
||||||
|
|
||||||
p.setOpacity(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::resizeEvent(QResizeEvent *e) {
|
void PwdCheckWidget::setInnerFocus() {
|
||||||
if (e->oldSize().width() != width()) {
|
|
||||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
|
||||||
_pwdField->move((width() - _pwdField->width()) / 2, st::introTextTop + st::introTextSize.height() + st::introCountry.top);
|
|
||||||
_codeField->move((width() - _codeField->width()) / 2, st::introTextTop + st::introTextSize.height() + st::introCountry.top);
|
|
||||||
_toRecover->move(_next->x() + (_pwdField->width() - _toRecover->width()) / 2, _next->y() + _next->height() + st::introFinishSkip);
|
|
||||||
_toPassword->move(_next->x() + (_pwdField->width() - _toPassword->width()) / 2, _next->y() + _next->height() + st::introFinishSkip);
|
|
||||||
_reset->move((width() - _reset->width()) / 2, _toRecover->y() + _toRecover->height() + st::introFinishSkip);
|
|
||||||
}
|
|
||||||
_textRect = QRect((width() - st::introTextSize.width()) / 2, st::introTextTop, st::introTextSize.width(), st::introTextSize.height());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroPwdCheck::showError(const QString &error) {
|
|
||||||
if (!_a_error.animating() && error == _error) return;
|
|
||||||
|
|
||||||
if (error.length()) {
|
|
||||||
_error = error;
|
|
||||||
a_errorAlpha.start(1);
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.start(0);
|
|
||||||
}
|
|
||||||
_a_error.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroPwdCheck::step_error(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / st::introErrorDuration;
|
|
||||||
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_error.stop();
|
|
||||||
a_errorAlpha.finish();
|
|
||||||
if (!a_errorAlpha.current()) {
|
|
||||||
_error.clear();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroPwdCheck::activate() {
|
|
||||||
IntroStep::activate();
|
|
||||||
if (_pwdField->isHidden()) {
|
if (_pwdField->isHidden()) {
|
||||||
_codeField->setFocus();
|
_codeField->setFocus();
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,17 +83,25 @@ void IntroPwdCheck::activate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::cancelled() {
|
void PwdCheckWidget::activate() {
|
||||||
if (_sentRequest) {
|
if (_pwdField->isHidden() && _codeField->isHidden()) {
|
||||||
MTP::cancel(base::take(_sentRequest));
|
Step::activate();
|
||||||
|
_pwdField->show();
|
||||||
|
_pwdHint->show();
|
||||||
|
_toRecover->show();
|
||||||
}
|
}
|
||||||
|
setInnerFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::stopCheck() {
|
void PwdCheckWidget::cancelled() {
|
||||||
|
MTP::cancel(base::take(_sentRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PwdCheckWidget::stopCheck() {
|
||||||
_checkRequest->stop();
|
_checkRequest->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onCheckRequest() {
|
void PwdCheckWidget::onCheckRequest() {
|
||||||
int32 status = MTP::state(_sentRequest);
|
int32 status = MTP::state(_sentRequest);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
int32 leftms = -status;
|
int32 leftms = -status;
|
||||||
|
@ -176,7 +119,7 @@ void IntroPwdCheck::onCheckRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::pwdSubmitDone(bool recover, const MTPauth_Authorization &result) {
|
void PwdCheckWidget::pwdSubmitDone(bool recover, const MTPauth_Authorization &result) {
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
stopCheck();
|
stopCheck();
|
||||||
if (recover) {
|
if (recover) {
|
||||||
|
@ -184,22 +127,22 @@ void IntroPwdCheck::pwdSubmitDone(bool recover, const MTPauth_Authorization &res
|
||||||
}
|
}
|
||||||
_pwdField->setDisabled(false);
|
_pwdField->setDisabled(false);
|
||||||
_codeField->setDisabled(false);
|
_codeField->setDisabled(false);
|
||||||
const auto &d(result.c_auth_authorization());
|
auto &d = result.c_auth_authorization();
|
||||||
if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf?
|
if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf?
|
||||||
showError(lang(lng_server_error));
|
showError(lang(lng_server_error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
intro()->finish(d.vuser);
|
finish(d.vuser);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) {
|
bool PwdCheckWidget::pwdSubmitFail(const RPCError &error) {
|
||||||
if (MTP::isFloodError(error)) {
|
if (MTP::isFloodError(error)) {
|
||||||
_sentRequest = 0;
|
_sentRequest = 0;
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_codeField->setDisabled(false);
|
_codeField->setDisabled(false);
|
||||||
showError(lang(lng_flood_error));
|
showError(lang(lng_flood_error));
|
||||||
_pwdField->setDisabled(false);
|
_pwdField->setDisabled(false);
|
||||||
_pwdField->notaBene();
|
_pwdField->showError();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (MTP::isDefaultHandledError(error)) return false;
|
if (MTP::isDefaultHandledError(error)) return false;
|
||||||
|
@ -212,10 +155,10 @@ bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) {
|
||||||
if (err == qstr("PASSWORD_HASH_INVALID")) {
|
if (err == qstr("PASSWORD_HASH_INVALID")) {
|
||||||
showError(lang(lng_signin_bad_password));
|
showError(lang(lng_signin_bad_password));
|
||||||
_pwdField->selectAll();
|
_pwdField->selectAll();
|
||||||
_pwdField->notaBene();
|
_pwdField->showError();
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("PASSWORD_EMPTY")) {
|
} else if (err == qstr("PASSWORD_EMPTY")) {
|
||||||
intro()->onBack();
|
goBack();
|
||||||
}
|
}
|
||||||
if (cDebug()) { // internal server error
|
if (cDebug()) { // internal server error
|
||||||
showError(err + ": " + error.description());
|
showError(err + ": " + error.description());
|
||||||
|
@ -226,10 +169,10 @@ bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
bool PwdCheckWidget::codeSubmitFail(const RPCError &error) {
|
||||||
if (MTP::isFloodError(error)) {
|
if (MTP::isFloodError(error)) {
|
||||||
showError(lang(lng_flood_error));
|
showError(lang(lng_flood_error));
|
||||||
_codeField->notaBene();
|
_codeField->showError();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (MTP::isDefaultHandledError(error)) return false;
|
if (MTP::isDefaultHandledError(error)) return false;
|
||||||
|
@ -240,7 +183,7 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||||
_codeField->setDisabled(false);
|
_codeField->setDisabled(false);
|
||||||
const QString &err = error.type();
|
const QString &err = error.type();
|
||||||
if (err == qstr("PASSWORD_EMPTY")) {
|
if (err == qstr("PASSWORD_EMPTY")) {
|
||||||
intro()->onBack();
|
goBack();
|
||||||
return true;
|
return true;
|
||||||
} else if (err == qstr("PASSWORD_RECOVERY_NA")) {
|
} else if (err == qstr("PASSWORD_RECOVERY_NA")) {
|
||||||
recoverStartFail(error);
|
recoverStartFail(error);
|
||||||
|
@ -252,7 +195,7 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||||
} else if (err == qstr("CODE_INVALID")) {
|
} else if (err == qstr("CODE_INVALID")) {
|
||||||
showError(lang(lng_signin_wrong_code));
|
showError(lang(lng_signin_wrong_code));
|
||||||
_codeField->selectAll();
|
_codeField->selectAll();
|
||||||
_codeField->notaBene();
|
_codeField->showError();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (cDebug()) { // internal server error
|
if (cDebug()) { // internal server error
|
||||||
|
@ -264,39 +207,42 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::recoverStarted(const MTPauth_PasswordRecovery &result) {
|
void PwdCheckWidget::recoverStarted(const MTPauth_PasswordRecovery &result) {
|
||||||
_emailPattern = st::introFont->elided(lng_signin_recover_hint(lt_recover_email, qs(result.c_auth_passwordRecovery().vemail_pattern)), _textRect.width());
|
_emailPattern = qs(result.c_auth_passwordRecovery().vemail_pattern);
|
||||||
update();
|
updateDescriptionText();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroPwdCheck::recoverStartFail(const RPCError &error) {
|
bool PwdCheckWidget::recoverStartFail(const RPCError &error) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_pwdField->setDisabled(false);
|
_pwdField->setDisabled(false);
|
||||||
_codeField->setDisabled(false);
|
_codeField->setDisabled(false);
|
||||||
_pwdField->show();
|
_pwdField->show();
|
||||||
|
_pwdHint->show();
|
||||||
_codeField->hide();
|
_codeField->hide();
|
||||||
_pwdField->setFocus();
|
_pwdField->setFocus();
|
||||||
|
updateDescriptionText();
|
||||||
update();
|
update();
|
||||||
showError(QString());
|
hideError();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onToRecover() {
|
void PwdCheckWidget::onToRecover() {
|
||||||
if (_hasRecovery) {
|
if (_hasRecovery) {
|
||||||
if (_sentRequest) {
|
if (_sentRequest) {
|
||||||
MTP::cancel(base::take(_sentRequest));
|
MTP::cancel(base::take(_sentRequest));
|
||||||
}
|
}
|
||||||
showError(QString());
|
hideError();
|
||||||
_toRecover->hide();
|
_toRecover->hide();
|
||||||
_toPassword->show();
|
_toPassword->show();
|
||||||
_pwdField->hide();
|
_pwdField->hide();
|
||||||
|
_pwdHint->hide();
|
||||||
_pwdField->setText(QString());
|
_pwdField->setText(QString());
|
||||||
_codeField->show();
|
_codeField->show();
|
||||||
_codeField->setFocus();
|
_codeField->setFocus();
|
||||||
|
updateDescriptionText();
|
||||||
if (_emailPattern.isEmpty()) {
|
if (_emailPattern.isEmpty()) {
|
||||||
MTP::send(MTPauth_RequestPasswordRecovery(), rpcDone(&IntroPwdCheck::recoverStarted), rpcFail(&IntroPwdCheck::recoverStartFail));
|
MTP::send(MTPauth_RequestPasswordRecovery(), rpcDone(&PwdCheckWidget::recoverStarted), rpcFail(&PwdCheckWidget::recoverStartFail));
|
||||||
}
|
}
|
||||||
update();
|
|
||||||
} else {
|
} else {
|
||||||
ConfirmBox *box = new InformBox(lang(lng_signin_no_email_forgot));
|
ConfirmBox *box = new InformBox(lang(lng_signin_no_email_forgot));
|
||||||
Ui::showLayer(box);
|
Ui::showLayer(box);
|
||||||
|
@ -304,101 +250,63 @@ void IntroPwdCheck::onToRecover() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onToPassword() {
|
void PwdCheckWidget::onToPassword() {
|
||||||
ConfirmBox *box = new InformBox(lang(lng_signin_cant_email_forgot));
|
ConfirmBox *box = new InformBox(lang(lng_signin_cant_email_forgot));
|
||||||
Ui::showLayer(box);
|
Ui::showLayer(box);
|
||||||
connect(box, SIGNAL(destroyed(QObject*)), this, SLOT(onToReset()));
|
connect(box, SIGNAL(destroyed(QObject*)), this, SLOT(onToReset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onToReset() {
|
void PwdCheckWidget::onToReset() {
|
||||||
if (_sentRequest) {
|
if (_sentRequest) {
|
||||||
MTP::cancel(base::take(_sentRequest));
|
MTP::cancel(base::take(_sentRequest));
|
||||||
}
|
}
|
||||||
_toRecover->show();
|
_toRecover->show();
|
||||||
_toPassword->hide();
|
_toPassword->hide();
|
||||||
_pwdField->show();
|
_pwdField->show();
|
||||||
|
_pwdHint->show();
|
||||||
_codeField->hide();
|
_codeField->hide();
|
||||||
_codeField->setText(QString());
|
_codeField->setText(QString());
|
||||||
_pwdField->setFocus();
|
_pwdField->setFocus();
|
||||||
_reset->show();
|
showResetButton();
|
||||||
|
updateDescriptionText();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onReset() {
|
void PwdCheckWidget::updateDescriptionText() {
|
||||||
if (_sentRequest) return;
|
setDescriptionText(_pwdField->isHidden() ? lng_signin_recover_desc(lt_email, _emailPattern) : lang(lng_signin_desc));
|
||||||
ConfirmBox *box = new ConfirmBox(lang(lng_signin_sure_reset), lang(lng_signin_reset), st::attentionBoxButton);
|
|
||||||
connect(box, SIGNAL(confirmed()), this, SLOT(onResetSure()));
|
|
||||||
Ui::showLayer(box);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onResetSure() {
|
void PwdCheckWidget::onInputChange() {
|
||||||
if (_sentRequest) return;
|
hideError();
|
||||||
_sentRequest = MTP::send(MTPaccount_DeleteAccount(MTP_string("Forgot password")), rpcDone(&IntroPwdCheck::deleteDone), rpcFail(&IntroPwdCheck::deleteFail));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroPwdCheck::deleteFail(const RPCError &error) {
|
void PwdCheckWidget::submit() {
|
||||||
if (MTP::isDefaultHandledError(error)) return false;
|
|
||||||
|
|
||||||
_sentRequest = 0;
|
|
||||||
|
|
||||||
auto type = error.type();
|
|
||||||
if (type.startsWith(qstr("2FA_CONFIRM_WAIT_"))) {
|
|
||||||
int seconds = type.mid(qstr("2FA_CONFIRM_WAIT_").size()).toInt();
|
|
||||||
int days = (seconds + 59) / 86400;
|
|
||||||
int hours = ((seconds + 59) % 86400) / 3600;
|
|
||||||
int minutes = ((seconds + 59) % 3600) / 60;
|
|
||||||
QString when;
|
|
||||||
if (days > 0) {
|
|
||||||
when = lng_signin_reset_in_days(lt_count_days, days, lt_count_hours, hours, lt_count_minutes, minutes);
|
|
||||||
} else if (hours > 0) {
|
|
||||||
when = lng_signin_reset_in_hours(lt_count_hours, hours, lt_count_minutes, minutes);
|
|
||||||
} else {
|
|
||||||
when = lng_signin_reset_in_minutes(lt_count_minutes, minutes);
|
|
||||||
}
|
|
||||||
Ui::showLayer(new InformBox(lng_signin_reset_wait(lt_phone_number, App::formatPhone(intro()->getPhone()), lt_when, when)));
|
|
||||||
} else if (type == qstr("2FA_RECENT_CONFIRM")) {
|
|
||||||
Ui::showLayer(new InformBox(lang(lng_signin_reset_cancelled)));
|
|
||||||
} else {
|
|
||||||
Ui::hideLayer();
|
|
||||||
showError(lang(lng_server_error));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroPwdCheck::deleteDone(const MTPBool &v) {
|
|
||||||
Ui::hideLayer();
|
|
||||||
intro()->replaceStep(new IntroSignup(intro()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroPwdCheck::onInputChange() {
|
|
||||||
showError(QString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroPwdCheck::onSubmitPwd(bool force) {
|
|
||||||
if (_sentRequest) return;
|
if (_sentRequest) return;
|
||||||
if (_pwdField->isHidden()) {
|
if (_pwdField->isHidden()) {
|
||||||
if (!force && !_codeField->isEnabled()) return;
|
if (!_codeField->isEnabled()) return;
|
||||||
QString code = _codeField->text().trimmed();
|
auto code = _codeField->getLastText().trimmed();
|
||||||
if (code.isEmpty()) {
|
if (code.isEmpty()) {
|
||||||
_codeField->notaBene();
|
_codeField->showError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sentRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&IntroPwdCheck::pwdSubmitDone, true), rpcFail(&IntroPwdCheck::codeSubmitFail));
|
_sentRequest = MTP::send(MTPauth_RecoverPassword(MTP_string(code)), rpcDone(&PwdCheckWidget::pwdSubmitDone, true), rpcFail(&PwdCheckWidget::codeSubmitFail));
|
||||||
} else {
|
} else {
|
||||||
if (!force && !_pwdField->isEnabled()) return;
|
if (!_pwdField->isEnabled()) return;
|
||||||
|
|
||||||
_pwdField->setDisabled(true);
|
_pwdField->setDisabled(true);
|
||||||
setFocus();
|
setFocus();
|
||||||
|
|
||||||
showError(QString());
|
hideError();
|
||||||
|
|
||||||
QByteArray pwdData = _salt + _pwdField->text().toUtf8() + _salt, pwdHash(32, Qt::Uninitialized);
|
QByteArray pwdData = _salt + _pwdField->getLastText().toUtf8() + _salt, pwdHash(32, Qt::Uninitialized);
|
||||||
hashSha256(pwdData.constData(), pwdData.size(), pwdHash.data());
|
hashSha256(pwdData.constData(), pwdData.size(), pwdHash.data());
|
||||||
_sentRequest = MTP::send(MTPauth_CheckPassword(MTP_bytes(pwdHash)), rpcDone(&IntroPwdCheck::pwdSubmitDone, false), rpcFail(&IntroPwdCheck::pwdSubmitFail));
|
_sentRequest = MTP::send(MTPauth_CheckPassword(MTP_bytes(pwdHash)), rpcDone(&PwdCheckWidget::pwdSubmitDone, false), rpcFail(&PwdCheckWidget::pwdSubmitFail));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroPwdCheck::onSubmit() {
|
QString PwdCheckWidget::nextButtonText() const {
|
||||||
onSubmitPwd();
|
return lang(lng_intro_submit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -23,26 +23,37 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "intro/introwidget.h"
|
#include "intro/introwidget.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class FlatInput;
|
class InputField;
|
||||||
|
class PasswordInput;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class IntroPwdCheck final : public IntroStep {
|
namespace Intro {
|
||||||
|
|
||||||
|
class PwdCheckWidget : public Widget::Step {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntroPwdCheck(IntroWidget *parent);
|
PwdCheckWidget(QWidget *parent, Widget::Data *data);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
|
|
||||||
void step_error(float64 ms, bool timer);
|
|
||||||
|
|
||||||
|
void setInnerFocus() override;
|
||||||
void activate() override;
|
void activate() override;
|
||||||
void cancelled() override;
|
void cancelled() override;
|
||||||
void onSubmit() override;
|
void submit() override;
|
||||||
|
QString nextButtonText() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onToRecover();
|
||||||
|
void onToPassword();
|
||||||
|
void onInputChange();
|
||||||
|
void onCheckRequest();
|
||||||
|
void onToReset();
|
||||||
|
|
||||||
|
private:
|
||||||
void pwdSubmitDone(bool recover, const MTPauth_Authorization &result);
|
void pwdSubmitDone(bool recover, const MTPauth_Authorization &result);
|
||||||
bool pwdSubmitFail(const RPCError &error);
|
bool pwdSubmitFail(const RPCError &error);
|
||||||
bool codeSubmitFail(const RPCError &error);
|
bool codeSubmitFail(const RPCError &error);
|
||||||
|
@ -50,46 +61,24 @@ public:
|
||||||
|
|
||||||
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
||||||
|
|
||||||
public slots:
|
void updateDescriptionText();
|
||||||
void onSubmitPwd(bool force = false);
|
|
||||||
void onToRecover();
|
|
||||||
void onToPassword();
|
|
||||||
void onInputChange();
|
|
||||||
void onCheckRequest();
|
|
||||||
void onToReset();
|
|
||||||
void onReset();
|
|
||||||
void onResetSure();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void showError(const QString &error);
|
|
||||||
void stopCheck();
|
void stopCheck();
|
||||||
|
|
||||||
void deleteDone(const MTPBool &result);
|
|
||||||
bool deleteFail(const RPCError &error);
|
|
||||||
|
|
||||||
QString _error;
|
|
||||||
anim::fvalue a_errorAlpha;
|
|
||||||
Animation _a_error;
|
|
||||||
|
|
||||||
ChildWidget<Ui::RoundButton> _next;
|
|
||||||
|
|
||||||
QRect _textRect;
|
|
||||||
|
|
||||||
QByteArray _salt;
|
QByteArray _salt;
|
||||||
bool _hasRecovery;
|
bool _hasRecovery;
|
||||||
QString _hint, _emailPattern;
|
QString _hint, _emailPattern;
|
||||||
|
|
||||||
ChildWidget<Ui::FlatInput> _pwdField;
|
ChildWidget<Ui::PasswordInput> _pwdField;
|
||||||
ChildWidget<Ui::FlatInput> _codeField;
|
ChildWidget<Ui::FlatLabel> _pwdHint;
|
||||||
|
ChildWidget<Ui::InputField> _codeField;
|
||||||
ChildWidget<Ui::LinkButton> _toRecover;
|
ChildWidget<Ui::LinkButton> _toRecover;
|
||||||
ChildWidget<Ui::LinkButton> _toPassword;
|
ChildWidget<Ui::LinkButton> _toPassword;
|
||||||
ChildWidget<Ui::LinkButton> _reset;
|
|
||||||
mtpRequestId _sentRequest = 0;
|
mtpRequestId _sentRequest = 0;
|
||||||
|
|
||||||
Text _hintText;
|
|
||||||
|
|
||||||
QByteArray _pwdSalt;
|
QByteArray _pwdSalt;
|
||||||
|
|
||||||
ChildObject<QTimer> _checkRequest;
|
ChildObject<QTimer> _checkRequest;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -29,200 +29,106 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
|
#include "ui/buttons/peer_avatar_button.h"
|
||||||
|
|
||||||
IntroSignup::IntroSignup(IntroWidget *parent) : IntroStep(parent)
|
namespace Intro {
|
||||||
, a_errorAlpha(0)
|
|
||||||
, a_photoOver(0)
|
SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||||
, _a_error(animation(this, &IntroSignup::step_error))
|
, _photo(this, st::introPhotoSize, st::introPhotoIconPosition)
|
||||||
, _a_photo(animation(this, &IntroSignup::step_photo))
|
|
||||||
, _next(this, lang(lng_intro_finish), st::introNextButton)
|
|
||||||
, _first(this, st::introName, lang(lng_signup_firstname))
|
, _first(this, st::introName, lang(lng_signup_firstname))
|
||||||
, _last(this, st::introName, lang(lng_signup_lastname))
|
, _last(this, st::introName, lang(lng_signup_lastname))
|
||||||
, _invertOrder(langFirstNameGoesSecond())
|
, _invertOrder(langFirstNameGoesSecond())
|
||||||
, _checkRequest(this) {
|
, _checkRequest(this) {
|
||||||
setVisible(false);
|
|
||||||
setGeometry(parent->innerRect());
|
|
||||||
|
|
||||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitName()));
|
|
||||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||||
|
|
||||||
|
_photo->setClickedCallback([this] {
|
||||||
|
auto imgExtensions = cImgExtensions();
|
||||||
|
auto filter = qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter();
|
||||||
|
_readPhotoFileQueryId = FileDialog::queryReadFile(lang(lng_choose_images), filter);
|
||||||
|
});
|
||||||
|
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
||||||
|
notifyFileQueryUpdated(update);
|
||||||
|
});
|
||||||
|
|
||||||
if (_invertOrder) {
|
if (_invertOrder) {
|
||||||
setTabOrder(_last, _first);
|
setTabOrder(_last, _first);
|
||||||
}
|
}
|
||||||
|
setErrorCentered(true);
|
||||||
|
|
||||||
|
setTitleText(lang(lng_signup_title));
|
||||||
|
setDescriptionText(lang(lng_signup_desc));
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::mouseMoveEvent(QMouseEvent *e) {
|
void SignupWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
||||||
bool photoOver = QRect(_phLeft, _phTop, st::introPhotoSize, st::introPhotoSize).contains(e->pos());
|
if (_readPhotoFileQueryId != update.queryId) {
|
||||||
if (photoOver != _photoOver) {
|
return;
|
||||||
_photoOver = photoOver;
|
}
|
||||||
if (_photoSmall.isNull()) {
|
_readPhotoFileQueryId = 0;
|
||||||
a_photoOver.start(_photoOver ? 1 : 0);
|
if (update.remoteContent.isEmpty() && update.filePaths.isEmpty()) {
|
||||||
_a_photo.start();
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursor(_photoOver ? style::cur_pointer : style::cur_default);
|
QImage img;
|
||||||
}
|
if (!update.remoteContent.isEmpty()) {
|
||||||
|
img = App::readImage(update.remoteContent);
|
||||||
void IntroSignup::mousePressEvent(QMouseEvent *e) {
|
|
||||||
mouseMoveEvent(e);
|
|
||||||
if (QRect(_phLeft, _phTop, st::introPhotoSize, st::introPhotoSize).contains(e->pos())) {
|
|
||||||
QStringList imgExtensions(cImgExtensions());
|
|
||||||
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;") + filedialogAllFilesFilter());
|
|
||||||
|
|
||||||
QImage img;
|
|
||||||
QString file;
|
|
||||||
QByteArray remoteContent;
|
|
||||||
if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) {
|
|
||||||
if (!remoteContent.isEmpty()) {
|
|
||||||
img = App::readImage(remoteContent);
|
|
||||||
} else {
|
|
||||||
if (!file.isEmpty()) {
|
|
||||||
img = App::readImage(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
|
|
||||||
showError(lang(lng_bad_photo));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PhotoCropBox *box = new PhotoCropBox(img, PeerId(0));
|
|
||||||
connect(box, SIGNAL(ready(const QImage &)), this, SLOT(onPhotoReady(const QImage &)));
|
|
||||||
Ui::showLayer(box);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroSignup::paintEvent(QPaintEvent *e) {
|
|
||||||
bool trivial = (rect() == e->rect());
|
|
||||||
|
|
||||||
Painter p(this);
|
|
||||||
if (!trivial) {
|
|
||||||
p.setClipRect(e->rect());
|
|
||||||
}
|
|
||||||
if (trivial || e->rect().intersects(_textRect)) {
|
|
||||||
p.setFont(st::introHeaderFont->f);
|
|
||||||
p.drawText(_textRect, lang(lng_signup_title), style::al_top);
|
|
||||||
p.setFont(st::introFont->f);
|
|
||||||
p.drawText(_textRect, lang(lng_signup_desc), style::al_bottom);
|
|
||||||
}
|
|
||||||
if (_a_error.animating() || error.length()) {
|
|
||||||
p.setOpacity(a_errorAlpha.current());
|
|
||||||
|
|
||||||
QRect errRect;
|
|
||||||
if (_invertOrder) {
|
|
||||||
errRect = QRect((width() - st::introErrorWidth) / 2, (_first->y() + _first->height() + _next->y() - st::introErrorHeight) / 2, st::introErrorWidth, st::introErrorHeight);
|
|
||||||
} else {
|
|
||||||
errRect = QRect((width() - st::introErrorWidth) / 2, (_last->y() + _last->height() + _next->y() - st::introErrorHeight) / 2, st::introErrorWidth, st::introErrorHeight);
|
|
||||||
}
|
|
||||||
p.setFont(st::introErrorFont);
|
|
||||||
p.setPen(st::introErrorFg);
|
|
||||||
p.drawText(errRect, error, QTextOption(style::al_center));
|
|
||||||
|
|
||||||
p.setOpacity(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_photoSmall.isNull()) {
|
|
||||||
float64 o = a_photoOver.current();
|
|
||||||
QRect phRect(_phLeft, _phTop, st::introPhotoSize, st::introPhotoSize);
|
|
||||||
if (o > 0) {
|
|
||||||
if (o < 1) {
|
|
||||||
QColor c;
|
|
||||||
c.setRedF(st::newGroupPhotoBg->c.redF() * (1. - o) + st::newGroupPhotoBgOver->c.redF() * o);
|
|
||||||
c.setGreenF(st::newGroupPhotoBg->c.greenF() * (1. - o) + st::newGroupPhotoBgOver->c.greenF() * o);
|
|
||||||
c.setBlueF(st::newGroupPhotoBg->c.blueF() * (1. - o) + st::newGroupPhotoBgOver->c.blueF() * o);
|
|
||||||
p.fillRect(phRect, c);
|
|
||||||
} else {
|
|
||||||
p.fillRect(phRect, st::newGroupPhotoBgOver);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p.fillRect(phRect, st::newGroupPhotoBg);
|
|
||||||
}
|
|
||||||
st::newGroupPhotoIcon.paintInCenter(p, phRect);
|
|
||||||
} else {
|
} else {
|
||||||
p.drawPixmap(_phLeft, _phTop, _photoSmall);
|
img = App::readImage(update.filePaths.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) {
|
||||||
|
showError(lang(lng_bad_photo));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto box = new PhotoCropBox(img, PeerId(0));
|
||||||
|
connect(box, SIGNAL(ready(const QImage &)), this, SLOT(onPhotoReady(const QImage &)));
|
||||||
|
Ui::showLayer(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::resizeEvent(QResizeEvent *e) {
|
void SignupWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_phLeft = (width() - _next->width()) / 2;
|
Step::resizeEvent(e);
|
||||||
_phTop = st::introTextTop + st::introTextSize.height() + st::introCountry.top;
|
|
||||||
if (e->oldSize().width() != width()) {
|
|
||||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
|
||||||
if (_invertOrder) {
|
|
||||||
_last->move((width() - _next->width()) / 2 + _next->width() - _last->width(), _phTop);
|
|
||||||
_first->move((width() - _next->width()) / 2 + _next->width() - _first->width(), _last->y() + st::introCountry.height + st::introCountry.ptrSize.height() + st::introPhoneTop);
|
|
||||||
} else {
|
|
||||||
_first->move((width() - _next->width()) / 2 + _next->width() - _first->width(), _phTop);
|
|
||||||
_last->move((width() - _next->width()) / 2 + _next->width() - _last->width(), _first->y() + st::introCountry.height + st::introCountry.ptrSize.height() + st::introPhoneTop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_textRect = QRect((width() - st::introTextSize.width()) / 2, st::introTextTop, st::introTextSize.width(), st::introTextSize.height());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroSignup::showError(const QString &err) {
|
auto photoRight = contentLeft() + st::introNextButton.width;
|
||||||
if (!_a_error.animating() && err == error) return;
|
auto photoTop = contentTop() + st::introPhotoTop;
|
||||||
|
_photo->moveToLeft(photoRight - _photo->width(), photoTop);
|
||||||
|
|
||||||
if (err.length()) {
|
auto firstTop = contentTop() + st::introStepFieldTop;
|
||||||
error = err;
|
auto secondTop = firstTop + st::introName.height + st::introPhoneTop;
|
||||||
a_errorAlpha.start(1);
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.start(0);
|
|
||||||
}
|
|
||||||
_a_error.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroSignup::step_error(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / st::introErrorDuration;
|
|
||||||
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_error.stop();
|
|
||||||
a_errorAlpha.finish();
|
|
||||||
if (!a_errorAlpha.current()) {
|
|
||||||
error.clear();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a_errorAlpha.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroSignup::step_photo(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / st::introErrorDuration;
|
|
||||||
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_photo.stop();
|
|
||||||
a_photoOver.finish();
|
|
||||||
} else {
|
|
||||||
a_photoOver.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroSignup::activate() {
|
|
||||||
IntroStep::activate();
|
|
||||||
if (_invertOrder) {
|
if (_invertOrder) {
|
||||||
|
_last->moveToLeft(contentLeft(), firstTop);
|
||||||
|
_first->moveToLeft(contentLeft(), secondTop);
|
||||||
|
} else {
|
||||||
|
_first->moveToLeft(contentLeft(), firstTop);
|
||||||
|
_last->moveToLeft(contentLeft(), secondTop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignupWidget::setInnerFocus() {
|
||||||
|
if (_invertOrder || _last->hasFocus()) {
|
||||||
_last->setFocus();
|
_last->setFocus();
|
||||||
} else {
|
} else {
|
||||||
_first->setFocus();
|
_first->setFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::cancelled() {
|
void SignupWidget::activate() {
|
||||||
if (_sentRequest) {
|
Step::activate();
|
||||||
MTP::cancel(base::take(_sentRequest));
|
_first->show();
|
||||||
}
|
_last->show();
|
||||||
|
_photo->show();
|
||||||
|
setInnerFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::stopCheck() {
|
void SignupWidget::cancelled() {
|
||||||
|
MTP::cancel(base::take(_sentRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SignupWidget::stopCheck() {
|
||||||
_checkRequest->stop();
|
_checkRequest->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::onCheckRequest() {
|
void SignupWidget::onCheckRequest() {
|
||||||
int32 status = MTP::state(_sentRequest);
|
int32 status = MTP::state(_sentRequest);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
int32 leftms = -status;
|
int32 leftms = -status;
|
||||||
|
@ -244,13 +150,12 @@ void IntroSignup::onCheckRequest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::onPhotoReady(const QImage &img) {
|
void SignupWidget::onPhotoReady(const QImage &img) {
|
||||||
_photoBig = img;
|
_photoImage = img;
|
||||||
_photoSmall = App::pixmapFromImageInPlace(img.scaled(st::introPhotoSize * cIntRetinaFactor(), st::introPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
_photo->setImage(_photoImage);
|
||||||
_photoSmall.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) {
|
void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_first->setDisabled(false);
|
_first->setDisabled(false);
|
||||||
_last->setDisabled(false);
|
_last->setDisabled(false);
|
||||||
|
@ -259,10 +164,10 @@ void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) {
|
||||||
showError(lang(lng_server_error));
|
showError(lang(lng_server_error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
intro()->finish(d.vuser, _photoBig);
|
finish(d.vuser, _photoImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntroSignup::nameSubmitFail(const RPCError &error) {
|
bool SignupWidget::nameSubmitFail(const RPCError &error) {
|
||||||
if (MTP::isFloodError(error)) {
|
if (MTP::isFloodError(error)) {
|
||||||
stopCheck();
|
stopCheck();
|
||||||
_first->setDisabled(false);
|
_first->setDisabled(false);
|
||||||
|
@ -284,7 +189,7 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) {
|
||||||
if (err == qstr("PHONE_NUMBER_INVALID") || err == qstr("PHONE_CODE_EXPIRED") ||
|
if (err == qstr("PHONE_NUMBER_INVALID") || err == qstr("PHONE_CODE_EXPIRED") ||
|
||||||
err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID") ||
|
err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID") ||
|
||||||
err == qstr("PHONE_NUMBER_OCCUPIED")) {
|
err == qstr("PHONE_NUMBER_OCCUPIED")) {
|
||||||
intro()->onBack();
|
goBack();
|
||||||
return true;
|
return true;
|
||||||
} else if (err == "FIRSTNAME_INVALID") {
|
} else if (err == "FIRSTNAME_INVALID") {
|
||||||
showError(lang(lng_bad_name));
|
showError(lang(lng_bad_name));
|
||||||
|
@ -308,29 +213,29 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::onInputChange() {
|
void SignupWidget::onInputChange() {
|
||||||
showError(QString());
|
showError(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::onSubmitName(bool force) {
|
void SignupWidget::submit() {
|
||||||
if (_invertOrder) {
|
if (_invertOrder) {
|
||||||
if ((_last->hasFocus() || _last->text().trimmed().length()) && !_first->text().trimmed().length()) {
|
if ((_last->hasFocus() || _last->getLastText().trimmed().length()) && !_first->getLastText().trimmed().length()) {
|
||||||
_first->setFocus();
|
_first->setFocus();
|
||||||
return;
|
return;
|
||||||
} else if (!_last->text().trimmed().length()) {
|
} else if (!_last->getLastText().trimmed().length()) {
|
||||||
_last->setFocus();
|
_last->setFocus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((_first->hasFocus() || _first->text().trimmed().length()) && !_last->text().trimmed().length()) {
|
if ((_first->hasFocus() || _first->getLastText().trimmed().length()) && !_last->getLastText().trimmed().length()) {
|
||||||
_last->setFocus();
|
_last->setFocus();
|
||||||
return;
|
return;
|
||||||
} else if (!_first->text().trimmed().length()) {
|
} else if (!_first->getLastText().trimmed().length()) {
|
||||||
_first->setFocus();
|
_first->setFocus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!force && !_first->isEnabled()) return;
|
if (!_first->isEnabled()) return;
|
||||||
|
|
||||||
_first->setDisabled(true);
|
_first->setDisabled(true);
|
||||||
_last->setDisabled(true);
|
_last->setDisabled(true);
|
||||||
|
@ -338,11 +243,13 @@ void IntroSignup::onSubmitName(bool force) {
|
||||||
|
|
||||||
showError(QString());
|
showError(QString());
|
||||||
|
|
||||||
_firstName = _first->text().trimmed();
|
_firstName = _first->getLastText().trimmed();
|
||||||
_lastName = _last->text().trimmed();
|
_lastName = _last->getLastText().trimmed();
|
||||||
_sentRequest = MTP::send(MTPauth_SignUp(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash()), MTP_string(intro()->getCode()), MTP_string(_firstName), MTP_string(_lastName)), rpcDone(&IntroSignup::nameSubmitDone), rpcFail(&IntroSignup::nameSubmitFail));
|
_sentRequest = MTP::send(MTPauth_SignUp(MTP_string(getData()->phone), MTP_string(getData()->phoneHash), MTP_string(getData()->code), MTP_string(_firstName), MTP_string(_lastName)), rpcDone(&SignupWidget::nameSubmitDone), rpcFail(&SignupWidget::nameSubmitFail));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroSignup::onSubmit() {
|
QString SignupWidget::nextButtonText() const {
|
||||||
onSubmitName();
|
return lang(lng_intro_finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -21,64 +21,58 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "intro/introwidget.h"
|
#include "intro/introwidget.h"
|
||||||
|
#include "ui/filedialog.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
class FlatInput;
|
class InputField;
|
||||||
|
class NewAvatarButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class IntroSignup final : public IntroStep {
|
namespace Intro {
|
||||||
|
|
||||||
|
class SignupWidget : public Widget::Step, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntroSignup(IntroWidget *parent);
|
SignupWidget(QWidget *parent, Widget::Data *data);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
|
||||||
|
|
||||||
void step_error(float64 ms, bool timer);
|
|
||||||
void step_photo(float64 ms, bool timer);
|
|
||||||
|
|
||||||
|
void setInnerFocus() override;
|
||||||
void activate() override;
|
void activate() override;
|
||||||
void cancelled() override;
|
void cancelled() override;
|
||||||
void onSubmit() override;
|
void submit() override;
|
||||||
|
QString nextButtonText() const override;
|
||||||
|
|
||||||
void nameSubmitDone(const MTPauth_Authorization &result);
|
protected:
|
||||||
bool nameSubmitFail(const RPCError &error);
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
public slots:
|
private slots:
|
||||||
void onSubmitName(bool force = false);
|
|
||||||
void onInputChange();
|
void onInputChange();
|
||||||
void onCheckRequest();
|
void onCheckRequest();
|
||||||
void onPhotoReady(const QImage &img);
|
void onPhotoReady(const QImage &img);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void showError(const QString &err);
|
void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update);
|
||||||
|
|
||||||
|
void nameSubmitDone(const MTPauth_Authorization &result);
|
||||||
|
bool nameSubmitFail(const RPCError &error);
|
||||||
|
|
||||||
void stopCheck();
|
void stopCheck();
|
||||||
|
|
||||||
QString error;
|
QImage _photoImage;
|
||||||
anim::fvalue a_errorAlpha, a_photoOver;
|
|
||||||
Animation _a_error;
|
|
||||||
Animation _a_photo;
|
|
||||||
|
|
||||||
ChildWidget<Ui::RoundButton> _next;
|
ChildWidget<Ui::NewAvatarButton> _photo;
|
||||||
|
ChildWidget<Ui::InputField> _first;
|
||||||
QRect _textRect;
|
ChildWidget<Ui::InputField> _last;
|
||||||
|
|
||||||
bool _photoOver = false;
|
|
||||||
QImage _photoBig;
|
|
||||||
QPixmap _photoSmall;
|
|
||||||
int32 _phLeft, _phTop;
|
|
||||||
|
|
||||||
ChildWidget<Ui::FlatInput> _first;
|
|
||||||
ChildWidget<Ui::FlatInput> _last;
|
|
||||||
QString _firstName, _lastName;
|
QString _firstName, _lastName;
|
||||||
mtpRequestId _sentRequest = 0;
|
mtpRequestId _sentRequest = 0;
|
||||||
|
|
||||||
|
FileDialog::QueryId _readPhotoFileQueryId = 0;
|
||||||
|
|
||||||
bool _invertOrder = false;
|
bool _invertOrder = false;
|
||||||
|
|
||||||
ChildObject<QTimer> _checkRequest;
|
ChildObject<QTimer> _checkRequest;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -24,67 +24,24 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "intro/introphone.h"
|
#include "intro/introphone.h"
|
||||||
#include "langloaderplain.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
|
|
||||||
IntroStart::IntroStart(IntroWidget *parent) : IntroStep(parent)
|
namespace Intro {
|
||||||
, _intro(this, lang(lng_intro), Ui::FlatLabel::InitType::Rich, st::introLabel, st::introLabelTextStyle)
|
|
||||||
, _changeLang(this, QString())
|
|
||||||
, _next(this, lang(lng_start_msgs), st::introNextButton) {
|
|
||||||
_changeLang->hide();
|
|
||||||
if (cLang() == languageDefault) {
|
|
||||||
int32 l = Sandbox::LangSystem();
|
|
||||||
if (l != languageDefault) {
|
|
||||||
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[l].c_str() + qsl(".strings"), langLoaderRequest(lng_switch_to_this));
|
|
||||||
QString text = loader.found().value(lng_switch_to_this);
|
|
||||||
if (!text.isEmpty()) {
|
|
||||||
_changeLang->setText(text);
|
|
||||||
parent->langChangeTo(l);
|
|
||||||
_changeLang->show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_changeLang->setText(langOriginal(lng_switch_to_this));
|
|
||||||
parent->langChangeTo(languageDefault);
|
|
||||||
_changeLang->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
_headerWidth = st::introHeaderFont->width(qsl("Telegram Desktop"));
|
|
||||||
|
|
||||||
setGeometry(parent->innerRect());
|
|
||||||
|
|
||||||
connect(_next, SIGNAL(clicked()), parent, SLOT(onStepSubmit()));
|
|
||||||
|
|
||||||
connect(_changeLang, SIGNAL(clicked()), parent, SLOT(onChangeLang()));
|
|
||||||
|
|
||||||
|
StartWidget::StartWidget(QWidget *parent, Widget::Data *data) : Step(parent, data, true) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
setTitleText(qsl("Telegram Desktop"));
|
||||||
|
setDescriptionText(lang(lng_intro_about));
|
||||||
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroStart::paintEvent(QPaintEvent *e) {
|
void StartWidget::submit() {
|
||||||
bool trivial = (rect() == e->rect());
|
goNext(new Intro::PhoneWidget(parentWidget(), getData()));
|
||||||
|
|
||||||
Painter p(this);
|
|
||||||
if (!trivial) {
|
|
||||||
p.setClipRect(e->rect());
|
|
||||||
}
|
|
||||||
int32 hy = _intro->y() - st::introHeaderFont->height - st::introHeaderSkip + st::introHeaderFont->ascent;
|
|
||||||
|
|
||||||
p.setFont(st::introHeaderFont);
|
|
||||||
p.setPen(st::introHeaderFg);
|
|
||||||
p.drawText((width() - _headerWidth) / 2, hy, qsl("Telegram Desktop"));
|
|
||||||
|
|
||||||
st::introIcon.paint(p, QPoint((width() - st::introIcon.width()) / 2, hy - st::introIconSkip - st::introIcon.height()), width());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroStart::resizeEvent(QResizeEvent *e) {
|
QString StartWidget::nextButtonText() const {
|
||||||
if (e->oldSize().width() != width()) {
|
return lang(lng_start_msgs);
|
||||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
|
||||||
_intro->move((width() - _intro->width()) / 2, _next->y() - _intro->height() - st::introSkip);
|
|
||||||
_changeLang->move((width() - _changeLang->width()) / 2, _next->y() + _next->height() + _changeLang->height());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroStart::onSubmit() {
|
} // namespace Intro
|
||||||
intro()->nextStep(new IntroPhone(intro()));
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,22 +28,15 @@ class LinkButton;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class IntroStart final : public IntroStep {
|
namespace Intro {
|
||||||
|
|
||||||
|
class StartWidget : public Widget::Step {
|
||||||
public:
|
public:
|
||||||
IntroStart(IntroWidget *parent);
|
StartWidget(QWidget *parent, Widget::Data *data);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void submit() override;
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
QString nextButtonText() const override;
|
||||||
|
|
||||||
void onSubmit() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ChildWidget<Ui::FlatLabel> _intro;
|
|
||||||
|
|
||||||
ChildWidget<Ui::LinkButton> _changeLang;
|
|
||||||
|
|
||||||
ChildWidget<Ui::RoundButton> _next;
|
|
||||||
|
|
||||||
int32 _headerWidth = 0;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
#include "langloaderplain.h"
|
||||||
#include "intro/introstart.h"
|
#include "intro/introstart.h"
|
||||||
#include "intro/introphone.h"
|
#include "intro/introphone.h"
|
||||||
#include "intro/introcode.h"
|
#include "intro/introcode.h"
|
||||||
|
@ -31,39 +32,60 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
#include "boxes/confirmbox.h"
|
||||||
#include "ui/text/text.h"
|
#include "ui/text/text.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/effects/widget_fade_wrap.h"
|
#include "ui/effects/widget_fade_wrap.h"
|
||||||
#include "styles/style_intro.h"
|
#include "ui/effects/slide_animation.h"
|
||||||
#include "autoupdater.h"
|
#include "autoupdater.h"
|
||||||
#include "window/slide_animation.h"
|
#include "window/window_slide_animation.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_intro.h"
|
||||||
|
#include "styles/style_window.h"
|
||||||
|
|
||||||
IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
|
namespace Intro {
|
||||||
, _a_stage(animation(this, &IntroWidget::step_stage))
|
|
||||||
, _a_show(animation(this, &IntroWidget::step_show))
|
Widget::Widget(QWidget *parent) : TWidget(parent)
|
||||||
|
, _a_show(animation(this, &Widget::step_show))
|
||||||
, _back(this, new Ui::IconButton(this, st::introBackButton), base::lambda<void()>(), st::introSlideDuration)
|
, _back(this, new Ui::IconButton(this, st::introBackButton), base::lambda<void()>(), st::introSlideDuration)
|
||||||
, _settings(this, lang(lng_menu_settings), st::defaultBoxButton) {
|
, _settings(this, new Ui::RoundButton(this, lang(lng_menu_settings), st::defaultBoxButton), base::lambda<void()>(), st::introCoverDuration)
|
||||||
_back->entity()->setClickedCallback([this] { onBack(); });
|
, _next(this, QString(), st::introNextButton) {
|
||||||
|
getData()->country = psCurrentCountry();
|
||||||
|
|
||||||
|
_back->entity()->setClickedCallback([this] { historyMove(Direction::Back); });
|
||||||
_back->hideFast();
|
_back->hideFast();
|
||||||
|
|
||||||
_settings->setClickedCallback([] { App::wnd()->showSettings(); });
|
_next->setClickedCallback([this] { getStep()->submit(); });
|
||||||
|
|
||||||
_countryForReg = psCurrentCountry();
|
_settings->entity()->setClickedCallback([] { App::wnd()->showSettings(); });
|
||||||
|
|
||||||
MTP::send(MTPhelp_GetNearestDc(), rpcDone(&IntroWidget::gotNearestDC));
|
if (cLang() == languageDefault) {
|
||||||
|
auto systemLangId = Sandbox::LangSystem();
|
||||||
|
if (systemLangId != languageDefault) {
|
||||||
|
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[systemLangId].c_str() + qsl(".strings"), langLoaderRequest(lng_switch_to_this));
|
||||||
|
QString text = loader.found().value(lng_switch_to_this);
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
_changeLanguage.create(this, new Ui::LinkButton(this, text), base::lambda<void()>(), st::introCoverDuration);
|
||||||
|
_changeLanguage->entity()->setClickedCallback([this, systemLangId] { changeLanguage(systemLangId); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_changeLanguage.create(this, new Ui::LinkButton(this, langOriginal(lng_switch_to_this)), base::lambda<void()>(), st::introCoverDuration);
|
||||||
|
_changeLanguage->entity()->setClickedCallback([this] { changeLanguage(languageDefault); });
|
||||||
|
}
|
||||||
|
|
||||||
_stepHistory.push_back(new IntroStart(this));
|
MTP::send(MTPhelp_GetNearestDc(), rpcDone(&Widget::gotNearestDC));
|
||||||
_back->raise();
|
|
||||||
_settings->raise();
|
appendStep(new StartWidget(this, getData()));
|
||||||
|
fixOrder();
|
||||||
|
|
||||||
show();
|
show();
|
||||||
setFocus();
|
showControls();
|
||||||
|
getStep()->showFast();
|
||||||
|
|
||||||
cSetPasswordRecovered(false);
|
cSetPasswordRecovered(false);
|
||||||
|
|
||||||
_back->moveToLeft(0, 0);
|
|
||||||
|
|
||||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||||
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
|
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
|
||||||
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
|
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
|
||||||
|
@ -74,12 +96,12 @@ IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||||
void IntroWidget::onCheckUpdateStatus() {
|
void Widget::onCheckUpdateStatus() {
|
||||||
if (Sandbox::updatingState() == Application::UpdatingReady) {
|
if (Sandbox::updatingState() == Application::UpdatingReady) {
|
||||||
if (_update) return;
|
if (_update) return;
|
||||||
_update.create(this, lang(lng_menu_update).toUpper(), st::defaultBoxButton);
|
_update.create(this, new Ui::RoundButton(this, lang(lng_menu_update).toUpper(), st::defaultBoxButton), base::lambda<void()>(), st::introCoverDuration);
|
||||||
if (!_a_show.animating()) _update->show();
|
if (!_a_show.animating()) _update->show();
|
||||||
_update->setClickedCallback([] {
|
_update->entity()->setClickedCallback([] {
|
||||||
checkReadyUpdate();
|
checkReadyUpdate();
|
||||||
App::restart();
|
App::restart();
|
||||||
});
|
});
|
||||||
|
@ -91,123 +113,204 @@ void IntroWidget::onCheckUpdateStatus() {
|
||||||
}
|
}
|
||||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||||
|
|
||||||
void IntroWidget::langChangeTo(int32 langId) {
|
void Widget::changeLanguage(int32 languageId) {
|
||||||
_langChangeTo = langId;
|
cSetLang(languageId);
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::onChangeLang() {
|
|
||||||
cSetLang(_langChangeTo);
|
|
||||||
Local::writeSettings();
|
Local::writeSettings();
|
||||||
App::restart();
|
App::restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::onStepSubmit() {
|
void Widget::setInnerFocus() {
|
||||||
step()->onSubmit();
|
if (getStep()->animating()) {
|
||||||
|
setFocus();
|
||||||
|
} else {
|
||||||
|
getStep()->setInnerFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::onBack() {
|
void Widget::historyMove(Direction direction) {
|
||||||
historyMove(MoveBack);
|
if (getStep()->animating()) return;
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::historyMove(MoveType type) {
|
|
||||||
if (_a_stage.animating()) return;
|
|
||||||
|
|
||||||
t_assert(_stepHistory.size() > 1);
|
t_assert(_stepHistory.size() > 1);
|
||||||
|
|
||||||
if (App::app()) App::app()->mtpPause();
|
auto wasStep = getStep((direction == Direction::Back) ? 0 : 1);
|
||||||
|
if (direction == Direction::Back) {
|
||||||
switch (type) {
|
|
||||||
case MoveBack: {
|
|
||||||
_cacheHide = grabStep();
|
|
||||||
|
|
||||||
IntroStep *back = step();
|
|
||||||
_backFrom = back->hasBack() ? 1 : 0;
|
|
||||||
_stepHistory.pop_back();
|
_stepHistory.pop_back();
|
||||||
back->cancelled();
|
wasStep->cancelled();
|
||||||
delete back;
|
} else if (direction == Direction::Replace) {
|
||||||
} break;
|
|
||||||
|
|
||||||
case MoveForward: {
|
|
||||||
_cacheHide = grabStep(1);
|
|
||||||
_backFrom = step(1)->hasBack() ? 1 : 0;
|
|
||||||
step(1)->finished();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case MoveReplace: {
|
|
||||||
_cacheHide = grabStep(1);
|
|
||||||
IntroStep *replaced = step(1);
|
|
||||||
_backFrom = replaced->hasBack() ? 1 : 0;
|
|
||||||
_stepHistory.removeAt(_stepHistory.size() - 2);
|
_stepHistory.removeAt(_stepHistory.size() - 2);
|
||||||
replaced->finished();
|
}
|
||||||
delete replaced;
|
getStep()->prepareShowAnimated(wasStep);
|
||||||
} break;
|
if (wasStep->hasCover() != getStep()->hasCover()) {
|
||||||
|
_nextTopFrom = wasStep->contentTop() + st::introStepHeight;
|
||||||
|
_controlsTopFrom = wasStep->hasCover() ? st::introCoverHeight : 0;
|
||||||
|
_coverShownAnimation.start([this] { updateControlsGeometry(); }, 0., 1., st::introCoverDuration, anim::easeOutCirc);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cacheShow = grabStep();
|
if (direction == Direction::Forward || direction == Direction::Replace) {
|
||||||
_backTo = step()->hasBack() ? 1 : 0;
|
wasStep->finished();
|
||||||
|
}
|
||||||
int32 m = (type == MoveBack) ? -1 : 1;
|
if (direction == Direction::Back || direction == Direction::Replace) {
|
||||||
a_coordHide = anim::ivalue(0, -m * st::introSlideShift);
|
delete base::take(wasStep);
|
||||||
a_opacityHide = anim::fvalue(1, 0);
|
}
|
||||||
a_coordShow = anim::ivalue(m * st::introSlideShift, 0);
|
if (getStep()->hasBack()) {
|
||||||
a_opacityShow = anim::fvalue(0, 1);
|
|
||||||
_a_stage.start();
|
|
||||||
|
|
||||||
_a_stage.step();
|
|
||||||
if (_backTo) {
|
|
||||||
_back->fadeIn();
|
_back->fadeIn();
|
||||||
} else {
|
} else {
|
||||||
_back->fadeOut();
|
_back->fadeOut();
|
||||||
}
|
}
|
||||||
step()->hide();
|
if (getStep()->hasCover()) {
|
||||||
|
_settings->fadeOut();
|
||||||
|
if (_update) _update->fadeOut();
|
||||||
|
if (_changeLanguage) _changeLanguage->fadeIn();
|
||||||
|
} else {
|
||||||
|
_settings->fadeIn();
|
||||||
|
if (_update) _update->fadeIn();
|
||||||
|
if (_changeLanguage) _changeLanguage->fadeOut();
|
||||||
|
}
|
||||||
|
_next->setText(getStep()->nextButtonText());
|
||||||
|
if (_resetAccount) _resetAccount->fadeOut();
|
||||||
|
getStep()->showAnimated(direction);
|
||||||
|
fixOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::pushStep(IntroStep *step, MoveType type) {
|
void Widget::fixOrder() {
|
||||||
_stepHistory.push_back(step);
|
_next->raise();
|
||||||
|
if (_update) _update->raise();
|
||||||
|
_settings->raise();
|
||||||
|
_back->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::moveToStep(Step *step, Direction direction) {
|
||||||
|
appendStep(step);
|
||||||
_back->raise();
|
_back->raise();
|
||||||
_settings->raise();
|
_settings->raise();
|
||||||
if (_update) {
|
if (_update) {
|
||||||
_update->raise();
|
_update->raise();
|
||||||
}
|
}
|
||||||
_stepHistory.back()->hide();
|
|
||||||
|
|
||||||
historyMove(type);
|
historyMove(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::gotNearestDC(const MTPNearestDc &result) {
|
void Widget::appendStep(Step *step) {
|
||||||
const auto &nearest(result.c_nearestDc());
|
_stepHistory.push_back(step);
|
||||||
|
step->setGeometry(calculateStepRect());
|
||||||
|
step->setGoCallback([this](Step *step, Direction direction) {
|
||||||
|
if (direction == Direction::Back) {
|
||||||
|
historyMove(direction);
|
||||||
|
} else {
|
||||||
|
moveToStep(step, direction);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
step->setShowResetCallback([this] {
|
||||||
|
showResetButton();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::showResetButton() {
|
||||||
|
if (!_resetAccount) {
|
||||||
|
_resetAccount.create(this, new Ui::RoundButton(this, lang(lng_signin_reset_account), st::introResetButton), base::lambda<void()>(), st::introErrorDuration);
|
||||||
|
_resetAccount->hideFast();
|
||||||
|
_resetAccount->entity()->setClickedCallback([this] { resetAccount(); });
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
_resetAccount->fadeIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::resetAccount() {
|
||||||
|
if (_resetRequest) return;
|
||||||
|
|
||||||
|
auto box = new ConfirmBox(lang(lng_signin_sure_reset), lang(lng_signin_reset), st::attentionBoxButton);
|
||||||
|
box->setConfirmedCallback([this] { resetAccountSure(); });
|
||||||
|
Ui::showLayer(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::resetAccountSure() {
|
||||||
|
if (_resetRequest) return;
|
||||||
|
_resetRequest = MTP::send(MTPaccount_DeleteAccount(MTP_string("Forgot password")), rpcDone(&Widget::resetDone), rpcFail(&Widget::resetFail));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::resetDone(const MTPBool &result) {
|
||||||
|
Ui::hideLayer();
|
||||||
|
moveToStep(new SignupWidget(this, getData()), Direction::Replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::resetFail(const RPCError &error) {
|
||||||
|
if (MTP::isDefaultHandledError(error)) return false;
|
||||||
|
|
||||||
|
_resetRequest = 0;
|
||||||
|
|
||||||
|
auto type = error.type();
|
||||||
|
if (type.startsWith(qstr("2FA_CONFIRM_WAIT_"))) {
|
||||||
|
int seconds = type.mid(qstr("2FA_CONFIRM_WAIT_").size()).toInt();
|
||||||
|
int days = (seconds + 59) / 86400;
|
||||||
|
int hours = ((seconds + 59) % 86400) / 3600;
|
||||||
|
int minutes = ((seconds + 59) % 3600) / 60;
|
||||||
|
QString when;
|
||||||
|
if (days > 0) {
|
||||||
|
when = lng_signin_reset_in_days(lt_count_days, days, lt_count_hours, hours, lt_count_minutes, minutes);
|
||||||
|
} else if (hours > 0) {
|
||||||
|
when = lng_signin_reset_in_hours(lt_count_hours, hours, lt_count_minutes, minutes);
|
||||||
|
} else {
|
||||||
|
when = lng_signin_reset_in_minutes(lt_count_minutes, minutes);
|
||||||
|
}
|
||||||
|
Ui::showLayer(new InformBox(lng_signin_reset_wait(lt_phone_number, App::formatPhone(getData()->phone), lt_when, when)));
|
||||||
|
} else if (type == qstr("2FA_RECENT_CONFIRM")) {
|
||||||
|
Ui::showLayer(new InformBox(lang(lng_signin_reset_cancelled)));
|
||||||
|
} else {
|
||||||
|
Ui::hideLayer();
|
||||||
|
getStep()->showError(lang(lng_server_error));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::gotNearestDC(const MTPNearestDc &result) {
|
||||||
|
auto &nearest = result.c_nearestDc();
|
||||||
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
|
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
|
||||||
MTP::setdc(result.c_nearestDc().vnearest_dc.v, true);
|
MTP::setdc(nearest.vnearest_dc.v, true);
|
||||||
if (_countryForReg != nearest.vcountry.c_string().v.c_str()) {
|
auto nearestCountry = qs(nearest.vcountry);
|
||||||
_countryForReg = nearest.vcountry.c_string().v.c_str();
|
if (getData()->country != nearestCountry) {
|
||||||
emit countryChanged();
|
getData()->country = nearestCountry;
|
||||||
|
getData()->updated.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap IntroWidget::grabStep(int skip) {
|
void Widget::showControls() {
|
||||||
return myGrab(step(skip), QRect(st::introSlideShift, 0, st::introSize.width(), st::introSize.height()));
|
getStep()->show();
|
||||||
|
_next->show();
|
||||||
|
_next->setText(getStep()->nextButtonText());
|
||||||
|
if (getStep()->hasCover()) {
|
||||||
|
_settings->hideFast();
|
||||||
|
if (_update) _update->hideFast();
|
||||||
|
if (_changeLanguage) _changeLanguage->showFast();
|
||||||
|
} else {
|
||||||
|
_settings->showFast();
|
||||||
|
if (_update) _update->showFast();
|
||||||
|
if (_changeLanguage) _changeLanguage->hideFast();
|
||||||
|
}
|
||||||
|
if (getStep()->hasBack()) {
|
||||||
|
_back->showFast();
|
||||||
|
} else {
|
||||||
|
_back->hideFast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) {
|
void Widget::hideControls() {
|
||||||
|
getStep()->hide();
|
||||||
|
_next->hide();
|
||||||
|
_settings->hideFast();
|
||||||
|
if (_update) _update->hideFast();
|
||||||
|
if (_changeLanguage) _changeLanguage->hideFast();
|
||||||
|
_back->hideFast();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||||
if (App::app()) App::app()->mtpPause();
|
if (App::app()) App::app()->mtpPause();
|
||||||
|
|
||||||
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
|
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
|
||||||
|
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
step()->show();
|
showControls();
|
||||||
_settings->show();
|
|
||||||
if (_update) _update->show();
|
|
||||||
if (step()->hasBack()) {
|
|
||||||
_back->showFast();
|
|
||||||
} else {
|
|
||||||
_back->hideFast();
|
|
||||||
}
|
|
||||||
(back ? _cacheUnder : _cacheOver) = myGrab(this);
|
(back ? _cacheUnder : _cacheOver) = myGrab(this);
|
||||||
|
hideControls();
|
||||||
step()->hide();
|
|
||||||
_back->hideFast();
|
|
||||||
_settings->hide();
|
|
||||||
if (_update) _update->hide();
|
|
||||||
|
|
||||||
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift);
|
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift);
|
||||||
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
|
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
|
||||||
|
@ -217,7 +320,7 @@ void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::step_show(float64 ms, bool timer) {
|
void Widget::step_show(float64 ms, bool timer) {
|
||||||
float64 dt = ms / st::slideDuration;
|
float64 dt = ms / st::slideDuration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
_a_show.stop();
|
_a_show.stop();
|
||||||
|
@ -228,13 +331,9 @@ void IntroWidget::step_show(float64 ms, bool timer) {
|
||||||
|
|
||||||
_cacheUnder = _cacheOver = QPixmap();
|
_cacheUnder = _cacheOver = QPixmap();
|
||||||
|
|
||||||
setFocus();
|
showControls();
|
||||||
step()->activate();
|
getStep()->activate();
|
||||||
if (step()->hasBack()) {
|
|
||||||
_back->showFast();
|
|
||||||
}
|
|
||||||
_settings->show();
|
|
||||||
if (_update) _update->show();
|
|
||||||
if (App::app()) App::app()->mtpUnpause();
|
if (App::app()) App::app()->mtpUnpause();
|
||||||
} else {
|
} else {
|
||||||
a_coordUnder.update(dt, Window::SlideAnimation::transition());
|
a_coordUnder.update(dt, Window::SlideAnimation::transition());
|
||||||
|
@ -244,37 +343,14 @@ void IntroWidget::step_show(float64 ms, bool timer) {
|
||||||
if (timer) update();
|
if (timer) update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::stop_show() {
|
void Widget::paintEvent(QPaintEvent *e) {
|
||||||
_a_show.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::step_stage(float64 ms, bool timer) {
|
|
||||||
float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration;
|
|
||||||
float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0;
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_stage.stop();
|
|
||||||
|
|
||||||
a_coordShow.finish();
|
|
||||||
a_opacityShow.finish();
|
|
||||||
|
|
||||||
_cacheHide = _cacheShow = QPixmap();
|
|
||||||
|
|
||||||
setFocus();
|
|
||||||
step()->activate();
|
|
||||||
if (App::app()) App::app()->mtpUnpause();
|
|
||||||
} else {
|
|
||||||
a_coordShow.update(dt2, anim::easeOutCirc);
|
|
||||||
a_opacityShow.update(dt2, anim::easeInCirc);
|
|
||||||
a_coordHide.update(dt1, anim::easeInCirc);
|
|
||||||
a_opacityHide.update(dt1, anim::easeOutCirc);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::paintEvent(QPaintEvent *e) {
|
|
||||||
bool trivial = (rect() == e->rect());
|
bool trivial = (rect() == e->rect());
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
if (_coverShownAnimation.animating()) {
|
||||||
|
_coverShownAnimation.step(getms());
|
||||||
|
}
|
||||||
|
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
if (!trivial) {
|
if (!trivial) {
|
||||||
p.setClipRect(e->rect());
|
p.setClipRect(e->rect());
|
||||||
|
@ -290,130 +366,406 @@ void IntroWidget::paintEvent(QPaintEvent *e) {
|
||||||
p.drawPixmap(a_coordOver.current(), 0, _cacheOver);
|
p.drawPixmap(a_coordOver.current(), 0, _cacheOver);
|
||||||
p.setOpacity(a_shadow.current());
|
p.setOpacity(a_shadow.current());
|
||||||
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
|
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
|
||||||
} else if (_a_stage.animating()) {
|
|
||||||
p.setOpacity(a_opacityHide.current());
|
|
||||||
p.drawPixmap(step()->x() + st::introSlideShift + a_coordHide.current(), step()->y(), _cacheHide);
|
|
||||||
p.setOpacity(a_opacityShow.current());
|
|
||||||
p.drawPixmap(step()->x() + st::introSlideShift + a_coordShow.current(), step()->y(), _cacheShow);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect IntroWidget::innerRect() const {
|
QRect Widget::calculateStepRect() const {
|
||||||
int innerWidth = st::introSize.width() + 2 * st::introSlideShift, innerHeight = st::introSize.height();
|
auto stepInnerTop = (height() - st::introHeight) / 2;
|
||||||
return QRect((width() - innerWidth) / 2, (height() - innerHeight) / 2, innerWidth, (height() + innerHeight) / 2);
|
accumulate_max(stepInnerTop, st::introStepTopMin);
|
||||||
|
auto nextTop = stepInnerTop + st::introStepHeight;
|
||||||
|
auto additionalHeight = st::introStepHeightAdd;
|
||||||
|
auto stepWidth = width();
|
||||||
|
auto stepHeight = nextTop + additionalHeight;
|
||||||
|
return QRect(0, 0, stepWidth, stepHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString IntroWidget::currentCountry() const {
|
void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
return _countryForReg;
|
auto stepRect = calculateStepRect();
|
||||||
}
|
for_const (auto step, _stepHistory) {
|
||||||
|
step->setGeometry(stepRect);
|
||||||
void IntroWidget::setPhone(const QString &phone, const QString &phone_hash, bool registered) {
|
|
||||||
_phone = phone;
|
|
||||||
_phone_hash = phone_hash;
|
|
||||||
_registered = registered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::setCode(const QString &code) {
|
|
||||||
_code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::setPwdSalt(const QByteArray &salt) {
|
|
||||||
_pwdSalt = salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::setHasRecovery(bool has) {
|
|
||||||
_hasRecovery = has;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::setPwdHint(const QString &hint) {
|
|
||||||
_pwdHint = hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::setCodeByTelegram(bool byTelegram) {
|
|
||||||
_codeByTelegram = byTelegram;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::setCallStatus(const CallStatus &status) {
|
|
||||||
_callStatus = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &IntroWidget::getPhone() const {
|
|
||||||
return _phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &IntroWidget::getPhoneHash() const {
|
|
||||||
return _phone_hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &IntroWidget::getCode() const {
|
|
||||||
return _code;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IntroWidget::CallStatus &IntroWidget::getCallStatus() const {
|
|
||||||
return _callStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray &IntroWidget::getPwdSalt() const {
|
|
||||||
return _pwdSalt;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IntroWidget::getHasRecovery() const {
|
|
||||||
return _hasRecovery;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &IntroWidget::getPwdHint() const {
|
|
||||||
return _pwdHint;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IntroWidget::codeByTelegram() const {
|
|
||||||
return _codeByTelegram;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntroWidget::resizeEvent(QResizeEvent *e) {
|
|
||||||
auto r = innerRect();
|
|
||||||
for (auto step : _stepHistory) {
|
|
||||||
step->setGeometry(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::updateControlsGeometry() {
|
void Widget::moveControls() {
|
||||||
_settings->moveToRight(st::boxButtonPadding.right(), st::boxButtonPadding.top());
|
}
|
||||||
|
|
||||||
|
void Widget::updateControlsGeometry() {
|
||||||
|
auto shown = _coverShownAnimation.current(1.);
|
||||||
|
|
||||||
|
auto controlsTopTo = getStep()->hasCover() ? st::introCoverHeight : 0;
|
||||||
|
auto controlsTop = anim::interpolate(_controlsTopFrom, controlsTopTo, shown);
|
||||||
|
_settings->moveToRight(st::introSettingsSkip, controlsTop + st::introSettingsSkip);
|
||||||
if (_update) {
|
if (_update) {
|
||||||
_update->moveToRight(st::boxButtonPadding.right() + _settings->width() + st::boxButtonPadding.left(), _settings->y());
|
_update->moveToRight(st::introSettingsSkip + _settings->width() + st::introSettingsSkip, _settings->y());
|
||||||
|
}
|
||||||
|
_back->moveToLeft(0, controlsTop);
|
||||||
|
|
||||||
|
auto nextTopTo = getStep()->contentTop() + st::introStepHeight;
|
||||||
|
auto nextTop = anim::interpolate(_nextTopFrom, nextTopTo, shown);
|
||||||
|
_next->moveToLeft((width() - _next->width()) / 2, nextTop);
|
||||||
|
if (_changeLanguage) {
|
||||||
|
_changeLanguage->moveToLeft((width() - _changeLanguage->width()) / 2, _next->y() + _next->height() + _changeLanguage->height());
|
||||||
|
}
|
||||||
|
if (_resetAccount) {
|
||||||
|
_resetAccount->moveToLeft((width() - _resetAccount->width()) / 2, height() - st::introResetBottom - _resetAccount->height());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::finish(const MTPUser &user, const QImage &photo) {
|
|
||||||
|
void Widget::keyPressEvent(QKeyEvent *e) {
|
||||||
|
if (_a_show.animating() || getStep()->animating()) return;
|
||||||
|
|
||||||
|
if (e->key() == Qt::Key_Escape) {
|
||||||
|
if (getStep()->hasBack()) {
|
||||||
|
historyMove(Direction::Back);
|
||||||
|
}
|
||||||
|
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) {
|
||||||
|
getStep()->submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::~Widget() {
|
||||||
|
for (auto step : base::take(_stepHistory)) {
|
||||||
|
delete step;
|
||||||
|
}
|
||||||
|
if (App::wnd()) App::wnd()->noIntro(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Widget::Step::nextButtonText() const {
|
||||||
|
return lang(lng_intro_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::finish(const MTPUser &user, QImage photo) {
|
||||||
App::wnd()->setupMain(&user);
|
App::wnd()->setupMain(&user);
|
||||||
|
|
||||||
|
// "this" is already deleted here by creating the main widget.
|
||||||
if (!photo.isNull()) {
|
if (!photo.isNull()) {
|
||||||
App::app()->uploadProfilePhoto(photo, MTP::authedId());
|
App::app()->uploadProfilePhoto(photo, MTP::authedId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::keyPressEvent(QKeyEvent *e) {
|
void Widget::Step::paintEvent(QPaintEvent *e) {
|
||||||
if (_a_show.animating() || _a_stage.animating()) return;
|
Painter p(this);
|
||||||
|
paintAnimated(p, e->rect());
|
||||||
|
}
|
||||||
|
|
||||||
if (e->key() == Qt::Key_Escape) {
|
void Widget::Step::resizeEvent(QResizeEvent *e) {
|
||||||
if (step()->hasBack()) {
|
updateLabelsPosition();
|
||||||
onBack();
|
}
|
||||||
|
|
||||||
|
void Widget::Step::updateLabelsPosition() {
|
||||||
|
myEnsureResized(_description->entity());
|
||||||
|
if (hasCover()) {
|
||||||
|
_title->moveToLeft((width() - _title->width()) / 2, contentTop() + st::introCoverTitleTop);
|
||||||
|
_description->moveToLeft((width() - _description->width()) / 2, contentTop() + st::introCoverDescriptionTop);
|
||||||
|
} else {
|
||||||
|
_title->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introTitleTop);
|
||||||
|
_description->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introDescriptionTop);
|
||||||
|
}
|
||||||
|
if (_error) {
|
||||||
|
if (_errorCentered) {
|
||||||
|
_error->entity()->resizeToWidth(width());
|
||||||
}
|
}
|
||||||
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) {
|
myEnsureResized(_error->entity());
|
||||||
onStepSubmit();
|
auto errorLeft = _errorCentered ? 0 : (contentLeft() + st::buttonRadius);
|
||||||
|
auto errorTop = contentTop() + (_errorBelowLink ? st::introErrorBelowLinkTop : st::introErrorTop);
|
||||||
|
_error->moveToLeft(errorLeft, errorTop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntroWidget::rpcClear() {
|
void Widget::Step::setTitleText(QString richText) {
|
||||||
for (IntroStep *step : _stepHistory) {
|
_title->setRichText(richText);
|
||||||
step->rpcClear();
|
updateLabelsPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::setDescriptionText(QString richText) {
|
||||||
|
_description->entity()->setRichText(richText);
|
||||||
|
updateLabelsPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::showFinished() {
|
||||||
|
_a_show.finish();
|
||||||
|
_coverAnimation = CoverAnimation();
|
||||||
|
_slideAnimation.reset();
|
||||||
|
prepareCoverMask();
|
||||||
|
activate();
|
||||||
|
if (App::app()) App::app()->mtpUnpause();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::Step::paintAnimated(Painter &p, QRect clip) {
|
||||||
|
if (_slideAnimation) {
|
||||||
|
_slideAnimation->paintFrame(p, (width() - st::introStepWidth) / 2, contentTop(), width(), getms());
|
||||||
|
if (!_slideAnimation->animating()) {
|
||||||
|
showFinished();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto guard = base::scope_guard([this, &p] {
|
||||||
|
if (hasCover()) paintCover(p, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto dt = _a_show.current(getms(), 1.);
|
||||||
|
if (!_a_show.animating()) {
|
||||||
|
if (_coverAnimation.title) {
|
||||||
|
showFinished();
|
||||||
|
}
|
||||||
|
if (!QRect(0, contentTop(), width(), st::introStepHeight).intersects(clip)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto easeOut = anim::easeOutCirc(1., dt);
|
||||||
|
auto arrivingAlpha = easeOut;
|
||||||
|
auto departingAlpha = 1. - easeOut;
|
||||||
|
auto showCoverMethod = easeOut;
|
||||||
|
auto hideCoverMethod = easeOut;
|
||||||
|
auto coverTop = (hasCover() ? anim::interpolate(-st::introCoverHeight, 0, showCoverMethod) : anim::interpolate(0, -st::introCoverHeight, hideCoverMethod));
|
||||||
|
|
||||||
|
paintCover(p, coverTop);
|
||||||
|
guard.dismiss();
|
||||||
|
|
||||||
|
auto positionReady = hasCover() ? showCoverMethod : hideCoverMethod;
|
||||||
|
_coverAnimation.title->paintFrame(p, positionReady, departingAlpha, arrivingAlpha);
|
||||||
|
_coverAnimation.description->paintFrame(p, positionReady, departingAlpha, arrivingAlpha);
|
||||||
|
|
||||||
|
paintContentSnapshot(p, _coverAnimation.contentSnapshotWas, departingAlpha, showCoverMethod);
|
||||||
|
paintContentSnapshot(p, _coverAnimation.contentSnapshotNow, arrivingAlpha, 1. - hideCoverMethod);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::fillSentCodeData(const MTPauth_SentCodeType &type) {
|
||||||
|
switch (type.type()) {
|
||||||
|
case mtpc_auth_sentCodeTypeApp: {
|
||||||
|
getData()->codeByTelegram = true;
|
||||||
|
getData()->codeLength = type.c_auth_sentCodeTypeApp().vlength.v;
|
||||||
|
} break;
|
||||||
|
case mtpc_auth_sentCodeTypeSms: {
|
||||||
|
getData()->codeByTelegram = false;
|
||||||
|
getData()->codeLength = type.c_auth_sentCodeTypeSms().vlength.v;
|
||||||
|
} break;
|
||||||
|
case mtpc_auth_sentCodeTypeCall: {
|
||||||
|
getData()->codeByTelegram = false;
|
||||||
|
getData()->codeLength = type.c_auth_sentCodeTypeCall().vlength.v;
|
||||||
|
} break;
|
||||||
|
case mtpc_auth_sentCodeTypeFlashCall: LOG(("Error: should not be flashcall!")); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IntroWidget::~IntroWidget() {
|
void Widget::Step::showDescription() {
|
||||||
while (!_stepHistory.isEmpty()) {
|
_description->fadeIn();
|
||||||
IntroStep *back = _stepHistory.back();
|
|
||||||
_stepHistory.pop_back();
|
|
||||||
delete back;
|
|
||||||
}
|
|
||||||
if (App::wnd()) App::wnd()->noIntro(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::Step::hideDescription() {
|
||||||
|
_description->fadeOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::paintContentSnapshot(Painter &p, const QPixmap &snapshot, float64 alpha, float64 howMuchHidden) {
|
||||||
|
if (!snapshot.isNull()) {
|
||||||
|
auto contentTop = anim::interpolate(height() - (snapshot.height() / cIntRetinaFactor()), height(), howMuchHidden);
|
||||||
|
if (contentTop < height()) {
|
||||||
|
p.setOpacity(alpha);
|
||||||
|
p.drawPixmap(QPoint(contentLeft(), contentTop), snapshot, QRect(0, 0, snapshot.width(), (height() - contentTop) * cIntRetinaFactor()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::prepareCoverMask() {
|
||||||
|
if (!_coverMask.isNull()) return;
|
||||||
|
|
||||||
|
auto maskWidth = cIntRetinaFactor();
|
||||||
|
auto maskHeight = st::introCoverHeight * cIntRetinaFactor();
|
||||||
|
auto mask = QImage(maskWidth, maskHeight, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
auto maskInts = reinterpret_cast<uint32*>(mask.bits());
|
||||||
|
t_assert(mask.depth() == (sizeof(uint32) << 3));
|
||||||
|
auto maskIntsPerLineAdded = (mask.bytesPerLine() >> 2) - maskWidth;
|
||||||
|
t_assert(maskIntsPerLineAdded >= 0);
|
||||||
|
auto realHeight = static_cast<float64>(maskHeight - 1);
|
||||||
|
for (auto y = 0; y != maskHeight; ++y) {
|
||||||
|
auto color = anim::color(st::introCoverTopBg, st::introCoverBottomBg, y / realHeight);
|
||||||
|
auto colorInt = anim::getPremultiplied(color);
|
||||||
|
for (auto x = 0; x != maskWidth; ++x) {
|
||||||
|
*maskInts++ = colorInt;
|
||||||
|
}
|
||||||
|
maskInts += maskIntsPerLineAdded;
|
||||||
|
}
|
||||||
|
_coverMask = App::pixmapFromImageInPlace(std_::move(mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::paintCover(Painter &p, int top) {
|
||||||
|
auto coverHeight = top + st::introCoverHeight;
|
||||||
|
if (coverHeight > 0) {
|
||||||
|
p.drawPixmap(QRect(0, 0, width(), coverHeight), _coverMask, QRect(0, -top * cIntRetinaFactor(), _coverMask.width(), coverHeight * cIntRetinaFactor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto left = 0;
|
||||||
|
auto right = 0;
|
||||||
|
if (width() < st::introCoverMaxWidth) {
|
||||||
|
auto iconsMaxSkip = st::introCoverMaxWidth - st::introCoverLeft.width() - st::introCoverRight.width();
|
||||||
|
auto iconsSkip = st::introCoverIconsMinSkip + (iconsMaxSkip - st::introCoverIconsMinSkip) * (width() - st::introStepWidth) / (st::introCoverMaxWidth - st::introStepWidth);
|
||||||
|
auto outside = iconsSkip + st::introCoverLeft.width() + st::introCoverRight.width() - width();
|
||||||
|
left = -outside / 2;
|
||||||
|
right = -outside - left;
|
||||||
|
}
|
||||||
|
if (top < 0) {
|
||||||
|
auto shown = float64(coverHeight) / st::introCoverHeight;
|
||||||
|
auto leftShown = qRound(shown * (left + st::introCoverLeft.width()));
|
||||||
|
left = leftShown - st::introCoverLeft.width();
|
||||||
|
auto rightShown = qRound(shown * (right + st::introCoverRight.width()));
|
||||||
|
right = rightShown - st::introCoverRight.width();
|
||||||
|
}
|
||||||
|
st::introCoverLeft.paint(p, left, coverHeight - st::introCoverLeft.height(), width());
|
||||||
|
st::introCoverRight.paint(p, width() - right - st::introCoverRight.width(), coverHeight - st::introCoverRight.height(), width());
|
||||||
|
|
||||||
|
auto planeLeft = (width() - st::introCoverIcon.width()) / 2 - st::introCoverIconLeft;
|
||||||
|
auto planeTop = top + st::introCoverIconTop;
|
||||||
|
if (top < 0 && !_hasCover) {
|
||||||
|
auto deltaLeft = -qRound(float64(st::introPlaneWidth / st::introPlaneHeight) * top);
|
||||||
|
// auto deltaTop = top;
|
||||||
|
planeLeft += deltaLeft;
|
||||||
|
// planeTop += top;
|
||||||
|
}
|
||||||
|
st::introCoverIcon.paint(p, planeLeft, planeTop, width());
|
||||||
|
}
|
||||||
|
|
||||||
|
int Widget::Step::contentLeft() const {
|
||||||
|
return (width() - st::introNextButton.width) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Widget::Step::contentTop() const {
|
||||||
|
auto result = height() - st::introStepHeight - st::introStepHeightAdd;
|
||||||
|
if (_hasCover) {
|
||||||
|
auto added = 1. - snap(float64(height() - st::windowMinHeight) / (st::introStepHeightFull - st::windowMinHeight), 0., 1.);
|
||||||
|
result += qRound(added * st::introStepHeightAdd);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::setErrorCentered(bool centered) {
|
||||||
|
_errorCentered = centered;
|
||||||
|
_error.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::setErrorBelowLink(bool below) {
|
||||||
|
_errorBelowLink = below;
|
||||||
|
if (_error) {
|
||||||
|
updateLabelsPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::showError(const QString &text) {
|
||||||
|
_errorText = text;
|
||||||
|
if (_errorText.isEmpty()) {
|
||||||
|
if (_error) _error->fadeOut();
|
||||||
|
} else {
|
||||||
|
if (!_error) {
|
||||||
|
auto &st = _errorCentered ? st::introErrorCentered : st::introError;
|
||||||
|
_error.create(this, new Ui::FlatLabel(this, st, st::introErrorTextStyle), base::lambda<void()>(), st::introErrorDuration);
|
||||||
|
_error->hideFast();
|
||||||
|
}
|
||||||
|
_error->entity()->setText(text);
|
||||||
|
updateLabelsPosition();
|
||||||
|
_error->fadeIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::Step::Step(QWidget *parent, Data *data, bool hasCover) : TWidget(parent)
|
||||||
|
, _data(data)
|
||||||
|
, _hasCover(hasCover)
|
||||||
|
, _title(this, _hasCover ? st::introCoverTitle : st::introTitle, st::defaultTextStyle)
|
||||||
|
, _description(this, new Ui::FlatLabel(this, _hasCover ? st::introCoverDescription : st::introDescription, _hasCover ? st::introCoverDescriptionTextStyle : st::introDescriptionTextStyle), base::lambda<void()>(), st::introErrorDuration) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::prepareShowAnimated(Step *after) {
|
||||||
|
if (hasCover() || after->hasCover()) {
|
||||||
|
_coverAnimation = prepareCoverAnimation(after);
|
||||||
|
prepareCoverMask();
|
||||||
|
} else {
|
||||||
|
auto leftSnapshot = after->prepareSlideAnimation();
|
||||||
|
auto rightSnapshot = prepareSlideAnimation();
|
||||||
|
_slideAnimation = std_::make_unique<Ui::SlideAnimation>();
|
||||||
|
_slideAnimation->setSnapshots(std_::move(leftSnapshot), std_::move(rightSnapshot));
|
||||||
|
_slideAnimation->setOverflowHidden(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::Step::CoverAnimation Widget::Step::prepareCoverAnimation(Step *after) {
|
||||||
|
auto result = CoverAnimation();
|
||||||
|
result.title = Ui::FlatLabel::CrossFade(after->_title, _title, st::introBg);
|
||||||
|
result.description = Ui::FlatLabel::CrossFade(after->_description->entity(), _description->entity(), st::introBg, after->_description->pos(), _description->pos());
|
||||||
|
result.contentSnapshotWas = after->prepareContentSnapshot();
|
||||||
|
result.contentSnapshotNow = prepareContentSnapshot();
|
||||||
|
return std_::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap Widget::Step::prepareContentSnapshot() {
|
||||||
|
auto otherTop = _description->y() + _description->height();
|
||||||
|
auto otherRect = myrtlrect(contentLeft(), otherTop, st::introStepWidth, height() - otherTop);
|
||||||
|
return myGrab(this, otherRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap Widget::Step::prepareSlideAnimation() {
|
||||||
|
auto grabLeft = (width() - st::introStepWidth) / 2;
|
||||||
|
auto grabTop = contentTop();
|
||||||
|
return myGrab(this, QRect(grabLeft, grabTop, st::introStepWidth, st::introStepHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::showAnimated(Direction direction) {
|
||||||
|
show();
|
||||||
|
if (App::app()) App::app()->mtpPause();
|
||||||
|
hideChildren();
|
||||||
|
if (_slideAnimation) {
|
||||||
|
auto slideLeft = (direction == Direction::Back);
|
||||||
|
_slideAnimation->start(slideLeft, [this] { update(0, contentTop(), width(), st::introStepHeight); }, st::introSlideDuration);
|
||||||
|
} else {
|
||||||
|
_a_show.start([this] { update(); }, 0., 1., st::introCoverDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::setGoCallback(base::lambda<void(Step *step, Direction direction)> &&callback) {
|
||||||
|
_goCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::setShowResetCallback(base::lambda<void()> &&callback) {
|
||||||
|
_showResetCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::showFast() {
|
||||||
|
show();
|
||||||
|
showFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::Step::animating() const {
|
||||||
|
return (_slideAnimation && _slideAnimation->animating()) || _a_show.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::Step::hasCover() const {
|
||||||
|
return _hasCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::Step::hasBack() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::activate() {
|
||||||
|
_title->show();
|
||||||
|
_description->show();
|
||||||
|
if (!_errorText.isEmpty()) {
|
||||||
|
_error->showFast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::cancelled() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::Step::finished() {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Intro
|
||||||
|
|
|
@ -23,77 +23,32 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
|
class LinkButton;
|
||||||
|
class SlideAnimation;
|
||||||
|
class CrossFadeAnimation;
|
||||||
|
class FlatLabel;
|
||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
class WidgetFadeWrap;
|
class WidgetFadeWrap;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class IntroStep;
|
namespace Intro {
|
||||||
class IntroWidget : public TWidget, public RPCSender {
|
|
||||||
|
class Widget : public TWidget, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntroWidget(QWidget *window);
|
Widget(QWidget *parent);
|
||||||
|
|
||||||
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
||||||
void step_show(float64 ms, bool timer);
|
void setInnerFocus();
|
||||||
void stop_show();
|
|
||||||
|
|
||||||
void step_stage(float64 ms, bool timer);
|
~Widget();
|
||||||
|
|
||||||
QRect innerRect() const;
|
|
||||||
QString currentCountry() const;
|
|
||||||
|
|
||||||
enum CallStatusType {
|
|
||||||
CallWaiting,
|
|
||||||
CallCalling,
|
|
||||||
CallCalled,
|
|
||||||
CallDisabled,
|
|
||||||
};
|
|
||||||
struct CallStatus {
|
|
||||||
CallStatusType type;
|
|
||||||
int timeout;
|
|
||||||
};
|
|
||||||
void setPhone(const QString &phone, const QString &phone_hash, bool registered);
|
|
||||||
void setCode(const QString &code);
|
|
||||||
void setCallStatus(const CallStatus &status);
|
|
||||||
void setPwdSalt(const QByteArray &salt);
|
|
||||||
void setHasRecovery(bool hasRecovery);
|
|
||||||
void setPwdHint(const QString &hint);
|
|
||||||
void setCodeByTelegram(bool byTelegram);
|
|
||||||
|
|
||||||
const QString &getPhone() const;
|
|
||||||
const QString &getPhoneHash() const;
|
|
||||||
const QString &getCode() const;
|
|
||||||
const CallStatus &getCallStatus() const;
|
|
||||||
const QByteArray &getPwdSalt() const;
|
|
||||||
bool getHasRecovery() const;
|
|
||||||
const QString &getPwdHint() const;
|
|
||||||
bool codeByTelegram() const;
|
|
||||||
|
|
||||||
void finish(const MTPUser &user, const QImage &photo = QImage());
|
|
||||||
|
|
||||||
void rpcClear() override;
|
|
||||||
void langChangeTo(int32 langId);
|
|
||||||
|
|
||||||
void nextStep(IntroStep *step) {
|
|
||||||
pushStep(step, MoveForward);
|
|
||||||
}
|
|
||||||
void replaceStep(IntroStep *step) {
|
|
||||||
pushStep(step, MoveReplace);
|
|
||||||
}
|
|
||||||
|
|
||||||
~IntroWidget();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
public slots:
|
|
||||||
void onStepSubmit();
|
|
||||||
void onBack();
|
|
||||||
void onChangeLang();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void countryChanged();
|
void countryChanged();
|
||||||
|
|
||||||
|
@ -102,86 +57,199 @@ private slots:
|
||||||
void onCheckUpdateStatus();
|
void onCheckUpdateStatus();
|
||||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||||
|
|
||||||
|
// Internal interface.
|
||||||
|
public:
|
||||||
|
struct Data {
|
||||||
|
QString country;
|
||||||
|
QString phone;
|
||||||
|
QString phoneHash;
|
||||||
|
bool phoneIsRegistered = false;
|
||||||
|
|
||||||
|
enum class CallStatus {
|
||||||
|
Waiting,
|
||||||
|
Calling,
|
||||||
|
Called,
|
||||||
|
Disabled,
|
||||||
|
};
|
||||||
|
CallStatus callStatus = CallStatus::Disabled;
|
||||||
|
int callTimeout = 0;
|
||||||
|
|
||||||
|
QString code;
|
||||||
|
int codeLength = 5;
|
||||||
|
bool codeByTelegram = false;
|
||||||
|
|
||||||
|
QByteArray pwdSalt;
|
||||||
|
bool hasRecovery = false;
|
||||||
|
QString pwdHint;
|
||||||
|
|
||||||
|
base::Observable<void> updated;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Direction {
|
||||||
|
Back,
|
||||||
|
Forward,
|
||||||
|
Replace,
|
||||||
|
};
|
||||||
|
class Step : public TWidget, public RPCSender {
|
||||||
|
public:
|
||||||
|
Step(QWidget *parent, Data *data, bool hasCover = false);
|
||||||
|
|
||||||
|
virtual void setInnerFocus() {
|
||||||
|
setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGoCallback(base::lambda<void(Step *step, Direction direction)> &&callback);
|
||||||
|
void setShowResetCallback(base::lambda<void()> &&callback);
|
||||||
|
|
||||||
|
void prepareShowAnimated(Step *after);
|
||||||
|
void showAnimated(Direction direction);
|
||||||
|
void showFast();
|
||||||
|
bool animating() const;
|
||||||
|
|
||||||
|
bool hasCover() const;
|
||||||
|
virtual bool hasBack() const;
|
||||||
|
virtual void activate();
|
||||||
|
virtual void cancelled();
|
||||||
|
virtual void finished();
|
||||||
|
|
||||||
|
virtual void submit() = 0;
|
||||||
|
virtual QString nextButtonText() const;
|
||||||
|
|
||||||
|
int contentLeft() const;
|
||||||
|
int contentTop() const;
|
||||||
|
|
||||||
|
void setErrorCentered(bool centered);
|
||||||
|
void setErrorBelowLink(bool below);
|
||||||
|
void showError(const QString &text);
|
||||||
|
void hideError() {
|
||||||
|
showError(QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
void setTitleText(QString richText);
|
||||||
|
void setDescriptionText(QString richText);
|
||||||
|
bool paintAnimated(Painter &p, QRect clip);
|
||||||
|
|
||||||
|
void fillSentCodeData(const MTPauth_SentCodeType &type);
|
||||||
|
|
||||||
|
void showDescription();
|
||||||
|
void hideDescription();
|
||||||
|
|
||||||
|
Data *getData() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
void finish(const MTPUser &user, QImage photo = QImage());
|
||||||
|
|
||||||
|
void goBack() {
|
||||||
|
if (_goCallback) _goCallback(nullptr, Direction::Back);
|
||||||
|
}
|
||||||
|
void goNext(Step *step) {
|
||||||
|
if (_goCallback) _goCallback(step, Direction::Forward);
|
||||||
|
}
|
||||||
|
void goReplace(Step *step) {
|
||||||
|
if (_goCallback) _goCallback(step, Direction::Replace);
|
||||||
|
}
|
||||||
|
void showResetButton() {
|
||||||
|
if (_showResetCallback) _showResetCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CoverAnimation {
|
||||||
|
std_::unique_ptr<Ui::CrossFadeAnimation> title;
|
||||||
|
std_::unique_ptr<Ui::CrossFadeAnimation> description;
|
||||||
|
|
||||||
|
// From content top till the next button top.
|
||||||
|
QPixmap contentSnapshotWas;
|
||||||
|
QPixmap contentSnapshotNow;
|
||||||
|
};
|
||||||
|
void updateLabelsPosition();
|
||||||
|
void paintContentSnapshot(Painter &p, const QPixmap &snapshot, float64 alpha, float64 howMuchHidden);
|
||||||
|
|
||||||
|
CoverAnimation prepareCoverAnimation(Step *step);
|
||||||
|
QPixmap prepareContentSnapshot();
|
||||||
|
QPixmap prepareSlideAnimation();
|
||||||
|
void showFinished();
|
||||||
|
|
||||||
|
void prepareCoverMask();
|
||||||
|
void paintCover(Painter &p, int top);
|
||||||
|
|
||||||
|
Data *_data = nullptr;
|
||||||
|
bool _hasCover = false;
|
||||||
|
base::lambda<void(Step *step, Direction direction)> _goCallback;
|
||||||
|
base::lambda<void()> _showResetCallback;
|
||||||
|
|
||||||
|
ChildWidget<Ui::FlatLabel> _title;
|
||||||
|
ChildWidget<Ui::WidgetFadeWrap<Ui::FlatLabel>> _description;
|
||||||
|
|
||||||
|
bool _errorCentered = false;
|
||||||
|
bool _errorBelowLink = false;
|
||||||
|
QString _errorText;
|
||||||
|
ChildWidget<Ui::WidgetFadeWrap<Ui::FlatLabel>> _error = { nullptr };
|
||||||
|
|
||||||
|
FloatAnimation _a_show;
|
||||||
|
CoverAnimation _coverAnimation;
|
||||||
|
std_::unique_ptr<Ui::SlideAnimation> _slideAnimation;
|
||||||
|
QPixmap _coverMask;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void step_show(float64 ms, bool timer);
|
||||||
|
|
||||||
|
void changeLanguage(int32 languageId);
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
QPixmap grabStep(int skip = 0);
|
Data *getData() {
|
||||||
|
return &_data;
|
||||||
|
}
|
||||||
|
|
||||||
int _langChangeTo = 0;
|
void fixOrder();
|
||||||
|
void showControls();
|
||||||
|
void hideControls();
|
||||||
|
void moveControls();
|
||||||
|
QRect calculateStepRect() const;
|
||||||
|
|
||||||
Animation _a_stage;
|
void showResetButton();
|
||||||
QPixmap _cacheHide, _cacheShow;
|
void resetAccount();
|
||||||
int _cacheHideIndex = 0;
|
void resetAccountSure();
|
||||||
int _cacheShowIndex = 0;
|
void resetDone(const MTPBool &result);
|
||||||
anim::ivalue a_coordHide, a_coordShow;
|
bool resetFail(const RPCError &error);
|
||||||
anim::fvalue a_opacityHide, a_opacityShow;
|
|
||||||
|
|
||||||
Animation _a_show;
|
Animation _a_show;
|
||||||
QPixmap _cacheUnder, _cacheOver;
|
QPixmap _cacheUnder, _cacheOver;
|
||||||
anim::ivalue a_coordUnder, a_coordOver;
|
anim::ivalue a_coordUnder, a_coordOver;
|
||||||
anim::fvalue a_shadow;
|
anim::fvalue a_shadow;
|
||||||
|
|
||||||
QVector<IntroStep*> _stepHistory;
|
QVector<Step*> _stepHistory;
|
||||||
IntroStep *step(int skip = 0) {
|
Step *getStep(int skip = 0) {
|
||||||
t_assert(_stepHistory.size() + skip > 0);
|
t_assert(_stepHistory.size() + skip > 0);
|
||||||
return _stepHistory.at(_stepHistory.size() - skip - 1);
|
return _stepHistory.at(_stepHistory.size() - skip - 1);
|
||||||
}
|
}
|
||||||
enum MoveType {
|
void historyMove(Direction direction);
|
||||||
MoveBack,
|
void moveToStep(Step *step, Direction direction);
|
||||||
MoveForward,
|
void appendStep(Step *step);
|
||||||
MoveReplace,
|
|
||||||
};
|
|
||||||
void historyMove(MoveType type);
|
|
||||||
void pushStep(IntroStep *step, MoveType type);
|
|
||||||
|
|
||||||
void gotNearestDC(const MTPNearestDc &dc);
|
void gotNearestDC(const MTPNearestDc &dc);
|
||||||
|
|
||||||
QString _countryForReg;
|
Data _data;
|
||||||
|
|
||||||
QString _phone, _phone_hash;
|
FloatAnimation _coverShownAnimation;
|
||||||
CallStatus _callStatus = { CallDisabled, 0 };
|
int _nextTopFrom = 0;
|
||||||
bool _registered = false;
|
int _controlsTopFrom = 0;
|
||||||
|
|
||||||
QString _code;
|
|
||||||
|
|
||||||
QByteArray _pwdSalt;
|
|
||||||
bool _hasRecovery = false;
|
|
||||||
bool _codeByTelegram = false;
|
|
||||||
QString _pwdHint;
|
|
||||||
|
|
||||||
QString _firstname, _lastname;
|
|
||||||
|
|
||||||
ChildWidget<Ui::WidgetFadeWrap<Ui::IconButton>> _back;
|
ChildWidget<Ui::WidgetFadeWrap<Ui::IconButton>> _back;
|
||||||
ChildWidget<Ui::RoundButton> _settings;
|
ChildWidget<Ui::WidgetFadeWrap<Ui::RoundButton>> _update = { nullptr };
|
||||||
ChildWidget<Ui::RoundButton> _update = { nullptr };
|
ChildWidget<Ui::WidgetFadeWrap<Ui::RoundButton>> _settings;
|
||||||
|
|
||||||
float64 _backFrom = 0.;
|
ChildWidget<Ui::RoundButton> _next;
|
||||||
float64 _backTo = 0.;
|
ChildWidget<Ui::WidgetFadeWrap<Ui::LinkButton>> _changeLanguage = { nullptr };
|
||||||
|
ChildWidget<Ui::WidgetFadeWrap<Ui::RoundButton>> _resetAccount = { nullptr };
|
||||||
|
|
||||||
|
mtpRequestId _resetRequest = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IntroStep : public TWidget, public RPCSender {
|
} // namespace Intro
|
||||||
public:
|
|
||||||
IntroStep(IntroWidget *parent) : TWidget(parent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool hasBack() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual void activate() {
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
virtual void cancelled() {
|
|
||||||
}
|
|
||||||
virtual void finished() {
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
virtual void onSubmit() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
IntroWidget *intro() {
|
|
||||||
IntroWidget *result = qobject_cast<IntroWidget*>(parentWidget());
|
|
||||||
t_assert(result != nullptr);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
|
@ -173,7 +173,6 @@ class Manager : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Manager();
|
Manager();
|
||||||
|
|
||||||
void writeMap(bool fast);
|
void writeMap(bool fast);
|
||||||
|
@ -182,13 +181,11 @@ public:
|
||||||
void writingLocations();
|
void writingLocations();
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void mapWriteTimeout();
|
void mapWriteTimeout();
|
||||||
void locationsWriteTimeout();
|
void locationsWriteTimeout();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QTimer _mapWriteTimer;
|
QTimer _mapWriteTimer;
|
||||||
QTimer _locationsWriteTimer;
|
QTimer _locationsWriteTimer;
|
||||||
|
|
||||||
|
|
|
@ -2269,7 +2269,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
|
||||||
_topBar->hide();
|
_topBar->hide();
|
||||||
_history->hide();
|
_history->hide();
|
||||||
if (!_a_show.animating()) {
|
if (!_a_show.animating()) {
|
||||||
if (!animationParams.oldContentCache.isNull()) {
|
if (!animationParams.oldContentCache.isNull() && !App::passcoded()) {
|
||||||
_dialogs->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams);
|
_dialogs->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams);
|
||||||
} else {
|
} else {
|
||||||
_dialogs->showFast();
|
_dialogs->showFast();
|
||||||
|
|
|
@ -213,11 +213,7 @@ void MainWindow::clearWidgets() {
|
||||||
Ui::hideLayer(true);
|
Ui::hideLayer(true);
|
||||||
_passcode.destroyDelayed();
|
_passcode.destroyDelayed();
|
||||||
_main.destroy();
|
_main.destroy();
|
||||||
if (_intro) {
|
_intro.destroy();
|
||||||
_intro->stop_show();
|
|
||||||
_intro->rpcClear();
|
|
||||||
_intro.destroyDelayed();
|
|
||||||
}
|
|
||||||
if (_mediaView) {
|
if (_mediaView) {
|
||||||
hideMediaview();
|
hideMediaview();
|
||||||
_mediaView->rpcClear();
|
_mediaView->rpcClear();
|
||||||
|
@ -229,10 +225,10 @@ QPixmap MainWindow::grabInner() {
|
||||||
QPixmap result;
|
QPixmap result;
|
||||||
if (_intro) {
|
if (_intro) {
|
||||||
result = myGrab(_intro);
|
result = myGrab(_intro);
|
||||||
} else if (_main) {
|
|
||||||
result = myGrab(_main);
|
|
||||||
} else if (_passcode) {
|
} else if (_passcode) {
|
||||||
result = myGrab(_passcode);
|
result = myGrab(_passcode);
|
||||||
|
} else if (_main) {
|
||||||
|
result = myGrab(_main);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -240,10 +236,9 @@ QPixmap MainWindow::grabInner() {
|
||||||
void MainWindow::clearPasscode() {
|
void MainWindow::clearPasscode() {
|
||||||
if (!_passcode) return;
|
if (!_passcode) return;
|
||||||
|
|
||||||
QPixmap bg = grabInner();
|
auto bg = grabInner();
|
||||||
|
|
||||||
_passcode->stop_show();
|
_passcode.destroy();
|
||||||
_passcode.destroyDelayed();
|
|
||||||
if (_intro) {
|
if (_intro) {
|
||||||
_intro->animShow(bg, true);
|
_intro->animShow(bg, true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -260,10 +255,6 @@ void MainWindow::clearPasscode() {
|
||||||
void MainWindow::setupPasscode() {
|
void MainWindow::setupPasscode() {
|
||||||
auto animated = (_main || _intro);
|
auto animated = (_main || _intro);
|
||||||
auto bg = animated ? grabInner() : QPixmap();
|
auto bg = animated ? grabInner() : QPixmap();
|
||||||
if (_passcode) {
|
|
||||||
_passcode->stop_show();
|
|
||||||
_passcode.destroyDelayed();
|
|
||||||
}
|
|
||||||
_passcode.create(bodyWidget());
|
_passcode.create(bodyWidget());
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
|
|
||||||
|
@ -446,10 +437,6 @@ void MainWindow::updateConnectingStatus() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IntroWidget *MainWindow::introWidget() {
|
|
||||||
return _intro;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainWidget *MainWindow::mainWidget() {
|
MainWidget *MainWindow::mainWidget() {
|
||||||
return _main;
|
return _main;
|
||||||
}
|
}
|
||||||
|
@ -650,6 +637,8 @@ void MainWindow::setInnerFocus() {
|
||||||
_settings->setInnerFocus();
|
_settings->setInnerFocus();
|
||||||
} else if (_main) {
|
} else if (_main) {
|
||||||
_main->setInnerFocus();
|
_main->setInnerFocus();
|
||||||
|
} else if (_intro) {
|
||||||
|
_intro->setInnerFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +823,7 @@ void MainWindow::activate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::noIntro(IntroWidget *was) {
|
void MainWindow::noIntro(Intro::Widget *was) {
|
||||||
if (was == _intro) {
|
if (was == _intro) {
|
||||||
_intro = nullptr;
|
_intro = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
class MediaView;
|
class MediaView;
|
||||||
class PasscodeWidget;
|
class PasscodeWidget;
|
||||||
class IntroWidget;
|
|
||||||
class MainWidget;
|
class MainWidget;
|
||||||
class LayerStackWidget;
|
class LayerStackWidget;
|
||||||
class LayerWidget;
|
class LayerWidget;
|
||||||
|
|
||||||
|
namespace Intro {
|
||||||
|
class Widget;
|
||||||
|
} // namespace Intro
|
||||||
|
|
||||||
namespace Local {
|
namespace Local {
|
||||||
class ClearManager;
|
class ClearManager;
|
||||||
} // namespace Local
|
} // namespace Local
|
||||||
|
@ -99,7 +102,6 @@ public:
|
||||||
|
|
||||||
void mtpStateChanged(int32 dc, int32 state);
|
void mtpStateChanged(int32 dc, int32 state);
|
||||||
|
|
||||||
IntroWidget *introWidget();
|
|
||||||
MainWidget *mainWidget();
|
MainWidget *mainWidget();
|
||||||
PasscodeWidget *passcodeWidget();
|
PasscodeWidget *passcodeWidget();
|
||||||
|
|
||||||
|
@ -112,7 +114,7 @@ public:
|
||||||
|
|
||||||
void activate();
|
void activate();
|
||||||
|
|
||||||
void noIntro(IntroWidget *was);
|
void noIntro(Intro::Widget *was);
|
||||||
void noMain(MainWidget *was);
|
void noMain(MainWidget *was);
|
||||||
void noLayerStack(LayerStackWidget *was);
|
void noLayerStack(LayerStackWidget *was);
|
||||||
void layerFinishedHide(LayerStackWidget *was);
|
void layerFinishedHide(LayerStackWidget *was);
|
||||||
|
@ -239,7 +241,7 @@ private:
|
||||||
mtpRequestId _serviceHistoryRequest = 0;
|
mtpRequestId _serviceHistoryRequest = 0;
|
||||||
|
|
||||||
ChildWidget<PasscodeWidget> _passcode = { nullptr };
|
ChildWidget<PasscodeWidget> _passcode = { nullptr };
|
||||||
ChildWidget<IntroWidget> _intro = { nullptr };
|
ChildWidget<Intro::Widget> _intro = { nullptr };
|
||||||
ChildWidget<MainWidget> _main = { nullptr };
|
ChildWidget<MainWidget> _main = { nullptr };
|
||||||
ChildWidget<Settings::Widget> _settings = { nullptr };
|
ChildWidget<Settings::Widget> _settings = { nullptr };
|
||||||
ChildWidget<LayerStackWidget> _layerBg = { nullptr };
|
ChildWidget<LayerStackWidget> _layerBg = { nullptr };
|
||||||
|
|
|
@ -30,7 +30,6 @@ class HTTPConnection : public AbstractConnection {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPConnection(QThread *thread);
|
HTTPConnection(QThread *thread);
|
||||||
|
|
||||||
void sendData(mtpBuffer &buffer) override;
|
void sendData(mtpBuffer &buffer) override;
|
||||||
|
@ -46,15 +45,13 @@ public:
|
||||||
|
|
||||||
QString transport() const override;
|
QString transport() const override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void requestFinished(QNetworkReply *reply);
|
void requestFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
static mtpBuffer handleResponse(QNetworkReply *reply);
|
static mtpBuffer handleResponse(QNetworkReply *reply);
|
||||||
static bool handleError(QNetworkReply *reply); // returnes "maybe bad key"
|
static bool handleError(QNetworkReply *reply); // returnes "maybe bad key"
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
WaitingHttp = 0,
|
WaitingHttp = 0,
|
||||||
UsingHttp,
|
UsingHttp,
|
||||||
|
|
|
@ -754,7 +754,7 @@ void ping() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void cancel(mtpRequestId requestId) {
|
void cancel(mtpRequestId requestId) {
|
||||||
if (!_started) return;
|
if (!_started || !requestId) return;
|
||||||
|
|
||||||
mtpMsgId msgId = 0;
|
mtpMsgId msgId = 0;
|
||||||
requestsDelays.remove(requestId);
|
requestsDelays.remove(requestId);
|
||||||
|
|
|
@ -29,14 +29,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "window/slide_animation.h"
|
#include "window/window_slide_animation.h"
|
||||||
|
|
||||||
PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
|
PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
|
||||||
, _a_show(animation(this, &PasscodeWidget::step_show))
|
, _a_show(animation(this, &PasscodeWidget::step_show))
|
||||||
, _passcode(this, st::passcodeInput)
|
, _passcode(this, st::passcodeInput)
|
||||||
, _submit(this, lang(lng_passcode_submit), st::passcodeSubmit)
|
, _submit(this, lang(lng_passcode_submit), st::passcodeSubmit)
|
||||||
, _logout(this, lang(lng_passcode_logout)) {
|
, _logout(this, lang(lng_passcode_logout)) {
|
||||||
_passcode->setEchoMode(QLineEdit::Password);
|
|
||||||
connect(_passcode, SIGNAL(changed()), this, SLOT(onChanged()));
|
connect(_passcode, SIGNAL(changed()), this, SLOT(onChanged()));
|
||||||
connect(_passcode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
connect(_passcode, SIGNAL(submitted(bool)), this, SLOT(onSubmit()));
|
||||||
|
|
||||||
|
@ -49,12 +48,12 @@ PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
|
||||||
|
|
||||||
void PasscodeWidget::onSubmit() {
|
void PasscodeWidget::onSubmit() {
|
||||||
if (_passcode->text().isEmpty()) {
|
if (_passcode->text().isEmpty()) {
|
||||||
_passcode->notaBene();
|
_passcode->showError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!passcodeCanTry()) {
|
if (!passcodeCanTry()) {
|
||||||
_error = lang(lng_flood_error);
|
_error = lang(lng_flood_error);
|
||||||
_passcode->notaBene();
|
_passcode->showError();
|
||||||
update();
|
update();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +61,8 @@ void PasscodeWidget::onSubmit() {
|
||||||
if (App::main()) {
|
if (App::main()) {
|
||||||
if (Local::checkPasscode(_passcode->text().toUtf8())) {
|
if (Local::checkPasscode(_passcode->text().toUtf8())) {
|
||||||
cSetPasscodeBadTries(0);
|
cSetPasscodeBadTries(0);
|
||||||
App::wnd()->clearPasscode();
|
App::wnd()->clearPasscode(); // Destroys this widget.
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
|
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
|
||||||
cSetPasscodeLastTry(getms(true));
|
cSetPasscodeLastTry(getms(true));
|
||||||
|
@ -93,7 +93,7 @@ void PasscodeWidget::onSubmit() {
|
||||||
void PasscodeWidget::onError() {
|
void PasscodeWidget::onError() {
|
||||||
_error = lang(lng_passcode_wrong);
|
_error = lang(lng_passcode_wrong);
|
||||||
_passcode->selectAll();
|
_passcode->selectAll();
|
||||||
_passcode->notaBene();
|
_passcode->showError();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class FlatInput;
|
class PasswordInput;
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
@ -56,7 +56,7 @@ private:
|
||||||
anim::ivalue a_coordUnder, a_coordOver;
|
anim::ivalue a_coordUnder, a_coordOver;
|
||||||
anim::fvalue a_shadow;
|
anim::fvalue a_shadow;
|
||||||
|
|
||||||
ChildWidget<Ui::FlatInput> _passcode;
|
ChildWidget<Ui::PasswordInput> _passcode;
|
||||||
ChildWidget<Ui::RoundButton> _submit;
|
ChildWidget<Ui::RoundButton> _submit;
|
||||||
ChildWidget<Ui::LinkButton> _logout;
|
ChildWidget<Ui::LinkButton> _logout;
|
||||||
QString _error;
|
QString _error;
|
||||||
|
|
|
@ -144,7 +144,7 @@ void CloudPasswordState::getPasswordDone(const MTPaccount_Password &result) {
|
||||||
void CloudPasswordState::paintEvent(QPaintEvent *e) {
|
void CloudPasswordState::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
auto text = st::linkFont->elided(_waitingConfirm, width() - _turnOff->width());
|
auto text = st::boxTextFont->elided(_waitingConfirm, width() - _turnOff->width() - st::boxTextFont->spacew);
|
||||||
if (!text.isEmpty()) {
|
if (!text.isEmpty()) {
|
||||||
p.setPen(st::windowFg);
|
p.setPen(st::windowFg);
|
||||||
p.setFont(st::boxTextFont);
|
p.setFont(st::boxTextFont);
|
||||||
|
|
|
@ -149,7 +149,6 @@ emojiPanShowDuration: 200;
|
||||||
emojiPanDuration: 200;
|
emojiPanDuration: 200;
|
||||||
emojiPanHover: windowBgOver;
|
emojiPanHover: windowBgOver;
|
||||||
emojiPanSlideDuration: 200;
|
emojiPanSlideDuration: 200;
|
||||||
emojiPanSlideDelta: 0; // between hide start and show start
|
|
||||||
|
|
||||||
emojiPanHeader: 42px;
|
emojiPanHeader: 42px;
|
||||||
emojiPanHeaderFont: semiboldFont;
|
emojiPanHeaderFont: semiboldFont;
|
||||||
|
|
|
@ -73,8 +73,9 @@ void AbstractButton::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
_modifiers = e->modifiers();
|
_modifiers = e->modifiers();
|
||||||
if (_clickedCallback) {
|
if (_clickedCallback) {
|
||||||
_clickedCallback();
|
_clickedCallback();
|
||||||
|
} else {
|
||||||
|
emit clicked();
|
||||||
}
|
}
|
||||||
emit clicked();
|
|
||||||
} else {
|
} else {
|
||||||
leaveEvent(e);
|
leaveEvent(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,6 +269,14 @@ FORCE_INLINE Shifted shifted(QColor color) {
|
||||||
return reshifted(components * alpha);
|
return reshifted(components * alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE uint32 getPremultiplied(QColor color) {
|
||||||
|
// Make it premultiplied.
|
||||||
|
auto alpha = static_cast<uint32>((color.alpha() & 0xFF) + 1);
|
||||||
|
auto components = Shifted(static_cast<uint32>(color.blue() & 0xFF) | (static_cast<uint32>(color.green() & 0xFF) << 16),
|
||||||
|
static_cast<uint32>(color.red() & 0xFF) | (static_cast<uint32>(255) << 16));
|
||||||
|
return unshifted(components * alpha);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE uint32 getAlpha(Shifted components) {
|
FORCE_INLINE uint32 getAlpha(Shifted components) {
|
||||||
return (components.high & 0x00FF0000U) >> 16;
|
return (components.high & 0x00FF0000U) >> 16;
|
||||||
}
|
}
|
||||||
|
@ -344,6 +352,16 @@ FORCE_INLINE Shifted shifted(QColor color) {
|
||||||
return reshifted(components * alpha);
|
return reshifted(components * alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE uint32 getPremultiplied(QColor color) {
|
||||||
|
// Make it premultiplied.
|
||||||
|
auto alpha = static_cast<uint64>((color.alpha() & 0xFF) + 1);
|
||||||
|
auto components = static_cast<uint64>(color.blue() & 0xFF)
|
||||||
|
| (static_cast<uint64>(color.green() & 0xFF) << 16)
|
||||||
|
| (static_cast<uint64>(color.red() & 0xFF) << 32)
|
||||||
|
| (static_cast<uint64>(255) << 48);
|
||||||
|
return unshifted(components * alpha);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE uint32 getAlpha(Shifted components) {
|
FORCE_INLINE uint32 getAlpha(Shifted components) {
|
||||||
return (components.value & 0x00FF000000000000ULL) >> 48;
|
return (components.value & 0x00FF000000000000ULL) >> 48;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,8 @@ void PeerAvatarButton::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NewAvatarButton::NewAvatarButton(QWidget *parent, int size) : RippleButton(parent, st::defaultActiveButton.ripple) {
|
NewAvatarButton::NewAvatarButton(QWidget *parent, int size, QPoint position) : RippleButton(parent, st::defaultActiveButton.ripple)
|
||||||
|
, _position(position) {
|
||||||
resize(size, size);
|
resize(size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ void NewAvatarButton::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
paintRipple(p, 0, 0, getms());
|
paintRipple(p, 0, 0, getms());
|
||||||
|
|
||||||
st::newGroupPhotoIcon.paint(p, st::newGroupPhotoIconPosition, width());
|
st::newGroupPhotoIcon.paint(p, _position, width());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewAvatarButton::setImage(const QImage &image) {
|
void NewAvatarButton::setImage(const QImage &image) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ private:
|
||||||
|
|
||||||
class NewAvatarButton : public RippleButton {
|
class NewAvatarButton : public RippleButton {
|
||||||
public:
|
public:
|
||||||
NewAvatarButton(QWidget *parent, int size);
|
NewAvatarButton(QWidget *parent, int size, QPoint position);
|
||||||
|
|
||||||
void setImage(const QImage &image);
|
void setImage(const QImage &image);
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPixmap _image;
|
QPixmap _image;
|
||||||
|
QPoint _position;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/contactsbox.h"
|
#include "boxes/contactsbox.h"
|
||||||
#include "countries.h"
|
#include "countries.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_intro.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -89,50 +90,33 @@ QString findValidCode(QString fullCode) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
CountryInput::CountryInput(QWidget *parent, const style::countryInput &st) : QWidget(parent), _st(st), _active(false), _text(lang(lng_country_code)) {
|
CountryInput::CountryInput(QWidget *parent, const style::InputField &st) : TWidget(parent)
|
||||||
|
, _st(st)
|
||||||
|
, _text(lang(lng_country_code)) {
|
||||||
initCountries();
|
initCountries();
|
||||||
|
resize(_st.width, _st.height);
|
||||||
resize(_st.width, _st.height + _st.ptrSize.height());
|
|
||||||
QImage trImage(_st.ptrSize.width(), _st.ptrSize.height(), QImage::Format_ARGB32_Premultiplied);
|
|
||||||
{
|
|
||||||
static const QPoint trPoints[3] = {
|
|
||||||
QPoint(0, 0),
|
|
||||||
QPoint(_st.ptrSize.width(), 0),
|
|
||||||
QPoint(qCeil(trImage.width() / 2.), trImage.height())
|
|
||||||
};
|
|
||||||
QPainter p(&trImage);
|
|
||||||
p.setRenderHint(QPainter::Antialiasing);
|
|
||||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
|
||||||
p.fillRect(0, 0, trImage.width(), trImage.height(), Qt::transparent);
|
|
||||||
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(_st.bgColor);
|
|
||||||
p.drawPolygon(trPoints, 3);
|
|
||||||
}
|
|
||||||
_arrow = App::pixmapFromImageInPlace(std_::move(trImage));
|
|
||||||
_inner = QRect(0, 0, _st.width, _st.height);
|
|
||||||
_arrowRect = QRect((st::introCountryCode.width - _arrow.width() - 1) / 2, _st.height, _arrow.width(), _arrow.height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountryInput::paintEvent(QPaintEvent *e) {
|
void CountryInput::paintEvent(QPaintEvent *e) {
|
||||||
QPainter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
QRect r(rect().intersected(e->rect()));
|
||||||
p.setBrush(_st.bgColor);
|
if (_st.textBg->c.alphaF() > 0.) {
|
||||||
p.setPen(Qt::NoPen);
|
p.fillRect(r, _st.textBg);
|
||||||
p.drawRoundedRect(_inner, st::buttonRadius, st::buttonRadius);
|
}
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
if (_st.border) {
|
||||||
|
p.fillRect(0, height() - _st.border, width(), _st.border, _st.borderFg->b);
|
||||||
|
}
|
||||||
|
|
||||||
p.drawPixmap(_arrowRect.x(), _arrowRect.top(), _arrow);
|
st::introCountryIcon.paint(p, width() - st::introCountryIcon.width() - st::introCountryIconPosition.x(), st::introCountryIconPosition.y(), width());
|
||||||
|
|
||||||
p.setFont(_st.font);
|
p.setFont(_st.font);
|
||||||
p.setPen(st::windowFg);
|
p.setPen(_st.textFg);
|
||||||
|
p.drawText(rect().marginsRemoved(_st.textMargins), _text, _st.textAlign);
|
||||||
p.drawText(rect().marginsRemoved(_st.textMrg), _text, QTextOption(_st.align));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountryInput::mouseMoveEvent(QMouseEvent *e) {
|
void CountryInput::mouseMoveEvent(QMouseEvent *e) {
|
||||||
bool newActive = _inner.contains(e->pos()) || _arrowRect.contains(e->pos());
|
bool newActive = rect().contains(e->pos());
|
||||||
if (_active != newActive) {
|
if (_active != newActive) {
|
||||||
_active = newActive;
|
_active = newActive;
|
||||||
setCursor(_active ? style::cur_pointer : style::cur_default);
|
setCursor(_active ? style::cur_pointer : style::cur_default);
|
||||||
|
@ -192,7 +176,7 @@ bool CountryInput::onChooseCountry(const QString &iso) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountryInput::setText(const QString &newText) {
|
void CountryInput::setText(const QString &newText) {
|
||||||
_text = _st.font->elided(newText, width() - _st.textMrg.left() - _st.textMrg.right());
|
_text = _st.font->elided(newText, width() - _st.textMargins.left() - _st.textMargins.right());
|
||||||
}
|
}
|
||||||
|
|
||||||
CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxWidth)
|
CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxWidth)
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "ui/effects/rect_shadow.h"
|
#include "ui/effects/rect_shadow.h"
|
||||||
#include "boxes/abstractbox.h"
|
#include "boxes/abstractbox.h"
|
||||||
#include "styles/style_intro.h"
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
QString findValidCode(QString fullCode);
|
QString findValidCode(QString fullCode);
|
||||||
|
|
||||||
|
@ -30,11 +30,11 @@ namespace Ui {
|
||||||
class MultiSelect;
|
class MultiSelect;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class CountryInput : public QWidget {
|
class CountryInput : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CountryInput(QWidget *parent, const style::countryInput &st);
|
CountryInput(QWidget *parent, const style::InputField &st);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onChooseCode(const QString &code);
|
void onChooseCode(const QString &code);
|
||||||
|
@ -53,10 +53,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
void setText(const QString &newText);
|
void setText(const QString &newText);
|
||||||
|
|
||||||
QPixmap _arrow;
|
const style::InputField &_st;
|
||||||
QRect _inner, _arrowRect;
|
bool _active = false;
|
||||||
const style::countryInput &_st;
|
|
||||||
bool _active;
|
|
||||||
QString _text;
|
QString _text;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/effects/slide_animation.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
void SlideAnimation::setSnapshots(QPixmap leftSnapshot, QPixmap rightSnapshot) {
|
||||||
|
_leftSnapshot = std_::move(leftSnapshot);
|
||||||
|
_rightSnapshot = std_::move(rightSnapshot);
|
||||||
|
t_assert(!_leftSnapshot.isNull());
|
||||||
|
t_assert(!_rightSnapshot.isNull());
|
||||||
|
_leftSnapshot.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
_rightSnapshot.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlideAnimation::paintFrame(Painter &p, int x, int y, int outerWidth, uint64 ms) {
|
||||||
|
auto dt = _animation.current(ms, 1.);
|
||||||
|
if (!animating()) return;
|
||||||
|
|
||||||
|
auto easeOut = anim::easeOutCirc(1., dt);
|
||||||
|
auto easeIn = anim::easeInCirc(1., dt);
|
||||||
|
auto arrivingAlpha = easeIn;
|
||||||
|
auto departingAlpha = 1. - easeOut;
|
||||||
|
auto leftCoord = (_slideLeft ? anim::interpolate(-_leftSnapshotWidth, 0, easeOut) : anim::interpolate(0, -_leftSnapshotWidth, easeIn));
|
||||||
|
auto leftAlpha = (_slideLeft ? arrivingAlpha : departingAlpha);
|
||||||
|
auto rightCoord = (_slideLeft ? anim::interpolate(0, _rightSnapshotWidth, easeIn) : anim::interpolate(_rightSnapshotWidth, 0, easeOut));
|
||||||
|
auto rightAlpha = (_slideLeft ? departingAlpha : arrivingAlpha);
|
||||||
|
|
||||||
|
if (_overflowHidden) {
|
||||||
|
auto leftWidth = (_leftSnapshotWidth + leftCoord);
|
||||||
|
if (leftWidth > 0) {
|
||||||
|
p.setOpacity(leftAlpha);
|
||||||
|
p.drawPixmap(x, y, leftWidth, _leftSnapshotHeight, _leftSnapshot, (_leftSnapshot.width() - leftWidth * cIntRetinaFactor()), 0, leftWidth * cIntRetinaFactor(), _leftSnapshot.height());
|
||||||
|
}
|
||||||
|
auto rightWidth = _rightSnapshotWidth - rightCoord;
|
||||||
|
if (rightWidth > 0) {
|
||||||
|
p.setOpacity(rightAlpha);
|
||||||
|
p.drawPixmap(x + rightCoord, y, _rightSnapshot, 0, 0, rightWidth * cIntRetinaFactor(), _rightSnapshot.height());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.setOpacity(leftAlpha);
|
||||||
|
p.drawPixmap(x + leftCoord, y, _leftSnapshot);
|
||||||
|
p.setOpacity(rightAlpha);
|
||||||
|
p.drawPixmap(x + rightCoord, y, _rightSnapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class SlideAnimation {
|
||||||
|
public:
|
||||||
|
void setSnapshots(QPixmap leftSnapshot, QPixmap rightSnapshot);
|
||||||
|
|
||||||
|
void setOverflowHidden(bool hidden) {
|
||||||
|
_overflowHidden = hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Lambda>
|
||||||
|
void start(bool slideLeft, Lambda &&updateCallback, float64 duration);
|
||||||
|
|
||||||
|
void paintFrame(Painter &p, int x, int y, int outerWidth, uint64 ms);
|
||||||
|
|
||||||
|
bool animating() const {
|
||||||
|
return _animation.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FloatAnimation _animation;
|
||||||
|
QPixmap _leftSnapshot;
|
||||||
|
QPixmap _rightSnapshot;
|
||||||
|
bool _slideLeft = false;
|
||||||
|
bool _overflowHidden = true;
|
||||||
|
int _leftSnapshotWidth = 0;
|
||||||
|
int _leftSnapshotHeight = 0;
|
||||||
|
int _rightSnapshotWidth = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Lambda>
|
||||||
|
void SlideAnimation::start(bool slideLeft, Lambda &&updateCallback, float64 duration) {
|
||||||
|
_slideLeft = slideLeft;
|
||||||
|
if (_slideLeft) {
|
||||||
|
std_::swap_moveable(_leftSnapshot, _rightSnapshot);
|
||||||
|
}
|
||||||
|
_leftSnapshotWidth = _leftSnapshot.width() / cIntRetinaFactor();
|
||||||
|
_leftSnapshotHeight = _leftSnapshot.height() / cIntRetinaFactor();
|
||||||
|
_rightSnapshotWidth = _rightSnapshot.width() / cIntRetinaFactor();
|
||||||
|
_animation.start(std_::forward<Lambda>(updateCallback), 0., 1., duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -90,6 +90,7 @@ void FadeAnimation::fadeOut(int duration) {
|
||||||
|
|
||||||
void FadeAnimation::startAnimation(int duration) {
|
void FadeAnimation::startAnimation(int duration) {
|
||||||
if (_cache.isNull()) {
|
if (_cache.isNull()) {
|
||||||
|
_widget->showChildren();
|
||||||
_cache = myGrab(_widget);
|
_cache = myGrab(_widget);
|
||||||
_widget->hideChildren();
|
_widget->hideChildren();
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ QPixmap myGrab(TWidget *target, QRect rect) {
|
||||||
myEnsureResized(target);
|
myEnsureResized(target);
|
||||||
if (rect.isNull()) rect = target->rect();
|
if (rect.isNull()) rect = target->rect();
|
||||||
|
|
||||||
QPixmap result(rect.size() * cRetinaFactor());
|
auto result = QPixmap(rect.size() * cRetinaFactor());
|
||||||
result.setDevicePixelRatio(cRetinaFactor());
|
result.setDevicePixelRatio(cRetinaFactor());
|
||||||
result.fill(Qt::transparent);
|
result.fill(Qt::transparent);
|
||||||
|
|
||||||
|
@ -75,7 +75,24 @@ QPixmap myGrab(TWidget *target, QRect rect) {
|
||||||
target->render(&result, QPoint(0, 0), rect, QWidget::DrawChildren | QWidget::IgnoreMask);
|
target->render(&result, QPoint(0, 0), rect, QWidget::DrawChildren | QWidget::IgnoreMask);
|
||||||
target->grabFinish();
|
target->grabFinish();
|
||||||
|
|
||||||
return result;
|
return std_::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage myGrabImage(TWidget *target, QRect rect) {
|
||||||
|
myEnsureResized(target);
|
||||||
|
if (rect.isNull()) rect = target->rect();
|
||||||
|
|
||||||
|
auto result = QImage(rect.size() * cRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
if (!target->testAttribute(Qt::WA_OpaquePaintEvent)) {
|
||||||
|
result.fill(Qt::transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
target->grabStart();
|
||||||
|
target->render(&result, QPoint(0, 0), rect, QWidget::DrawChildren | QWidget::IgnoreMask);
|
||||||
|
target->grabFinish();
|
||||||
|
|
||||||
|
return std_::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) {
|
void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint) {
|
||||||
|
|
|
@ -207,6 +207,7 @@ protected:
|
||||||
|
|
||||||
void myEnsureResized(QWidget *target);
|
void myEnsureResized(QWidget *target);
|
||||||
QPixmap myGrab(TWidget *target, QRect rect = QRect());
|
QPixmap myGrab(TWidget *target, QRect rect = QRect());
|
||||||
|
QImage myGrabImage(TWidget *target, QRect rect = QRect());
|
||||||
|
|
||||||
class SingleDelayedCall : public QObject {
|
class SingleDelayedCall : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -255,6 +255,7 @@ void RoundButton::updateText() {
|
||||||
_secondaryTextWidth = _secondaryText.isEmpty() ? 0 : _st.font->width(_secondaryText);
|
_secondaryTextWidth = _secondaryText.isEmpty() ? 0 : _st.font->width(_secondaryText);
|
||||||
|
|
||||||
resizeToText();
|
resizeToText();
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoundButton::resizeToText() {
|
void RoundButton::resizeToText() {
|
||||||
|
|
|
@ -1798,199 +1798,6 @@ void FlatInput::notaBene() {
|
||||||
_a_appearance.start();
|
_a_appearance.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
CountryCodeInput::CountryCodeInput(QWidget *parent, const style::FlatInput &st) : FlatInput(parent, st)
|
|
||||||
, _nosignal(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void CountryCodeInput::startErasing(QKeyEvent *e) {
|
|
||||||
setFocus();
|
|
||||||
keyPressEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CountryCodeInput::codeSelected(const QString &code) {
|
|
||||||
QString wasText(getLastText()), newText = '+' + code;
|
|
||||||
setText(newText);
|
|
||||||
_nosignal = true;
|
|
||||||
correctValue(wasText, newText);
|
|
||||||
_nosignal = false;
|
|
||||||
emit changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CountryCodeInput::correctValue(const QString &was, QString &now) {
|
|
||||||
QString newText, addToNumber;
|
|
||||||
int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), start = 0, digits = 5;
|
|
||||||
newText.reserve(oldLen + 1);
|
|
||||||
newText += '+';
|
|
||||||
if (oldLen && now[0] == '+') {
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
for (int i = start; i < oldLen; ++i) {
|
|
||||||
QChar ch(now[i]);
|
|
||||||
if (ch.isDigit()) {
|
|
||||||
if (!digits || !--digits) {
|
|
||||||
addToNumber += ch;
|
|
||||||
} else {
|
|
||||||
newText += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == oldPos) {
|
|
||||||
newPos = newText.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!addToNumber.isEmpty()) {
|
|
||||||
QString validCode = findValidCode(newText.mid(1));
|
|
||||||
addToNumber = newText.mid(1 + validCode.length()) + addToNumber;
|
|
||||||
newText = '+' + validCode;
|
|
||||||
}
|
|
||||||
if (newPos < 0 || newPos > newText.length()) {
|
|
||||||
newPos = newText.length();
|
|
||||||
}
|
|
||||||
if (newText != now) {
|
|
||||||
now = newText;
|
|
||||||
setText(newText);
|
|
||||||
updatePlaceholder();
|
|
||||||
if (newPos != oldPos) {
|
|
||||||
setCursorPosition(newPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!_nosignal && was != newText) {
|
|
||||||
emit codeChanged(newText.mid(1));
|
|
||||||
}
|
|
||||||
if (!addToNumber.isEmpty()) {
|
|
||||||
emit addedToNumber(addToNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PhonePartInput::PhonePartInput(QWidget *parent, const style::FlatInput &st) : FlatInput(parent, st, lang(lng_phone_ph)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhonePartInput::paintEvent(QPaintEvent *e) {
|
|
||||||
FlatInput::paintEvent(e);
|
|
||||||
|
|
||||||
Painter p(this);
|
|
||||||
auto t = text();
|
|
||||||
if (!_pattern.isEmpty() && !t.isEmpty()) {
|
|
||||||
auto ph = placeholder().mid(t.size());
|
|
||||||
if (!ph.isEmpty()) {
|
|
||||||
p.setClipRect(rect());
|
|
||||||
auto phRect = placeholderRect();
|
|
||||||
int tw = phFont()->width(t);
|
|
||||||
if (tw < phRect.width()) {
|
|
||||||
phRect.setLeft(phRect.left() + tw);
|
|
||||||
phPrepare(p);
|
|
||||||
p.drawText(phRect, ph, style::al_left);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhonePartInput::keyPressEvent(QKeyEvent *e) {
|
|
||||||
if (e->key() == Qt::Key_Backspace && text().isEmpty()) {
|
|
||||||
emit voidBackspace(e);
|
|
||||||
} else {
|
|
||||||
FlatInput::keyPressEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhonePartInput::correctValue(const QString &was, QString &now) {
|
|
||||||
QString newText;
|
|
||||||
int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), digitCount = 0;
|
|
||||||
for (int i = 0; i < oldLen; ++i) {
|
|
||||||
if (now[i].isDigit()) {
|
|
||||||
++digitCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength;
|
|
||||||
|
|
||||||
bool inPart = !_pattern.isEmpty();
|
|
||||||
int curPart = -1, leftInPart = 0;
|
|
||||||
newText.reserve(oldLen);
|
|
||||||
for (int i = 0; i < oldLen; ++i) {
|
|
||||||
if (i == oldPos && newPos < 0) {
|
|
||||||
newPos = newText.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
QChar ch(now[i]);
|
|
||||||
if (ch.isDigit()) {
|
|
||||||
if (!digitCount--) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (inPart) {
|
|
||||||
if (leftInPart) {
|
|
||||||
--leftInPart;
|
|
||||||
} else {
|
|
||||||
newText += ' ';
|
|
||||||
++curPart;
|
|
||||||
inPart = curPart < _pattern.size();
|
|
||||||
leftInPart = inPart ? (_pattern.at(curPart) - 1) : 0;
|
|
||||||
|
|
||||||
++oldPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newText += ch;
|
|
||||||
} else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') {
|
|
||||||
if (inPart) {
|
|
||||||
if (leftInPart) {
|
|
||||||
} else {
|
|
||||||
newText += ch;
|
|
||||||
++curPart;
|
|
||||||
inPart = curPart < _pattern.size();
|
|
||||||
leftInPart = inPart ? _pattern.at(curPart) : 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newText += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int32 newlen = newText.size();
|
|
||||||
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
|
||||||
--newlen;
|
|
||||||
}
|
|
||||||
if (newlen < newText.size()) newText = newText.mid(0, newlen);
|
|
||||||
if (newPos < 0) {
|
|
||||||
newPos = newText.length();
|
|
||||||
}
|
|
||||||
if (newText != now) {
|
|
||||||
now = newText;
|
|
||||||
setText(now);
|
|
||||||
updatePlaceholder();
|
|
||||||
setCursorPosition(newPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhonePartInput::addedToNumber(const QString &added) {
|
|
||||||
setFocus();
|
|
||||||
QString wasText(getLastText()), newText = added + wasText;
|
|
||||||
setText(newText);
|
|
||||||
setCursorPosition(added.length());
|
|
||||||
correctValue(wasText, newText);
|
|
||||||
updatePlaceholder();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhonePartInput::onChooseCode(const QString &code) {
|
|
||||||
_pattern = phoneNumberParse(code);
|
|
||||||
if (!_pattern.isEmpty() && _pattern.at(0) == code.size()) {
|
|
||||||
_pattern.pop_front();
|
|
||||||
} else {
|
|
||||||
_pattern.clear();
|
|
||||||
}
|
|
||||||
if (_pattern.isEmpty()) {
|
|
||||||
setPlaceholder(lang(lng_phone_ph));
|
|
||||||
} else {
|
|
||||||
QString ph;
|
|
||||||
ph.reserve(20);
|
|
||||||
for (int i = 0, l = _pattern.size(); i < l; ++i) {
|
|
||||||
ph.append(' ');
|
|
||||||
ph.append(QString(_pattern.at(i), QChar(0x2212)));
|
|
||||||
}
|
|
||||||
setPlaceholder(ph);
|
|
||||||
}
|
|
||||||
auto newText = getLastText();
|
|
||||||
correctValue(newText, newText);
|
|
||||||
setPlaceholderFast(!_pattern.isEmpty());
|
|
||||||
updatePlaceholder();
|
|
||||||
}
|
|
||||||
|
|
||||||
InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString &ph, const QString &val) : TWidget(parent)
|
InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString &ph, const QString &val) : TWidget(parent)
|
||||||
, _maxLength(-1)
|
, _maxLength(-1)
|
||||||
, _inner(this)
|
, _inner(this)
|
||||||
|
@ -3533,6 +3340,23 @@ MaskedInputField::MaskedInputField(QWidget *parent, const style::InputField &st,
|
||||||
updatePlaceholder();
|
updatePlaceholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MaskedInputField::setCorrectedText(QString &now, int &nowCursor, const QString &newText, int newPos) {
|
||||||
|
if (newPos < 0 || newPos > newText.size()) {
|
||||||
|
newPos = newText.size();
|
||||||
|
}
|
||||||
|
auto updateText = (newText != now);
|
||||||
|
if (updateText) {
|
||||||
|
now = newText;
|
||||||
|
setText(now);
|
||||||
|
updatePlaceholder();
|
||||||
|
}
|
||||||
|
auto updateCursorPosition = (newPos != nowCursor) || updateText;
|
||||||
|
if (updateCursorPosition) {
|
||||||
|
nowCursor = newPos;
|
||||||
|
setCursorPosition(nowCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MaskedInputField::customUpDown(bool custom) {
|
void MaskedInputField::customUpDown(bool custom) {
|
||||||
_customUpDown = custom;
|
_customUpDown = custom;
|
||||||
}
|
}
|
||||||
|
@ -3770,9 +3594,6 @@ QRect MaskedInputField::placeholderRect() const {
|
||||||
return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins);
|
return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaskedInputField::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaskedInputField::paintPlaceholder(Painter &p) {
|
void MaskedInputField::paintPlaceholder(Painter &p) {
|
||||||
bool drawPlaceholder = _placeholderVisible;
|
bool drawPlaceholder = _placeholderVisible;
|
||||||
if (_a_placeholderShift.animating()) {
|
if (_a_placeholderShift.animating()) {
|
||||||
|
@ -3860,6 +3681,195 @@ void MaskedInputField::onCursorPositionChanged(int oldPosition, int position) {
|
||||||
_oldcursor = position;
|
_oldcursor = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CountryCodeInput::CountryCodeInput(QWidget *parent, const style::InputField &st) : MaskedInputField(parent, st)
|
||||||
|
, _nosignal(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CountryCodeInput::startErasing(QKeyEvent *e) {
|
||||||
|
setFocus();
|
||||||
|
keyPressEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CountryCodeInput::codeSelected(const QString &code) {
|
||||||
|
auto wasText = getLastText();
|
||||||
|
auto wasCursor = cursorPosition();
|
||||||
|
auto newText = '+' + code;
|
||||||
|
auto newCursor = newText.size();
|
||||||
|
setText(newText);
|
||||||
|
_nosignal = true;
|
||||||
|
correctValue(wasText, wasCursor, newText, newCursor);
|
||||||
|
_nosignal = false;
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CountryCodeInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
||||||
|
QString newText, addToNumber;
|
||||||
|
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), start = 0, digits = 5;
|
||||||
|
newText.reserve(oldLen + 1);
|
||||||
|
if (oldLen && now[0] == '+') {
|
||||||
|
if (start == oldPos) {
|
||||||
|
newPos = newText.length();
|
||||||
|
}
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
newText += '+';
|
||||||
|
for (int i = start; i < oldLen; ++i) {
|
||||||
|
if (i == oldPos) {
|
||||||
|
newPos = newText.length();
|
||||||
|
}
|
||||||
|
auto ch = now[i];
|
||||||
|
if (ch.isDigit()) {
|
||||||
|
if (!digits || !--digits) {
|
||||||
|
addToNumber += ch;
|
||||||
|
} else {
|
||||||
|
newText += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!addToNumber.isEmpty()) {
|
||||||
|
auto validCode = findValidCode(newText.mid(1));
|
||||||
|
addToNumber = newText.mid(1 + validCode.length()) + addToNumber;
|
||||||
|
newText = '+' + validCode;
|
||||||
|
}
|
||||||
|
setCorrectedText(now, nowCursor, newText, newPos);
|
||||||
|
|
||||||
|
if (!_nosignal && was != newText) {
|
||||||
|
emit codeChanged(newText.mid(1));
|
||||||
|
}
|
||||||
|
if (!addToNumber.isEmpty()) {
|
||||||
|
emit addedToNumber(addToNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PhonePartInput::PhonePartInput(QWidget *parent, const style::InputField &st) : MaskedInputField(parent, st, lang(lng_phone_ph)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhonePartInput::paintPlaceholder(Painter &p) {
|
||||||
|
auto t = getLastText();
|
||||||
|
if (!_pattern.isEmpty() && !t.isEmpty()) {
|
||||||
|
auto ph = placeholder().mid(t.size());
|
||||||
|
if (!ph.isEmpty()) {
|
||||||
|
p.setClipRect(rect());
|
||||||
|
auto phRect = placeholderRect();
|
||||||
|
int tw = phFont()->width(t);
|
||||||
|
if (tw < phRect.width()) {
|
||||||
|
phRect.setLeft(phRect.left() + tw);
|
||||||
|
placeholderPreparePaint(p);
|
||||||
|
p.drawText(phRect, ph, style::al_topleft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MaskedInputField::paintPlaceholder(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhonePartInput::keyPressEvent(QKeyEvent *e) {
|
||||||
|
if (e->key() == Qt::Key_Backspace && getLastText().isEmpty()) {
|
||||||
|
emit voidBackspace(e);
|
||||||
|
} else {
|
||||||
|
MaskedInputField::keyPressEvent(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhonePartInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
||||||
|
QString newText;
|
||||||
|
int oldPos(nowCursor), newPos(-1), oldLen(now.length()), digitCount = 0;
|
||||||
|
for (int i = 0; i < oldLen; ++i) {
|
||||||
|
if (now[i].isDigit()) {
|
||||||
|
++digitCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength;
|
||||||
|
|
||||||
|
bool inPart = !_pattern.isEmpty();
|
||||||
|
int curPart = -1, leftInPart = 0;
|
||||||
|
newText.reserve(oldLen);
|
||||||
|
for (int i = 0; i < oldLen; ++i) {
|
||||||
|
if (i == oldPos && newPos < 0) {
|
||||||
|
newPos = newText.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ch = now[i];
|
||||||
|
if (ch.isDigit()) {
|
||||||
|
if (!digitCount--) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (inPart) {
|
||||||
|
if (leftInPart) {
|
||||||
|
--leftInPart;
|
||||||
|
} else {
|
||||||
|
newText += ' ';
|
||||||
|
++curPart;
|
||||||
|
inPart = curPart < _pattern.size();
|
||||||
|
leftInPart = inPart ? (_pattern.at(curPart) - 1) : 0;
|
||||||
|
|
||||||
|
++oldPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newText += ch;
|
||||||
|
} else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') {
|
||||||
|
if (inPart) {
|
||||||
|
if (leftInPart) {
|
||||||
|
} else {
|
||||||
|
newText += ch;
|
||||||
|
++curPart;
|
||||||
|
inPart = curPart < _pattern.size();
|
||||||
|
leftInPart = inPart ? _pattern.at(curPart) : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newText += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto newlen = newText.size();
|
||||||
|
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
||||||
|
--newlen;
|
||||||
|
}
|
||||||
|
if (newlen < newText.size()) {
|
||||||
|
newText = newText.mid(0, newlen);
|
||||||
|
}
|
||||||
|
setCorrectedText(now, nowCursor, newText, newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhonePartInput::addedToNumber(const QString &added) {
|
||||||
|
setFocus();
|
||||||
|
auto wasText = getLastText();
|
||||||
|
auto wasCursor = cursorPosition();
|
||||||
|
auto newText = added + wasText;
|
||||||
|
auto newCursor = newText.size();
|
||||||
|
setText(newText);
|
||||||
|
setCursorPosition(added.length());
|
||||||
|
correctValue(wasText, wasCursor, newText, newCursor);
|
||||||
|
updatePlaceholder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhonePartInput::onChooseCode(const QString &code) {
|
||||||
|
_pattern = phoneNumberParse(code);
|
||||||
|
if (!_pattern.isEmpty() && _pattern.at(0) == code.size()) {
|
||||||
|
_pattern.pop_front();
|
||||||
|
} else {
|
||||||
|
_pattern.clear();
|
||||||
|
}
|
||||||
|
if (_pattern.isEmpty()) {
|
||||||
|
setPlaceholder(lang(lng_phone_ph));
|
||||||
|
} else {
|
||||||
|
QString ph;
|
||||||
|
ph.reserve(20);
|
||||||
|
for (int i = 0, l = _pattern.size(); i < l; ++i) {
|
||||||
|
ph.append(' ');
|
||||||
|
ph.append(QString(_pattern.at(i), QChar(0x2212)));
|
||||||
|
}
|
||||||
|
setPlaceholder(ph);
|
||||||
|
}
|
||||||
|
auto wasText = getLastText();
|
||||||
|
auto wasCursor = cursorPosition();
|
||||||
|
auto newText = getLastText();
|
||||||
|
auto newCursor = newText.size();
|
||||||
|
correctValue(wasText, wasCursor, newText, newCursor);
|
||||||
|
setPlaceholderFast(!_pattern.isEmpty());
|
||||||
|
updatePlaceholder();
|
||||||
|
}
|
||||||
|
|
||||||
PasswordInput::PasswordInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val) {
|
PasswordInput::PasswordInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val) {
|
||||||
setEchoMode(QLineEdit::Password);
|
setEchoMode(QLineEdit::Password);
|
||||||
}
|
}
|
||||||
|
@ -3873,29 +3883,22 @@ PortInput::PortInput(QWidget *parent, const style::InputField &st, const QString
|
||||||
void PortInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
void PortInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
||||||
QString newText;
|
QString newText;
|
||||||
newText.reserve(now.size());
|
newText.reserve(now.size());
|
||||||
int32 newCursor = nowCursor;
|
auto newPos = nowCursor;
|
||||||
for (int32 i = 0, l = now.size(); i < l; ++i) {
|
for (auto i = 0, l = now.size(); i < l; ++i) {
|
||||||
if (now.at(i).isDigit()) {
|
if (now.at(i).isDigit()) {
|
||||||
newText.append(now.at(i));
|
newText.append(now.at(i));
|
||||||
} else if (i < nowCursor) {
|
} else if (i < nowCursor) {
|
||||||
--newCursor;
|
--newPos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!newText.toInt()) {
|
if (!newText.toInt()) {
|
||||||
newText = QString();
|
newText = QString();
|
||||||
newCursor = 0;
|
newPos = 0;
|
||||||
} else if (newText.toInt() > 65535) {
|
} else if (newText.toInt() > 65535) {
|
||||||
newText = was;
|
newText = was;
|
||||||
newCursor = wasCursor;
|
newPos = wasCursor;
|
||||||
}
|
|
||||||
if (newText != now) {
|
|
||||||
now = newText;
|
|
||||||
setText(newText);
|
|
||||||
}
|
|
||||||
if (newCursor != nowCursor) {
|
|
||||||
nowCursor = newCursor;
|
|
||||||
setCursorPosition(newCursor);
|
|
||||||
}
|
}
|
||||||
|
setCorrectedText(now, nowCursor, newText, newPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val, bool isLink) : MaskedInputField(parent, st, ph, val),
|
UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val, bool isLink) : MaskedInputField(parent, st, ph, val),
|
||||||
|
@ -3916,13 +3919,13 @@ void UsernameInput::paintPlaceholder(Painter &p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsernameInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
void UsernameInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
||||||
QString newText;
|
auto newPos = nowCursor;
|
||||||
int32 newCursor = nowCursor, from, len = now.size();
|
auto from = 0, len = now.size();
|
||||||
for (from = 0; from < len; ++from) {
|
for (; from < len; ++from) {
|
||||||
if (!now.at(from).isSpace()) {
|
if (!now.at(from).isSpace()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (newCursor > 0) --newCursor;
|
if (newPos > 0) --newPos;
|
||||||
}
|
}
|
||||||
len -= from;
|
len -= from;
|
||||||
if (len > MaxUsernameLength) len = MaxUsernameLength + (now.at(from) == '@' ? 1 : 0);
|
if (len > MaxUsernameLength) len = MaxUsernameLength + (now.at(from) == '@' ? 1 : 0);
|
||||||
|
@ -3933,18 +3936,7 @@ void UsernameInput::correctValue(const QString &was, int32 wasCursor, QString &n
|
||||||
}
|
}
|
||||||
--len;
|
--len;
|
||||||
}
|
}
|
||||||
newText = now.mid(from, len);
|
setCorrectedText(now, nowCursor, now.mid(from, len), newPos);
|
||||||
if (newCursor > len) {
|
|
||||||
newCursor = len;
|
|
||||||
}
|
|
||||||
if (newText != now) {
|
|
||||||
now = newText;
|
|
||||||
setText(newText);
|
|
||||||
}
|
|
||||||
if (newCursor != nowCursor) {
|
|
||||||
nowCursor = newCursor;
|
|
||||||
setCursorPosition(newCursor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PhoneInput::PhoneInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val)
|
PhoneInput::PhoneInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val)
|
||||||
|
@ -3996,7 +3988,7 @@ void PhoneInput::paintPlaceholder(Painter &p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhoneInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
void PhoneInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
||||||
QString digits(now);
|
auto digits = now;
|
||||||
digits.replace(QRegularExpression(qsl("[^\\d]")), QString());
|
digits.replace(QRegularExpression(qsl("[^\\d]")), QString());
|
||||||
_pattern = phoneNumberParse(digits);
|
_pattern = phoneNumberParse(digits);
|
||||||
|
|
||||||
|
@ -4075,16 +4067,10 @@ void PhoneInput::correctValue(const QString &was, int32 wasCursor, QString &now,
|
||||||
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
while (newlen > 0 && newText.at(newlen - 1).isSpace()) {
|
||||||
--newlen;
|
--newlen;
|
||||||
}
|
}
|
||||||
if (newlen < newText.size()) newText = newText.mid(0, newlen);
|
if (newlen < newText.size()) {
|
||||||
if (newPos < 0) {
|
newText = newText.mid(0, newlen);
|
||||||
newPos = newText.length();
|
|
||||||
}
|
|
||||||
if (newText != now) {
|
|
||||||
now = newText;
|
|
||||||
setText(newText);
|
|
||||||
updatePlaceholder();
|
|
||||||
setCursorPosition(newPos);
|
|
||||||
}
|
}
|
||||||
|
setCorrectedText(now, nowCursor, newText, newPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -114,7 +114,7 @@ public:
|
||||||
};
|
};
|
||||||
void setTagMimeProcessor(std_::unique_ptr<TagMimeProcessor> &&processor);
|
void setTagMimeProcessor(std_::unique_ptr<TagMimeProcessor> &&processor);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onTouchTimer();
|
void onTouchTimer();
|
||||||
|
|
||||||
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
||||||
|
@ -267,7 +267,7 @@ public:
|
||||||
return _oldtext;
|
return _oldtext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onTextChange(const QString &text);
|
void onTextChange(const QString &text);
|
||||||
void onTextEdited();
|
void onTextEdited();
|
||||||
|
|
||||||
|
@ -330,52 +330,6 @@ private:
|
||||||
QPoint _touchStart;
|
QPoint _touchStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CountryCodeInput : public FlatInput {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
CountryCodeInput(QWidget *parent, const style::FlatInput &st);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void startErasing(QKeyEvent *e);
|
|
||||||
void codeSelected(const QString &code);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void codeChanged(const QString &code);
|
|
||||||
void addedToNumber(const QString &added);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void correctValue(const QString &was, QString &now) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _nosignal;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class PhonePartInput : public FlatInput {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PhonePartInput(QWidget *parent, const style::FlatInput &st);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void addedToNumber(const QString &added);
|
|
||||||
void onChooseCode(const QString &code);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void voidBackspace(QKeyEvent *e);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
|
||||||
|
|
||||||
void correctValue(const QString &was, QString &now) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVector<int> _pattern;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CtrlEnterSubmit {
|
enum CtrlEnterSubmit {
|
||||||
CtrlEnterSubmitEnter,
|
CtrlEnterSubmitEnter,
|
||||||
CtrlEnterSubmitCtrlEnter,
|
CtrlEnterSubmitCtrlEnter,
|
||||||
|
@ -439,7 +393,7 @@ public:
|
||||||
_inner.clearFocus();
|
_inner.clearFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onTouchTimer();
|
void onTouchTimer();
|
||||||
|
|
||||||
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
||||||
|
@ -610,7 +564,7 @@ public:
|
||||||
_inner.setTextCursor(c);
|
_inner.setTextCursor(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onTouchTimer();
|
void onTouchTimer();
|
||||||
|
|
||||||
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
||||||
|
@ -715,20 +669,11 @@ private:
|
||||||
|
|
||||||
class MaskedInputField : public QLineEdit {
|
class MaskedInputField : public QLineEdit {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
T_WIDGET
|
T_WIDGET
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder = QString(), const QString &val = QString());
|
MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder = QString(), const QString &val = QString());
|
||||||
|
|
||||||
bool event(QEvent *e) override;
|
|
||||||
void touchEvent(QTouchEvent *e);
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void focusInEvent(QFocusEvent *e) override;
|
|
||||||
void focusOutEvent(QFocusEvent *e) override;
|
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
|
||||||
|
|
||||||
void showError();
|
void showError();
|
||||||
|
|
||||||
bool setPlaceholder(const QString &ph);
|
bool setPlaceholder(const QString &ph);
|
||||||
|
@ -757,7 +702,7 @@ public:
|
||||||
updatePlaceholder();
|
updatePlaceholder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onTextChange(const QString &text);
|
void onTextChange(const QString &text);
|
||||||
void onCursorPositionChanged(int oldPosition, int position);
|
void onCursorPositionChanged(int oldPosition, int position);
|
||||||
|
|
||||||
|
@ -773,6 +718,15 @@ signals:
|
||||||
void blurred();
|
void blurred();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool event(QEvent *e) override;
|
||||||
|
void touchEvent(QTouchEvent *e);
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void focusInEvent(QFocusEvent *e) override;
|
||||||
|
void focusOutEvent(QFocusEvent *e) override;
|
||||||
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||||
|
|
||||||
void enterEventHook(QEvent *e) {
|
void enterEventHook(QEvent *e) {
|
||||||
return QLineEdit::enterEvent(e);
|
return QLineEdit::enterEvent(e);
|
||||||
}
|
}
|
||||||
|
@ -780,7 +734,10 @@ protected:
|
||||||
return QLineEdit::leaveEvent(e);
|
return QLineEdit::leaveEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor);
|
virtual void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) {
|
||||||
|
}
|
||||||
|
void setCorrectedText(QString &now, int &nowCursor, const QString &newText, int newPos);
|
||||||
|
|
||||||
virtual void paintPlaceholder(Painter &p);
|
virtual void paintPlaceholder(Painter &p);
|
||||||
|
|
||||||
style::font phFont() {
|
style::font phFont() {
|
||||||
|
@ -828,6 +785,52 @@ private:
|
||||||
QPoint _touchStart;
|
QPoint _touchStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CountryCodeInput : public MaskedInputField {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CountryCodeInput(QWidget *parent, const style::InputField &st);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startErasing(QKeyEvent *e);
|
||||||
|
void codeSelected(const QString &code);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void codeChanged(const QString &code);
|
||||||
|
void addedToNumber(const QString &added);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _nosignal;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class PhonePartInput : public MaskedInputField {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PhonePartInput(QWidget *parent, const style::InputField &st);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void addedToNumber(const QString &added);
|
||||||
|
void onChooseCode(const QString &code);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void voidBackspace(QKeyEvent *e);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
|
void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override;
|
||||||
|
void paintPlaceholder(Painter &p) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVector<int> _pattern;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class PasswordInput : public MaskedInputField {
|
class PasswordInput : public MaskedInputField {
|
||||||
public:
|
public:
|
||||||
PasswordInput(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString());
|
PasswordInput(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString());
|
||||||
|
|
|
@ -43,6 +43,57 @@ TextParseOptions _labelMarkedOptions = {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
CrossFadeAnimation::CrossFadeAnimation(const style::color &bg) : _bg(bg) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossFadeAnimation::addLine(Part was, Part now) {
|
||||||
|
_lines.push_back(Line(std_::move(was), std_::move(now)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossFadeAnimation::paintFrame(Painter &p, float64 positionReady, float64 alphaWas, float64 alphaNow) {
|
||||||
|
if (_lines.isEmpty()) return;
|
||||||
|
|
||||||
|
for_const (auto &line, _lines) {
|
||||||
|
paintLine(p, line, positionReady, alphaWas, alphaNow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossFadeAnimation::paintLine(Painter &p, const Line &line, float64 positionReady, float64 alphaWas, float64 alphaNow) {
|
||||||
|
auto &snapshotWas = line.was.snapshot;
|
||||||
|
auto &snapshotNow = line.now.snapshot;
|
||||||
|
t_assert(!snapshotWas.isNull() || !snapshotNow.isNull());
|
||||||
|
|
||||||
|
auto positionWas = line.was.position;
|
||||||
|
auto positionNow = line.now.position;
|
||||||
|
auto left = anim::interpolate(positionWas.x(), positionNow.x(), positionReady);
|
||||||
|
auto topDelta = (snapshotNow.height() / cIntRetinaFactor()) - (snapshotWas.height() / cIntRetinaFactor());
|
||||||
|
auto widthDelta = (snapshotNow.width() / cIntRetinaFactor()) - (snapshotWas.width() / cIntRetinaFactor());
|
||||||
|
auto topWas = anim::interpolate(positionWas.y(), positionNow.y() + topDelta, positionReady);
|
||||||
|
auto topNow = topWas - topDelta;
|
||||||
|
|
||||||
|
p.setOpacity(alphaWas);
|
||||||
|
if (!snapshotWas.isNull()) {
|
||||||
|
p.drawPixmap(left, topWas, snapshotWas);
|
||||||
|
if (topDelta > 0) {
|
||||||
|
p.fillRect(left, topWas - topDelta, snapshotWas.width() / cIntRetinaFactor(), topDelta, _bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (widthDelta > 0) {
|
||||||
|
p.fillRect(left + (snapshotWas.width() / cIntRetinaFactor()), topNow, widthDelta, snapshotNow.height() / cIntRetinaFactor(), _bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setOpacity(alphaNow);
|
||||||
|
if (!snapshotNow.isNull()) {
|
||||||
|
p.drawPixmap(left, topNow, snapshotNow);
|
||||||
|
if (topDelta < 0) {
|
||||||
|
p.fillRect(left, topNow + topDelta, snapshotNow.width() / cIntRetinaFactor(), -topDelta, _bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (widthDelta < 0) {
|
||||||
|
p.fillRect(left + (snapshotNow.width() / cIntRetinaFactor()), topWas, -widthDelta, snapshotWas.height() / cIntRetinaFactor(), _bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LabelSimple::LabelSimple(QWidget *parent, const style::LabelSimple &st, const QString &value) : TWidget(parent)
|
LabelSimple::LabelSimple(QWidget *parent, const style::LabelSimple &st, const QString &value) : TWidget(parent)
|
||||||
, _st(st) {
|
, _st(st) {
|
||||||
setText(value);
|
setText(value);
|
||||||
|
@ -548,6 +599,72 @@ void FlatLabel::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool a
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std_::unique_ptr<CrossFadeAnimation> FlatLabel::CrossFade(FlatLabel *from, FlatLabel *to, const style::color &bg, QPoint fromPosition, QPoint toPosition) {
|
||||||
|
auto result = std_::make_unique<CrossFadeAnimation>(bg);
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
QImage full;
|
||||||
|
QVector<int> lineWidths;
|
||||||
|
int lineHeight = 0;
|
||||||
|
int lineAddTop = 0;
|
||||||
|
};
|
||||||
|
auto prepareData = [&bg](FlatLabel *label) {
|
||||||
|
auto result = Data();
|
||||||
|
result.full = QImage(label->size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result.full.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
result.full.fill(bg->c);
|
||||||
|
Painter(&result.full).drawImage(0, 0, myGrabImage(label));
|
||||||
|
auto textWidth = label->width() - label->_st.margin.left() - label->_st.margin.right();
|
||||||
|
label->_text.countLineWidths(textWidth, &result.lineWidths);
|
||||||
|
result.lineHeight = label->_st.font->height;
|
||||||
|
auto addedHeight = (label->_tst.lineHeight - result.lineHeight);
|
||||||
|
if (addedHeight > 0) {
|
||||||
|
result.lineAddTop = addedHeight / 2;
|
||||||
|
result.lineHeight += addedHeight;
|
||||||
|
}
|
||||||
|
return std_::move(result);
|
||||||
|
};
|
||||||
|
auto was = prepareData(from);
|
||||||
|
auto now = prepareData(to);
|
||||||
|
|
||||||
|
auto maxLines = qMax(was.lineWidths.size(), now.lineWidths.size());
|
||||||
|
auto fillDataTill = [maxLines](Data &data) {
|
||||||
|
for (auto i = data.lineWidths.size(); i != maxLines; ++i) {
|
||||||
|
data.lineWidths.push_back(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fillDataTill(was);
|
||||||
|
fillDataTill(now);
|
||||||
|
auto preparePart = [](FlatLabel *label, QPoint position, Data &data, int index, Data &other) {
|
||||||
|
auto result = CrossFadeAnimation::Part();
|
||||||
|
auto lineWidth = data.lineWidths[index];
|
||||||
|
if (lineWidth < 0) {
|
||||||
|
lineWidth = other.lineWidths[index];
|
||||||
|
}
|
||||||
|
auto fullWidth = data.full.width() / cIntRetinaFactor();
|
||||||
|
auto top = index * data.lineHeight + data.lineAddTop;
|
||||||
|
auto left = 0;
|
||||||
|
if (label->_st.align & Qt::AlignHCenter) {
|
||||||
|
left += (fullWidth - lineWidth) / 2;
|
||||||
|
} else if (label->_st.align & Qt::AlignRight) {
|
||||||
|
left += (fullWidth - lineWidth);
|
||||||
|
}
|
||||||
|
auto snapshotRect = data.full.rect().intersected(QRect(left * cIntRetinaFactor(), top * cIntRetinaFactor(), lineWidth * cIntRetinaFactor(), label->_st.font->height * cIntRetinaFactor()));
|
||||||
|
if (!snapshotRect.isEmpty()) {
|
||||||
|
result.snapshot = App::pixmapFromImageInPlace(data.full.copy(snapshotRect));
|
||||||
|
result.snapshot.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
}
|
||||||
|
auto positionBase = position + label->pos();
|
||||||
|
result.position = positionBase + QPoint(label->_st.margin.left() + left, label->_st.margin.top() + top);
|
||||||
|
return std_::move(result);
|
||||||
|
};
|
||||||
|
for (int i = 0; i != maxLines; ++i) {
|
||||||
|
result->addLine(preparePart(from, fromPosition, was, i, now), preparePart(to, toPosition, now, i, was));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std_::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
Text::StateResult FlatLabel::dragActionUpdate() {
|
Text::StateResult FlatLabel::dragActionUpdate() {
|
||||||
auto m = mapFromGlobal(_lastMousePos);
|
auto m = mapFromGlobal(_lastMousePos);
|
||||||
auto state = getTextState(m);
|
auto state = getTextState(m);
|
||||||
|
|
|
@ -26,6 +26,37 @@ namespace Ui {
|
||||||
|
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
|
||||||
|
class CrossFadeAnimation {
|
||||||
|
public:
|
||||||
|
CrossFadeAnimation(const style::color &bg);
|
||||||
|
|
||||||
|
struct Part {
|
||||||
|
QPixmap snapshot;
|
||||||
|
QPoint position;
|
||||||
|
};
|
||||||
|
void addLine(Part was, Part now);
|
||||||
|
|
||||||
|
void paintFrame(Painter &p, float64 dt) {
|
||||||
|
auto progress = anim::linear(1., dt);
|
||||||
|
paintFrame(p, progress, 1. - progress, progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintFrame(Painter &p, float64 positionReady, float64 alphaWas, float64 alphaNow);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Line {
|
||||||
|
Line(Part was, Part now) : was(std_::move(was)), now(std_::move(now)) {
|
||||||
|
}
|
||||||
|
Part was;
|
||||||
|
Part now;
|
||||||
|
};
|
||||||
|
void paintLine(Painter &p, const Line &line, float64 positionReady, float64 alphaWas, float64 alphaNow);
|
||||||
|
|
||||||
|
const style::color &_bg;
|
||||||
|
QList<Line> _lines;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class LabelSimple : public TWidget {
|
class LabelSimple : public TWidget {
|
||||||
public:
|
public:
|
||||||
LabelSimple(QWidget *parent, const style::LabelSimple &st = st::defaultLabelSimple, const QString &value = QString());
|
LabelSimple(QWidget *parent, const style::LabelSimple &st = st::defaultLabelSimple, const QString &value = QString());
|
||||||
|
@ -81,6 +112,8 @@ public:
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
|
void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
|
void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
|
||||||
|
|
||||||
|
static std_::unique_ptr<CrossFadeAnimation> CrossFade(FlatLabel *from, FlatLabel *to, const style::color &bg, QPoint fromPosition = QPoint(), QPoint toPosition = QPoint());
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
|
|
@ -160,7 +160,7 @@ private:
|
||||||
class SplittedWidgetOther;
|
class SplittedWidgetOther;
|
||||||
class ScrollArea : public QScrollArea {
|
class ScrollArea : public QScrollArea {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
T_WIDGET
|
T_WIDGET
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScrollArea(QWidget *parent, const style::FlatScroll &st = st::defaultFlatScroll, bool handleTouch = true);
|
ScrollArea(QWidget *parent, const style::FlatScroll &st = st::defaultFlatScroll, bool handleTouch = true);
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/twidget.h"
|
#include "ui/twidget.h"
|
||||||
#include "window/slide_animation.h"
|
#include "window/window_slide_animation.h"
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "window/slide_animation.h"
|
#include "window/window_slide_animation.h"
|
||||||
|
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
|
|
|
@ -466,6 +466,8 @@
|
||||||
'<(src_loc)/ui/effects/ripple_animation.h',
|
'<(src_loc)/ui/effects/ripple_animation.h',
|
||||||
'<(src_loc)/ui/effects/round_checkbox.cpp',
|
'<(src_loc)/ui/effects/round_checkbox.cpp',
|
||||||
'<(src_loc)/ui/effects/round_checkbox.h',
|
'<(src_loc)/ui/effects/round_checkbox.h',
|
||||||
|
'<(src_loc)/ui/effects/slide_animation.cpp',
|
||||||
|
'<(src_loc)/ui/effects/slide_animation.h',
|
||||||
'<(src_loc)/ui/effects/widget_fade_wrap.cpp',
|
'<(src_loc)/ui/effects/widget_fade_wrap.cpp',
|
||||||
'<(src_loc)/ui/effects/widget_fade_wrap.h',
|
'<(src_loc)/ui/effects/widget_fade_wrap.h',
|
||||||
'<(src_loc)/ui/effects/widget_slide_wrap.cpp',
|
'<(src_loc)/ui/effects/widget_slide_wrap.cpp',
|
||||||
|
@ -546,8 +548,8 @@
|
||||||
'<(src_loc)/window/player_wrap_widget.h',
|
'<(src_loc)/window/player_wrap_widget.h',
|
||||||
'<(src_loc)/window/section_widget.cpp',
|
'<(src_loc)/window/section_widget.cpp',
|
||||||
'<(src_loc)/window/section_widget.h',
|
'<(src_loc)/window/section_widget.h',
|
||||||
'<(src_loc)/window/slide_animation.cpp',
|
'<(src_loc)/window/window_slide_animation.cpp',
|
||||||
'<(src_loc)/window/slide_animation.h',
|
'<(src_loc)/window/window_slide_animation.h',
|
||||||
'<(src_loc)/window/top_bar_widget.cpp',
|
'<(src_loc)/window/top_bar_widget.cpp',
|
||||||
'<(src_loc)/window/top_bar_widget.h',
|
'<(src_loc)/window/top_bar_widget.h',
|
||||||
'<(src_loc)/window/window_main_menu.cpp',
|
'<(src_loc)/window/window_main_menu.cpp',
|
||||||
|
|