From 5fc4f4ed365c2c5ee80c8332ab872a3a1bcbeb7f Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Tue, 30 May 2017 16:54:05 +0300 Subject: [PATCH] Realtime UI translation in Intro. Also support realtime translation testing by F7-F6-F7-F8 keys. --- Telegram/SourceFiles/intro/introcode.cpp | 43 +++++++---- Telegram/SourceFiles/intro/introcode.h | 4 +- Telegram/SourceFiles/intro/introphone.cpp | 23 +++--- Telegram/SourceFiles/intro/introphone.h | 6 +- Telegram/SourceFiles/intro/intropwdcheck.cpp | 42 ++++++++--- Telegram/SourceFiles/intro/intropwdcheck.h | 2 + Telegram/SourceFiles/intro/introsignup.cpp | 34 ++++++--- Telegram/SourceFiles/intro/introsignup.h | 2 + Telegram/SourceFiles/intro/introstart.cpp | 4 +- Telegram/SourceFiles/intro/introwidget.cpp | 73 ++++++++++++++----- Telegram/SourceFiles/intro/introwidget.h | 24 ++++-- .../SourceFiles/lang/lang_cloud_manager.cpp | 9 +-- Telegram/SourceFiles/lang/lang_instance.cpp | 24 +++++- Telegram/SourceFiles/lang/lang_instance.h | 2 +- Telegram/SourceFiles/mainwindow.cpp | 32 +++++++- .../SourceFiles/settings/settings_widget.cpp | 4 +- .../SourceFiles/ui/widgets/input_fields.cpp | 23 ++++++ .../SourceFiles/ui/widgets/input_fields.h | 4 + 18 files changed, 266 insertions(+), 89 deletions(-) diff --git a/Telegram/SourceFiles/intro/introcode.cpp b/Telegram/SourceFiles/intro/introcode.cpp index f25231b83..4ebf58aca 100644 --- a/Telegram/SourceFiles/intro/introcode.cpp +++ b/Telegram/SourceFiles/intro/introcode.cpp @@ -88,6 +88,8 @@ CodeWidget::CodeWidget(QWidget *parent, Widget::Data *data) : Step(parent, data) , _callTimeout(getData()->callTimeout) , _callLabel(this, st::introDescription) , _checkRequest(this) { + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); + connect(_code, SIGNAL(changed()), this, SLOT(onInputChange())); connect(_callTimer, SIGNAL(timeout()), this, SLOT(onSendCall())); connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest())); @@ -96,12 +98,19 @@ CodeWidget::CodeWidget(QWidget *parent, Widget::Data *data) : Step(parent, data) _code->setDigitsCountMax(getData()->codeLength); setErrorBelowLink(true); - setTitleText(App::formatPhone(getData()->phone)); + setTitleText([text = App::formatPhone(getData()->phone)] { return text; }); updateDescText(); } +void CodeWidget::refreshLang() { + if (_noTelegramCode) _noTelegramCode->setText(lang(lng_code_no_telegram)); + if (_code) _code->setPlaceholder(lang(lng_code_ph)); + updateDescText(); + updateControlsGeometry(); +} + void CodeWidget::updateDescText() { - setDescriptionText(lang(getData()->codeByTelegram ? lng_code_telegram : lng_code_desc)); + setDescriptionText([byTelegram = getData()->codeByTelegram] { return lang(byTelegram ? lng_code_telegram : lng_code_desc); }); if (getData()->codeByTelegram) { _noTelegramCode->show(); _callTimer->stop(); @@ -140,15 +149,19 @@ void CodeWidget::updateCallText() { void CodeWidget::resizeEvent(QResizeEvent *e) { Step::resizeEvent(e); + updateControlsGeometry(); +} + +void CodeWidget::updateControlsGeometry() { _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 CodeWidget::showCodeError(const QString &text) { - if (!text.isEmpty()) _code->showError(); - showError(text); +void CodeWidget::showCodeError(base::lambda<QString()> textFactory) { + if (textFactory) _code->showError(); + showError(std::move(textFactory)); } void CodeWidget::setInnerFocus() { @@ -208,7 +221,7 @@ void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) { _sentRequest = 0; auto &d = result.c_auth_authorization(); if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf? - showCodeError(lang(lng_server_error)); + showCodeError([] { return lang(lng_server_error); }); return; } cSetLoggedPhoneNumber(getData()->phone); @@ -219,7 +232,7 @@ bool CodeWidget::codeSubmitFail(const RPCError &error) { if (MTP::isFloodError(error)) { stopCheck(); _sentRequest = 0; - showCodeError(lang(lng_flood_error)); + showCodeError([] { return lang(lng_flood_error); }); return true; } if (MTP::isDefaultHandledError(error)) return false; @@ -231,7 +244,7 @@ bool CodeWidget::codeSubmitFail(const RPCError &error) { goBack(); return true; } else if (err == qstr("PHONE_CODE_EMPTY") || err == qstr("PHONE_CODE_INVALID")) { - showCodeError(lang(lng_bad_code)); + showCodeError([] { return lang(lng_bad_code); }); return true; } else if (err == qstr("PHONE_NUMBER_UNOCCUPIED")) { // success, need to signUp getData()->code = _sentCode; @@ -244,9 +257,10 @@ bool CodeWidget::codeSubmitFail(const RPCError &error) { return true; } if (cDebug()) { // internal server error - showCodeError(err + ": " + error.description()); + auto text = err + ": " + error.description(); + showCodeError([text] { return text; }); } else { - showCodeError(lang(lng_server_error)); + showCodeError([] { return lang(lng_server_error); }); } return false; } @@ -324,7 +338,7 @@ void CodeWidget::onNoTelegramCode() { void CodeWidget::noTelegramCodeDone(const MTPauth_SentCode &result) { if (result.type() != mtpc_auth_sentCode) { - showCodeError(lang(lng_server_error)); + showCodeError([] { return lang(lng_server_error); }); return; } @@ -344,15 +358,16 @@ void CodeWidget::noTelegramCodeDone(const MTPauth_SentCode &result) { bool CodeWidget::noTelegramCodeFail(const RPCError &error) { if (MTP::isFloodError(error)) { - showCodeError(lang(lng_flood_error)); + showCodeError([] { return lang(lng_flood_error); }); return true; } if (MTP::isDefaultHandledError(error)) return false; if (cDebug()) { // internal server error - showCodeError(error.type() + ": " + error.description()); + auto text = error.type() + ": " + error.description(); + showCodeError([text] { return text; }); } else { - showCodeError(lang(lng_server_error)); + showCodeError([] { return lang(lng_server_error); }); } return false; } diff --git a/Telegram/SourceFiles/intro/introcode.h b/Telegram/SourceFiles/intro/introcode.h index 4c9ee071a..37f8f5ad8 100644 --- a/Telegram/SourceFiles/intro/introcode.h +++ b/Telegram/SourceFiles/intro/introcode.h @@ -78,11 +78,13 @@ private slots: private: void updateCallText(); + void refreshLang(); + void updateControlsGeometry(); void codeSubmitDone(const MTPauth_Authorization &result); bool codeSubmitFail(const RPCError &error); - void showCodeError(const QString &text); + void showCodeError(base::lambda<QString()> textFactory); void callDone(const MTPauth_SentCode &v); void gotPassword(const MTPaccount_Password &result); diff --git a/Telegram/SourceFiles/intro/introphone.cpp b/Telegram/SourceFiles/intro/introphone.cpp index 3665efcfa..9b69b361f 100644 --- a/Telegram/SourceFiles/intro/introphone.cpp +++ b/Telegram/SourceFiles/intro/introphone.cpp @@ -48,8 +48,8 @@ PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, dat connect(_code, SIGNAL(changed()), this, SLOT(onInputChange())); connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest())); - setTitleText(lang(lng_phone_title)); - setDescriptionText(lang(lng_phone_desc)); + setTitleText([] { return lang(lng_phone_title); }); + setDescriptionText([] { return lang(lng_phone_desc); }); subscribe(getData()->updated, [this] { countryChanged(); }); setErrorCentered(true); @@ -76,9 +76,9 @@ void PhoneWidget::updateSignupGeometry() { } } -void PhoneWidget::showPhoneError(const QString &text) { +void PhoneWidget::showPhoneError(base::lambda<QString()> textFactory) { _phone->showError(); - showError(text); + showError(std::move(textFactory)); } void PhoneWidget::hidePhoneError() { @@ -90,7 +90,7 @@ void PhoneWidget::hidePhoneError() { } void PhoneWidget::showSignup() { - showPhoneError(lang(lng_bad_phone_noreg)); + showPhoneError([] { return 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 = object_ptr<Ui::FlatLabel>(this, signupText, Ui::FlatLabel::InitType::Rich, st::introDescription); @@ -121,7 +121,7 @@ void PhoneWidget::submit() { if (_sentRequest || isHidden()) return; if (!App::isValidPhone(fullNumber())) { - showPhoneError(lang(lng_bad_phone)); + showPhoneError([] { return lang(lng_bad_phone); }); _phone->setFocus(); return; } @@ -172,7 +172,7 @@ void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) { _sentRequest = 0; if (result.type() != mtpc_auth_sentCode) { - showPhoneError(lang(lng_server_error)); + showPhoneError([] { return lang(lng_server_error); }); return; } @@ -203,7 +203,7 @@ bool PhoneWidget::phoneSubmitFail(const RPCError &error) { if (MTP::isFloodError(error)) { stopCheck(); _sentRequest = 0; - showPhoneError(lang(lng_flood_error)); + showPhoneError([] { return lang(lng_flood_error); }); return true; } if (MTP::isDefaultHandledError(error)) return false; @@ -215,13 +215,14 @@ bool PhoneWidget::phoneSubmitFail(const RPCError &error) { Ui::show(Box<InformBox>(lang(lng_error_phone_flood))); return true; } else if (err == qstr("PHONE_NUMBER_INVALID")) { // show error - showPhoneError(lang(lng_bad_phone)); + showPhoneError([] { return lang(lng_bad_phone); }); return true; } if (cDebug()) { // internal server error - showPhoneError(err + ": " + error.description()); + auto text = err + ": " + error.description(); + showPhoneError([text] { return text; }); } else { - showPhoneError(lang(lng_server_error)); + showPhoneError([] { return lang(lng_server_error); }); } return false; } diff --git a/Telegram/SourceFiles/intro/introphone.h b/Telegram/SourceFiles/intro/introphone.h index fd2c35857..2f1ae2ed4 100644 --- a/Telegram/SourceFiles/intro/introphone.h +++ b/Telegram/SourceFiles/intro/introphone.h @@ -53,6 +53,10 @@ public: protected: void resizeEvent(QResizeEvent *e) override; + bool hasChangeLanguageNoCover() const override { + return true; + } + private slots: void onInputChange(); void onCheckRequest(); @@ -70,7 +74,7 @@ private: QString fullNumber() const; void stopCheck(); - void showPhoneError(const QString &text); + void showPhoneError(base::lambda<QString()> textFactory); void hidePhoneError(); void showSignup(); diff --git a/Telegram/SourceFiles/intro/intropwdcheck.cpp b/Telegram/SourceFiles/intro/intropwdcheck.cpp index 9f25f4ce8..2b2debf48 100644 --- a/Telegram/SourceFiles/intro/intropwdcheck.cpp +++ b/Telegram/SourceFiles/intro/intropwdcheck.cpp @@ -43,13 +43,15 @@ PwdCheckWidget::PwdCheckWidget(QWidget *parent, Widget::Data *data) : Step(paren , _toRecover(this, lang(lng_signin_recover)) , _toPassword(this, lang(lng_signin_try_password)) , _checkRequest(this) { + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); + 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())); - setTitleText(lang(lng_signin_title)); + setTitleText([] { return lang(lng_signin_title); }); updateDescriptionText(); setErrorBelowLink(true); @@ -64,8 +66,20 @@ PwdCheckWidget::PwdCheckWidget(QWidget *parent, Widget::Data *data) : Step(paren setMouseTracking(true); } +void PwdCheckWidget::refreshLang() { + if (_pwdField) _pwdField->setPlaceholder(lang(lng_signin_password)); + if (_codeField) _codeField->setPlaceholder(lang(lng_signin_code)); + if (_toRecover) _toRecover->setText(lang(lng_signin_recover)); + if (_toPassword) _toPassword->setText(lang(lng_signin_try_password)); + updateControlsGeometry(); +} + void PwdCheckWidget::resizeEvent(QResizeEvent *e) { Step::resizeEvent(e); + updateControlsGeometry(); +} + +void PwdCheckWidget::updateControlsGeometry() { _pwdField->moveToLeft(contentLeft(), contentTop() + st::introPasswordTop); _pwdHint->moveToLeft(contentLeft() + st::buttonRadius, contentTop() + st::introPasswordHintTop); _codeField->moveToLeft(contentLeft(), contentTop() + st::introStepFieldTop); @@ -121,7 +135,7 @@ void PwdCheckWidget::pwdSubmitDone(bool recover, const MTPauth_Authorization &re } auto &d = result.c_auth_authorization(); if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf? - showError(lang(lng_server_error)); + showError([] { return lang(lng_server_error); }); return; } finish(d.vuser); @@ -131,7 +145,7 @@ bool PwdCheckWidget::pwdSubmitFail(const RPCError &error) { if (MTP::isFloodError(error)) { _sentRequest = 0; stopCheck(); - showError(lang(lng_flood_error)); + showError([] { return lang(lng_flood_error); }); _pwdField->showError(); return true; } @@ -141,7 +155,7 @@ bool PwdCheckWidget::pwdSubmitFail(const RPCError &error) { stopCheck(); auto &err = error.type(); if (err == qstr("PASSWORD_HASH_INVALID")) { - showError(lang(lng_signin_bad_password)); + showError([] { return lang(lng_signin_bad_password); }); _pwdField->selectAll(); _pwdField->showError(); return true; @@ -149,9 +163,10 @@ bool PwdCheckWidget::pwdSubmitFail(const RPCError &error) { goBack(); } if (cDebug()) { // internal server error - showError(err + ": " + error.description()); + auto text = err + ": " + error.description(); + showError([text] { return text; }); } else { - showError(lang(lng_server_error)); + showError([] { return lang(lng_server_error); }); } _pwdField->setFocus(); return false; @@ -159,7 +174,7 @@ bool PwdCheckWidget::pwdSubmitFail(const RPCError &error) { bool PwdCheckWidget::codeSubmitFail(const RPCError &error) { if (MTP::isFloodError(error)) { - showError(lang(lng_flood_error)); + showError([] { return lang(lng_flood_error); }); _codeField->showError(); return true; } @@ -179,15 +194,16 @@ bool PwdCheckWidget::codeSubmitFail(const RPCError &error) { onToPassword(); return true; } else if (err == qstr("CODE_INVALID")) { - showError(lang(lng_signin_wrong_code)); + showError([] { return lang(lng_signin_wrong_code); }); _codeField->selectAll(); _codeField->showError(); return true; } if (cDebug()) { // internal server error - showError(err + ": " + error.description()); + auto text = err + ": " + error.description(); + showError([text] { return text; }); } else { - showError(lang(lng_server_error)); + showError([] { return lang(lng_server_error); }); } _codeField->setFocus(); return false; @@ -253,7 +269,11 @@ void PwdCheckWidget::showReset() { } void PwdCheckWidget::updateDescriptionText() { - setDescriptionText(_pwdField->isHidden() ? lng_signin_recover_desc(lt_email, _emailPattern) : lang(lng_signin_desc)); + auto pwdHidden = _pwdField->isHidden(); + auto emailPattern = _emailPattern; + setDescriptionText([pwdHidden, emailPattern] { + return pwdHidden ? lng_signin_recover_desc(lt_email, emailPattern) : lang(lng_signin_desc); + }); } void PwdCheckWidget::onInputChange() { diff --git a/Telegram/SourceFiles/intro/intropwdcheck.h b/Telegram/SourceFiles/intro/intropwdcheck.h index 9998dd2b3..182649268 100644 --- a/Telegram/SourceFiles/intro/intropwdcheck.h +++ b/Telegram/SourceFiles/intro/intropwdcheck.h @@ -54,6 +54,8 @@ private slots: private: void showReset(); + void refreshLang(); + void updateControlsGeometry(); void pwdSubmitDone(bool recover, const MTPauth_Authorization &result); bool pwdSubmitFail(const RPCError &error); diff --git a/Telegram/SourceFiles/intro/introsignup.cpp b/Telegram/SourceFiles/intro/introsignup.cpp index 6dfa587de..3cf46afa6 100644 --- a/Telegram/SourceFiles/intro/introsignup.cpp +++ b/Telegram/SourceFiles/intro/introsignup.cpp @@ -40,6 +40,8 @@ SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, d , _last(this, st::introName, lang(lng_signup_lastname)) , _invertOrder(langFirstNameGoesSecond()) , _checkRequest(this) { + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); + connect(_checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest())); setupPhotoButton(); @@ -49,11 +51,17 @@ SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, d } setErrorCentered(true); - setTitleText(lang(lng_signup_title)); - setDescriptionText(lang(lng_signup_desc)); + setTitleText([] { return lang(lng_signup_title); }); + setDescriptionText([] { return lang(lng_signup_desc); }); setMouseTracking(true); } +void SignupWidget::refreshLang() { + _first->setPlaceholder(lang(lng_signup_firstname)); + _last->setPlaceholder(lang(lng_signup_lastname)); + updateControlsGeometry(); +} + void SignupWidget::setupPhotoButton() { _photo->setClickedCallback(App::LambdaDelayed(st::defaultActiveButton.ripple.hideDuration, this, [this] { auto imgExtensions = cImgExtensions(); @@ -71,7 +79,7 @@ void SignupWidget::setupPhotoButton() { } if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { - showError(lang(lng_bad_photo)); + showError([] { return lang(lng_bad_photo); }); return; } auto box = Ui::show(Box<PhotoCropBox>(img, PeerId(0))); @@ -82,7 +90,10 @@ void SignupWidget::setupPhotoButton() { void SignupWidget::resizeEvent(QResizeEvent *e) { Step::resizeEvent(e); + updateControlsGeometry(); +} +void SignupWidget::updateControlsGeometry() { auto photoRight = contentLeft() + st::introNextButton.width; auto photoTop = contentTop() + st::introPhotoTop; _photo->moveToLeft(photoRight - _photo->width(), photoTop); @@ -144,7 +155,7 @@ void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) { stopCheck(); auto &d = result.c_auth_authorization(); if (d.vuser.type() != mtpc_user || !d.vuser.c_user().is_self()) { // wtf? - showError(lang(lng_server_error)); + showError([] { return lang(lng_server_error); }); return; } finish(d.vuser, _photoImage); @@ -153,7 +164,7 @@ void SignupWidget::nameSubmitDone(const MTPauth_Authorization &result) { bool SignupWidget::nameSubmitFail(const RPCError &error) { if (MTP::isFloodError(error)) { stopCheck(); - showError(lang(lng_flood_error)); + showError([] { return lang(lng_flood_error); }); if (_invertOrder) { _first->setFocus(); } else { @@ -174,18 +185,19 @@ bool SignupWidget::nameSubmitFail(const RPCError &error) { goBack(); return true; } else if (err == "FIRSTNAME_INVALID") { - showError(lang(lng_bad_name)); + showError([] { return lang(lng_bad_name); }); _first->setFocus(); return true; } else if (err == "LASTNAME_INVALID") { - showError(lang(lng_bad_name)); + showError([] { return lang(lng_bad_name); }); _last->setFocus(); return true; } if (cDebug()) { // internal server error - showError(err + ": " + error.description()); + auto text = err + ": " + error.description(); + showError([text] { return text; }); } else { - showError(lang(lng_server_error)); + showError([] { return lang(lng_server_error); }); } if (_invertOrder) { _last->setFocus(); @@ -196,7 +208,7 @@ bool SignupWidget::nameSubmitFail(const RPCError &error) { } void SignupWidget::onInputChange() { - showError(QString()); + hideError(); } void SignupWidget::submit() { @@ -219,7 +231,7 @@ void SignupWidget::submit() { } } - showError(QString()); + hideError(); _firstName = _first->getLastText().trimmed(); _lastName = _last->getLastText().trimmed(); diff --git a/Telegram/SourceFiles/intro/introsignup.h b/Telegram/SourceFiles/intro/introsignup.h index 3b87e373b..2cda87e86 100644 --- a/Telegram/SourceFiles/intro/introsignup.h +++ b/Telegram/SourceFiles/intro/introsignup.h @@ -52,6 +52,8 @@ private slots: private: void setupPhotoButton(); + void refreshLang(); + void updateControlsGeometry(); void nameSubmitDone(const MTPauth_Authorization &result); bool nameSubmitFail(const RPCError &error); diff --git a/Telegram/SourceFiles/intro/introstart.cpp b/Telegram/SourceFiles/intro/introstart.cpp index c98f4993f..6cba84bf0 100644 --- a/Telegram/SourceFiles/intro/introstart.cpp +++ b/Telegram/SourceFiles/intro/introstart.cpp @@ -30,8 +30,8 @@ namespace Intro { StartWidget::StartWidget(QWidget *parent, Widget::Data *data) : Step(parent, data, true) { setMouseTracking(true); - setTitleText(qsl("Telegram Desktop")); - setDescriptionText(lang(lng_intro_about)); + setTitleText([] { return qsl("Telegram Desktop"); }); + setDescriptionText([] { return lang(lng_intro_about); }); show(); } diff --git a/Telegram/SourceFiles/intro/introwidget.cpp b/Telegram/SourceFiles/intro/introwidget.cpp index f22992e25..72c501b0f 100644 --- a/Telegram/SourceFiles/intro/introwidget.cpp +++ b/Telegram/SourceFiles/intro/introwidget.cpp @@ -71,14 +71,17 @@ Widget::Widget(QWidget *parent) : TWidget(parent) _settings->entity()->setClickedCallback([] { App::wnd()->showSettings(); }); - subscribe(Lang::CurrentCloudManager().firstLanguageSuggestion(), [this] { createLanguageLink(); }); - createLanguageLink(); - getNearestDC(); appendStep(new StartWidget(this, getData())); fixOrder(); + subscribe(Lang::CurrentCloudManager().firstLanguageSuggestion(), [this] { createLanguageLink(); }); + createLanguageLink(); + if (_changeLanguage) _changeLanguage->finishAnimation(); + + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); + show(); showControls(); getStep()->showFast(); @@ -94,14 +97,26 @@ Widget::Widget(QWidget *parent) : TWidget(parent) #endif // !TDESKTOP_DISABLE_AUTOUPDATE } +void Widget::refreshLang() { + if (_settings) _settings->entity()->setText(lang(lng_menu_settings)); + if (_update) _update->entity()->setText(lang(lng_menu_update)); + if (_resetAccount) _resetAccount->entity()->setText(lang(lng_signin_reset_account)); + if (_next) _next->setText(getStep()->nextButtonText()); + updateControlsGeometry(); +} + void Widget::createLanguageLink() { if (_changeLanguage) return; auto createLink = [this](const QString &text, const QString &languageId) { _changeLanguage.create(this, object_ptr<Ui::LinkButton>(this, text), st::introCoverDuration); + _changeLanguage->show(); + _changeLanguage->hideFast(); _changeLanguage->entity()->setClickedCallback([this, languageId] { Lang::CurrentCloudManager().switchToLanguage(languageId); }); + _changeLanguage->toggleAnimated(getStep()->hasChangeLanguage()); + updateControlsGeometry(); }; auto currentId = Lang::Current().id(); @@ -124,7 +139,7 @@ void Widget::createLanguageLink() { void Widget::onCheckUpdateStatus() { if (Sandbox::updatingState() == Application::UpdatingReady) { if (_update) return; - _update.create(this, object_ptr<Ui::RoundButton>(this, lang(lng_menu_update).toUpper(), st::defaultBoxButton), st::introCoverDuration); + _update.create(this, object_ptr<Ui::RoundButton>(this, lang(lng_menu_update), st::defaultBoxButton), st::introCoverDuration); if (!_a_show.animating()) _update->show(); _update->entity()->setClickedCallback([] { checkReadyUpdate(); @@ -176,7 +191,7 @@ void Widget::historyMove(Direction direction) { auto stepHasCover = getStep()->hasCover(); _settings->toggleAnimated(!stepHasCover); if (_update) _update->toggleAnimated(!stepHasCover); - if (_changeLanguage) _changeLanguage->toggleAnimated(stepHasCover); + if (_changeLanguage) _changeLanguage->toggleAnimated(getStep()->hasChangeLanguage()); _next->setText(getStep()->nextButtonText()); if (_resetAccount) _resetAccount->hideAnimated(); getStep()->showAnimated(direction); @@ -259,7 +274,7 @@ void Widget::resetAccount() { Ui::show(Box<InformBox>(lang(lng_signin_reset_cancelled))); } else { Ui::hideLayer(); - getStep()->showError(lang(lng_server_error)); + getStep()->showError([] { return lang(lng_server_error); }); } }).send(); }))); @@ -285,7 +300,7 @@ void Widget::showControls() { auto hasCover = getStep()->hasCover(); _settings->toggleFast(!hasCover); if (_update) _update->toggleFast(!hasCover); - if (_changeLanguage) _changeLanguage->toggleFast(hasCover); + if (_changeLanguage) _changeLanguage->toggleFast(getStep()->hasChangeLanguage()); _back->toggleFast(getStep()->hasBack()); } @@ -372,9 +387,6 @@ void Widget::resizeEvent(QResizeEvent *e) { updateControlsGeometry(); } -void Widget::moveControls() { -} - void Widget::updateControlsGeometry() { auto shown = _coverShownAnimation.current(1.); @@ -468,13 +480,30 @@ void Widget::Step::updateLabelsPosition() { } } -void Widget::Step::setTitleText(QString richText) { - _title->setRichText(richText); +void Widget::Step::setTitleText(base::lambda<QString()> richTitleTextFactory) { + _titleTextFactory = std::move(richTitleTextFactory); + refreshTitle(); updateLabelsPosition(); } -void Widget::Step::setDescriptionText(QString richText) { - _description->entity()->setRichText(richText); +void Widget::Step::refreshTitle() { + _title->setRichText(_titleTextFactory()); +} + +void Widget::Step::setDescriptionText(base::lambda<QString()> richDescriptionTextFactory) { + _descriptionTextFactory = std::move(richDescriptionTextFactory); + refreshDescription(); + updateLabelsPosition(); +} + +void Widget::Step::refreshDescription() { + _description->entity()->setRichText(_descriptionTextFactory()); +} + +void Widget::Step::refreshLang() { + refreshTitle(); + refreshDescription(); + refreshError(); updateLabelsPosition(); } @@ -650,16 +679,21 @@ void Widget::Step::setErrorBelowLink(bool below) { } } -void Widget::Step::showError(const QString &text) { - _errorText = text; - if (_errorText.isEmpty()) { +void Widget::Step::showError(base::lambda<QString()> textFactory) { + _errorTextFactory = std::move(textFactory); + refreshError(); + updateLabelsPosition(); +} + +void Widget::Step::refreshError() { + if (!_errorTextFactory) { if (_error) _error->hideAnimated(); } else { if (!_error) { _error.create(this, object_ptr<Ui::FlatLabel>(this, _errorCentered ? st::introErrorCentered : st::introError), st::introErrorDuration); _error->hideFast(); } - _error->entity()->setText(text); + _error->entity()->setText(_errorTextFactory()); updateLabelsPosition(); _error->showAnimated(); } @@ -679,6 +713,7 @@ Widget::Step::Step(QWidget *parent, Data *data, bool hasCover) : TWidget(parent) } } }); + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); } void Widget::Step::prepareShowAnimated(Step *after) { @@ -755,7 +790,7 @@ bool Widget::Step::hasBack() const { void Widget::Step::activate() { _title->show(); _description->show(); - if (!_errorText.isEmpty()) { + if (_errorTextFactory) { _error->showFast(); } } diff --git a/Telegram/SourceFiles/intro/introwidget.h b/Telegram/SourceFiles/intro/introwidget.h index 4097b70d8..2fa647ab4 100644 --- a/Telegram/SourceFiles/intro/introwidget.h +++ b/Telegram/SourceFiles/intro/introwidget.h @@ -111,6 +111,9 @@ public: bool animating() const; bool hasCover() const; + bool hasChangeLanguage() const { + return hasCover() || hasChangeLanguageNoCover(); + } virtual bool hasBack() const; virtual void activate(); virtual void cancelled(); @@ -124,9 +127,9 @@ public: void setErrorCentered(bool centered); void setErrorBelowLink(bool below); - void showError(const QString &text); + void showError(base::lambda<QString()> textFactory); void hideError() { - showError(QString()); + showError(base::lambda<QString()>()); } ~Step(); @@ -135,8 +138,8 @@ public: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; - void setTitleText(QString richText); - void setDescriptionText(QString richText); + void setTitleText(base::lambda<QString()> richTitleTextFactory); + void setDescriptionText(base::lambda<QString()> richDescriptionTextFactory); bool paintAnimated(Painter &p, QRect clip); void fillSentCodeData(const MTPauth_SentCodeType &type); @@ -161,6 +164,9 @@ public: void showResetButton() { if (_showResetCallback) _showResetCallback(); } + virtual bool hasChangeLanguageNoCover() const { + return false; + } private: struct CoverAnimation { @@ -178,6 +184,10 @@ public: }; void updateLabelsPosition(); void paintContentSnapshot(Painter &p, const QPixmap &snapshot, float64 alpha, float64 howMuchHidden); + void refreshError(); + void refreshTitle(); + void refreshDescription(); + void refreshLang(); CoverAnimation prepareCoverAnimation(Step *step); QPixmap prepareContentSnapshot(); @@ -193,11 +203,13 @@ public: base::lambda<void()> _showResetCallback; object_ptr<Ui::FlatLabel> _title; + base::lambda<QString()> _titleTextFactory; object_ptr<Ui::WidgetFadeWrap<Ui::FlatLabel>> _description; + base::lambda<QString()> _descriptionTextFactory; bool _errorCentered = false; bool _errorBelowLink = false; - QString _errorText; + base::lambda<QString()> _errorTextFactory; object_ptr<Ui::WidgetFadeWrap<Ui::FlatLabel>> _error = { nullptr }; Animation _a_show; @@ -208,6 +220,7 @@ public: }; private: + void refreshLang(); void animationCallback(); void createLanguageLink(); @@ -219,7 +232,6 @@ private: void fixOrder(); void showControls(); void hideControls(); - void moveControls(); QRect calculateStepRect() const; void showResetButton(); diff --git a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp index e9426d04a..8410ba5bf 100644 --- a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp +++ b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp @@ -59,8 +59,7 @@ void CloudManager::requestLangPackDifference() { } void CloudManager::setSuggestedLanguage(const QString &langCode) { - if (_langpack.id().isEmpty() - && !langCode.isEmpty() + if (!langCode.isEmpty() && langCode != Lang::DefaultLanguageId()) { _suggestedLanguage = langCode; } else { @@ -71,7 +70,7 @@ void CloudManager::setSuggestedLanguage(const QString &langCode) { _languageWasSuggested = true; _firstLanguageSuggestion.notify(); - if (AuthSession::Exists() && !_suggestedLanguage.isEmpty()) { + if (AuthSession::Exists() && _langpack.id().isEmpty() && !_suggestedLanguage.isEmpty()) { _offerSwitchToId = _suggestedLanguage; offerSwitchLangPack(); } @@ -174,10 +173,6 @@ void CloudManager::applyLangPackData(const MTPDlangPackDifference &data) { } else if (!data.vstrings.v.isEmpty()) { _langpack.applyDifference(data); Local::writeLangPack(); - auto fullLangPackUpdated = (data.vfrom_version.v == 0); - if (fullLangPackUpdated) { - _langpack.updated().notify(); - } } else { LOG(("Lang Info: Up to date.")); } diff --git a/Telegram/SourceFiles/lang/lang_instance.cpp b/Telegram/SourceFiles/lang/lang_instance.cpp index 052c3d9e9..53d57f0b0 100644 --- a/Telegram/SourceFiles/lang/lang_instance.cpp +++ b/Telegram/SourceFiles/lang/lang_instance.cpp @@ -230,6 +230,21 @@ bool ValueParser::parse() { return true; } +QString PrepareTestValue(const QString ¤t, QChar filler) { + auto size = current.size(); + auto result = QString(size + 1, filler); + auto inCommand = false; + for (auto i = 0; i != size; ++i) { + auto ch = current[i]; + auto newInCommand = (ch.unicode() == TextCommand) ? (!inCommand) : inCommand; + if (inCommand || newInCommand || ch.isSpace()) { + result[i + 1] = ch; + } + inCommand = newInCommand; + } + return result; +} + } // namespace QString DefaultLanguageId() { @@ -239,6 +254,12 @@ QString DefaultLanguageId() { void Instance::switchToId(const QString &id) { reset(); _id = id; + if (_id == qstr("TEST_X") || _id == qstr("TEST_0")) { + for (auto &value : _values) { + value = PrepareTestValue(value, _id[5]); + } + _updated.notify(); + } } void Instance::chooseCustomFile() { @@ -263,7 +284,7 @@ void Instance::switchToCustomFile(const QString &filePath) { reset(); fillFromCustomFile(filePath); Local::writeLangPack(); - updated().notify(); + _updated.notify(); } void Instance::reset() { @@ -488,6 +509,7 @@ void Instance::applyDifference(const MTPDlangPackDifference &difference) { resetValue(key); }); } + _updated.notify(); } std::map<LangKey, QString> Instance::ParseStrings(const MTPVector<MTPLangPackString> &strings) { diff --git a/Telegram/SourceFiles/lang/lang_instance.h b/Telegram/SourceFiles/lang/lang_instance.h index 252c76cf6..f32b8a940 100644 --- a/Telegram/SourceFiles/lang/lang_instance.h +++ b/Telegram/SourceFiles/lang/lang_instance.h @@ -55,7 +55,7 @@ public: return _id; } bool isCustom() const { - return id() == qstr("custom"); + return (_id == qstr("custom") || _id == qstr("TEST_X") || _id == qstr("TEST_0")); } int version() const { return _version; diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 3472cc710..2aa41056b 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -27,6 +27,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/popup_menu.h" #include "ui/widgets/buttons.h" #include "base/zlib_help.h" +#include "lang/lang_cloud_manager.h" +#include "lang/lang_instance.h" #include "lang/lang_keys.h" #include "shortcuts.h" #include "messenger.h" @@ -54,6 +56,29 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "auth_session.h" #include "window/window_controller.h" +namespace { + +// Code for testing languages is F7-F6-F7-F8 +void FeedLangTestingKey(int key) { + static auto codeState = 0; + if ((codeState == 0 && key == Qt::Key_F7) + || (codeState == 1 && key == Qt::Key_F6) + || (codeState == 2 && key == Qt::Key_F7) + || (codeState == 3 && key == Qt::Key_F8)) { + ++codeState; + } else { + codeState = 0; + } + if (codeState == 4) { + codeState = 0; + + auto testLanguageId = (Lang::Current().id() == qstr("TEST_X")) ? qsl("TEST_0") : qsl("TEST_X"); + Lang::CurrentCloudManager().switchToLanguage(testLanguageId); + } +} + +} // namespace + ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : TWidget(parent) , _reconnect(this, QString()) { set(text, reconnect); @@ -568,8 +593,13 @@ void MainWindow::setInnerFocus() { bool MainWindow::eventFilter(QObject *object, QEvent *e) { switch (e->type()) { - case QEvent::MouseButtonPress: case QEvent::KeyPress: + if (cDebug() && e->type() == QEvent::KeyPress && object == windowHandle()) { + auto key = static_cast<QKeyEvent*>(e)->key(); + FeedLangTestingKey(key); + } + [[fallthrough]]; + case QEvent::MouseButtonPress: case QEvent::TouchBegin: case QEvent::Wheel: psUserActionDone(); diff --git a/Telegram/SourceFiles/settings/settings_widget.cpp b/Telegram/SourceFiles/settings/settings_widget.cpp index 6b1196807..62a1cb846 100644 --- a/Telegram/SourceFiles/settings/settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_widget.cpp @@ -198,9 +198,7 @@ void codesFeedString(const QString &text) { Widget::Widget(QWidget *parent) { refreshLang(); - subscribe(Lang::Current().updated(), [this] { - refreshLang(); - }); + subscribe(Lang::Current().updated(), [this] { refreshLang(); }); _inner = setInnerWidget(object_ptr<InnerWidget>(this)); setCloseClickHandler([]() { diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.cpp b/Telegram/SourceFiles/ui/widgets/input_fields.cpp index 49703bb70..230b97c2e 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.cpp +++ b/Telegram/SourceFiles/ui/widgets/input_fields.cpp @@ -1621,6 +1621,11 @@ void FlatInput::resizeEvent(QResizeEvent *e) { return QLineEdit::resizeEvent(e); } +void FlatInput::setPlaceholder(const QString &ph) { + _fullph = ph; + updatePlaceholderText(); +} + void FlatInput::updatePlaceholderText() { int32 availw = width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1; if (_st.font->width(_fullph) > availw) { @@ -2464,6 +2469,12 @@ void InputArea::createPlaceholderPath() { } } +void InputArea::setPlaceholder(const QString &ph) { + _placeholderFull = ph; + createPlaceholderPath(); + update(); +} + void InputArea::showError() { setErrorShown(true); if (!hasFocus()) { @@ -3222,6 +3233,12 @@ void InputField::createPlaceholderPath() { } } +void InputField::setPlaceholder(const QString &ph) { + _placeholderFull = ph; + createPlaceholderPath(); + update(); +} + void InputField::showError() { setErrorShown(true); if (!hasFocus()) { @@ -3505,6 +3522,12 @@ void MaskedInputField::createPlaceholderPath() { } } +void MaskedInputField::setPlaceholder(const QString &ph) { + _placeholderFull = ph; + createPlaceholderPath(); + update(); +} + void MaskedInputField::contextMenuEvent(QContextMenuEvent *e) { if (auto menu = createStandardContextMenu()) { (new Ui::PopupMenu(nullptr, menu))->popup(e->globalPos()); diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.h b/Telegram/SourceFiles/ui/widgets/input_fields.h index e4012d328..3c0af6c39 100644 --- a/Telegram/SourceFiles/ui/widgets/input_fields.h +++ b/Telegram/SourceFiles/ui/widgets/input_fields.h @@ -238,6 +238,7 @@ public: FlatInput(QWidget *parent, const style::FlatInput &st, const QString &ph = QString(), const QString &val = QString()); void updatePlaceholder(); + void setPlaceholder(const QString &ph); const QString &placeholder() const; QRect placeholderRect() const; @@ -325,6 +326,7 @@ public: const QString &getLastText() const { return _oldtext; } + void setPlaceholder(const QString &ph); void setDisplayFocused(bool focused); void finishAnimations(); void setFocusFast() { @@ -503,6 +505,7 @@ public: const QString &getLastText() const { return _oldtext; } + void setPlaceholder(const QString &ph); void setPlaceholderHidden(bool forcePlaceholderHidden); void setDisplayFocused(bool focused); void finishAnimations(); @@ -689,6 +692,7 @@ public: const QString &getLastText() const { return _oldtext; } + void setPlaceholder(const QString &ph); void setPlaceholderHidden(bool forcePlaceholderHidden); void setDisplayFocused(bool focused); void finishAnimations();