tdesktop/Telegram/SourceFiles/intro/introwidget.cpp

412 lines
11 KiB
C++
Raw Normal View History

/*
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.
2015-10-03 13:16:42 +00:00
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
2016-02-08 10:56:18 +00:00
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "intro/introwidget.h"
#include "lang.h"
#include "localstorage.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 "mainwindow.h"
#include "application.h"
#include "ui/text/text.h"
#include "ui/buttons/icon_button.h"
#include "ui/effects/widget_fade_wrap.h"
2016-10-27 14:10:28 +00:00
#include "styles/style_intro.h"
#include "autoupdater.h"
IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
2015-12-08 12:33:37 +00:00
, _a_stage(animation(this, &IntroWidget::step_stage))
, _a_show(animation(this, &IntroWidget::step_show))
, _back(this, new Ui::IconButton(this, st::introBackButton), base::lambda_unique<void()>(), st::introSlideDuration)
, _settings(this, lang(lng_menu_settings), st::defaultBoxButton) {
_back->entity()->setClickedCallback([this] { onBack(); });
_back->hideFast();
_settings->setClickedCallback([] { App::wnd()->showSettings(); });
2016-04-14 19:24:42 +00:00
_countryForReg = psCurrentCountry();
2016-04-14 19:24:42 +00:00
MTP::send(MTPhelp_GetNearestDc(), rpcDone(&IntroWidget::gotNearestDC));
_stepHistory.push_back(new IntroStart(this));
_back->raise();
_settings->raise();
show();
setFocus();
cSetPasswordRecovered(false);
_back->moveToLeft(st::introBackPosition.x(), st::introBackPosition.y());
2016-04-14 19:24:42 +00:00
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onCheckUpdateStatus()));
Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onCheckUpdateStatus()));
Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onCheckUpdateStatus()));
2016-04-14 19:24:42 +00:00
Sandbox::startUpdateCheck();
onCheckUpdateStatus();
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void IntroWidget::onCheckUpdateStatus() {
if (Sandbox::updatingState() == Application::UpdatingReady) {
if (_update) return;
_update.create(this, lang(lng_menu_update).toUpper(), st::defaultBoxButton);
_update->show();
_update->setClickedCallback([] {
checkReadyUpdate();
App::restart();
});
} else {
if (!_update) return;
_update.destroy();
}
updateControlsGeometry();
}
#endif // TDESKTOP_DISABLE_AUTOUPDATE
void IntroWidget::langChangeTo(int32 langId) {
_langChangeTo = langId;
}
void IntroWidget::onChangeLang() {
cSetLang(_langChangeTo);
Local::writeSettings();
App::restart();
}
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);
2015-10-15 11:51:10 +00:00
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;
}
2015-04-04 20:01:34 +00:00
_cacheShow = grabStep();
_backTo = step()->hasBack() ? 1 : 0;
int32 m = (type == MoveBack) ? -1 : 1;
2015-10-17 14:52:26 +00:00
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();
2015-12-08 12:33:37 +00:00
_a_stage.step();
if (_backTo) {
_back->fadeIn();
} else {
_back->fadeOut();
}
step()->hide();
}
void IntroWidget::pushStep(IntroStep *step, MoveType type) {
_stepHistory.push_back(step);
_back->raise();
_settings->raise();
if (_update) {
_update->raise();
}
_stepHistory.back()->hide();
historyMove(type);
}
2016-04-14 19:24:42 +00:00
void IntroWidget::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 countryChanged();
}
}
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) {
2015-10-15 11:51:10 +00:00
if (App::app()) App::app()->mtpPause();
2015-10-17 14:52:26 +00:00
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
2015-10-17 14:52:26 +00:00
_a_show.stop();
step()->show();
if (step()->hasBack()) {
_back->showFast();
} else {
_back->hideFast();
}
2015-10-17 14:52:26 +00:00
(back ? _cacheUnder : _cacheOver) = myGrab(this);
step()->hide();
_back->hideFast();
2015-10-17 14:52:26 +00:00
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift);
2015-10-17 14:52:26 +00:00
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();
}
2015-12-08 12:33:37 +00:00
void IntroWidget::step_show(float64 ms, bool timer) {
2015-10-17 14:52:26 +00:00
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->showFast();
}
2015-10-17 14:52:26 +00:00
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);
}
2015-12-08 12:33:37 +00:00
if (timer) update();
2015-10-17 14:52:26 +00:00
}
2015-12-08 12:33:37 +00:00
void IntroWidget::stop_show() {
2015-10-17 14:52:26 +00:00
_a_show.stop();
}
2015-12-08 12:33:37 +00:00
void IntroWidget::step_stage(float64 ms, bool timer) {
2015-10-17 14:52:26 +00:00
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) {
2015-12-08 12:33:37 +00:00
_a_stage.stop();
2015-10-17 14:52:26 +00:00
a_coordShow.finish();
a_opacityShow.finish();
2015-10-17 14:52:26 +00:00
_cacheHide = _cacheShow = QPixmap();
setFocus();
step()->activate();
if (App::app()) App::app()->mtpUnpause();
} else {
2015-10-17 14:52:26 +00:00
a_coordShow.update(dt2, st::introShowFunc);
a_opacityShow.update(dt2, st::introAlphaShowFunc);
a_coordHide.update(dt1, st::introHideFunc);
a_opacityHide.update(dt1, st::introAlphaHideFunc);
}
2015-12-08 12:33:37 +00:00
if (timer) update();
}
void IntroWidget::paintEvent(QPaintEvent *e) {
bool trivial = (rect() == e->rect());
setMouseTracking(true);
QPainter p(this);
if (!trivial) {
p.setClipRect(e->rect());
}
2016-10-31 12:29:26 +00:00
p.fillRect(e->rect(), st::windowBg);
2015-10-17 14:52:26 +00:00
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()));
2016-10-31 12:29:26 +00:00
p.setOpacity(a_shadow.current());
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg);
2015-10-17 14:52:26 +00:00
p.setOpacity(1);
}
2015-10-17 14:52:26 +00:00
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()));
2015-10-17 14:52:26 +00:00
} else if (_a_stage.animating()) {
p.setOpacity(a_opacityHide.current());
p.drawPixmap(step()->x() + st::introSlideShift + a_coordHide.current(), step()->y(), _cacheHide);
2015-10-17 14:52:26 +00:00
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 {
2016-04-14 19:24:42 +00:00
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;
}
2016-03-15 19:38:30 +00:00
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;
}
2016-03-15 19:38:30 +00:00
const IntroWidget::CallStatus &IntroWidget::getCallStatus() const {
return _callStatus;
}
const QByteArray &IntroWidget::getPwdSalt() const {
return _pwdSalt;
}
bool IntroWidget::getHasRecovery() const {
return _hasRecovery;
}
const QString &IntroWidget::getPwdHint() const {
return _pwdHint;
}
bool IntroWidget::codeByTelegram() const {
return _codeByTelegram;
}
void IntroWidget::resizeEvent(QResizeEvent *e) {
auto r = innerRect();
for (auto step : _stepHistory) {
step->setGeometry(r);
}
updateControlsGeometry();
}
void IntroWidget::updateControlsGeometry() {
_settings->moveToLeft(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _settings->height());
if (_update) {
_update->moveToLeft(st::boxButtonPadding.right() + _settings->width() + st::boxButtonPadding.left(), _settings->y());
}
}
void IntroWidget::finish(const MTPUser &user, const QImage &photo) {
App::wnd()->setupMain(&user);
if (!photo.isNull()) {
App::app()->uploadProfilePhoto(photo, MTP::authedId());
}
}
void IntroWidget::keyPressEvent(QKeyEvent *e) {
2015-10-17 14:52:26 +00:00
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::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);
}