mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-09-01 15:15:13 +00:00
initial commit for 0.4.18 version of Telegram Desktop
This commit is contained in:
297
Telegram/SourceFiles/intro/intro.cpp
Normal file
297
Telegram/SourceFiles/intro/intro.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
#include "style.h"
|
||||
|
||||
#include "intro/intro.h"
|
||||
#include "intro/introsteps.h"
|
||||
#include "intro/introphone.h"
|
||||
#include "intro/introcode.h"
|
||||
#include "intro/introsignup.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
#include "application.h"
|
||||
#include "gui/text.h"
|
||||
|
||||
namespace {
|
||||
IntroWidget *signalEmitOn = 0;
|
||||
QString countryForReg;
|
||||
void gotNearestDC(const MTPNearestDc &result) {
|
||||
const MTPDnearestDc &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 signalEmitOn->countryChanged();
|
||||
}
|
||||
if (App::app()) App::app()->startUpdateCheck();
|
||||
}
|
||||
}
|
||||
|
||||
IntroWidget::IntroWidget(Window *window) : QWidget(window),
|
||||
wnd(window), cacheForHideInd(0), cacheForShowInd(0), _callTimeout(60),
|
||||
steps(new IntroSteps(this)), phone(0), code(0), signup(0), current(0), moving(0), visibilityChanging(0) {
|
||||
setGeometry(QRect(0, st::titleHeight, wnd->width(), wnd->height() - st::titleHeight));
|
||||
|
||||
countryForReg = psCurrentCountry();
|
||||
|
||||
MTP::send(MTPhelp_GetNearestDc(), rpcDone(gotNearestDC));
|
||||
signalEmitOn = this;
|
||||
|
||||
stages[0] = steps;
|
||||
memset(stages + 1, 0, sizeof(QWidget*) * 3);
|
||||
|
||||
connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &)));
|
||||
|
||||
show();
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void IntroWidget::onParentResize(const QSize &newSize) {
|
||||
resize(newSize);
|
||||
}
|
||||
|
||||
void IntroWidget::onIntroBack() {
|
||||
if (!current) return;
|
||||
moving = -1;
|
||||
prepareMove();
|
||||
}
|
||||
|
||||
void IntroWidget::onIntroNext() {
|
||||
if (!createNext()) return;
|
||||
moving = 1;
|
||||
prepareMove();
|
||||
}
|
||||
|
||||
bool IntroWidget::createNext() {
|
||||
if (current == sizeof(stages) / sizeof(stages[0]) - 1) return false;
|
||||
if (!stages[current + 1]) {
|
||||
switch (current) {
|
||||
case 0: stages[current + 1] = phone = new IntroPhone(this); break;
|
||||
case 1: stages[current + 1] = code = new IntroCode(this); break;
|
||||
case 2: stages[current + 1] = signup = new IntroSignup(this); break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntroWidget::prepareMove() {
|
||||
if (cacheForHide.isNull() || cacheForHideInd != current) makeHideCache();
|
||||
if (cacheForShow.isNull() || cacheForShowInd != current + moving) makeShowCache();
|
||||
|
||||
xCoordHide = anim::ivalue(0, -moving * st::introSlideShift);
|
||||
cAlphaHide = anim::fvalue(1, 0);
|
||||
xCoordShow = anim::ivalue(moving * st::introSlideShift, 0);
|
||||
cAlphaShow = anim::fvalue(0, 1);
|
||||
anim::start(this);
|
||||
|
||||
stages[current]->deactivate();
|
||||
stages[current + moving]->hide();
|
||||
}
|
||||
|
||||
void IntroWidget::onDoneStateChanged(int oldState, ButtonStateChangeSource source) {
|
||||
if (animating()) return;
|
||||
if (source == ButtonByPress) {
|
||||
if (oldState & Button::StateDown) {
|
||||
cacheForHide = QPixmap();
|
||||
} else {
|
||||
makeHideCache();
|
||||
}
|
||||
} else if (source == ButtonByHover) {
|
||||
if (!createNext()) return;
|
||||
if (!cacheForShow) makeShowCache(current + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroWidget::makeHideCache(int stage) {
|
||||
if (stage < 0) stage = current;
|
||||
int w = st::introSize.width(), h = st::introSize.height();
|
||||
cacheForHide = stages[stage]->grab(QRect(st::introSlideShift, 0, w, h));
|
||||
cacheForHideInd = stage;
|
||||
}
|
||||
|
||||
void IntroWidget::makeShowCache(int stage) {
|
||||
if (stage < 0) stage = current + moving;
|
||||
int w = st::introSize.width(), h = st::introSize.height();
|
||||
cacheForShow = stages[stage]->grab(QRect(st::introSlideShift, 0, w, h));
|
||||
cacheForShowInd = stage;
|
||||
}
|
||||
|
||||
void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||
_bgAnimCache = bgAnimCache;
|
||||
|
||||
anim::stop(this);
|
||||
stages[current]->show();
|
||||
_animCache = grab(rect());
|
||||
|
||||
visibilityChanging = 1;
|
||||
a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0);
|
||||
a_alpha = anim::fvalue(0, 1);
|
||||
a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift);
|
||||
a_bgAlpha = anim::fvalue(1, 0);
|
||||
|
||||
stages[current]->deactivate();
|
||||
stages[current]->hide();
|
||||
anim::start(this);
|
||||
show();
|
||||
}
|
||||
|
||||
bool IntroWidget::animStep(float64 ms) {
|
||||
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;
|
||||
bool res = true;
|
||||
if (visibilityChanging) {
|
||||
if (dt2 >= 1) {
|
||||
res = false;
|
||||
a_bgCoord.finish();
|
||||
a_bgAlpha.finish();
|
||||
a_coord.finish();
|
||||
a_alpha.finish();
|
||||
|
||||
_animCache = _bgAnimCache = QPixmap();
|
||||
|
||||
visibilityChanging = 0;
|
||||
setFocus();
|
||||
stages[current]->show();
|
||||
stages[current]->activate();
|
||||
} else {
|
||||
a_bgCoord.update(dt1, st::introHideFunc);
|
||||
a_bgAlpha.update(dt1, st::introAlphaHideFunc);
|
||||
a_coord.update(dt2, st::introShowFunc);
|
||||
a_alpha.update(dt2, st::introAlphaShowFunc);
|
||||
}
|
||||
} else if (dt >= 1) {
|
||||
res = false;
|
||||
xCoordShow.finish();
|
||||
cAlphaShow.finish();
|
||||
|
||||
cacheForHide = cacheForShow = QPixmap();
|
||||
|
||||
current += moving;
|
||||
moving = 0;
|
||||
setFocus();
|
||||
stages[current]->activate();
|
||||
} else {
|
||||
xCoordShow.update(dt2, st::introShowFunc);
|
||||
cAlphaShow.update(dt2, st::introAlphaShowFunc);
|
||||
xCoordHide.update(dt1, st::introHideFunc);
|
||||
cAlphaHide.update(dt1, st::introAlphaHideFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void IntroWidget::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
setMouseTracking(true);
|
||||
|
||||
QPainter p(this);
|
||||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
}
|
||||
if (animating()) {
|
||||
if (visibilityChanging) {
|
||||
p.setOpacity(a_bgAlpha.current());
|
||||
p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache);
|
||||
p.setOpacity(a_alpha.current());
|
||||
p.drawPixmap(a_coord.current(), 0, _animCache);
|
||||
} else {
|
||||
p.setOpacity(cAlphaHide.current());
|
||||
p.drawPixmap(stages[current]->x() + st::introSlideShift + xCoordHide.current(), stages[current]->y(), cacheForHide.width(), cacheForHide.height(), cacheForHide);
|
||||
p.setOpacity(cAlphaShow.current());
|
||||
p.drawPixmap(stages[current + moving]->x() + st::introSlideShift + xCoordShow.current(), stages[current + moving]->y(), cacheForShow.width(), cacheForShow.height(), cacheForShow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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::setCallTimeout(int32 callTimeout) {
|
||||
_callTimeout = callTimeout;
|
||||
}
|
||||
|
||||
const QString &IntroWidget::getPhone() const {
|
||||
return _phone;
|
||||
}
|
||||
|
||||
const QString &IntroWidget::getPhoneHash() const {
|
||||
return _phone_hash;
|
||||
}
|
||||
|
||||
const QString &IntroWidget::getCode() const {
|
||||
return _code;
|
||||
}
|
||||
|
||||
int32 IntroWidget::getCallTimeout() const {
|
||||
return _callTimeout;
|
||||
}
|
||||
|
||||
void IntroWidget::resizeEvent(QResizeEvent *e) {
|
||||
QRect r(innerRect());
|
||||
if (steps) steps->setGeometry(r);
|
||||
if (phone) phone->setGeometry(r);
|
||||
if (code) code->setGeometry(r);
|
||||
if (signup) signup->setGeometry(r);
|
||||
}
|
||||
|
||||
void IntroWidget::mousePressEvent(QMouseEvent *e) {
|
||||
|
||||
}
|
||||
|
||||
void IntroWidget::finish(const MTPUser &user, const QImage &photo) {
|
||||
wnd->setupMain(true);
|
||||
wnd->startMain(user);
|
||||
if (!photo.isNull()) {
|
||||
App::app()->uploadProfilePhoto(photo, MTP::authedId());
|
||||
}
|
||||
}
|
||||
|
||||
void IntroWidget::keyPressEvent(QKeyEvent *e) {
|
||||
if (animating()) return;
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
stages[current]->onBack();
|
||||
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) {
|
||||
stages[current]->onNext();
|
||||
}
|
||||
}
|
||||
|
||||
IntroWidget::~IntroWidget() {
|
||||
delete steps;
|
||||
delete phone;
|
||||
delete code;
|
||||
delete signup;
|
||||
if (App::wnd()) App::wnd()->noIntro(this);
|
||||
}
|
124
Telegram/SourceFiles/intro/intro.h
Normal file
124
Telegram/SourceFiles/intro/intro.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "gui/flatbutton.h"
|
||||
|
||||
class Window;
|
||||
class IntroSteps;
|
||||
class IntroPhone;
|
||||
class IntroCode;
|
||||
class IntroSignup;
|
||||
class IntroStage;
|
||||
class Text;
|
||||
|
||||
class IntroWidget : public QWidget, public Animated {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IntroWidget(Window *window);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
|
||||
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
||||
bool animStep(float64 ms);
|
||||
|
||||
QRect innerRect() const;
|
||||
QString currentCountry() const;
|
||||
|
||||
void setPhone(const QString &phone, const QString &phone_hash, bool registered);
|
||||
void setCode(const QString &code);
|
||||
void setCallTimeout(int32 callTimeout);
|
||||
|
||||
const QString &getPhone() const;
|
||||
const QString &getPhoneHash() const;
|
||||
const QString &getCode() const;
|
||||
int32 getCallTimeout() const;
|
||||
|
||||
void finish(const MTPUser &user, const QImage &photo = QImage());
|
||||
|
||||
~IntroWidget();
|
||||
|
||||
public slots:
|
||||
|
||||
void onIntroNext();
|
||||
void onIntroBack();
|
||||
void onDoneStateChanged(int oldState, ButtonStateChangeSource source);
|
||||
void onParentResize(const QSize &newSize);
|
||||
|
||||
signals:
|
||||
|
||||
void countryChanged();
|
||||
|
||||
private:
|
||||
|
||||
void makeHideCache(int stage = -1);
|
||||
void makeShowCache(int stage = -1);
|
||||
void prepareMove();
|
||||
bool createNext();
|
||||
|
||||
QPixmap cacheForHide, cacheForShow;
|
||||
int cacheForHideInd, cacheForShowInd;
|
||||
anim::ivalue xCoordHide, xCoordShow;
|
||||
anim::fvalue cAlphaHide, cAlphaShow;
|
||||
|
||||
QPixmap _animCache, _bgAnimCache;
|
||||
anim::ivalue a_coord, a_bgCoord;
|
||||
anim::fvalue a_alpha, a_bgAlpha;
|
||||
|
||||
Window *wnd;
|
||||
IntroSteps *steps;
|
||||
IntroPhone *phone;
|
||||
IntroCode *code;
|
||||
IntroSignup *signup;
|
||||
IntroStage *stages[4];
|
||||
int current, moving, visibilityChanging;
|
||||
|
||||
QString _phone, _phone_hash;
|
||||
int32 _callTimeout;
|
||||
bool _registered;
|
||||
|
||||
QString _code;
|
||||
|
||||
QString _firstname, _lastname;
|
||||
|
||||
};
|
||||
|
||||
class IntroStage : public QWidget {
|
||||
public:
|
||||
|
||||
IntroStage(IntroWidget *parent) : QWidget(parent) {
|
||||
}
|
||||
|
||||
virtual void activate() = 0; // show and activate
|
||||
virtual void deactivate() = 0; // deactivate and hide
|
||||
virtual void onNext() = 0;
|
||||
virtual void onBack() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
IntroWidget *intro() {
|
||||
return qobject_cast<IntroWidget*>(parent());
|
||||
}
|
||||
|
||||
};
|
279
Telegram/SourceFiles/intro/introcode.cpp
Normal file
279
Telegram/SourceFiles/intro/introcode.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
#include "style.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#include "intro/introcode.h"
|
||||
#include "intro/intro.h"
|
||||
|
||||
CodeInput::CodeInput(QWidget *parent, const style::flatInput &st, const QString &ph) : FlatInput(parent, st, ph) {
|
||||
}
|
||||
|
||||
void CodeInput::correctValue(QKeyEvent *e, const QString &was) {
|
||||
QString oldText(text()), newText;
|
||||
int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), digitCount = 0;
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
if (oldText[i].isDigit()) {
|
||||
++digitCount;
|
||||
}
|
||||
}
|
||||
if (digitCount > 5) digitCount = 5;
|
||||
bool strict = (digitCount == 5);
|
||||
|
||||
newText.reserve(oldLen);
|
||||
for (int i = 0; i < oldLen; ++i) {
|
||||
QChar ch(oldText[i]);
|
||||
if (ch.isDigit()) {
|
||||
if (!digitCount--) {
|
||||
break;
|
||||
}
|
||||
newText += ch;
|
||||
if (strict && !digitCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == oldPos) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
}
|
||||
if (newPos < 0) {
|
||||
newPos = newText.length();
|
||||
}
|
||||
if (newText != oldText) {
|
||||
setText(newText);
|
||||
if (newPos != oldPos) {
|
||||
setCursorPosition(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (strict) emit codeEntered();
|
||||
}
|
||||
|
||||
IntroCode::IntroCode(IntroWidget *parent) : IntroStage(parent),
|
||||
next(this, lang(lng_intro_next), st::btnIntroNext),
|
||||
back(this, lang(lng_intro_back), st::btnIntroBack),
|
||||
code(this, st::inpIntroCode, lang(lng_code_ph)), errorAlpha(0), waitTillCall(intro()->getCallTimeout()) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(&next, SIGNAL(stateChanged(int, ButtonStateChangeSource)), parent, SLOT(onDoneStateChanged(int, ButtonStateChangeSource)));
|
||||
connect(&next, SIGNAL(clicked()), this, SLOT(onSubmitCode()));
|
||||
connect(&back, SIGNAL(clicked()), parent, SLOT(onIntroBack()));
|
||||
connect(&code, SIGNAL(changed()), this, SLOT(onInputChange()));
|
||||
connect(&callTimer, SIGNAL(timeout()), this, SLOT(onSendCall()));
|
||||
connect(&checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||
}
|
||||
|
||||
void IntroCode::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, intro()->getPhone(), style::al_topleft);
|
||||
p.setFont(st::introFont->f);
|
||||
p.drawText(textRect, lang(lng_code_desc), style::al_bottomleft);
|
||||
}
|
||||
QString callText = lang(lng_code_calling);
|
||||
if (waitTillCall >= 3600) {
|
||||
callText = lang(lng_code_call).arg(QString("%1:%2").arg(waitTillCall / 3600).arg((waitTillCall / 60) % 60, 2, 10, QChar('0'))).arg(waitTillCall % 60, 2, 10, QChar('0'));
|
||||
} else if (waitTillCall > 0) {
|
||||
callText = lang(lng_code_call).arg(waitTillCall / 60).arg(waitTillCall % 60, 2, 10, QChar('0'));
|
||||
} else if (waitTillCall < 0) {
|
||||
callText = lang(lng_code_called);
|
||||
}
|
||||
p.drawText(QRect(textRect.left(), code.y() + code.height() + st::introSkip, st::introTextSize.width(), st::introErrHeight), callText, style::al_left);
|
||||
if (animating() || error.length()) {
|
||||
p.setOpacity(errorAlpha.current());
|
||||
p.setFont(st::introErrFont->f);
|
||||
p.setPen(st::introErrColor->p);
|
||||
p.drawText(textRect.left(), next.y() + next.height() + st::introErrTop + st::introErrFont->ascent, error);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroCode::resizeEvent(QResizeEvent *e) {
|
||||
int sumBack = st::btnIntroNext.width + st::btnIntroBack.width + st::btnIntroSep;
|
||||
if (e->oldSize().width() != width()) {
|
||||
int sumNext = st::btnIntroNext.width - st::btnIntroBack.width - st::btnIntroSep;
|
||||
back.move((width() - sumBack) / 2, st::introBtnTop);
|
||||
next.move((width() - sumNext) / 2, st::introBtnTop);
|
||||
code.move((width() - sumBack) / 2, st::introTextSize.height() + 24);
|
||||
}
|
||||
textRect = QRect((width() - sumBack) / 2, 0, st::introTextSize.width(), st::introTextSize.height());
|
||||
}
|
||||
|
||||
void IntroCode::showError(const QString &err) {
|
||||
if (!err.isEmpty()) code.notaBene();
|
||||
if (!animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
}
|
||||
anim::start(this);
|
||||
}
|
||||
|
||||
bool IntroCode::animStep(float64 ms) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
error = "";
|
||||
}
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void IntroCode::activate() {
|
||||
waitTillCall = intro()->getCallTimeout();
|
||||
callTimer.start(1000);
|
||||
error = "";
|
||||
errorAlpha = anim::fvalue(0);
|
||||
show();
|
||||
code.setDisabled(false);
|
||||
code.setFocus();
|
||||
}
|
||||
|
||||
void IntroCode::deactivate() {
|
||||
callTimer.stop();
|
||||
hide();
|
||||
code.clearFocus();
|
||||
}
|
||||
|
||||
void IntroCode::stopCheck() {
|
||||
checkRequest.stop();
|
||||
}
|
||||
|
||||
void IntroCode::onCheckRequest() {
|
||||
int32 status = MTP::state(sentRequest);
|
||||
if (status < 0) {
|
||||
int32 leftms = -status;
|
||||
if (leftms >= 1000) {
|
||||
if (sentRequest) {
|
||||
MTP::cancel(sentRequest);
|
||||
sentCode = "";
|
||||
}
|
||||
sentRequest = 0;
|
||||
if (!code.isEnabled()) {
|
||||
code.setDisabled(false);
|
||||
code.setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sentRequest && status == MTP::RequestSent) {
|
||||
stopCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroCode::codeSubmitDone(const MTPauth_Authorization &result) {
|
||||
stopCheck();
|
||||
code.setDisabled(false);
|
||||
const MTPDauth_authorization &d(result.c_auth_authorization());
|
||||
if (d.vuser.type() != mtpc_userSelf) { // wtf?
|
||||
showError(lang(lng_server_error));
|
||||
return;
|
||||
}
|
||||
cSetLoggedPhoneNumber(intro()->getPhone());
|
||||
intro()->finish(d.vuser);
|
||||
}
|
||||
|
||||
bool IntroCode::codeSubmitFail(const RPCError &error) {
|
||||
stopCheck();
|
||||
code.setDisabled(false);
|
||||
const QString &err = error.type();
|
||||
if (err == "PHONE_NUMBER_INVALID" || err == "PHONE_CODE_EXPIRED") { // show error
|
||||
onBack();
|
||||
return true;
|
||||
} else if (err == "PHONE_CODE_EMPTY" || err == "PHONE_CODE_INVALID") {
|
||||
showError(lang(lng_bad_code));
|
||||
code.setFocus();
|
||||
return true;
|
||||
} else if (err == "PHONE_NUMBER_UNOCCUPIED") { // success, need to signUp
|
||||
intro()->setCode(sentCode);
|
||||
intro()->onIntroNext();
|
||||
return true;
|
||||
}
|
||||
if (QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err).hasMatch()) {
|
||||
showError(lang(lng_flood_error));
|
||||
code.setFocus();
|
||||
return true;
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
showError(err + ": " + error.description());
|
||||
} else {
|
||||
showError(lang(lng_server_error));
|
||||
}
|
||||
code.setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntroCode::onInputChange() {
|
||||
showError("");
|
||||
if (code.text().length() == 5) onSubmitCode();
|
||||
}
|
||||
|
||||
void IntroCode::onSendCall() {
|
||||
if (!--waitTillCall) {
|
||||
callTimer.stop();
|
||||
MTP::send(MTPauth_SendCall(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash())), rpcDone(&IntroCode::callDone));
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void IntroCode::callDone(const MTPBool &v) {
|
||||
if (!waitTillCall) {
|
||||
waitTillCall = -1;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroCode::onSubmitCode(bool force) {
|
||||
if (!force && (code.text() == sentCode || !code.isEnabled())) return;
|
||||
|
||||
code.setDisabled(true);
|
||||
setFocus();
|
||||
|
||||
showError("");
|
||||
|
||||
checkRequest.start(1000);
|
||||
|
||||
sentCode = code.text();
|
||||
sentRequest = MTP::send(MTPauth_SignIn(MTP_string(intro()->getPhone()), MTP_string(intro()->getPhoneHash()), MTP_string(sentCode)), rpcDone(&IntroCode::codeSubmitDone), rpcFail(&IntroCode::codeSubmitFail));
|
||||
}
|
||||
|
||||
void IntroCode::onNext() {
|
||||
onSubmitCode();
|
||||
}
|
||||
|
||||
void IntroCode::onBack() {
|
||||
intro()->onIntroBack();
|
||||
}
|
89
Telegram/SourceFiles/intro/introcode.h
Normal file
89
Telegram/SourceFiles/intro/introcode.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "gui/flatbutton.h"
|
||||
#include "gui/flatinput.h"
|
||||
#include "intro.h"
|
||||
|
||||
class CodeInput : public FlatInput {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
CodeInput(QWidget *parent, const style::flatInput &st, const QString &ph);
|
||||
|
||||
signals:
|
||||
|
||||
void codeEntered();
|
||||
|
||||
protected:
|
||||
|
||||
void correctValue(QKeyEvent *e, const QString &was);
|
||||
|
||||
};
|
||||
|
||||
class IntroCode : public IntroStage, public Animated, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IntroCode(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
void onNext();
|
||||
void onBack();
|
||||
|
||||
void codeSubmitDone(const MTPauth_Authorization &result);
|
||||
bool codeSubmitFail(const RPCError &error);
|
||||
|
||||
public slots:
|
||||
|
||||
void onSubmitCode(bool force = false);
|
||||
void onInputChange();
|
||||
void onSendCall();
|
||||
void onCheckRequest();
|
||||
|
||||
private:
|
||||
|
||||
void showError(const QString &err);
|
||||
void callDone(const MTPBool &v);
|
||||
void stopCheck();
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha;
|
||||
|
||||
FlatButton next, back;
|
||||
|
||||
QRect textRect;
|
||||
|
||||
CodeInput code;
|
||||
QString sentCode;
|
||||
mtpRequestId sentRequest;
|
||||
QTimer callTimer;
|
||||
int32 waitTillCall;
|
||||
|
||||
QTimer checkRequest;
|
||||
};
|
300
Telegram/SourceFiles/intro/introphone.cpp
Normal file
300
Telegram/SourceFiles/intro/introphone.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
#include "style.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#include "intro/introphone.h"
|
||||
#include "intro/intro.h"
|
||||
|
||||
namespace {
|
||||
class SignUpLink : public ITextLink {
|
||||
public:
|
||||
|
||||
SignUpLink(IntroPhone *widget) : _widget(widget) {
|
||||
}
|
||||
|
||||
void onClick(Qt::MouseButton) const {
|
||||
_widget->toSignUp();
|
||||
}
|
||||
|
||||
private:
|
||||
IntroPhone *_widget;
|
||||
};
|
||||
}
|
||||
|
||||
IntroPhone::IntroPhone(IntroWidget *parent) : IntroStage(parent), changed(false),
|
||||
next(this, lang(lng_intro_next), st::btnIntroStart),
|
||||
country(this, st::introCountry), errorAlpha(0), _signup(this, lang(lng_phone_notreg).replace(qsl("{signup}"), textcmdStartLink(1)).replace(qsl("{/signup}"), textcmdStopLink()), st::introErrLabel), _showSignup(false),
|
||||
phone(this, st::inpIntroPhone, lang(lng_phone_ph)), code(this, st::inpIntroCountryCode) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(&next, SIGNAL(stateChanged(int, ButtonStateChangeSource)), parent, SLOT(onDoneStateChanged(int, ButtonStateChangeSource)));
|
||||
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 &)));
|
||||
connect(&code, SIGNAL(addedToNumber(const QString &)), &phone, SLOT(addedToNumber(const QString &)));
|
||||
connect(&country, SIGNAL(selectClosed()), this, SLOT(onSelectClose()));
|
||||
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, TextLinkPtr(new SignUpLink(this)));
|
||||
_signup.hide();
|
||||
|
||||
_signupCache = _signup.grab(_signup.rect());
|
||||
|
||||
if (!country.onChooseCountry(intro()->currentCountry())) {
|
||||
country.onChooseCountry(qsl("US"));
|
||||
}
|
||||
changed = false;
|
||||
}
|
||||
|
||||
void IntroPhone::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_phone_title), style::al_topleft);
|
||||
p.setFont(st::introFont->f);
|
||||
p.drawText(textRect, lang(lng_phone_desc), style::al_bottomleft);
|
||||
}
|
||||
if (animating() || error.length()) {
|
||||
p.setOpacity(errorAlpha.current());
|
||||
p.setFont(st::introErrFont->f);
|
||||
p.setPen(st::introErrColor->p);
|
||||
p.drawText(textRect.x(), next.y() + next.height() + st::introErrTop + st::introErrFont->ascent, error);
|
||||
|
||||
if (_signup.isHidden() && _showSignup) {
|
||||
p.drawPixmap(_signup.x(), _signup.y(), _signupCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::introTextSize.height() + st::introCountry.top);
|
||||
int phoneTop = country.y() + country.height() + st::introPhoneTop;
|
||||
phone.move((width() + country.width()) / 2 - st::inpIntroPhone.width, phoneTop);
|
||||
code.move((width() - country.width()) / 2, phoneTop);
|
||||
}
|
||||
_signup.move((width() - next.width()) / 2, next.y() + next.height() + st::introErrTop * 2 + st::introErrFont->height);
|
||||
textRect = QRect((width() - next.width()) / 2, 0, st::introTextSize.width(), st::introTextSize.height());
|
||||
}
|
||||
|
||||
void IntroPhone::showError(const QString &err, bool signUp) {
|
||||
if (!err.isEmpty()) {
|
||||
phone.notaBene();
|
||||
_showSignup = signUp;
|
||||
}
|
||||
|
||||
if (!animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
}
|
||||
_signup.hide();
|
||||
anim::start(this);
|
||||
}
|
||||
|
||||
bool IntroPhone::animStep(float64 ms) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
error = "";
|
||||
_signup.hide();
|
||||
} else if (!error.isEmpty() && _showSignup) {
|
||||
_signup.show();
|
||||
}
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void IntroPhone::countryChanged() {
|
||||
if (!changed) {
|
||||
selectCountry(intro()->currentCountry());
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPhone::onSelectClose() {
|
||||
phone.setFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::onInputChange() {
|
||||
changed = true;
|
||||
showError("");
|
||||
}
|
||||
|
||||
void IntroPhone::disableAll() {
|
||||
next.setDisabled(true);
|
||||
phone.setDisabled(true);
|
||||
country.setDisabled(true);
|
||||
code.setDisabled(true);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::enableAll(bool failed) {
|
||||
next.setDisabled(false);
|
||||
phone.setDisabled(false);
|
||||
country.setDisabled(false);
|
||||
code.setDisabled(false);
|
||||
if (failed) phone.setFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::onSubmitPhone(bool force) {
|
||||
if (!force && !next.isEnabled()) return;
|
||||
|
||||
if (!App::isValidPhone(fullNumber())) {
|
||||
showError(lang(lng_bad_phone));
|
||||
phone.setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
disableAll();
|
||||
showError("");
|
||||
|
||||
checkRequest.start(1000);
|
||||
|
||||
sentPhone = fullNumber();
|
||||
sentRequest = MTP::send(MTPauth_CheckPhone(MTP_string(sentPhone)), rpcDone(&IntroPhone::phoneCheckDone), rpcFail(&IntroPhone::phoneSubmitFail));
|
||||
}
|
||||
|
||||
void IntroPhone::stopCheck() {
|
||||
checkRequest.stop();
|
||||
}
|
||||
|
||||
void IntroPhone::onCheckRequest() {
|
||||
int32 status = MTP::state(sentRequest);
|
||||
if (status < 0) {
|
||||
int32 leftms = -status;
|
||||
if (leftms >= 1000) {
|
||||
MTP::cancel(sentRequest);
|
||||
sentRequest = 0;
|
||||
if (!phone.isEnabled()) enableAll(true);
|
||||
}
|
||||
}
|
||||
if (!sentRequest && status == MTP::RequestSent) {
|
||||
stopCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPhone::phoneCheckDone(const MTPauth_CheckedPhone &result) {
|
||||
stopCheck();
|
||||
|
||||
const MTPDauth_checkedPhone &d(result.c_auth_checkedPhone());
|
||||
if (d.vphone_registered.v) {
|
||||
disableAll();
|
||||
showError("");
|
||||
|
||||
checkRequest.start(1000);
|
||||
|
||||
sentRequest = MTP::send(MTPauth_SendCode(MTP_string(sentPhone), MTP_int(0), MTP_int(ApiId), MTP_string(ApiHash), MTP_string(Application::lang())), rpcDone(&IntroPhone::phoneSubmitDone), rpcFail(&IntroPhone::phoneSubmitFail));
|
||||
} else {
|
||||
showError(lang(lng_bad_phone_noreg), true);
|
||||
enableAll(true);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPhone::phoneSubmitDone(const MTPauth_SentCode &result) {
|
||||
stopCheck();
|
||||
enableAll(false);
|
||||
|
||||
const MTPDauth_sentCode &d(result.c_auth_sentCode());
|
||||
intro()->setPhone(sentPhone, d.vphone_code_hash.c_string().v.c_str(), d.vphone_registered.v);
|
||||
intro()->setCallTimeout(result.c_auth_sentCode().vsend_call_timeout.v);
|
||||
intro()->onIntroNext();
|
||||
}
|
||||
|
||||
void IntroPhone::toSignUp() {
|
||||
disableAll();
|
||||
showError("");
|
||||
|
||||
checkRequest.start(1000);
|
||||
|
||||
sentRequest = MTP::send(MTPauth_SendCode(MTP_string(sentPhone), MTP_int(0), MTP_int(ApiId), MTP_string(ApiHash), MTP_string(Application::lang())), rpcDone(&IntroPhone::phoneSubmitDone), rpcFail(&IntroPhone::phoneSubmitFail));
|
||||
}
|
||||
|
||||
bool IntroPhone::phoneSubmitFail(const RPCError &error) {
|
||||
stopCheck();
|
||||
const QString &err = error.type();
|
||||
if (err == "PHONE_NUMBER_INVALID") { // show error
|
||||
showError(lang(lng_bad_phone));
|
||||
enableAll(true);
|
||||
return true;
|
||||
}
|
||||
if (QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err).hasMatch()) {
|
||||
showError(lang(lng_flood_error));
|
||||
enableAll(true);
|
||||
return true;
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
showError(err + ": " + error.description());
|
||||
} else {
|
||||
showError(lang(lng_server_error));
|
||||
}
|
||||
enableAll(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString IntroPhone::fullNumber() const {
|
||||
return code.text() + phone.text();
|
||||
}
|
||||
|
||||
void IntroPhone::selectCountry(const QString &c) {
|
||||
country.onChooseCountry(c);
|
||||
}
|
||||
|
||||
void IntroPhone::activate() {
|
||||
error = "";
|
||||
errorAlpha = anim::fvalue(0);
|
||||
show();
|
||||
enableAll(true);
|
||||
}
|
||||
|
||||
void IntroPhone::deactivate() {
|
||||
checkRequest.stop();
|
||||
hide();
|
||||
phone.clearFocus();
|
||||
}
|
||||
|
||||
void IntroPhone::onNext() {
|
||||
onSubmitPhone();
|
||||
}
|
||||
|
||||
void IntroPhone::onBack() {
|
||||
}
|
89
Telegram/SourceFiles/intro/introphone.h
Normal file
89
Telegram/SourceFiles/intro/introphone.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "gui/flatbutton.h"
|
||||
#include "gui/phoneinput.h"
|
||||
#include "gui/countrycodeinput.h"
|
||||
#include "gui/countryinput.h"
|
||||
#include "intro.h"
|
||||
|
||||
class IntroPhone : public IntroStage, public Animated, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IntroPhone(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void selectCountry(const QString &country);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
void onNext();
|
||||
void onBack();
|
||||
|
||||
void phoneCheckDone(const MTPauth_CheckedPhone &result);
|
||||
void phoneSubmitDone(const MTPauth_SentCode &result);
|
||||
bool phoneSubmitFail(const RPCError &error);
|
||||
|
||||
void toSignUp();
|
||||
|
||||
public slots:
|
||||
|
||||
void countryChanged();
|
||||
void onSelectClose();
|
||||
void onInputChange();
|
||||
void onSubmitPhone(bool force = false);
|
||||
void onCheckRequest();
|
||||
|
||||
private:
|
||||
|
||||
QString fullNumber() const;
|
||||
void disableAll();
|
||||
void enableAll(bool failed);
|
||||
void stopCheck();
|
||||
|
||||
void showError(const QString &err, bool signUp = false);
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha;
|
||||
|
||||
bool changed;
|
||||
FlatButton next;
|
||||
|
||||
QRect textRect;
|
||||
|
||||
CountryInput country;
|
||||
PhoneInput phone;
|
||||
CountryCodeInput code;
|
||||
|
||||
FlatLabel _signup;
|
||||
QPixmap _signupCache;
|
||||
bool _showSignup;
|
||||
|
||||
QString sentPhone;
|
||||
mtpRequestId sentRequest;
|
||||
|
||||
QTimer checkRequest;
|
||||
};
|
283
Telegram/SourceFiles/intro/introsignup.cpp
Normal file
283
Telegram/SourceFiles/intro/introsignup.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
#include "style.h"
|
||||
|
||||
#include "gui/filedialog.h"
|
||||
#include "boxes/photocropbox.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#include "intro/introsignup.h"
|
||||
#include "intro/intro.h"
|
||||
|
||||
IntroSignup::IntroSignup(IntroWidget *parent) : IntroStage(parent),
|
||||
next(this, lang(lng_intro_finish), st::btnIntroFinish), errorAlpha(0), a_photo(0),
|
||||
first(this, st::inpIntroName, lang(lng_signup_firstname)),
|
||||
last(this, st::inpIntroName, lang(lng_signup_lastname)) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(&next, SIGNAL(clicked()), this, SLOT(onSubmitName()));
|
||||
connect(&checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void IntroSignup::mouseMoveEvent(QMouseEvent *e) {
|
||||
bool photoOver = QRect(_phLeft, _phTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos());
|
||||
if (photoOver != _photoOver) {
|
||||
_photoOver = photoOver;
|
||||
if (_photoSmall.isNull()) {
|
||||
a_photo.start(_photoOver ? 1 : 0);
|
||||
errorAlpha.restart();
|
||||
anim::start(this);
|
||||
}
|
||||
}
|
||||
|
||||
setCursor(_photoOver ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
|
||||
void IntroSignup::mousePressEvent(QMouseEvent *e) {
|
||||
mouseMoveEvent(e);
|
||||
if (QRect(_phLeft, _phTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos())) {
|
||||
QStringList imgExtensions(cImgExtensions());
|
||||
QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)"));
|
||||
|
||||
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, 0);
|
||||
connect(box, SIGNAL(ready(const QImage &)), this, SLOT(onPhotoReady(const QImage &)));
|
||||
App::wnd()->showLayer(box);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSignup::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::introTitleFont->f);
|
||||
p.drawText(textRect, lang(lng_signup_title), QTextOption(Qt::AlignHCenter | Qt::AlignTop));
|
||||
}
|
||||
if (animating() || error.length()) {
|
||||
p.setOpacity(errorAlpha.current());
|
||||
|
||||
QRect errRect((width() - st::introErrWidth) / 2, (last.y() + last.height() + next.y() - st::introErrHeight) / 2, st::introErrWidth, st::introErrHeight);
|
||||
p.fillRect(errRect, st::introErrBG->b);
|
||||
p.setFont(st::introErrFont->f);
|
||||
p.setPen(st::introErrColor->p);
|
||||
p.drawText(errRect, error, QTextOption(style::al_center));
|
||||
|
||||
p.setOpacity(1);
|
||||
}
|
||||
|
||||
if (_photoSmall.isNull()) {
|
||||
if (a_photo.current() < 1) {
|
||||
p.drawPixmap(QPoint(_phLeft, _phTop), App::sprite(), st::setPhotoImg);
|
||||
}
|
||||
if (a_photo.current() > 0) {
|
||||
p.setOpacity(a_photo.current());
|
||||
p.drawPixmap(QPoint(_phLeft, _phTop), App::sprite(), st::setOverPhotoImg);
|
||||
p.setOpacity(1);
|
||||
}
|
||||
} else {
|
||||
p.drawPixmap(_phLeft, _phTop, _photoSmall);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSignup::resizeEvent(QResizeEvent *e) {
|
||||
textRect = QRect((width() - st::introTextSize.width()) / 2, 0, st::introTextSize.width(), st::introTextSize.height());
|
||||
_phLeft = (width() - st::setPhotoImg.width()) / 2;
|
||||
_phTop = st::introHeaderFont->height + st::introFinishSkip;
|
||||
if (e->oldSize().width() != width()) {
|
||||
int sumNext = st::btnIntroNext.width - st::btnIntroBack.width - st::btnIntroSep;
|
||||
next.move((width() - sumNext) / 2, st::introSize.height() - st::btnIntroNext.height);
|
||||
}
|
||||
if (e->oldSize().width() != width()) {
|
||||
next.move((width() - next.width()) / 2, st::introSize.height() - st::btnIntroNext.height);
|
||||
first.move((width() - first.width()) / 2, _phTop + st::setPhotoImg.height() + st::introFinishSkip);
|
||||
last.move((width() - last.width()) / 2, first.y() + first.height() + st::introFinishSkip);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSignup::showError(const QString &err) {
|
||||
if (!animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
}
|
||||
a_photo.restart();
|
||||
anim::start(this);
|
||||
}
|
||||
|
||||
bool IntroSignup::animStep(float64 ms) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
error = "";
|
||||
}
|
||||
a_photo.finish();
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
a_photo.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void IntroSignup::activate() {
|
||||
show();
|
||||
first.setFocus();
|
||||
}
|
||||
|
||||
void IntroSignup::deactivate() {
|
||||
hide();
|
||||
}
|
||||
|
||||
void IntroSignup::stopCheck() {
|
||||
checkRequest.stop();
|
||||
}
|
||||
|
||||
void IntroSignup::onCheckRequest() {
|
||||
int32 status = MTP::state(sentRequest);
|
||||
if (status < 0) {
|
||||
int32 leftms = -status;
|
||||
if (leftms >= 1000) {
|
||||
MTP::cancel(sentRequest);
|
||||
sentRequest = 0;
|
||||
if (!first.isEnabled()) {
|
||||
first.setDisabled(false);
|
||||
last.setDisabled(false);
|
||||
last.setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sentRequest && status == MTP::RequestSent) {
|
||||
stopCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSignup::onPhotoReady(const QImage &img) {
|
||||
_photoBig = img;
|
||||
_photoSmall = QPixmap::fromImage(img.scaled(st::setPhotoSize, st::setPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
App::wnd()->hideLayer();
|
||||
}
|
||||
|
||||
void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) {
|
||||
stopCheck();
|
||||
first.setDisabled(false);
|
||||
last.setDisabled(false);
|
||||
const MTPDauth_authorization &d(result.c_auth_authorization());
|
||||
if (d.vuser.type() != mtpc_userSelf) { // wtf?
|
||||
showError(lang(lng_server_error));
|
||||
return;
|
||||
}
|
||||
intro()->finish(d.vuser, _photoBig);
|
||||
}
|
||||
|
||||
bool IntroSignup::nameSubmitFail(const RPCError &error) {
|
||||
stopCheck();
|
||||
first.setDisabled(false);
|
||||
last.setDisabled(false);
|
||||
const QString &err = error.type();
|
||||
if (err == "PHONE_NUMBER_INVALID" || err == "PHONE_CODE_EXPIRED" || err == "PHONE_CODE_EMPTY" || err == "PHONE_CODE_INVALID" || err == "PHONE_NUMBER_OCCUPIED") {
|
||||
intro()->onIntroBack();
|
||||
return true;
|
||||
} else if (err == "FIRSTNAME_INVALID") {
|
||||
showError(lang(lng_bad_name));
|
||||
first.setFocus();
|
||||
return true;
|
||||
} else if (err == "LASTNAME_INVALID") {
|
||||
showError(lang(lng_bad_name));
|
||||
last.setFocus();
|
||||
return true;
|
||||
}
|
||||
if (QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err).hasMatch()) {
|
||||
showError(lang(lng_flood_error));
|
||||
last.setFocus();
|
||||
return true;
|
||||
}
|
||||
if (cDebug()) { // internal server error
|
||||
showError(err + ": " + error.description());
|
||||
} else {
|
||||
showError(lang(lng_server_error));
|
||||
}
|
||||
first.setFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntroSignup::onInputChange() {
|
||||
showError("");
|
||||
}
|
||||
|
||||
void IntroSignup::onSubmitName(bool force) {
|
||||
if ((first.hasFocus() || first.text().trimmed().length()) && !last.text().trimmed().length()) {
|
||||
last.setFocus();
|
||||
return;
|
||||
} else if (!first.text().trimmed().length()) {
|
||||
first.setFocus();
|
||||
return;
|
||||
}
|
||||
if (!force && !first.isEnabled()) return;
|
||||
|
||||
first.setDisabled(true);
|
||||
last.setDisabled(true);
|
||||
setFocus();
|
||||
|
||||
showError("");
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void IntroSignup::onNext() {
|
||||
onSubmitName();
|
||||
}
|
||||
|
||||
void IntroSignup::onBack() {
|
||||
}
|
76
Telegram/SourceFiles/intro/introsignup.h
Normal file
76
Telegram/SourceFiles/intro/introsignup.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "gui/flatbutton.h"
|
||||
#include "gui/flatinput.h"
|
||||
#include "intro.h"
|
||||
|
||||
class IntroSignup : public IntroStage, public Animated, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IntroSignup(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
void onNext();
|
||||
void onBack();
|
||||
|
||||
void nameSubmitDone(const MTPauth_Authorization &result);
|
||||
bool nameSubmitFail(const RPCError &error);
|
||||
|
||||
public slots:
|
||||
|
||||
void onSubmitName(bool force = false);
|
||||
void onInputChange();
|
||||
void onCheckRequest();
|
||||
void onPhotoReady(const QImage &img);
|
||||
|
||||
private:
|
||||
|
||||
void showError(const QString &err);
|
||||
void stopCheck();
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha, a_photo;
|
||||
|
||||
FlatButton next;
|
||||
|
||||
QRect textRect;
|
||||
|
||||
bool _photoOver;
|
||||
QImage _photoBig;
|
||||
QPixmap _photoSmall;
|
||||
int32 _phLeft, _phTop;
|
||||
|
||||
FlatInput first, last;
|
||||
QString firstName, lastName;
|
||||
mtpRequestId sentRequest;
|
||||
|
||||
QTimer checkRequest;
|
||||
};
|
80
Telegram/SourceFiles/intro/introsteps.cpp
Normal file
80
Telegram/SourceFiles/intro/introsteps.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
#include "style.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
#include "intro/introsteps.h"
|
||||
#include "intro/intro.h"
|
||||
|
||||
IntroSteps::IntroSteps(IntroWidget *parent) : IntroStage(parent),
|
||||
_intro1(this, lang(lng_intro1), st::introLabel),
|
||||
_intro2(this, lang(lng_intro2), st::introLabel),
|
||||
_next(this, lang(lng_start_msgs), st::btnIntroStart) {
|
||||
|
||||
_headerWidth = st::introHeaderFont->m.width(lang(lng_maintitle));
|
||||
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
connect(&_next, SIGNAL(stateChanged(int, ButtonStateChangeSource)), parent, SLOT(onDoneStateChanged(int, ButtonStateChangeSource)));
|
||||
connect(&_next, SIGNAL(clicked()), parent, SLOT(onIntroNext()));
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void IntroSteps::paintEvent(QPaintEvent *e) {
|
||||
bool trivial = (rect() == e->rect());
|
||||
|
||||
QPainter p(this);
|
||||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
}
|
||||
int32 hy = _intro1.y() - st::introHeaderFont->height - st::introHeaderSkip + st::introHeaderFont->ascent;
|
||||
|
||||
p.setFont(st::introHeaderFont->f);
|
||||
p.drawText(_next.x(), hy, lang(lng_maintitle));
|
||||
p.setPen(st::introColor->p);
|
||||
p.setFont(st::introVersionFont->f);
|
||||
p.setPen(st::introVersionColor->p);
|
||||
p.drawText(_next.x() + _headerWidth + st::introVersionSkip, hy, qsl("alpha ") + QString::fromWCharArray(AppVersionStr));
|
||||
}
|
||||
|
||||
void IntroSteps::resizeEvent(QResizeEvent *e) {
|
||||
if (e->oldSize().width() != width()) {
|
||||
_next.move((width() - st::btnIntroStart.width) / 2, st::introBtnTop);
|
||||
_intro2.move(_next.x(), _next.y() - _intro2.height() - st::intro2Skip);
|
||||
_intro1.move(_next.x(), _intro2.y() - _intro1.height() - st::intro1Skip);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroSteps::activate() {
|
||||
show();
|
||||
}
|
||||
|
||||
void IntroSteps::deactivate() {
|
||||
hide();
|
||||
}
|
||||
|
||||
void IntroSteps::onNext() {
|
||||
intro()->onIntroNext();
|
||||
}
|
||||
|
||||
void IntroSteps::onBack() {
|
||||
}
|
43
Telegram/SourceFiles/intro/introsteps.h
Normal file
43
Telegram/SourceFiles/intro/introsteps.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "gui/flatbutton.h"
|
||||
#include "intro.h"
|
||||
|
||||
class IntroSteps : public IntroStage {
|
||||
public:
|
||||
|
||||
IntroSteps(IntroWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
void onNext();
|
||||
void onBack();
|
||||
|
||||
private:
|
||||
|
||||
FlatLabel _intro1, _intro2;
|
||||
|
||||
FlatButton _next;
|
||||
int32 _headerWidth;
|
||||
};
|
Reference in New Issue
Block a user