1
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-04-11 04:01:18 +00:00
tdesktop/Telegram/SourceFiles/intro/introwidget.cpp
John Preston 8e89486fbc Error handling changed, 'auto' keyword used for MTP types.
All errors that lead to MTP request resending by default
error handler now can be handled differently. For example
inline bot requests are not being resent on 5XX error codes.
+ extensive use of auto keyword in MTP types handling.
2016-04-08 14:44:35 +04:00

408 lines
10 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "lang.h"
#include "ui/style.h"
#include "localstorage.h"
#include "intro/introwidget.h"
#include "intro/introstart.h"
#include "intro/introphone.h"
#include "intro/introcode.h"
#include "intro/introsignup.h"
#include "intro/intropwdcheck.h"
#include "mainwidget.h"
#include "window.h"
#include "application.h"
#include "ui/text.h"
namespace {
IntroWidget *signalEmitOn = 0;
QString countryForReg;
void gotNearestDC(const MTPNearestDc &result) {
const 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 signalEmitOn->countryChanged();
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::startUpdateCheck();
#endif
}
}
IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
, _langChangeTo(0)
, _a_stage(animation(this, &IntroWidget::step_stage))
, _cacheHideIndex(0)
, _cacheShowIndex(0)
, _a_show(animation(this, &IntroWidget::step_show))
, _callStatus({ CallDisabled, 0 })
, _registered(false)
, _hasRecovery(false)
, _codeByTelegram(false)
, _back(this, st::setClose)
, _backFrom(0)
, _backTo(0) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
connect(&_back, SIGNAL(clicked()), this, SLOT(onBack()));
_back.hide();
countryForReg = psCurrentCountry();
MTP::send(MTPhelp_GetNearestDc(), rpcDone(gotNearestDC));
signalEmitOn = this;
_stepHistory.push_back(new IntroStart(this));
_back.raise();
connect(parent, SIGNAL(resized(const QSize&)), this, SLOT(onParentResize(const QSize&)));
show();
setFocus();
cSetPasswordRecovered(false);
_back.move(st::setClosePos.x(), st::setClosePos.y());
}
void IntroWidget::langChangeTo(int32 langId) {
_langChangeTo = langId;
}
void IntroWidget::onChangeLang() {
cSetLang(_langChangeTo);
Local::writeSettings();
cSetRestarting(true);
cSetRestartingToSettings(false);
App::quit();
}
void IntroWidget::onParentResize(const QSize &newSize) {
resize(newSize);
}
void IntroWidget::onStepSubmit() {
step()->onSubmit();
}
void IntroWidget::onBack() {
historyMove(MoveBack);
}
void IntroWidget::historyMove(MoveType type) {
if (_a_stage.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;
_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;
_stepHistory.removeAt(_stepHistory.size() - 2);
replaced->finished();
delete replaced;
} break;
}
_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 (_backFrom > 0 || _backTo > 0) {
_back.show();
} else {
_back.hide();
}
step()->hide();
}
void IntroWidget::pushStep(IntroStep *step, MoveType type) {
_stepHistory.push_back(step);
_back.raise();
_stepHistory.back()->hide();
historyMove(type);
}
QPixmap IntroWidget::grabStep(int skip) {
return myGrab(step(skip), QRect(st::introSlideShift, 0, st::introSize.width(), st::introSize.height()));
}
void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) {
if (App::app()) App::app()->mtpPause();
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
_a_show.stop();
step()->show();
if (step()->hasBack()) {
_back.setOpacity(1);
_back.show();
} else {
_back.hide();
}
(back ? _cacheUnder : _cacheOver) = myGrab(this);
step()->hide();
_back.hide();
a_coordUnder = back ? anim::ivalue(-qFloor(st::slideShift * width()), 0) : anim::ivalue(0, -qFloor(st::slideShift * width()));
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
a_shadow = back ? anim::fvalue(1, 0) : anim::fvalue(0, 1);
_a_show.start();
show();
}
void IntroWidget::step_show(float64 ms, bool timer) {
float64 dt = ms / st::slideDuration;
if (dt >= 1) {
_a_show.stop();
a_coordUnder.finish();
a_coordOver.finish();
a_shadow.finish();
_cacheUnder = _cacheOver = QPixmap();
setFocus();
step()->activate();
if (step()->hasBack()) {
_back.setOpacity(1);
_back.show();
}
if (App::app()) App::app()->mtpUnpause();
} else {
a_coordUnder.update(dt, st::slideFunction);
a_coordOver.update(dt, st::slideFunction);
a_shadow.update(dt, st::slideFunction);
}
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 (!step()->hasBack()) {
_back.hide();
}
if (App::app()) App::app()->mtpUnpause();
} else {
a_coordShow.update(dt2, st::introShowFunc);
a_opacityShow.update(dt2, st::introAlphaShowFunc);
a_coordHide.update(dt1, st::introHideFunc);
a_opacityHide.update(dt1, st::introAlphaHideFunc);
if (_backFrom != _backTo) {
_back.setOpacity((_backFrom > _backTo) ? a_opacityHide.current() : a_opacityShow.current());
} else {
_back.setOpacity(1);
}
}
if (timer) update();
}
void IntroWidget::paintEvent(QPaintEvent *e) {
bool trivial = (rect() == e->rect());
setMouseTracking(true);
QPainter p(this);
if (!trivial) {
p.setClipRect(e->rect());
}
p.fillRect(e->rect(), st::white->b);
if (_a_show.animating()) {
if (a_coordOver.current() > 0) {
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * cRetinaFactor(), 0, a_coordOver.current() * cRetinaFactor(), height() * cRetinaFactor()));
p.setOpacity(a_shadow.current() * st::slideFadeOut);
p.fillRect(0, 0, a_coordOver.current(), height(), st::black->b);
p.setOpacity(1);
}
p.drawPixmap(a_coordOver.current(), 0, _cacheOver);
p.setOpacity(a_shadow.current());
p.drawPixmap(QRect(a_coordOver.current() - st::slideShadow.pxWidth(), 0, st::slideShadow.pxWidth(), height()), App::sprite(), st::slideShadow);
} 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);
}
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) {
QRect r(innerRect());
for (IntroStep *step : _stepHistory) {
step->setGeometry(r);
}
}
void IntroWidget::finish(const MTPUser &user, const QImage &photo) {
App::wnd()->setupMain(true, &user);
if (!photo.isNull()) {
App::app()->uploadProfilePhoto(photo, MTP::authedId());
}
}
void IntroWidget::keyPressEvent(QKeyEvent *e) {
if (_a_show.animating() || _a_stage.animating()) return;
if (e->key() == Qt::Key_Escape) {
if (step()->hasBack()) {
onBack();
}
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) {
onStepSubmit();
}
}
void IntroWidget::updateAdaptiveLayout() {
}
void IntroWidget::rpcClear() {
for (IntroStep *step : _stepHistory) {
step->rpcClear();
}
}
IntroWidget::~IntroWidget() {
while (!_stepHistory.isEmpty()) {
IntroStep *back = _stepHistory.back();
_stepHistory.pop_back();
delete back;
}
if (App::wnd()) App::wnd()->noIntro(this);
}