mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-31 14:38:15 +00:00
Intro redesign done.
This commit is contained in:
@@ -21,119 +21,135 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
using "basic.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
countryInput {
|
||||
width: pixels;
|
||||
height: pixels;
|
||||
top: pixels;
|
||||
bgColor: color;
|
||||
ptrSize: size;
|
||||
textMrg: margins;
|
||||
font: font;
|
||||
align: align;
|
||||
}
|
||||
introCoverHeight: 208px;
|
||||
introCoverTopBg: #0f89d0;
|
||||
introCoverBottomBg: #39b0f0;
|
||||
introCoverIconsFg: #5ec6ff;
|
||||
introCoverMaxWidth: 880px;
|
||||
introCoverIconsMinSkip: 120px;
|
||||
introCoverLeft: icon {{ "intro_left", introCoverIconsFg }};
|
||||
introCoverRight: icon {{ "intro_right", introCoverIconsFg }};
|
||||
introCoverIcon: icon {
|
||||
{ "intro_plane_trace", #5ec6ff69 },
|
||||
{ "intro_plane_inner", #c6d8e8 },
|
||||
{ "intro_plane_outer", #a1bed4 },
|
||||
{ "intro_plane_top", #ffffff },
|
||||
};
|
||||
introCoverIconLeft: 50px;
|
||||
introCoverIconTop: 46px;
|
||||
|
||||
introCountry: countryInput {
|
||||
width: 300px;
|
||||
height: 41px;
|
||||
top: 33px;
|
||||
bgColor: windowBgOver;
|
||||
ptrSize: size(15px, 8px);
|
||||
textMrg: margins(16px, 5px, 16px, 15px);
|
||||
font: defaultInputFont;
|
||||
align: align(left);
|
||||
}
|
||||
introSettingsSkip: 10px;
|
||||
|
||||
introIcon: icon {{ "intro_logo", #008ed5 }};
|
||||
introPhotoSize: 76px;
|
||||
introPhotoIconPosition: point(23px, 25px);
|
||||
introPhotoTop: 10px;
|
||||
|
||||
introResetLink: LinkButton(defaultLinkButton) {
|
||||
color: #d15948;
|
||||
overColor: #d15948;
|
||||
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;
|
||||
introCoverTitle: FlatLabel(defaultFlatLabel) {
|
||||
font: font(22px semibold);
|
||||
textFg: introTitleFg;
|
||||
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);
|
||||
introSize: size(400px, 460px);
|
||||
introSlideShift: 500px; // intro hiding animation
|
||||
introLink: defaultLinkButton;
|
||||
|
||||
introPlaneWidth: 48px;
|
||||
introPlaneHeight: 38px;
|
||||
introHeight: 396px;
|
||||
introStepTopMin: 86px;
|
||||
introStepWidth: 380px;
|
||||
introStepHeight: 256px;
|
||||
introStepHeightAdd: 30px;
|
||||
introStepHeightFull: 580px;
|
||||
introSlideDuration: 200;
|
||||
introSlideDelta: 0; // between hide start and show start
|
||||
introTextTop: 22px;
|
||||
introTextSize: size(400px, 93px);
|
||||
introCallSkip: 15px;
|
||||
introPwdTextSize: size(400px, 73px);
|
||||
introCoverDuration: 200;
|
||||
|
||||
introNextButton: RoundButton(defaultActiveButton) {
|
||||
width: 300px;
|
||||
height: 56px;
|
||||
|
||||
textTop: 16px;
|
||||
|
||||
font: font(17px);
|
||||
textTop: 17px;
|
||||
font: font(17px semibold);
|
||||
}
|
||||
|
||||
introPhoneTop: 8px;
|
||||
introCountryCode: FlatInput(defaultFlatInput) {
|
||||
width: 70px;
|
||||
introStepFieldTop: 116px;
|
||||
introPhoneTop: 16px;
|
||||
introLinkTop: 21px;
|
||||
introCountry: InputField(defaultInputField) {
|
||||
textMargins: margins(3px, 7px, 3px, 6px);
|
||||
font: font(16px);
|
||||
width: 300px;
|
||||
height: 41px;
|
||||
align: align(center);
|
||||
}
|
||||
introPhone: FlatInput(defaultFlatInput) {
|
||||
textMrg: margins(12px, 5px, 12px, 6px);
|
||||
introCountryCode: InputField(introCountry) {
|
||||
width: 64px;
|
||||
height: 41px;
|
||||
textAlign: align(top);
|
||||
}
|
||||
introPhone: InputField(introCountry) {
|
||||
textMargins: margins(12px, 7px, 12px, 6px);
|
||||
width: 225px;
|
||||
height: 41px;
|
||||
}
|
||||
introCode: FlatInput(defaultFlatInput) {
|
||||
textMrg: margins(12px, 5px, 12px, 6px);
|
||||
width: 106px;
|
||||
height: 41px;
|
||||
align: align(center);
|
||||
introCode: introCountry;
|
||||
introName: introCountry;
|
||||
introPassword: introCountry;
|
||||
introPasswordTop: 94px;
|
||||
introPasswordHintTop: 146px;
|
||||
|
||||
phPos: point(0px, 0px);
|
||||
phAlign: align(center);
|
||||
phShift: 0px;
|
||||
introPasswordHint: FlatLabel(introDescription) {
|
||||
textFg: windowFg;
|
||||
}
|
||||
introName: FlatInput(introPhone) {
|
||||
width: 192px;
|
||||
}
|
||||
introPassword: FlatInput(introPhone) {
|
||||
width: 300px;
|
||||
introPasswordHintTextStyle: introDescriptionTextStyle;
|
||||
|
||||
introResetButton: RoundButton(defaultLightButton) {
|
||||
textFg: attentionButtonFg;
|
||||
textFgOver: attentionButtonFgOver;
|
||||
textBgOver: attentionButtonBgOver;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: attentionButtonBgRipple;
|
||||
}
|
||||
}
|
||||
introResetBottom: 20px;
|
||||
|
||||
introCountryIcon: icon {{ "intro_country_dropdown", menuIconFg }};
|
||||
introCountryIconPosition: point(8px, 17px);
|
||||
|
||||
introSelectDelta: 30px;
|
||||
|
||||
introErrorWidth: 450px;
|
||||
introErrorTop: 225px;
|
||||
introErrorBelowLinkTop: 213px;
|
||||
introErrorDuration: 200;
|
||||
introErrorTop: 15px;
|
||||
introErrorHeight: 40px;
|
||||
introErrorFont: font(16px);
|
||||
|
||||
introLabelTextStyle: TextStyle(defaultTextStyle) {
|
||||
lineHeight: 30px;
|
||||
}
|
||||
introErrorLabelTextStyle: TextStyle(defaultTextStyle) {
|
||||
lineHeight: 27px;
|
||||
}
|
||||
|
||||
introErrorLabel: FlatLabel(defaultFlatLabel) {
|
||||
font: introErrorFont;
|
||||
introError: introDescription;
|
||||
introErrorCentered: FlatLabel(introError) {
|
||||
align: align(center);
|
||||
}
|
||||
introErrorTextStyle: introDescriptionTextStyle;
|
||||
|
||||
introBackButton: IconButton(defaultIconButton) {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
|
@@ -26,21 +26,28 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "intro/introsignup.h"
|
||||
#include "intro/intropwdcheck.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.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;
|
||||
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) {
|
||||
if (now[i].isDigit()) {
|
||||
++digitCount;
|
||||
}
|
||||
}
|
||||
if (digitCount > 5) digitCount = 5;
|
||||
bool strict = (digitCount == 5);
|
||||
accumulate_min(digitCount, _digitsCountMax);
|
||||
auto strict = (digitCount == _digitsCountMax);
|
||||
|
||||
newText.reserve(oldLen);
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
@@ -58,177 +65,131 @@ void CodeInput::correctValue(const QString &was, QString &now) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
}
|
||||
if (newPos < 0) {
|
||||
newPos = newText.length();
|
||||
if (newPos < 0 || newPos > newText.size()) {
|
||||
newPos = newText.size();
|
||||
}
|
||||
if (newText != now) {
|
||||
now = newText;
|
||||
setText(now);
|
||||
updatePlaceholder();
|
||||
if (newPos != oldPos) {
|
||||
setCursorPosition(newPos);
|
||||
}
|
||||
}
|
||||
if (newPos != nowCursor) {
|
||||
nowCursor = newPos;
|
||||
setCursorPosition(nowCursor);
|
||||
}
|
||||
|
||||
if (strict) emit codeEntered();
|
||||
}
|
||||
|
||||
IntroCode::IntroCode(IntroWidget *parent) : IntroStep(parent)
|
||||
, a_errorAlpha(0)
|
||||
, _a_error(animation(this, &IntroCode::step_error))
|
||||
, _next(this, lang(lng_intro_next), st::introNextButton)
|
||||
, _desc(st::introTextSize.width())
|
||||
CodeWidget::CodeWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||
, _noTelegramCode(this, lang(lng_code_no_telegram), st::introLink)
|
||||
, _noTelegramCodeRequestId(0)
|
||||
, _code(this, st::introCode, lang(lng_code_ph))
|
||||
, _callTimer(this)
|
||||
, _callStatus(intro()->getCallStatus())
|
||||
, _callStatus(getData()->callStatus)
|
||||
, _callTimeout(getData()->callTimeout)
|
||||
, _callLabel(this, st::introDescription, st::introDescriptionTextStyle)
|
||||
, _checkRequest(this) {
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitCode()));
|
||||
connect(_code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||
connect(_callTimer, SIGNAL(timeout()), this, SLOT(onSendCall()));
|
||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||
connect(_noTelegramCode, SIGNAL(clicked()), this, SLOT(onNoTelegramCode()));
|
||||
|
||||
updateDescText();
|
||||
_code->setDigitsCountMax(getData()->codeLength);
|
||||
setErrorBelowLink(true);
|
||||
|
||||
if (!intro()->codeByTelegram()) {
|
||||
if (_callStatus.type == IntroWidget::CallWaiting) {
|
||||
_callTimer->start(1000);
|
||||
}
|
||||
}
|
||||
setTitleText(App::formatPhone(getData()->phone));
|
||||
updateDescText();
|
||||
}
|
||||
|
||||
void IntroCode::updateDescText() {
|
||||
_desc.setRichText(st::introFont, lang(intro()->codeByTelegram() ? lng_code_telegram : lng_code_desc));
|
||||
if (intro()->codeByTelegram()) {
|
||||
void CodeWidget::updateDescText() {
|
||||
setDescriptionText(lang(getData()->codeByTelegram ? lng_code_telegram : lng_code_desc));
|
||||
if (getData()->codeByTelegram) {
|
||||
_noTelegramCode->show();
|
||||
_callTimer->stop();
|
||||
} else {
|
||||
_noTelegramCode->hide();
|
||||
_callStatus = intro()->getCallStatus();
|
||||
if (_callStatus.type == IntroWidget::CallWaiting && !_callTimer->isActive()) {
|
||||
_callStatus = getData()->callStatus;
|
||||
_callTimeout = getData()->callTimeout;
|
||||
if (_callStatus == Widget::Data::CallStatus::Waiting && !_callTimer->isActive()) {
|
||||
_callTimer->start(1000);
|
||||
}
|
||||
}
|
||||
update();
|
||||
updateCallText();
|
||||
}
|
||||
|
||||
void IntroCode::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
|
||||
QPainter p(this);
|
||||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
}
|
||||
bool codeByTelegram = intro()->codeByTelegram();
|
||||
if (trivial || e->rect().intersects(_textRect)) {
|
||||
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')));
|
||||
void CodeWidget::updateCallText() {
|
||||
auto text = ([this]() -> QString {
|
||||
if (getData()->codeByTelegram) {
|
||||
return QString();
|
||||
}
|
||||
switch (_callStatus) {
|
||||
case Widget::Data::CallStatus::Waiting: {
|
||||
if (_callTimeout >= 3600) {
|
||||
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')));
|
||||
} 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;
|
||||
|
||||
case IntroWidget::CallCalling: {
|
||||
callText = lang(lng_code_calling);
|
||||
} break;
|
||||
|
||||
case IntroWidget::CallCalled: {
|
||||
callText = lang(lng_code_called);
|
||||
} break;
|
||||
case Widget::Data::CallStatus::Calling: return lang(lng_code_calling);
|
||||
case Widget::Data::CallStatus::Called: return lang(lng_code_called);
|
||||
}
|
||||
if (!callText.isEmpty()) {
|
||||
p.drawText(QRect(_textRect.left(), _code->y() + _code->height() + st::introCallSkip, st::introTextSize.width(), st::introErrorHeight), callText, style::al_center);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
return QString();
|
||||
})();
|
||||
_callLabel->setText(text);
|
||||
_callLabel->setVisible(!text.isEmpty() && !animating());
|
||||
}
|
||||
|
||||
void IntroCode::resizeEvent(QResizeEvent *e) {
|
||||
if (e->oldSize().width() != width()) {
|
||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
||||
_code->move((width() - _code->width()) / 2, st::introTextTop + st::introTextSize.height() + st::introCountry.top);
|
||||
}
|
||||
_textRect = QRect((width() - st::introTextSize.width()) / 2, st::introTextTop, st::introTextSize.width(), st::introTextSize.height());
|
||||
_noTelegramCode->move(_textRect.left() + (st::introTextSize.width() - _noTelegramCode->width()) / 2, _code->y() + _code->height() + st::introCallSkip + (st::introErrorHeight - _noTelegramCode->height()) / 2);
|
||||
void CodeWidget::resizeEvent(QResizeEvent *e) {
|
||||
Step::resizeEvent(e);
|
||||
_code->moveToLeft(contentLeft(), contentTop() + st::introStepFieldTop);
|
||||
auto linkTop = _code->y() + _code->height() + st::introLinkTop;
|
||||
_noTelegramCode->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||
_callLabel->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||
}
|
||||
|
||||
void IntroCode::showError(const QString &error) {
|
||||
if (!error.isEmpty()) _code->notaBene();
|
||||
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 CodeWidget::showCodeError(const QString &text) {
|
||||
if (!text.isEmpty()) _code->showError();
|
||||
showError(text);
|
||||
}
|
||||
|
||||
void IntroCode::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 IntroCode::activate() {
|
||||
IntroStep::activate();
|
||||
void CodeWidget::setInnerFocus() {
|
||||
_code->setFocus();
|
||||
}
|
||||
|
||||
void IntroCode::finished() {
|
||||
IntroStep::finished();
|
||||
_error.clear();
|
||||
a_errorAlpha = anim::fvalue(0);
|
||||
|
||||
_sentCode.clear();
|
||||
_code->setDisabled(false);
|
||||
|
||||
_callTimer->stop();
|
||||
_code->setText(QString());
|
||||
rpcClear();
|
||||
}
|
||||
|
||||
void IntroCode::cancelled() {
|
||||
if (_sentRequest) {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
void CodeWidget::activate() {
|
||||
Step::activate();
|
||||
_code->show();
|
||||
if (getData()->codeByTelegram) {
|
||||
_noTelegramCode->show();
|
||||
} else {
|
||||
_callLabel->show();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
void IntroCode::onCheckRequest() {
|
||||
void CodeWidget::onCheckRequest() {
|
||||
int32 status = MTP::state(_sentRequest);
|
||||
if (status < 0) {
|
||||
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();
|
||||
_sentRequest = 0;
|
||||
_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?
|
||||
showError(lang(lng_server_error));
|
||||
showCodeError(lang(lng_server_error));
|
||||
return;
|
||||
}
|
||||
cSetLoggedPhoneNumber(intro()->getPhone());
|
||||
intro()->finish(d.vuser);
|
||||
cSetLoggedPhoneNumber(getData()->phone);
|
||||
finish(d.vuser);
|
||||
}
|
||||
|
||||
bool IntroCode::codeSubmitFail(const RPCError &error) {
|
||||
bool CodeWidget::codeSubmitFail(const RPCError &error) {
|
||||
if (MTP::isFloodError(error)) {
|
||||
stopCheck();
|
||||
_sentRequest = 0;
|
||||
showError(lang(lng_flood_error));
|
||||
_code->setDisabled(false);
|
||||
_code->setFocus();
|
||||
showCodeError(lang(lng_flood_error));
|
||||
return true;
|
||||
}
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
@@ -277,138 +237,138 @@ bool IntroCode::codeSubmitFail(const RPCError &error) {
|
||||
_code->setDisabled(false);
|
||||
const QString &err = error.type();
|
||||
if (err == qstr("PHONE_NUMBER_INVALID") || err == qstr("PHONE_CODE_EXPIRED")) { // show error
|
||||
intro()->onBack();
|
||||
goBack();
|
||||
return true;
|
||||
} else if (err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID")) {
|
||||
showError(lang(lng_bad_code));
|
||||
_code->notaBene();
|
||||
showCodeError(lang(lng_bad_code));
|
||||
return true;
|
||||
} else if (err == qstr("PHONE_NUMBER_UNOCCUPIED")) { // success, need to signUp
|
||||
intro()->setCode(_sentCode);
|
||||
intro()->replaceStep(new IntroSignup(intro()));
|
||||
getData()->code = _sentCode;
|
||||
goReplace(new Intro::SignupWidget(parentWidget(), getData()));
|
||||
return true;
|
||||
} else if (err == qstr("SESSION_PASSWORD_NEEDED")) {
|
||||
intro()->setCode(_sentCode);
|
||||
getData()->code = _sentCode;
|
||||
_code->setDisabled(false);
|
||||
_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;
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
showError(err + ": " + error.description());
|
||||
showCodeError(err + ": " + error.description());
|
||||
} else {
|
||||
showError(lang(lng_server_error));
|
||||
showCodeError(lang(lng_server_error));
|
||||
}
|
||||
_code->setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntroCode::onInputChange() {
|
||||
showError(QString());
|
||||
if (_code->text().length() == 5) onSubmitCode();
|
||||
void CodeWidget::onInputChange() {
|
||||
hideError();
|
||||
if (_code->getLastText().length() == getData()->codeLength) {
|
||||
submit();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroCode::onSendCall() {
|
||||
if (_callStatus.type == IntroWidget::CallWaiting) {
|
||||
if (--_callStatus.timeout <= 0) {
|
||||
_callStatus.type = IntroWidget::CallCalling;
|
||||
void CodeWidget::onSendCall() {
|
||||
if (_callStatus == Widget::Data::CallStatus::Waiting) {
|
||||
if (--_callTimeout <= 0) {
|
||||
_callStatus = Widget::Data::CallStatus::Calling;
|
||||
_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 {
|
||||
intro()->setCallStatus(_callStatus);
|
||||
getData()->callStatus = _callStatus;
|
||||
getData()->callTimeout = _callTimeout;
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void IntroCode::callDone(const MTPauth_SentCode &v) {
|
||||
if (_callStatus.type == IntroWidget::CallCalling) {
|
||||
_callStatus.type = IntroWidget::CallCalled;
|
||||
intro()->setCallStatus(_callStatus);
|
||||
update();
|
||||
updateCallText();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
_sentRequest = 0;
|
||||
_code->setDisabled(false);
|
||||
switch (result.type()) {
|
||||
case mtpc_account_noPassword: // should not happen
|
||||
case mtpc_account_noPassword: { // should not happen
|
||||
_code->setFocus();
|
||||
break;
|
||||
} break;
|
||||
|
||||
case mtpc_account_password: {
|
||||
const auto &d(result.c_account_password());
|
||||
intro()->setPwdSalt(qba(d.vcurrent_salt));
|
||||
intro()->setHasRecovery(mtpIsTrue(d.vhas_recovery));
|
||||
intro()->setPwdHint(qs(d.vhint));
|
||||
intro()->replaceStep(new IntroPwdCheck(intro()));
|
||||
auto &d = result.c_account_password();
|
||||
getData()->pwdSalt = qba(d.vcurrent_salt);
|
||||
getData()->hasRecovery = mtpIsTrue(d.vhas_recovery);
|
||||
getData()->pwdHint = qs(d.vhint);
|
||||
goReplace(new Intro::PwdCheckWidget(parentWidget(), getData()));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void IntroCode::onSubmitCode() {
|
||||
void CodeWidget::submit() {
|
||||
if (_sentRequest) return;
|
||||
|
||||
_code->setDisabled(true);
|
||||
setFocus();
|
||||
|
||||
showError(QString());
|
||||
hideError();
|
||||
|
||||
_checkRequest->start(1000);
|
||||
|
||||
_sentCode = _code->text();
|
||||
intro()->setPwdSalt(QByteArray());
|
||||
intro()->setHasRecovery(false);
|
||||
intro()->setPwdHint(QString());
|
||||
_sentRequest = MTP::send(MTPauth_SignIn(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash()), MTP_string(_sentCode)), rpcDone(&IntroCode::codeSubmitDone), rpcFail(&IntroCode::codeSubmitFail));
|
||||
_sentCode = _code->getLastText();
|
||||
getData()->pwdSalt = QByteArray();
|
||||
getData()->hasRecovery = false;
|
||||
getData()->pwdHint = QString();
|
||||
_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;
|
||||
_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) {
|
||||
showError(lang(lng_server_error));
|
||||
showCodeError(lang(lng_server_error));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &d(result.c_auth_sentCode());
|
||||
switch (d.vtype.type()) {
|
||||
case mtpc_auth_sentCodeTypeApp: intro()->setCodeByTelegram(true);
|
||||
case mtpc_auth_sentCodeTypeSms:
|
||||
case mtpc_auth_sentCodeTypeCall: intro()->setCodeByTelegram(false);
|
||||
case mtpc_auth_sentCodeTypeFlashCall: LOG(("Error: should not be flashcall!")); break;
|
||||
}
|
||||
auto &d = result.c_auth_sentCode();
|
||||
fillSentCodeData(d.vtype);
|
||||
_code->setDigitsCountMax(getData()->codeLength);
|
||||
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 {
|
||||
intro()->setCallStatus({ IntroWidget::CallDisabled, 0 });
|
||||
getData()->callStatus = Widget::Data::CallStatus::Disabled;
|
||||
getData()->callTimeout = 0;
|
||||
}
|
||||
intro()->setCodeByTelegram(false);
|
||||
getData()->codeByTelegram = false;
|
||||
updateDescText();
|
||||
}
|
||||
|
||||
bool IntroCode::noTelegramCodeFail(const RPCError &error) {
|
||||
bool CodeWidget::noTelegramCodeFail(const RPCError &error) {
|
||||
if (MTP::isFloodError(error)) {
|
||||
showError(lang(lng_flood_error));
|
||||
_code->setFocus();
|
||||
showCodeError(lang(lng_flood_error));
|
||||
return true;
|
||||
}
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
|
||||
if (cDebug()) { // internal server error
|
||||
showError(error.type() + ": " + error.description());
|
||||
showCodeError(error.type() + ": " + error.description());
|
||||
} else {
|
||||
showError(lang(lng_server_error));
|
||||
showCodeError(lang(lng_server_error));
|
||||
}
|
||||
_code->setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntroCode::onSubmit() {
|
||||
onSubmitCode();
|
||||
}
|
||||
} // namespace Intro
|
||||
|
@@ -26,55 +26,63 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
class LinkButton;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
class CodeInput final : public Ui::FlatInput {
|
||||
namespace Intro {
|
||||
|
||||
class CodeInput final : public Ui::MaskedInputField {
|
||||
Q_OBJECT
|
||||
|
||||
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:
|
||||
void codeEntered();
|
||||
|
||||
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
|
||||
|
||||
public:
|
||||
IntroCode(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void step_error(float64 ms, bool timer);
|
||||
CodeWidget(QWidget *parent, Widget::Data *data);
|
||||
|
||||
bool hasBack() const override {
|
||||
return true;
|
||||
}
|
||||
void setInnerFocus() override;
|
||||
void activate() override;
|
||||
void finished() override;
|
||||
void cancelled() override;
|
||||
void onSubmit() override;
|
||||
|
||||
void codeSubmitDone(const MTPauth_Authorization &result);
|
||||
bool codeSubmitFail(const RPCError &error);
|
||||
void submit() override;
|
||||
|
||||
void updateDescText();
|
||||
|
||||
public slots:
|
||||
void onSubmitCode();
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
private slots:
|
||||
void onNoTelegramCode();
|
||||
void onInputChange();
|
||||
void onSendCall();
|
||||
void onCheckRequest();
|
||||
|
||||
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 gotPassword(const MTPaccount_Password &result);
|
||||
|
||||
@@ -83,23 +91,21 @@ private:
|
||||
|
||||
void stopCheck();
|
||||
|
||||
QString _error;
|
||||
anim::fvalue a_errorAlpha;
|
||||
Animation _a_error;
|
||||
|
||||
ChildWidget<Ui::RoundButton> _next;
|
||||
|
||||
Text _desc;
|
||||
ChildWidget<Ui::LinkButton> _noTelegramCode;
|
||||
mtpRequestId _noTelegramCodeRequestId;
|
||||
QRect _textRect;
|
||||
mtpRequestId _noTelegramCodeRequestId = 0;
|
||||
|
||||
ChildWidget<CodeInput> _code;
|
||||
QString _sentCode;
|
||||
mtpRequestId _sentRequest = 0;
|
||||
|
||||
ChildObject<QTimer> _callTimer;
|
||||
IntroWidget::CallStatus _callStatus;
|
||||
Widget::Data::CallStatus _callStatus;
|
||||
int _callTimeout;
|
||||
mtpRequestId _callRequestId = 0;
|
||||
ChildWidget<Ui::FlatLabel> _callLabel;
|
||||
|
||||
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 "ui/widgets/buttons.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)
|
||||
, a_errorAlpha(0)
|
||||
, _a_error(animation(this, &IntroPhone::step_error))
|
||||
, _next(this, lang(lng_intro_next), st::introNextButton)
|
||||
namespace Intro {
|
||||
|
||||
PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||
, _country(this, st::introCountry)
|
||||
, _phone(this, st::introPhone)
|
||||
, _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) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitPhone()));
|
||||
connect(_phone, SIGNAL(voidBackspace(QKeyEvent*)), _code, SLOT(startErasing(QKeyEvent*)));
|
||||
connect(_country, SIGNAL(codeChanged(const QString &)), _code, SLOT(codeSelected(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(_phone, 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()));
|
||||
|
||||
_signup->setLink(1, MakeShared<LambdaClickHandler>([this] {
|
||||
toSignUp();
|
||||
}));
|
||||
_signup->hide();
|
||||
setTitleText(lang(lng_phone_title));
|
||||
setDescriptionText(lang(lng_phone_desc));
|
||||
subscribe(getData()->updated, [this] { countryChanged(); });
|
||||
setErrorCentered(true);
|
||||
|
||||
_signupCache = myGrab(_signup);
|
||||
|
||||
if (!_country->onChooseCountry(intro()->currentCountry())) {
|
||||
if (!_country->onChooseCountry(getData()->country)) {
|
||||
_country->onChooseCountry(qsl("US"));
|
||||
}
|
||||
_changed = false;
|
||||
}
|
||||
|
||||
void IntroPhone::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
void PhoneWidget::resizeEvent(QResizeEvent *e) {
|
||||
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);
|
||||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
}
|
||||
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 PhoneWidget::updateSignupGeometry() {
|
||||
if (_signup) {
|
||||
_signup->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introDescriptionTop);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPhone::resizeEvent(QResizeEvent *e) {
|
||||
if (e->oldSize().width() != width()) {
|
||||
_next->move((width() - _next->width()) / 2, st::introBtnTop);
|
||||
_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 PhoneWidget::showPhoneError(const QString &text) {
|
||||
_phone->showError();
|
||||
showError(text);
|
||||
}
|
||||
|
||||
void IntroPhone::showError(const QString &error, bool signUp) {
|
||||
if (!error.isEmpty()) {
|
||||
_phone->notaBene();
|
||||
_showSignup = signUp;
|
||||
void PhoneWidget::hidePhoneError() {
|
||||
hideError();
|
||||
if (_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) {
|
||||
float64 dt = ms / st::introErrorDuration;
|
||||
|
||||
if (dt >= 1) {
|
||||
_a_error.stop();
|
||||
a_errorAlpha.finish();
|
||||
if (!a_errorAlpha.current()) {
|
||||
_error.clear();
|
||||
_signup->hide();
|
||||
} else if (!_error.isEmpty() && _showSignup) {
|
||||
_signup->show();
|
||||
}
|
||||
} else {
|
||||
a_errorAlpha.update(dt, anim::linear);
|
||||
void PhoneWidget::showSignup() {
|
||||
showPhoneError(lang(lng_bad_phone_noreg));
|
||||
if (!_signup) {
|
||||
auto signupText = lng_phone_notreg(lt_link_start, textcmdStartLink(1), lt_link_end, textcmdStopLink(), lt_signup_start, textcmdStartLink(2), lt_signup_end, textcmdStopLink());
|
||||
auto inner = new Ui::FlatLabel(this, signupText, Ui::FlatLabel::InitType::Rich, st::introDescription, st::introDescriptionTextStyle);
|
||||
_signup.create(this, inner, base::lambda<void()>(), st::introErrorDuration);
|
||||
_signup->entity()->setLink(1, MakeShared<UrlClickHandler>(qsl("https://telegram.org"), false));
|
||||
_signup->entity()->setLink(2, MakeShared<LambdaClickHandler>([this] {
|
||||
toSignUp();
|
||||
}));
|
||||
_signup->hideFast();
|
||||
updateSignupGeometry();
|
||||
}
|
||||
if (timer) update();
|
||||
_signup->fadeIn();
|
||||
hideDescription();
|
||||
}
|
||||
|
||||
void IntroPhone::countryChanged() {
|
||||
void PhoneWidget::countryChanged() {
|
||||
if (!_changed) {
|
||||
selectCountry(intro()->currentCountry());
|
||||
selectCountry(getData()->country);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPhone::onInputChange() {
|
||||
void PhoneWidget::onInputChange() {
|
||||
_changed = true;
|
||||
showError(QString());
|
||||
hidePhoneError();
|
||||
}
|
||||
|
||||
void IntroPhone::disableAll() {
|
||||
_next->setDisabled(true);
|
||||
void PhoneWidget::disableAll() {
|
||||
_phone->setDisabled(true);
|
||||
_country->setDisabled(true);
|
||||
_code->setDisabled(true);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::enableAll(bool failed) {
|
||||
_next->setDisabled(false);
|
||||
void PhoneWidget::enableAll(bool failed) {
|
||||
_phone->setDisabled(false);
|
||||
_country->setDisabled(false);
|
||||
_code->setDisabled(false);
|
||||
if (failed) _phone->setFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::onSubmitPhone() {
|
||||
void PhoneWidget::submit() {
|
||||
if (_sentRequest || isHidden()) return;
|
||||
|
||||
if (!App::isValidPhone(fullNumber())) {
|
||||
showError(lang(lng_bad_phone));
|
||||
showPhoneError(lang(lng_bad_phone));
|
||||
_phone->setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
disableAll();
|
||||
showError(QString());
|
||||
hidePhoneError();
|
||||
|
||||
_checkRequest->start(1000);
|
||||
|
||||
_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();
|
||||
}
|
||||
|
||||
void IntroPhone::onCheckRequest() {
|
||||
void PhoneWidget::onCheckRequest() {
|
||||
int32 status = MTP::state(_sentRequest);
|
||||
if (status < 0) {
|
||||
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();
|
||||
|
||||
const auto &d(result.c_auth_checkedPhone());
|
||||
auto &d = result.c_auth_checkedPhone();
|
||||
if (mtpIsTrue(d.vphone_registered)) {
|
||||
disableAll();
|
||||
showError(QString());
|
||||
hidePhoneError();
|
||||
|
||||
_checkRequest->start(1000);
|
||||
|
||||
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 {
|
||||
showError(lang(lng_bad_phone_noreg), true);
|
||||
showSignup();
|
||||
enableAll(true);
|
||||
_sentRequest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPhone::phoneSubmitDone(const MTPauth_SentCode &result) {
|
||||
void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) {
|
||||
stopCheck();
|
||||
_sentRequest = 0;
|
||||
enableAll(true);
|
||||
|
||||
if (result.type() != mtpc_auth_sentCode) {
|
||||
showError(lang(lng_server_error));
|
||||
showPhoneError(lang(lng_server_error));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &d(result.c_auth_sentCode());
|
||||
switch (d.vtype.type()) {
|
||||
case mtpc_auth_sentCodeTypeApp: intro()->setCodeByTelegram(true); break;
|
||||
case mtpc_auth_sentCodeTypeSms:
|
||||
case mtpc_auth_sentCodeTypeCall: intro()->setCodeByTelegram(false); break;
|
||||
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());
|
||||
auto &d = result.c_auth_sentCode();
|
||||
fillSentCodeData(d.vtype);
|
||||
getData()->phone = _sentPhone;
|
||||
getData()->phoneHash = d.vphone_code_hash.c_string().v.c_str();
|
||||
getData()->phoneIsRegistered = d.is_phone_registered();
|
||||
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 {
|
||||
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();
|
||||
showError(QString());
|
||||
hideError(); // Hide error, but leave the signup label visible.
|
||||
|
||||
_checkRequest->start(1000);
|
||||
|
||||
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)) {
|
||||
stopCheck();
|
||||
_sentRequest = 0;
|
||||
showError(lang(lng_flood_error));
|
||||
showPhoneError(lang(lng_flood_error));
|
||||
enableAll(true);
|
||||
return true;
|
||||
}
|
||||
@@ -271,48 +232,50 @@ bool IntroPhone::phoneSubmitFail(const RPCError &error) {
|
||||
_sentRequest = 0;
|
||||
const QString &err = error.type();
|
||||
if (err == qstr("PHONE_NUMBER_INVALID")) { // show error
|
||||
showError(lang(lng_bad_phone));
|
||||
showPhoneError(lang(lng_bad_phone));
|
||||
enableAll(true);
|
||||
return true;
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
showError(err + ": " + error.description());
|
||||
showPhoneError(err + ": " + error.description());
|
||||
} else {
|
||||
showError(lang(lng_server_error));
|
||||
showPhoneError(lang(lng_server_error));
|
||||
}
|
||||
enableAll(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString IntroPhone::fullNumber() const {
|
||||
return _code->text() + _phone->text();
|
||||
QString PhoneWidget::fullNumber() const {
|
||||
return _code->getLastText() + _phone->getLastText();
|
||||
}
|
||||
|
||||
void IntroPhone::selectCountry(const QString &c) {
|
||||
void PhoneWidget::selectCountry(const QString &c) {
|
||||
_country->onChooseCountry(c);
|
||||
}
|
||||
|
||||
void IntroPhone::activate() {
|
||||
IntroStep::activate();
|
||||
void PhoneWidget::setInnerFocus() {
|
||||
_phone->setFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::finished() {
|
||||
IntroStep::finished();
|
||||
void PhoneWidget::activate() {
|
||||
Step::activate();
|
||||
_country->show();
|
||||
_phone->show();
|
||||
_code->show();
|
||||
setInnerFocus();
|
||||
}
|
||||
|
||||
void PhoneWidget::finished() {
|
||||
Step::finished();
|
||||
_checkRequest->stop();
|
||||
rpcClear();
|
||||
|
||||
_error.clear();
|
||||
a_errorAlpha = anim::fvalue(0);
|
||||
cancelled();
|
||||
enableAll(true);
|
||||
}
|
||||
|
||||
void IntroPhone::cancelled() {
|
||||
if (_sentRequest) {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
}
|
||||
void PhoneWidget::cancelled() {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
}
|
||||
|
||||
void IntroPhone::onSubmit() {
|
||||
onSubmitPhone();
|
||||
}
|
||||
} // namespace Intro
|
||||
|
@@ -30,35 +30,41 @@ class RoundButton;
|
||||
class FlatLabel;
|
||||
} // namespace Ui
|
||||
|
||||
class IntroPhone final : public IntroStep {
|
||||
namespace Intro {
|
||||
|
||||
class PhoneWidget : public Widget::Step, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntroPhone(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void step_error(float64 ms, bool timer);
|
||||
PhoneWidget(QWidget *parent, Widget::Data *data);
|
||||
|
||||
void selectCountry(const QString &country);
|
||||
|
||||
void setInnerFocus() override;
|
||||
void activate() override;
|
||||
void finished() 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 phoneSubmitDone(const MTPauth_SentCode &result);
|
||||
bool phoneSubmitFail(const RPCError &error);
|
||||
|
||||
public slots:
|
||||
void countryChanged();
|
||||
void onInputChange();
|
||||
void onSubmitPhone();
|
||||
void onCheckRequest();
|
||||
|
||||
private:
|
||||
void toSignUp();
|
||||
|
||||
QString fullNumber() const;
|
||||
@@ -66,24 +72,17 @@ private:
|
||||
void enableAll(bool failed);
|
||||
void stopCheck();
|
||||
|
||||
void showError(const QString &err, bool signUp = false);
|
||||
|
||||
QString _error;
|
||||
anim::fvalue a_errorAlpha;
|
||||
Animation _a_error;
|
||||
void showPhoneError(const QString &text);
|
||||
void hidePhoneError();
|
||||
void showSignup();
|
||||
|
||||
bool _changed = false;
|
||||
ChildWidget<Ui::RoundButton> _next;
|
||||
|
||||
QRect _textRect;
|
||||
|
||||
ChildWidget<CountryInput> _country;
|
||||
ChildWidget<Ui::PhonePartInput> _phone;
|
||||
ChildWidget<Ui::CountryCodeInput> _code;
|
||||
ChildWidget<Ui::PhonePartInput> _phone;
|
||||
|
||||
ChildWidget<Ui::FlatLabel> _signup;
|
||||
QPixmap _signupCache;
|
||||
bool _showSignup = false;
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::FlatLabel>> _signup = { nullptr };
|
||||
|
||||
QString _sentPhone;
|
||||
mtpRequestId _sentRequest = 0;
|
||||
@@ -91,3 +90,5 @@ private:
|
||||
ChildObject<QTimer> _checkRequest;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Intro
|
||||
|
@@ -30,117 +30,52 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "intro/introsignup.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
||||
IntroPwdCheck::IntroPwdCheck(IntroWidget *parent) : IntroStep(parent)
|
||||
, a_errorAlpha(0)
|
||||
, _a_error(animation(this, &IntroPwdCheck::step_error))
|
||||
, _next(this, lang(lng_intro_submit), st::introNextButton)
|
||||
, _salt(parent->getPwdSalt())
|
||||
, _hasRecovery(parent->getHasRecovery())
|
||||
, _hint(parent->getPwdHint())
|
||||
namespace Intro {
|
||||
|
||||
PwdCheckWidget::PwdCheckWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||
, _salt(getData()->pwdSalt)
|
||||
, _hasRecovery(getData()->hasRecovery)
|
||||
, _hint(getData()->pwdHint)
|
||||
, _pwdField(this, st::introPassword, lang(lng_signin_password))
|
||||
, _pwdHint(this, st::introPasswordHint, st::introPasswordHintTextStyle)
|
||||
, _codeField(this, st::introPassword, lang(lng_signin_code))
|
||||
, _toRecover(this, lang(lng_signin_recover))
|
||||
, _toPassword(this, lang(lng_signin_try_password))
|
||||
, _reset(this, lang(lng_signin_reset_account), st::introResetLink)
|
||||
, _checkRequest(this) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitPwd()));
|
||||
connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||
connect(_toRecover, SIGNAL(clicked()), this, SLOT(onToRecover()));
|
||||
connect(_toPassword, SIGNAL(clicked()), this, SLOT(onToPassword()));
|
||||
connect(_pwdField, 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()) {
|
||||
_hintText.setText(st::introFont, lng_signin_hint(lt_password_hint, _hint));
|
||||
if (_hint.isEmpty()) {
|
||||
_pwdHint->hide();
|
||||
} else {
|
||||
_pwdHint->setText(lng_signin_hint(lt_password_hint, _hint));
|
||||
}
|
||||
_codeField->hide();
|
||||
_toPassword->hide();
|
||||
_toRecover->show();
|
||||
_reset->hide();
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void IntroPwdCheck::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
|
||||
QPainter p(this);
|
||||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
}
|
||||
if (trivial || e->rect().intersects(_textRect)) {
|
||||
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 PwdCheckWidget::resizeEvent(QResizeEvent *e) {
|
||||
Step::resizeEvent(e);
|
||||
_pwdField->moveToLeft(contentLeft(), contentTop() + st::introPasswordTop);
|
||||
_pwdHint->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introPasswordHintTop);
|
||||
_codeField->moveToLeft(contentLeft(), contentTop() + st::introStepFieldTop);
|
||||
auto linkTop = _codeField->y() + _codeField->height() + st::introLinkTop;
|
||||
_toRecover->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||
_toPassword->moveToLeft(contentLeft() + st::buttonRadius, linkTop);
|
||||
}
|
||||
|
||||
void IntroPwdCheck::resizeEvent(QResizeEvent *e) {
|
||||
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();
|
||||
void PwdCheckWidget::setInnerFocus() {
|
||||
if (_pwdField->isHidden()) {
|
||||
_codeField->setFocus();
|
||||
} else {
|
||||
@@ -148,17 +83,25 @@ void IntroPwdCheck::activate() {
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPwdCheck::cancelled() {
|
||||
if (_sentRequest) {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
void PwdCheckWidget::activate() {
|
||||
if (_pwdField->isHidden() && _codeField->isHidden()) {
|
||||
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();
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onCheckRequest() {
|
||||
void PwdCheckWidget::onCheckRequest() {
|
||||
int32 status = MTP::state(_sentRequest);
|
||||
if (status < 0) {
|
||||
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;
|
||||
stopCheck();
|
||||
if (recover) {
|
||||
@@ -184,22 +127,22 @@ void IntroPwdCheck::pwdSubmitDone(bool recover, const MTPauth_Authorization &res
|
||||
}
|
||||
_pwdField->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?
|
||||
showError(lang(lng_server_error));
|
||||
return;
|
||||
}
|
||||
intro()->finish(d.vuser);
|
||||
finish(d.vuser);
|
||||
}
|
||||
|
||||
bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) {
|
||||
bool PwdCheckWidget::pwdSubmitFail(const RPCError &error) {
|
||||
if (MTP::isFloodError(error)) {
|
||||
_sentRequest = 0;
|
||||
stopCheck();
|
||||
_codeField->setDisabled(false);
|
||||
showError(lang(lng_flood_error));
|
||||
_pwdField->setDisabled(false);
|
||||
_pwdField->notaBene();
|
||||
_pwdField->showError();
|
||||
return true;
|
||||
}
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
@@ -212,10 +155,10 @@ bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) {
|
||||
if (err == qstr("PASSWORD_HASH_INVALID")) {
|
||||
showError(lang(lng_signin_bad_password));
|
||||
_pwdField->selectAll();
|
||||
_pwdField->notaBene();
|
||||
_pwdField->showError();
|
||||
return true;
|
||||
} else if (err == qstr("PASSWORD_EMPTY")) {
|
||||
intro()->onBack();
|
||||
goBack();
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
showError(err + ": " + error.description());
|
||||
@@ -226,10 +169,10 @@ bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||
bool PwdCheckWidget::codeSubmitFail(const RPCError &error) {
|
||||
if (MTP::isFloodError(error)) {
|
||||
showError(lang(lng_flood_error));
|
||||
_codeField->notaBene();
|
||||
_codeField->showError();
|
||||
return true;
|
||||
}
|
||||
if (MTP::isDefaultHandledError(error)) return false;
|
||||
@@ -240,7 +183,7 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||
_codeField->setDisabled(false);
|
||||
const QString &err = error.type();
|
||||
if (err == qstr("PASSWORD_EMPTY")) {
|
||||
intro()->onBack();
|
||||
goBack();
|
||||
return true;
|
||||
} else if (err == qstr("PASSWORD_RECOVERY_NA")) {
|
||||
recoverStartFail(error);
|
||||
@@ -252,7 +195,7 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||
} else if (err == qstr("CODE_INVALID")) {
|
||||
showError(lang(lng_signin_wrong_code));
|
||||
_codeField->selectAll();
|
||||
_codeField->notaBene();
|
||||
_codeField->showError();
|
||||
return true;
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
@@ -264,39 +207,42 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntroPwdCheck::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());
|
||||
update();
|
||||
void PwdCheckWidget::recoverStarted(const MTPauth_PasswordRecovery &result) {
|
||||
_emailPattern = qs(result.c_auth_passwordRecovery().vemail_pattern);
|
||||
updateDescriptionText();
|
||||
}
|
||||
|
||||
bool IntroPwdCheck::recoverStartFail(const RPCError &error) {
|
||||
bool PwdCheckWidget::recoverStartFail(const RPCError &error) {
|
||||
stopCheck();
|
||||
_pwdField->setDisabled(false);
|
||||
_codeField->setDisabled(false);
|
||||
_pwdField->show();
|
||||
_pwdHint->show();
|
||||
_codeField->hide();
|
||||
_pwdField->setFocus();
|
||||
updateDescriptionText();
|
||||
update();
|
||||
showError(QString());
|
||||
hideError();
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onToRecover() {
|
||||
void PwdCheckWidget::onToRecover() {
|
||||
if (_hasRecovery) {
|
||||
if (_sentRequest) {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
}
|
||||
showError(QString());
|
||||
hideError();
|
||||
_toRecover->hide();
|
||||
_toPassword->show();
|
||||
_pwdField->hide();
|
||||
_pwdHint->hide();
|
||||
_pwdField->setText(QString());
|
||||
_codeField->show();
|
||||
_codeField->setFocus();
|
||||
updateDescriptionText();
|
||||
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 {
|
||||
ConfirmBox *box = new InformBox(lang(lng_signin_no_email_forgot));
|
||||
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));
|
||||
Ui::showLayer(box);
|
||||
connect(box, SIGNAL(destroyed(QObject*)), this, SLOT(onToReset()));
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onToReset() {
|
||||
void PwdCheckWidget::onToReset() {
|
||||
if (_sentRequest) {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
}
|
||||
_toRecover->show();
|
||||
_toPassword->hide();
|
||||
_pwdField->show();
|
||||
_pwdHint->show();
|
||||
_codeField->hide();
|
||||
_codeField->setText(QString());
|
||||
_pwdField->setFocus();
|
||||
_reset->show();
|
||||
showResetButton();
|
||||
updateDescriptionText();
|
||||
update();
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onReset() {
|
||||
if (_sentRequest) return;
|
||||
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 PwdCheckWidget::updateDescriptionText() {
|
||||
setDescriptionText(_pwdField->isHidden() ? lng_signin_recover_desc(lt_email, _emailPattern) : lang(lng_signin_desc));
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onResetSure() {
|
||||
if (_sentRequest) return;
|
||||
_sentRequest = MTP::send(MTPaccount_DeleteAccount(MTP_string("Forgot password")), rpcDone(&IntroPwdCheck::deleteDone), rpcFail(&IntroPwdCheck::deleteFail));
|
||||
void PwdCheckWidget::onInputChange() {
|
||||
hideError();
|
||||
}
|
||||
|
||||
bool IntroPwdCheck::deleteFail(const RPCError &error) {
|
||||
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) {
|
||||
void PwdCheckWidget::submit() {
|
||||
if (_sentRequest) return;
|
||||
if (_pwdField->isHidden()) {
|
||||
if (!force && !_codeField->isEnabled()) return;
|
||||
QString code = _codeField->text().trimmed();
|
||||
if (!_codeField->isEnabled()) return;
|
||||
auto code = _codeField->getLastText().trimmed();
|
||||
if (code.isEmpty()) {
|
||||
_codeField->notaBene();
|
||||
_codeField->showError();
|
||||
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 {
|
||||
if (!force && !_pwdField->isEnabled()) return;
|
||||
if (!_pwdField->isEnabled()) return;
|
||||
|
||||
_pwdField->setDisabled(true);
|
||||
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());
|
||||
_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() {
|
||||
onSubmitPwd();
|
||||
QString PwdCheckWidget::nextButtonText() const {
|
||||
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"
|
||||
|
||||
namespace Ui {
|
||||
class FlatInput;
|
||||
class InputField;
|
||||
class PasswordInput;
|
||||
class RoundButton;
|
||||
class LinkButton;
|
||||
} // namespace Ui
|
||||
|
||||
class IntroPwdCheck final : public IntroStep {
|
||||
namespace Intro {
|
||||
|
||||
class PwdCheckWidget : public Widget::Step {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntroPwdCheck(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void step_error(float64 ms, bool timer);
|
||||
PwdCheckWidget(QWidget *parent, Widget::Data *data);
|
||||
|
||||
void setInnerFocus() override;
|
||||
void activate() 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);
|
||||
bool pwdSubmitFail(const RPCError &error);
|
||||
bool codeSubmitFail(const RPCError &error);
|
||||
@@ -50,46 +61,24 @@ public:
|
||||
|
||||
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
||||
|
||||
public slots:
|
||||
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 updateDescriptionText();
|
||||
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;
|
||||
bool _hasRecovery;
|
||||
QString _hint, _emailPattern;
|
||||
|
||||
ChildWidget<Ui::FlatInput> _pwdField;
|
||||
ChildWidget<Ui::FlatInput> _codeField;
|
||||
ChildWidget<Ui::PasswordInput> _pwdField;
|
||||
ChildWidget<Ui::FlatLabel> _pwdHint;
|
||||
ChildWidget<Ui::InputField> _codeField;
|
||||
ChildWidget<Ui::LinkButton> _toRecover;
|
||||
ChildWidget<Ui::LinkButton> _toPassword;
|
||||
ChildWidget<Ui::LinkButton> _reset;
|
||||
mtpRequestId _sentRequest = 0;
|
||||
|
||||
Text _hintText;
|
||||
|
||||
QByteArray _pwdSalt;
|
||||
|
||||
ChildObject<QTimer> _checkRequest;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Intro
|
||||
|
@@ -29,200 +29,106 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "application.h"
|
||||
#include "ui/widgets/buttons.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)
|
||||
, a_errorAlpha(0)
|
||||
, a_photoOver(0)
|
||||
, _a_error(animation(this, &IntroSignup::step_error))
|
||||
, _a_photo(animation(this, &IntroSignup::step_photo))
|
||||
, _next(this, lang(lng_intro_finish), st::introNextButton)
|
||||
namespace Intro {
|
||||
|
||||
SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
|
||||
, _photo(this, st::introPhotoSize, st::introPhotoIconPosition)
|
||||
, _first(this, st::introName, lang(lng_signup_firstname))
|
||||
, _last(this, st::introName, lang(lng_signup_lastname))
|
||||
, _invertOrder(langFirstNameGoesSecond())
|
||||
, _checkRequest(this) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(_next, SIGNAL(clicked()), this, SLOT(onSubmitName()));
|
||||
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) {
|
||||
setTabOrder(_last, _first);
|
||||
}
|
||||
setErrorCentered(true);
|
||||
|
||||
setTitleText(lang(lng_signup_title));
|
||||
setDescriptionText(lang(lng_signup_desc));
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void IntroSignup::mouseMoveEvent(QMouseEvent *e) {
|
||||
bool photoOver = QRect(_phLeft, _phTop, st::introPhotoSize, st::introPhotoSize).contains(e->pos());
|
||||
if (photoOver != _photoOver) {
|
||||
_photoOver = photoOver;
|
||||
if (_photoSmall.isNull()) {
|
||||
a_photoOver.start(_photoOver ? 1 : 0);
|
||||
_a_photo.start();
|
||||
}
|
||||
void SignupWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
||||
if (_readPhotoFileQueryId != update.queryId) {
|
||||
return;
|
||||
}
|
||||
_readPhotoFileQueryId = 0;
|
||||
if (update.remoteContent.isEmpty() && update.filePaths.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCursor(_photoOver ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
|
||||
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);
|
||||
QImage img;
|
||||
if (!update.remoteContent.isEmpty()) {
|
||||
img = App::readImage(update.remoteContent);
|
||||
} 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) {
|
||||
_phLeft = (width() - _next->width()) / 2;
|
||||
_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 SignupWidget::resizeEvent(QResizeEvent *e) {
|
||||
Step::resizeEvent(e);
|
||||
|
||||
void IntroSignup::showError(const QString &err) {
|
||||
if (!_a_error.animating() && err == error) return;
|
||||
auto photoRight = contentLeft() + st::introNextButton.width;
|
||||
auto photoTop = contentTop() + st::introPhotoTop;
|
||||
_photo->moveToLeft(photoRight - _photo->width(), photoTop);
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
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();
|
||||
auto firstTop = contentTop() + st::introStepFieldTop;
|
||||
auto secondTop = firstTop + st::introName.height + st::introPhoneTop;
|
||||
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();
|
||||
} else {
|
||||
_first->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSignup::cancelled() {
|
||||
if (_sentRequest) {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
}
|
||||
void SignupWidget::activate() {
|
||||
Step::activate();
|
||||
_first->show();
|
||||
_last->show();
|
||||
_photo->show();
|
||||
setInnerFocus();
|
||||
}
|
||||
|
||||
void IntroSignup::stopCheck() {
|
||||
void SignupWidget::cancelled() {
|
||||
MTP::cancel(base::take(_sentRequest));
|
||||
}
|
||||
|
||||
void SignupWidget::stopCheck() {
|
||||
_checkRequest->stop();
|
||||
}
|
||||
|
||||
void IntroSignup::onCheckRequest() {
|
||||
void SignupWidget::onCheckRequest() {
|
||||
int32 status = MTP::state(_sentRequest);
|
||||
if (status < 0) {
|
||||
int32 leftms = -status;
|
||||
@@ -244,13 +150,12 @@ void IntroSignup::onCheckRequest() {
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSignup::onPhotoReady(const QImage &img) {
|
||||
_photoBig = img;
|
||||
_photoSmall = App::pixmapFromImageInPlace(img.scaled(st::introPhotoSize * cIntRetinaFactor(), st::introPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
_photoSmall.setDevicePixelRatio(cRetinaFactor());
|
||||
void SignupWidget::onPhotoReady(const QImage &img) {
|
||||
_photoImage = img;
|
||||
_photo->setImage(_photoImage);
|
||||
}
|
||||
|
||||
void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) {
|
||||
void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) {
|
||||
stopCheck();
|
||||
_first->setDisabled(false);
|
||||
_last->setDisabled(false);
|
||||
@@ -259,10 +164,10 @@ void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) {
|
||||
showError(lang(lng_server_error));
|
||||
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)) {
|
||||
stopCheck();
|
||||
_first->setDisabled(false);
|
||||
@@ -284,7 +189,7 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) {
|
||||
if (err == qstr("PHONE_NUMBER_INVALID") || err == qstr("PHONE_CODE_EXPIRED") ||
|
||||
err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID") ||
|
||||
err == qstr("PHONE_NUMBER_OCCUPIED")) {
|
||||
intro()->onBack();
|
||||
goBack();
|
||||
return true;
|
||||
} else if (err == "FIRSTNAME_INVALID") {
|
||||
showError(lang(lng_bad_name));
|
||||
@@ -308,29 +213,29 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntroSignup::onInputChange() {
|
||||
void SignupWidget::onInputChange() {
|
||||
showError(QString());
|
||||
}
|
||||
|
||||
void IntroSignup::onSubmitName(bool force) {
|
||||
void SignupWidget::submit() {
|
||||
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();
|
||||
return;
|
||||
} else if (!_last->text().trimmed().length()) {
|
||||
} else if (!_last->getLastText().trimmed().length()) {
|
||||
_last->setFocus();
|
||||
return;
|
||||
}
|
||||
} 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();
|
||||
return;
|
||||
} else if (!_first->text().trimmed().length()) {
|
||||
} else if (!_first->getLastText().trimmed().length()) {
|
||||
_first->setFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!force && !_first->isEnabled()) return;
|
||||
if (!_first->isEnabled()) return;
|
||||
|
||||
_first->setDisabled(true);
|
||||
_last->setDisabled(true);
|
||||
@@ -338,11 +243,13 @@ void IntroSignup::onSubmitName(bool force) {
|
||||
|
||||
showError(QString());
|
||||
|
||||
_firstName = _first->text().trimmed();
|
||||
_lastName = _last->text().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));
|
||||
_firstName = _first->getLastText().trimmed();
|
||||
_lastName = _last->getLastText().trimmed();
|
||||
_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() {
|
||||
onSubmitName();
|
||||
QString SignupWidget::nextButtonText() const {
|
||||
return lang(lng_intro_finish);
|
||||
}
|
||||
|
||||
} // namespace Intro
|
||||
|
@@ -21,64 +21,58 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#pragma once
|
||||
|
||||
#include "intro/introwidget.h"
|
||||
#include "ui/filedialog.h"
|
||||
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
class FlatInput;
|
||||
class InputField;
|
||||
class NewAvatarButton;
|
||||
} // namespace Ui
|
||||
|
||||
class IntroSignup final : public IntroStep {
|
||||
namespace Intro {
|
||||
|
||||
class SignupWidget : public Widget::Step, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntroSignup(IntroWidget *parent);
|
||||
|
||||
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);
|
||||
SignupWidget(QWidget *parent, Widget::Data *data);
|
||||
|
||||
void setInnerFocus() override;
|
||||
void activate() override;
|
||||
void cancelled() override;
|
||||
void onSubmit() override;
|
||||
void submit() override;
|
||||
QString nextButtonText() const override;
|
||||
|
||||
void nameSubmitDone(const MTPauth_Authorization &result);
|
||||
bool nameSubmitFail(const RPCError &error);
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
public slots:
|
||||
void onSubmitName(bool force = false);
|
||||
private slots:
|
||||
void onInputChange();
|
||||
void onCheckRequest();
|
||||
void onPhotoReady(const QImage &img);
|
||||
|
||||
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();
|
||||
|
||||
QString error;
|
||||
anim::fvalue a_errorAlpha, a_photoOver;
|
||||
Animation _a_error;
|
||||
Animation _a_photo;
|
||||
QImage _photoImage;
|
||||
|
||||
ChildWidget<Ui::RoundButton> _next;
|
||||
|
||||
QRect _textRect;
|
||||
|
||||
bool _photoOver = false;
|
||||
QImage _photoBig;
|
||||
QPixmap _photoSmall;
|
||||
int32 _phLeft, _phTop;
|
||||
|
||||
ChildWidget<Ui::FlatInput> _first;
|
||||
ChildWidget<Ui::FlatInput> _last;
|
||||
ChildWidget<Ui::NewAvatarButton> _photo;
|
||||
ChildWidget<Ui::InputField> _first;
|
||||
ChildWidget<Ui::InputField> _last;
|
||||
QString _firstName, _lastName;
|
||||
mtpRequestId _sentRequest = 0;
|
||||
|
||||
FileDialog::QueryId _readPhotoFileQueryId = 0;
|
||||
|
||||
bool _invertOrder = false;
|
||||
|
||||
ChildObject<QTimer> _checkRequest;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Intro
|
||||
|
@@ -24,67 +24,24 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "lang.h"
|
||||
#include "application.h"
|
||||
#include "intro/introphone.h"
|
||||
#include "langloaderplain.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
||||
IntroStart::IntroStart(IntroWidget *parent) : IntroStep(parent)
|
||||
, _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()));
|
||||
namespace Intro {
|
||||
|
||||
StartWidget::StartWidget(QWidget *parent, Widget::Data *data) : Step(parent, data, true) {
|
||||
setMouseTracking(true);
|
||||
setTitleText(qsl("Telegram Desktop"));
|
||||
setDescriptionText(lang(lng_intro_about));
|
||||
show();
|
||||
}
|
||||
|
||||
void IntroStart::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
|
||||
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 StartWidget::submit() {
|
||||
goNext(new Intro::PhoneWidget(parentWidget(), getData()));
|
||||
}
|
||||
|
||||
void IntroStart::resizeEvent(QResizeEvent *e) {
|
||||
if (e->oldSize().width() != width()) {
|
||||
_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());
|
||||
}
|
||||
QString StartWidget::nextButtonText() const {
|
||||
return lang(lng_start_msgs);
|
||||
}
|
||||
|
||||
void IntroStart::onSubmit() {
|
||||
intro()->nextStep(new IntroPhone(intro()));
|
||||
}
|
||||
} // namespace Intro
|
||||
|
@@ -28,22 +28,15 @@ class LinkButton;
|
||||
class RoundButton;
|
||||
} // namespace Ui
|
||||
|
||||
class IntroStart final : public IntroStep {
|
||||
namespace Intro {
|
||||
|
||||
class StartWidget : public Widget::Step {
|
||||
public:
|
||||
IntroStart(IntroWidget *parent);
|
||||
StartWidget(QWidget *parent, Widget::Data *data);
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void onSubmit() override;
|
||||
|
||||
private:
|
||||
ChildWidget<Ui::FlatLabel> _intro;
|
||||
|
||||
ChildWidget<Ui::LinkButton> _changeLang;
|
||||
|
||||
ChildWidget<Ui::RoundButton> _next;
|
||||
|
||||
int32 _headerWidth = 0;
|
||||
void submit() override;
|
||||
QString nextButtonText() const override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Intro
|
||||
|
@@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "lang.h"
|
||||
#include "localstorage.h"
|
||||
#include "langloaderplain.h"
|
||||
#include "intro/introstart.h"
|
||||
#include "intro/introphone.h"
|
||||
#include "intro/introcode.h"
|
||||
@@ -31,39 +32,60 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "application.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "ui/text/text.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/effects/widget_fade_wrap.h"
|
||||
#include "styles/style_intro.h"
|
||||
#include "ui/effects/slide_animation.h"
|
||||
#include "autoupdater.h"
|
||||
#include "window/slide_animation.h"
|
||||
#include "window/window_slide_animation.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_intro.h"
|
||||
#include "styles/style_window.h"
|
||||
|
||||
IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
|
||||
, _a_stage(animation(this, &IntroWidget::step_stage))
|
||||
, _a_show(animation(this, &IntroWidget::step_show))
|
||||
namespace Intro {
|
||||
|
||||
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)
|
||||
, _settings(this, lang(lng_menu_settings), st::defaultBoxButton) {
|
||||
_back->entity()->setClickedCallback([this] { onBack(); });
|
||||
, _settings(this, new Ui::RoundButton(this, lang(lng_menu_settings), st::defaultBoxButton), base::lambda<void()>(), st::introCoverDuration)
|
||||
, _next(this, QString(), st::introNextButton) {
|
||||
getData()->country = psCurrentCountry();
|
||||
|
||||
_back->entity()->setClickedCallback([this] { historyMove(Direction::Back); });
|
||||
_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));
|
||||
_back->raise();
|
||||
_settings->raise();
|
||||
MTP::send(MTPhelp_GetNearestDc(), rpcDone(&Widget::gotNearestDC));
|
||||
|
||||
appendStep(new StartWidget(this, getData()));
|
||||
fixOrder();
|
||||
|
||||
show();
|
||||
setFocus();
|
||||
showControls();
|
||||
getStep()->showFast();
|
||||
|
||||
cSetPasswordRecovered(false);
|
||||
|
||||
_back->moveToLeft(0, 0);
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
|
||||
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
|
||||
@@ -74,12 +96,12 @@ IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
|
||||
}
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
void IntroWidget::onCheckUpdateStatus() {
|
||||
void Widget::onCheckUpdateStatus() {
|
||||
if (Sandbox::updatingState() == Application::UpdatingReady) {
|
||||
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();
|
||||
_update->setClickedCallback([] {
|
||||
_update->entity()->setClickedCallback([] {
|
||||
checkReadyUpdate();
|
||||
App::restart();
|
||||
});
|
||||
@@ -91,123 +113,204 @@ void IntroWidget::onCheckUpdateStatus() {
|
||||
}
|
||||
#endif // TDESKTOP_DISABLE_AUTOUPDATE
|
||||
|
||||
void IntroWidget::langChangeTo(int32 langId) {
|
||||
_langChangeTo = langId;
|
||||
}
|
||||
|
||||
void IntroWidget::onChangeLang() {
|
||||
cSetLang(_langChangeTo);
|
||||
void Widget::changeLanguage(int32 languageId) {
|
||||
cSetLang(languageId);
|
||||
Local::writeSettings();
|
||||
App::restart();
|
||||
}
|
||||
|
||||
void IntroWidget::onStepSubmit() {
|
||||
step()->onSubmit();
|
||||
void Widget::setInnerFocus() {
|
||||
if (getStep()->animating()) {
|
||||
setFocus();
|
||||
} else {
|
||||
getStep()->setInnerFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroWidget::onBack() {
|
||||
historyMove(MoveBack);
|
||||
}
|
||||
|
||||
void IntroWidget::historyMove(MoveType type) {
|
||||
if (_a_stage.animating()) return;
|
||||
void Widget::historyMove(Direction direction) {
|
||||
if (getStep()->animating()) return;
|
||||
|
||||
t_assert(_stepHistory.size() > 1);
|
||||
|
||||
if (App::app()) App::app()->mtpPause();
|
||||
|
||||
switch (type) {
|
||||
case MoveBack: {
|
||||
_cacheHide = grabStep();
|
||||
|
||||
IntroStep *back = step();
|
||||
_backFrom = back->hasBack() ? 1 : 0;
|
||||
auto wasStep = getStep((direction == Direction::Back) ? 0 : 1);
|
||||
if (direction == Direction::Back) {
|
||||
_stepHistory.pop_back();
|
||||
back->cancelled();
|
||||
delete back;
|
||||
} 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;
|
||||
wasStep->cancelled();
|
||||
} else if (direction == Direction::Replace) {
|
||||
_stepHistory.removeAt(_stepHistory.size() - 2);
|
||||
replaced->finished();
|
||||
delete replaced;
|
||||
} break;
|
||||
}
|
||||
getStep()->prepareShowAnimated(wasStep);
|
||||
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();
|
||||
_backTo = step()->hasBack() ? 1 : 0;
|
||||
|
||||
int32 m = (type == MoveBack) ? -1 : 1;
|
||||
a_coordHide = anim::ivalue(0, -m * st::introSlideShift);
|
||||
a_opacityHide = anim::fvalue(1, 0);
|
||||
a_coordShow = anim::ivalue(m * st::introSlideShift, 0);
|
||||
a_opacityShow = anim::fvalue(0, 1);
|
||||
_a_stage.start();
|
||||
|
||||
_a_stage.step();
|
||||
if (_backTo) {
|
||||
if (direction == Direction::Forward || direction == Direction::Replace) {
|
||||
wasStep->finished();
|
||||
}
|
||||
if (direction == Direction::Back || direction == Direction::Replace) {
|
||||
delete base::take(wasStep);
|
||||
}
|
||||
if (getStep()->hasBack()) {
|
||||
_back->fadeIn();
|
||||
} else {
|
||||
_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) {
|
||||
_stepHistory.push_back(step);
|
||||
void Widget::fixOrder() {
|
||||
_next->raise();
|
||||
if (_update) _update->raise();
|
||||
_settings->raise();
|
||||
_back->raise();
|
||||
}
|
||||
|
||||
void Widget::moveToStep(Step *step, Direction direction) {
|
||||
appendStep(step);
|
||||
_back->raise();
|
||||
_settings->raise();
|
||||
if (_update) {
|
||||
_update->raise();
|
||||
}
|
||||
_stepHistory.back()->hide();
|
||||
|
||||
historyMove(type);
|
||||
historyMove(direction);
|
||||
}
|
||||
|
||||
void IntroWidget::gotNearestDC(const MTPNearestDc &result) {
|
||||
const auto &nearest(result.c_nearestDc());
|
||||
void Widget::appendStep(Step *step) {
|
||||
_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));
|
||||
MTP::setdc(result.c_nearestDc().vnearest_dc.v, true);
|
||||
if (_countryForReg != nearest.vcountry.c_string().v.c_str()) {
|
||||
_countryForReg = nearest.vcountry.c_string().v.c_str();
|
||||
emit countryChanged();
|
||||
MTP::setdc(nearest.vnearest_dc.v, true);
|
||||
auto nearestCountry = qs(nearest.vcountry);
|
||||
if (getData()->country != nearestCountry) {
|
||||
getData()->country = nearestCountry;
|
||||
getData()->updated.notify();
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap IntroWidget::grabStep(int skip) {
|
||||
return myGrab(step(skip), QRect(st::introSlideShift, 0, st::introSize.width(), st::introSize.height()));
|
||||
void Widget::showControls() {
|
||||
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();
|
||||
|
||||
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
|
||||
|
||||
_a_show.stop();
|
||||
step()->show();
|
||||
_settings->show();
|
||||
if (_update) _update->show();
|
||||
if (step()->hasBack()) {
|
||||
_back->showFast();
|
||||
} else {
|
||||
_back->hideFast();
|
||||
}
|
||||
showControls();
|
||||
(back ? _cacheUnder : _cacheOver) = myGrab(this);
|
||||
|
||||
step()->hide();
|
||||
_back->hideFast();
|
||||
_settings->hide();
|
||||
if (_update) _update->hide();
|
||||
hideControls();
|
||||
|
||||
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift);
|
||||
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
|
||||
@@ -217,7 +320,7 @@ void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||
show();
|
||||
}
|
||||
|
||||
void IntroWidget::step_show(float64 ms, bool timer) {
|
||||
void Widget::step_show(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::slideDuration;
|
||||
if (dt >= 1) {
|
||||
_a_show.stop();
|
||||
@@ -228,13 +331,9 @@ void IntroWidget::step_show(float64 ms, bool timer) {
|
||||
|
||||
_cacheUnder = _cacheOver = QPixmap();
|
||||
|
||||
setFocus();
|
||||
step()->activate();
|
||||
if (step()->hasBack()) {
|
||||
_back->showFast();
|
||||
}
|
||||
_settings->show();
|
||||
if (_update) _update->show();
|
||||
showControls();
|
||||
getStep()->activate();
|
||||
|
||||
if (App::app()) App::app()->mtpUnpause();
|
||||
} else {
|
||||
a_coordUnder.update(dt, Window::SlideAnimation::transition());
|
||||
@@ -244,37 +343,14 @@ void IntroWidget::step_show(float64 ms, bool timer) {
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroWidget::stop_show() {
|
||||
_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) {
|
||||
void Widget::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
setMouseTracking(true);
|
||||
|
||||
if (_coverShownAnimation.animating()) {
|
||||
_coverShownAnimation.step(getms());
|
||||
}
|
||||
|
||||
QPainter p(this);
|
||||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
@@ -290,130 +366,406 @@ void IntroWidget::paintEvent(QPaintEvent *e) {
|
||||
p.drawPixmap(a_coordOver.current(), 0, _cacheOver);
|
||||
p.setOpacity(a_shadow.current());
|
||||
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 {
|
||||
int innerWidth = st::introSize.width() + 2 * st::introSlideShift, innerHeight = st::introSize.height();
|
||||
return QRect((width() - innerWidth) / 2, (height() - innerHeight) / 2, innerWidth, (height() + innerHeight) / 2);
|
||||
QRect Widget::calculateStepRect() const {
|
||||
auto stepInnerTop = (height() - st::introHeight) / 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 {
|
||||
return _countryForReg;
|
||||
}
|
||||
|
||||
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);
|
||||
void Widget::resizeEvent(QResizeEvent *e) {
|
||||
auto stepRect = calculateStepRect();
|
||||
for_const (auto step, _stepHistory) {
|
||||
step->setGeometry(stepRect);
|
||||
}
|
||||
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void IntroWidget::updateControlsGeometry() {
|
||||
_settings->moveToRight(st::boxButtonPadding.right(), st::boxButtonPadding.top());
|
||||
void Widget::moveControls() {
|
||||
}
|
||||
|
||||
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) {
|
||||
_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);
|
||||
|
||||
// "this" is already deleted here by creating the main widget.
|
||||
if (!photo.isNull()) {
|
||||
App::app()->uploadProfilePhoto(photo, MTP::authedId());
|
||||
}
|
||||
}
|
||||
|
||||
void IntroWidget::keyPressEvent(QKeyEvent *e) {
|
||||
if (_a_show.animating() || _a_stage.animating()) return;
|
||||
void Widget::Step::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
paintAnimated(p, e->rect());
|
||||
}
|
||||
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
if (step()->hasBack()) {
|
||||
onBack();
|
||||
void Widget::Step::resizeEvent(QResizeEvent *e) {
|
||||
updateLabelsPosition();
|
||||
}
|
||||
|
||||
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) {
|
||||
onStepSubmit();
|
||||
myEnsureResized(_error->entity());
|
||||
auto errorLeft = _errorCentered ? 0 : (contentLeft() + st::buttonRadius);
|
||||
auto errorTop = contentTop() + (_errorBelowLink ? st::introErrorBelowLinkTop : st::introErrorTop);
|
||||
_error->moveToLeft(errorLeft, errorTop);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroWidget::rpcClear() {
|
||||
for (IntroStep *step : _stepHistory) {
|
||||
step->rpcClear();
|
||||
void Widget::Step::setTitleText(QString richText) {
|
||||
_title->setRichText(richText);
|
||||
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() {
|
||||
while (!_stepHistory.isEmpty()) {
|
||||
IntroStep *back = _stepHistory.back();
|
||||
_stepHistory.pop_back();
|
||||
delete back;
|
||||
}
|
||||
if (App::wnd()) App::wnd()->noIntro(this);
|
||||
void Widget::Step::showDescription() {
|
||||
_description->fadeIn();
|
||||
}
|
||||
|
||||
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 {
|
||||
class IconButton;
|
||||
class RoundButton;
|
||||
class LinkButton;
|
||||
class SlideAnimation;
|
||||
class CrossFadeAnimation;
|
||||
class FlatLabel;
|
||||
template <typename Widget>
|
||||
class WidgetFadeWrap;
|
||||
} // namespace Ui
|
||||
|
||||
class IntroStep;
|
||||
class IntroWidget : public TWidget, public RPCSender {
|
||||
namespace Intro {
|
||||
|
||||
class Widget : public TWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntroWidget(QWidget *window);
|
||||
Widget(QWidget *parent);
|
||||
|
||||
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
||||
void step_show(float64 ms, bool timer);
|
||||
void stop_show();
|
||||
void setInnerFocus();
|
||||
|
||||
void step_stage(float64 ms, bool timer);
|
||||
|
||||
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();
|
||||
~Widget();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
public slots:
|
||||
void onStepSubmit();
|
||||
void onBack();
|
||||
void onChangeLang();
|
||||
|
||||
signals:
|
||||
void countryChanged();
|
||||
|
||||
@@ -102,86 +57,199 @@ private slots:
|
||||
void onCheckUpdateStatus();
|
||||
#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:
|
||||
void step_show(float64 ms, bool timer);
|
||||
|
||||
void changeLanguage(int32 languageId);
|
||||
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;
|
||||
QPixmap _cacheHide, _cacheShow;
|
||||
int _cacheHideIndex = 0;
|
||||
int _cacheShowIndex = 0;
|
||||
anim::ivalue a_coordHide, a_coordShow;
|
||||
anim::fvalue a_opacityHide, a_opacityShow;
|
||||
void showResetButton();
|
||||
void resetAccount();
|
||||
void resetAccountSure();
|
||||
void resetDone(const MTPBool &result);
|
||||
bool resetFail(const RPCError &error);
|
||||
|
||||
Animation _a_show;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
anim::ivalue a_coordUnder, a_coordOver;
|
||||
anim::fvalue a_shadow;
|
||||
|
||||
QVector<IntroStep*> _stepHistory;
|
||||
IntroStep *step(int skip = 0) {
|
||||
QVector<Step*> _stepHistory;
|
||||
Step *getStep(int skip = 0) {
|
||||
t_assert(_stepHistory.size() + skip > 0);
|
||||
return _stepHistory.at(_stepHistory.size() - skip - 1);
|
||||
}
|
||||
enum MoveType {
|
||||
MoveBack,
|
||||
MoveForward,
|
||||
MoveReplace,
|
||||
};
|
||||
void historyMove(MoveType type);
|
||||
void pushStep(IntroStep *step, MoveType type);
|
||||
void historyMove(Direction direction);
|
||||
void moveToStep(Step *step, Direction direction);
|
||||
void appendStep(Step *step);
|
||||
|
||||
void gotNearestDC(const MTPNearestDc &dc);
|
||||
|
||||
QString _countryForReg;
|
||||
Data _data;
|
||||
|
||||
QString _phone, _phone_hash;
|
||||
CallStatus _callStatus = { CallDisabled, 0 };
|
||||
bool _registered = false;
|
||||
|
||||
QString _code;
|
||||
|
||||
QByteArray _pwdSalt;
|
||||
bool _hasRecovery = false;
|
||||
bool _codeByTelegram = false;
|
||||
QString _pwdHint;
|
||||
|
||||
QString _firstname, _lastname;
|
||||
FloatAnimation _coverShownAnimation;
|
||||
int _nextTopFrom = 0;
|
||||
int _controlsTopFrom = 0;
|
||||
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::IconButton>> _back;
|
||||
ChildWidget<Ui::RoundButton> _settings;
|
||||
ChildWidget<Ui::RoundButton> _update = { nullptr };
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::RoundButton>> _update = { nullptr };
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::RoundButton>> _settings;
|
||||
|
||||
float64 _backFrom = 0.;
|
||||
float64 _backTo = 0.;
|
||||
ChildWidget<Ui::RoundButton> _next;
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::LinkButton>> _changeLanguage = { nullptr };
|
||||
ChildWidget<Ui::WidgetFadeWrap<Ui::RoundButton>> _resetAccount = { nullptr };
|
||||
|
||||
mtpRequestId _resetRequest = 0;
|
||||
|
||||
};
|
||||
|
||||
class IntroStep : public TWidget, public RPCSender {
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace Intro
|
||||
|
Reference in New Issue
Block a user