2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-09-05 17:06:03 +00:00

Improve QR code login layout.

This commit is contained in:
John Preston
2019-11-26 14:10:44 +03:00
parent 32d567120b
commit 339a80e192
20 changed files with 1031 additions and 809 deletions

View File

@@ -7,11 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "intro/intro_qr.h"
#include "lang/lang_keys.h"
#include "intro/introphone.h"
#include "lang/lang_keys.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/text/text_utilities.h"
#include "main/main_account.h"
#include "boxes/confirm_box.h"
#include "core/application.h"
@@ -20,14 +22,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_intro.h"
namespace Intro {
namespace details {
namespace {
[[nodiscard]] QImage TelegramLogoImage(int size) {
return Core::App().logo().scaled(
size,
size,
constexpr auto kScale = 0.8;
const auto used = int(size * kScale);
const auto adjusted = used + ((used % 2) + (size % 2)) % 2;
const auto image = Core::App().logo().scaled(
adjusted,
adjusted,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
auto result = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
result.fill(Qt::transparent);
{
QPainter p(&result);
p.drawImage(
QRect(
(size - adjusted) / 2,
(size - adjusted) / 2,
adjusted,
adjusted),
image);
}
return result;
}
[[nodiscard]] QImage TelegramQrExact(const Qr::Data &data, int pixel) {
@@ -46,17 +65,22 @@ namespace {
}
[[nodiscard]] QImage TelegramQr(const QString &text, int pixel, int max) {
return TelegramQr(Qr::Encode(text), pixel, max);
return TelegramQr(
Qr::Encode(text, Qr::Redundancy::Quartile),
pixel,
max);
}
[[nodiscard]] not_null<Ui::RpWidget*> PrepareQrWidget(
not_null<QWidget*> parent,
rpl::producer<QImage> images) {
rpl::producer<QByteArray> codes) {
auto result = Ui::CreateChild<Ui::RpWidget>(parent.get());
auto current = result->lifetime().make_state<QImage>();
std::move(
images
) | rpl::start_with_next([=](QImage &&image) {
codes
) | rpl::map([](const QByteArray &code) {
return TelegramQr(code, st::introQrPixel, st::introQrMaxSize);
}) | rpl::start_with_next([=](QImage &&image) {
result->resize(image.size() / cIntRetinaFactor());
*current = std::move(image);
result->update();
@@ -77,12 +101,11 @@ namespace {
QrWidget::QrWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data)
: Step(parent, account, data)
, _code(PrepareQrWidget(this, _qrImages.events()))
, _refreshTimer([=] { refreshCode(); }) {
setTitleText(tr::lng_intro_qr_title());
setDescriptionText(tr::lng_intro_qr_description());
not_null<Data*> data)
: Step(parent, account, data)
, _refreshTimer([=] { refreshCode(); }) {
setTitleText(rpl::single(QString()));
setDescriptionText(rpl::single(QString()));
setErrorCentered(true);
account->destroyStaleAuthorizationKeys();
@@ -91,20 +114,10 @@ QrWidget::QrWidget(
checkForTokenUpdate(updates);
}, lifetime());
_code->widthValue(
) | rpl::start_with_next([=] {
updateCodeGeometry();
}, _code->lifetime());
_code->show();
setupControls();
refreshCode();
}
void QrWidget::resizeEvent(QResizeEvent *e) {
Step::resizeEvent(e);
updateCodeGeometry();
}
void QrWidget::checkForTokenUpdate(const MTPUpdates &updates) {
updates.match([&](const MTPDupdateShort &data) {
checkForTokenUpdate(data.vupdate());
@@ -130,18 +143,77 @@ void QrWidget::checkForTokenUpdate(const MTPUpdate &update) {
}, [](const auto &) {});
}
void QrWidget::updateCodeGeometry() {
_code->moveToLeft(
(width() - _code->width()) / 2,
contentTop() + st::introQrTop);
}
void QrWidget::submit() {
goReplace<PhoneWidget>();
}
rpl::producer<QString> QrWidget::nextButtonText() const {
return tr::lng_intro_qr_skip();
return rpl::single(QString());
}
void QrWidget::setupControls() {
const auto code = PrepareQrWidget(this, _qrCodes.events());
rpl::combine(
sizeValue(),
code->widthValue()
) | rpl::start_with_next([=](QSize size, int codeWidth) {
code->moveToLeft(
(size.width() - codeWidth) / 2,
contentTop() + st::introQrTop);
}, code->lifetime());
const auto title = Ui::CreateChild<Ui::FlatLabel>(
this,
tr::lng_intro_qr_title(),
st::introQrTitle);
rpl::combine(
sizeValue(),
title->widthValue()
) | rpl::start_with_next([=](QSize size, int titleWidth) {
title->moveToLeft(
(size.width() - st::introQrLabelsWidth) / 2,
contentTop() + st::introQrTitleTop);
}, title->lifetime());
const auto steps = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto texts = {
tr::lng_intro_qr_step1,
tr::lng_intro_qr_step2,
tr::lng_intro_qr_step3,
};
for (const auto &text : texts) {
steps->add(
object_ptr<Ui::FlatLabel>(
this,
text(Ui::Text::RichLangValue),
st::introQrStep),
st::introQrStepMargins);
}
steps->resizeToWidth(st::introQrLabelsWidth);
rpl::combine(
sizeValue(),
steps->widthValue()
) | rpl::start_with_next([=](QSize size, int stepsWidth) {
steps->moveToLeft(
(size.width() - stepsWidth) / 2,
contentTop() + st::introQrStepsTop);
}, steps->lifetime());
const auto skip = Ui::CreateChild<Ui::LinkButton>(
this,
tr::lng_intro_qr_skip(tr::now));
rpl::combine(
sizeValue(),
skip->widthValue()
) | rpl::start_with_next([=](QSize size, int skipWidth) {
skip->moveToLeft(
(size.width() - skipWidth) / 2,
contentTop() + st::introQrSkipTop);
}, skip->lifetime());
skip->setClickedCallback([=] {
goNext<PhoneWidget>();
});
}
void QrWidget::refreshCode() {
@@ -188,8 +260,7 @@ void QrWidget::showTokenError(const RPCError &error) {
void QrWidget::showToken(const QByteArray &token) {
const auto encoded = token.toBase64(QByteArray::Base64UrlEncoding);
const auto text = "tg_login/" + encoded;
_qrImages.fire(TelegramQr(text, st::introQrPixel, st::introQrMaxSize));
_qrCodes.fire_copy("tg_login/" + encoded);
}
void QrWidget::importTo(MTP::DcId dcId, const QByteArray &token) {
@@ -223,7 +294,7 @@ void QrWidget::done(const MTPauth_Authorization &authorization) {
void QrWidget::activate() {
Step::activate();
_code->show();
showChildren();
}
void QrWidget::finished() {
@@ -237,4 +308,5 @@ void QrWidget::cancelled() {
_api.request(base::take(_requestId)).cancel();
}
} // namespace details
} // namespace Intro