From d47a38dfcfd72434faa3f7a61526b740a53bc431 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 30 May 2017 12:31:40 +0300 Subject: [PATCH] Show change language link in intro. --- Telegram/SourceFiles/intro/introwidget.cpp | 134 +++++++++--------- Telegram/SourceFiles/intro/introwidget.h | 21 +-- Telegram/SourceFiles/lang/lang_instance.cpp | 119 ++++++++++------ Telegram/SourceFiles/lang/lang_instance.h | 11 ++ Telegram/SourceFiles/messenger.cpp | 4 + Telegram/SourceFiles/settings.cpp | 4 - Telegram/SourceFiles/settings.h | 3 - Telegram/SourceFiles/storage/localstorage.cpp | 1 - 8 files changed, 168 insertions(+), 129 deletions(-) diff --git a/Telegram/SourceFiles/intro/introwidget.cpp b/Telegram/SourceFiles/intro/introwidget.cpp index 7399de2da..f22992e25 100644 --- a/Telegram/SourceFiles/intro/introwidget.cpp +++ b/Telegram/SourceFiles/intro/introwidget.cpp @@ -44,6 +44,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_intro.h" #include "styles/style_window.h" #include "window/themes/window_theme.h" +#include "lang/lang_cloud_manager.h" #include "auth_session.h" namespace Intro { @@ -70,22 +71,10 @@ Widget::Widget(QWidget *parent) : TWidget(parent) _settings->entity()->setClickedCallback([] { App::wnd()->showSettings(); }); - //if (cLang() == languageDefault) { - // auto systemLangId = Sandbox::LangSystem(); - // if (systemLangId != languageDefault) { - // Lang::FileParser loader(qsl(":/langs/lang_") + LanguageCodes[systemLangId].c_str() + qsl(".strings"), { lng_switch_to_this }); - // auto text = loader.found().value(lng_switch_to_this); - // if (!text.isEmpty()) { - // _changeLanguage.create(this, object_ptr(this, text), st::introCoverDuration); - // _changeLanguage->entity()->setClickedCallback([this, systemLangId] { changeLanguage(systemLangId); }); - // } - // } - //} else { - // _changeLanguage.create(this, object_ptr(this, Lang::GetOriginalValue(lng_switch_to_this)), st::introCoverDuration); - // _changeLanguage->entity()->setClickedCallback([this] { changeLanguage(languageDefault); }); - //} + subscribe(Lang::CurrentCloudManager().firstLanguageSuggestion(), [this] { createLanguageLink(); }); + createLanguageLink(); - MTP::send(MTPhelp_GetNearestDc(), rpcDone(&Widget::gotNearestDC)); + getNearestDC(); appendStep(new StartWidget(this, getData())); fixOrder(); @@ -105,6 +94,32 @@ Widget::Widget(QWidget *parent) : TWidget(parent) #endif // !TDESKTOP_DISABLE_AUTOUPDATE } +void Widget::createLanguageLink() { + if (_changeLanguage) return; + + auto createLink = [this](const QString &text, const QString &languageId) { + _changeLanguage.create(this, object_ptr(this, text), st::introCoverDuration); + _changeLanguage->entity()->setClickedCallback([this, languageId] { + Lang::CurrentCloudManager().switchToLanguage(languageId); + }); + }; + + auto currentId = Lang::Current().id(); + auto defaultId = Lang::DefaultLanguageId(); + auto suggestedId = Lang::CurrentCloudManager().suggestedLanguage(); + if (!suggestedId.isEmpty() && suggestedId != currentId) { + request(MTPlangpack_GetStrings(MTP_string(suggestedId), MTP_vector(1, MTP_string("lng_switch_to_this")))).done([this, suggestedId, createLink](const MTPVector &result) { + auto strings = Lang::Instance::ParseStrings(result); + auto it = strings.find(lng_switch_to_this); + if (it != strings.end()) { + createLink(it->second, suggestedId); + } + }).send(); + } else if (!currentId.isEmpty() && currentId != defaultId) { + createLink(Lang::GetOriginalValue(lng_switch_to_this), defaultId); + } +} + #ifndef TDESKTOP_DISABLE_AUTOUPDATE void Widget::onCheckUpdateStatus() { if (Sandbox::updatingState() == Application::UpdatingReady) { @@ -123,12 +138,6 @@ void Widget::onCheckUpdateStatus() { } #endif // TDESKTOP_DISABLE_AUTOUPDATE -void Widget::changeLanguage(int32 languageId) { - cSetLang(languageId); - Local::writeSettings(); - App::restart(); -} - void Widget::setInnerFocus() { if (getStep()->animating()) { setFocus(); @@ -223,53 +232,50 @@ void Widget::resetAccount() { Ui::show(Box(lang(lng_signin_sure_reset), lang(lng_signin_reset), st::attentionBoxButton, base::lambda_guarded(this, [this] { if (_resetRequest) return; - _resetRequest = MTP::send(MTPaccount_DeleteAccount(MTP_string("Forgot password")), rpcDone(&Widget::resetDone), rpcFail(&Widget::resetFail)); + _resetRequest = request(MTPaccount_DeleteAccount(MTP_string("Forgot password"))).done([this](const MTPBool &result) { + _resetRequest = 0; + + Ui::hideLayer(); + moveToStep(new SignupWidget(this, getData()), Direction::Replace); + }).fail([this](const RPCError &error) { + _resetRequest = 0; + + auto type = error.type(); + if (type.startsWith(qstr("2FA_CONFIRM_WAIT_"))) { + int seconds = type.mid(qstr("2FA_CONFIRM_WAIT_").size()).toInt(); + int days = (seconds + 59) / 86400; + int hours = ((seconds + 59) % 86400) / 3600; + int minutes = ((seconds + 59) % 3600) / 60; + QString when; + if (days > 0) { + when = lng_signin_reset_in_days(lt_count_days, days, lt_count_hours, hours, lt_count_minutes, minutes); + } else if (hours > 0) { + when = lng_signin_reset_in_hours(lt_count_hours, hours, lt_count_minutes, minutes); + } else { + when = lng_signin_reset_in_minutes(lt_count_minutes, minutes); + } + Ui::show(Box(lng_signin_reset_wait(lt_phone_number, App::formatPhone(getData()->phone), lt_when, when))); + } else if (type == qstr("2FA_RECENT_CONFIRM")) { + Ui::show(Box(lang(lng_signin_reset_cancelled))); + } else { + Ui::hideLayer(); + getStep()->showError(lang(lng_server_error)); + } + }).send(); }))); } -void Widget::resetDone(const MTPBool &result) { - Ui::hideLayer(); - moveToStep(new SignupWidget(this, getData()), Direction::Replace); -} - -bool Widget::resetFail(const RPCError &error) { - if (MTP::isDefaultHandledError(error)) return false; - - _resetRequest = 0; - - auto type = error.type(); - if (type.startsWith(qstr("2FA_CONFIRM_WAIT_"))) { - int seconds = type.mid(qstr("2FA_CONFIRM_WAIT_").size()).toInt(); - int days = (seconds + 59) / 86400; - int hours = ((seconds + 59) % 86400) / 3600; - int minutes = ((seconds + 59) % 3600) / 60; - QString when; - if (days > 0) { - when = lng_signin_reset_in_days(lt_count_days, days, lt_count_hours, hours, lt_count_minutes, minutes); - } else if (hours > 0) { - when = lng_signin_reset_in_hours(lt_count_hours, hours, lt_count_minutes, minutes); - } else { - when = lng_signin_reset_in_minutes(lt_count_minutes, minutes); +void Widget::getNearestDC() { + request(MTPhelp_GetNearestDc()).done([this](const MTPNearestDc &result) { + auto &nearest = result.c_nearestDc(); + DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(qs(nearest.vcountry)).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v)); + Messenger::Instance().suggestMainDcId(nearest.vnearest_dc.v); + auto nearestCountry = qs(nearest.vcountry); + if (getData()->country != nearestCountry) { + getData()->country = nearestCountry; + getData()->updated.notify(); } - Ui::show(Box(lng_signin_reset_wait(lt_phone_number, App::formatPhone(getData()->phone), lt_when, when))); - } else if (type == qstr("2FA_RECENT_CONFIRM")) { - Ui::show(Box(lang(lng_signin_reset_cancelled))); - } else { - Ui::hideLayer(); - getStep()->showError(lang(lng_server_error)); - } - return true; -} - -void Widget::gotNearestDC(const MTPNearestDc &result) { - auto &nearest = result.c_nearestDc(); - DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(qs(nearest.vcountry)).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v)); - Messenger::Instance().suggestMainDcId(nearest.vnearest_dc.v); - auto nearestCountry = qs(nearest.vcountry); - if (getData()->country != nearestCountry) { - getData()->country = nearestCountry; - getData()->updated.notify(); - } + }).send(); } void Widget::showControls() { diff --git a/Telegram/SourceFiles/intro/introwidget.h b/Telegram/SourceFiles/intro/introwidget.h index d14d4c4a5..4097b70d8 100644 --- a/Telegram/SourceFiles/intro/introwidget.h +++ b/Telegram/SourceFiles/intro/introwidget.h @@ -20,6 +20,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include "mtproto/sender.h" + namespace Ui { class IconButton; class RoundButton; @@ -33,7 +35,7 @@ class WidgetFadeWrap; namespace Intro { -class Widget : public TWidget, public RPCSender { +class Widget : public TWidget, private MTP::Sender, private base::Subscriber { Q_OBJECT public: @@ -207,8 +209,8 @@ public: private: void animationCallback(); + void createLanguageLink(); - void changeLanguage(int32 languageId); void updateControlsGeometry(); Data *getData() { return &_data; @@ -222,14 +224,7 @@ private: void showResetButton(); void resetAccount(); - void resetDone(const MTPBool &result); - bool resetFail(const RPCError &error); - Animation _a_show; - bool _showBack = false; - QPixmap _cacheUnder, _cacheOver; - - QVector _stepHistory; Step *getStep(int skip = 0) { t_assert(_stepHistory.size() + skip > 0); return _stepHistory.at(_stepHistory.size() - skip - 1); @@ -238,7 +233,13 @@ private: void moveToStep(Step *step, Direction direction); void appendStep(Step *step); - void gotNearestDC(const MTPNearestDc &dc); + void getNearestDC(); + + Animation _a_show; + bool _showBack = false; + QPixmap _cacheUnder, _cacheOver; + + QVector _stepHistory; Data _data; diff --git a/Telegram/SourceFiles/lang/lang_instance.cpp b/Telegram/SourceFiles/lang/lang_instance.cpp index 25e27c543..052c3d9e9 100644 --- a/Telegram/SourceFiles/lang/lang_instance.cpp +++ b/Telegram/SourceFiles/lang/lang_instance.cpp @@ -298,7 +298,7 @@ QString Instance::systemLangCode() const { _systemLanguage = DefaultLanguageId(); } } -// _systemLanguage = "de"; // TESTING + _systemLanguage = "de"; // TESTING } return _systemLanguage; } @@ -442,6 +442,38 @@ void Instance::fillFromLegacy(int legacyId, const QString &legacyPath) { } } +template +void Instance::HandleString(const MTPLangPackString &mtpString, SetCallback setCallback, ResetCallback resetCallback) { + switch (mtpString.type()) { + case mtpc_langPackString: { + auto &string = mtpString.c_langPackString(); + setCallback(qba(string.vkey), qba(string.vvalue)); + } break; + + case mtpc_langPackStringPluralized: { + auto &string = mtpString.c_langPackStringPluralized(); + auto key = qba(string.vkey); + setCallback(key + "#zero", string.has_zero_value() ? qba(string.vzero_value) : QByteArray()); + setCallback(key + "#one", string.has_one_value() ? qba(string.vone_value) : QByteArray()); + setCallback(key + "#two", string.has_two_value() ? qba(string.vtwo_value) : QByteArray()); + setCallback(key + "#few", string.has_few_value() ? qba(string.vfew_value) : QByteArray()); + setCallback(key + "#many", string.has_many_value() ? qba(string.vmany_value) : QByteArray()); + setCallback(key + "#other", qba(string.vother_value)); + } break; + + case mtpc_langPackStringDeleted: { + auto &string = mtpString.c_langPackStringDeleted(); + auto key = qba(string.vkey); + resetCallback(key); + for (auto plural : { "#zero", "#one", "#two", "#few", "#many", "#other" }) { + resetCallback(key + plural); + } + } break; + + default: Unexpected("LangPack string type in applyUpdate()."); + } +} + void Instance::applyDifference(const MTPDlangPackDifference &difference) { auto updateLanguageId = qs(difference.vlang_code); auto isValidUpdate = (updateLanguageId == _id) || (_id.isEmpty() && updateLanguageId == DefaultLanguageId()); @@ -450,37 +482,51 @@ void Instance::applyDifference(const MTPDlangPackDifference &difference) { _version = difference.vversion.v; for_const (auto &mtpString, difference.vstrings.v) { - switch (mtpString.type()) { - case mtpc_langPackString: { - auto &string = mtpString.c_langPackString(); - applyValue(qba(string.vkey), qba(string.vvalue)); - } break; - - case mtpc_langPackStringPluralized: { - auto &string = mtpString.c_langPackStringPluralized(); - auto key = qba(string.vkey); - applyValue(key + "#zero", string.has_zero_value() ? qba(string.vzero_value) : QByteArray()); - applyValue(key + "#one", string.has_one_value() ? qba(string.vone_value) : QByteArray()); - applyValue(key + "#two", string.has_two_value() ? qba(string.vtwo_value) : QByteArray()); - applyValue(key + "#few", string.has_few_value() ? qba(string.vfew_value) : QByteArray()); - applyValue(key + "#many", string.has_many_value() ? qba(string.vmany_value) : QByteArray()); - applyValue(key + "#other", qba(string.vother_value)); - } break; - - case mtpc_langPackStringDeleted: { - auto &string = mtpString.c_langPackStringDeleted(); - auto key = qba(string.vkey); + HandleString(mtpString, [this](auto &&key, auto &&value) { + applyValue(key, value); + }, [this](auto &&key) { resetValue(key); - for (auto plural : { "#zero", "#one", "#two", "#few", "#many", "#other" }) { - resetValue(key + plural); - } - } break; + }); + } +} - default: Unexpected("LangPack string type in applyUpdate()."); +std::map Instance::ParseStrings(const MTPVector &strings) { + auto result = std::map(); + for (auto &mtpString : strings.v) { + HandleString(mtpString, [&result](auto &&key, auto &&value) { + ParseKeyValue(key, value, result); + }, [&result](auto &&key) { + auto keyIndex = GetKeyIndex(QLatin1String(key)); + if (keyIndex != kLangKeysCount) { + result.erase(keyIndex); + } + }); + } + return result; +} + +template +void Instance::ParseKeyValue(const QByteArray &key, const QByteArray &value, Result &result) { + auto keyIndex = GetKeyIndex(QLatin1String(key)); + if (keyIndex == kLangKeysCount) { + LOG(("Lang Error: Unknown key '%1'").arg(QString::fromLatin1(key))); + return; + } + + ValueParser parser(key, keyIndex, value); + if (parser.parse()) { + result[keyIndex] = parser.takeResult(); + for (auto &plural : parser.takePluralValues()) { + result[plural.first] = plural.second; } } } +void Instance::applyValue(const QByteArray &key, const QByteArray &value) { + _nonDefaultValues[key] = value; + ParseKeyValue(key, value, _values); +} + void Instance::resetValue(const QByteArray &key) { _nonDefaultValues.erase(key); @@ -490,27 +536,6 @@ void Instance::resetValue(const QByteArray &key) { } } -void Instance::applyValue(const QByteArray &key, const QByteArray &value) { - _nonDefaultValues[key] = value; - - auto pluralValues = std::map(); - auto keyIndex = GetKeyIndex(QLatin1String(key)); - if (keyIndex == kLangKeysCount) { - LOG(("Lang Error: Unknown key '%1'").arg(QString::fromLatin1(key))); - return; - } - - ValueParser parser(key, keyIndex, value); - if (!parser.parse()) { - return; - } - - _values[keyIndex] = parser.takeResult(); - for (auto &plural : parser.takePluralValues()) { - _values[plural.first] = plural.second; - } -} - Instance &Current() { return Messenger::Instance().langpack(); } diff --git a/Telegram/SourceFiles/lang/lang_instance.h b/Telegram/SourceFiles/lang/lang_instance.h index 22a8d8236..252c76cf6 100644 --- a/Telegram/SourceFiles/lang/lang_instance.h +++ b/Telegram/SourceFiles/lang/lang_instance.h @@ -66,6 +66,7 @@ public: void fillFromLegacy(int legacyId, const QString &legacyPath); void applyDifference(const MTPDlangPackDifference &difference); + static std::map ParseStrings(const MTPVector &strings); base::Observable &updated() { return _updated; } @@ -77,6 +78,16 @@ public: } private: + // SetCallback takes two QByteArrays: key, value. + // It is called for all key-value pairs in string. + // ResetCallback takes one QByteArray: key. + template + static void HandleString(const MTPLangPackString &mtpString, SetCallback setCallback, ResetCallback resetCallback); + + // Writes each key-value pair in the result container. + template + static void ParseKeyValue(const QByteArray &key, const QByteArray &value, Result &result); + void applyValue(const QByteArray &key, const QByteArray &value); void resetValue(const QByteArray &key); void reset(); diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 0117bda99..b06fb3567 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -734,6 +734,10 @@ Messenger::~Messenger() { App::clearHistories(); authSessionDestroy(); + // The langpack manager should be destroyed before MTProto instance, + // because it is MTP::Sender and it may have pending requests. + _langCloudManager.reset(); + _mtproto.reset(); _mtprotoForKeysDestroy.reset(); diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp index 5d99db480..1ed6babfe 100644 --- a/Telegram/SourceFiles/settings.cpp +++ b/Telegram/SourceFiles/settings.cpp @@ -21,7 +21,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "settings.h" #include "platform/platform_specific.h" -#include "lang/lang_keys.h" bool gRtl = false; Qt::LayoutDirection gLangDir = gRtl ? Qt::RightToLeft : Qt::LeftToRight; @@ -89,9 +88,6 @@ bool gPasswordRecovered = false; int32 gPasscodeBadTries = 0; TimeMs gPasscodeLastTry = 0; -int32 gLang = -2; // auto -QString gLangFile; - bool gRetina = false; float64 gRetinaFactor = 1.; int32 gIntRetinaFactor = 1; diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h index f2b2a1ab9..4245c368a 100644 --- a/Telegram/SourceFiles/settings.h +++ b/Telegram/SourceFiles/settings.h @@ -234,9 +234,6 @@ inline void incrementRecentHashtag(RecentHashtagPack &recent, const QString &tag } } -DeclareSetting(int32, Lang); -DeclareSetting(QString, LangFile); - DeclareSetting(QStringList, SendPaths); DeclareSetting(QString, StartUrl); diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 3fc7884df..995404df9 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -2309,7 +2309,6 @@ void writeSettings() { quint32 size = 12 * (sizeof(quint32) + sizeof(qint32)); size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized); - size += sizeof(quint32) + Serialize::stringSize(cLangFile()); size += sizeof(quint32) + sizeof(qint32); if (Global::ConnectionType() == dbictHttpProxy || Global::ConnectionType() == dbictTcpProxy) {