diff --git a/Telegram/SourceFiles/base/observer.h b/Telegram/SourceFiles/base/observer.h index 57a6f05bd..2989ab870 100644 --- a/Telegram/SourceFiles/base/observer.h +++ b/Telegram/SourceFiles/base/observer.h @@ -357,9 +357,9 @@ class Observable : public internal::BaseObservable languages); + + void setSelected(int index); + void refresh(); + +private: + void languageChanged(int languageIndex); + + gsl::not_null _languages; + std::shared_ptr _group; + std::vector> _buttons; + +}; + +LanguageBox::Inner::Inner(QWidget *parent, gsl::not_null languages) : TWidget(parent) +, _languages(languages) { + _group = std::make_shared(0); + _group->setChangedCallback([this](int value) { languageChanged(value); }); +} + +void LanguageBox::Inner::setSelected(int index) { + _group->setValue(index); +} + +void LanguageBox::Inner::refresh() { + for (auto &button : _buttons) { + button.destroy(); + } + _buttons.clear(); + + auto y = st::boxOptionListPadding.top(); + _buttons.reserve(_languages->size()); + auto index = 0; + for_const (auto &language, *_languages) { + _buttons.emplace_back(this, _group, index++, language.name, st::langsButton); + auto button = _buttons.back().data(); + button->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), y + st::langsButton.margin.top()); + button->show(); + y += button->heightNoMargins() + st::boxOptionListSkip; + } + auto newHeight = y + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); + resize(st::langsWidth, newHeight); +} + +void LanguageBox::Inner::languageChanged(int languageIndex) { + Expects(languageIndex >= 0 && languageIndex < _languages->size()); + + auto languageId = (*_languages)[languageIndex].id; + if (languageId != qsl("custom")) { + Lang::CurrentCloudManager().switchToLanguage(languageId); + } +} + void LanguageBox::prepare() { + refreshLangItems(); + subscribe(Lang::Current().updated(), [this] { + refreshLangItems(); + }); + + _inner = setInnerWidget(object_ptr(this, &_languages), st::boxLayerScroll); + + refresh(); + subscribe(Lang::CurrentCloudManager().languageListChanged(), [this] { + refresh(); + }); +} + +void LanguageBox::refreshLangItems() { + clearButtons(); addButton(lang(lng_box_ok), [this] { closeBox(); }); setTitle(lang(lng_languages)); - request(MTPlangpack_GetLanguages()).done([this](const MTPVector &result) { - auto currentId = Lang::Current().id(); - auto currentFound = false; - std::vector languageIds = { qsl("en") }; - std::vector languageNames = { qsl("English") }; - for (auto &language : result.v) { - t_assert(language.type() == mtpc_langPackLanguage); - auto &data = language.c_langPackLanguage(); - auto languageId = qs(data.vlang_code); - auto languageName = qs(data.vname); - if (languageId != qstr("en")) { - languageIds.push_back(languageId); - languageNames.push_back(languageName); - } - } - if (currentId == qstr("custom")) { - languageIds.insert(languageIds.begin(), currentId); - languageNames.insert(languageNames.begin(), qsl("Custom LangPack")); - currentFound = true; - } - - auto languageCount = languageIds.size(); - _langGroup = std::make_shared(cLang()); - auto y = st::boxOptionListPadding.top(); - _langs.reserve(languageCount); - for (auto i = 0; i != languageCount; ++i) { - if (!currentFound && languageIds[i] == currentId) { - currentFound = true; - } - _langs.emplace_back(this, _langGroup, i, languageNames[i], st::langsButton); - auto button = _langs.back().data(); - button->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), y + st::langsButton.margin.top()); - button->show(); - y += button->heightNoMargins() + st::boxOptionListSkip; - } - _langGroup->setChangedCallback([this](int value) { languageChanged(value); }); - - setDimensions(st::langsWidth, st::boxOptionListPadding.top() + languageCount * st::langsButton.height + languageCount * st::boxOptionListSkip + st::boxOptionListPadding.bottom() + st::boxPadding.bottom()); - }).fail([this](const RPCError &error) { - closeBox(); - }).send(); - - setDimensions(st::langsWidth, st::langsWidth); + update(); } -void LanguageBox::languageChanged(int languageId) { - //Expects(languageId == languageTest || (languageId >= 0 && languageId < base::array_size(LanguageCodes))); +void LanguageBox::refresh() { + refreshLanguages(); - //if (languageId == cLang()) { - // return; - //} - - //Lang::FileParser::Result result; - //if (languageId > 0) { - // Lang::FileParser loader(qsl(":/langs/lang_") + LanguageCodes[languageId].c_str() + qsl(".strings"), { lng_sure_save_language, lng_cancel, lng_box_ok }); - // result = loader.found(); - //} else if (languageId == languageTest) { - // Lang::FileParser loader(cLangFile(), { lng_sure_save_language, lng_cancel, lng_box_ok }); - // result = loader.found(); - //} - //auto text = result.value(lng_sure_save_language, Lang::GetOriginalValue(lng_sure_save_language)), - // save = result.value(lng_box_ok, Lang::GetOriginalValue(lng_box_ok)), - // cancel = result.value(lng_cancel, Lang::GetOriginalValue(lng_cancel)); - //Ui::show(Box(text, save, cancel, base::lambda_guarded(this, [this, languageId] { - // cSetLang(languageId); - // Local::writeSettings(); - // App::restart(); - //}), base::lambda_guarded(this, [this] { - // _langGroup->setValue(cLang()); - //})), KeepOtherLayers); + _inner->refresh(); + auto maxHeight = st::boxOptionListPadding.top() + _languages.size() * (st::langsButton.height + st::boxOptionListSkip) + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); + setDimensions(st::langsWidth, qMin(maxHeight, st::boxMaxListHeight)); +} + +void LanguageBox::refreshLanguages() { + _languages = Languages(); + auto list = Lang::CurrentCloudManager().languageList(); + _languages.reserve(list.size() + 1); + auto currentId = Lang::Current().id(); + auto currentIndex = -1; + _languages.push_back({ qsl("en"), qsl("English") }); + for (auto &language : list) { + auto isCurrent = (language.id == currentId); + if (language.id != qstr("en")) { + if (isCurrent) { + currentIndex = _languages.size(); + } + _languages.push_back(language); + } else if (isCurrent) { + currentIndex = 0; + } + } + if (currentId == qstr("custom")) { + _languages.insert(_languages.begin(), { currentId, qsl("Custom LangPack") }); + currentIndex = 0; + } else if (currentIndex < 0) { + currentIndex = _languages.size(); + _languages.push_back({ currentId, lang(lng_language_name) }); + } + _inner->setSelected(currentIndex); } diff --git a/Telegram/SourceFiles/boxes/language_box.h b/Telegram/SourceFiles/boxes/language_box.h index 9c1d4579a..6407a7730 100644 --- a/Telegram/SourceFiles/boxes/language_box.h +++ b/Telegram/SourceFiles/boxes/language_box.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include "lang/lang_cloud_manager.h" #include "boxes/abstract_box.h" #include "mtproto/sender.h" @@ -29,8 +30,6 @@ class Radiobutton; } // namespace Ui class LanguageBox : public BoxContent, private MTP::Sender { - Q_OBJECT - public: LanguageBox(QWidget*) { } @@ -39,9 +38,15 @@ protected: void prepare() override; private: - void languageChanged(int languageId); + using Languages = Lang::CloudManager::Languages; - std::shared_ptr _langGroup; - std::vector> _langs; + void refresh(); + void refreshLanguages(); + void refreshLangItems(); + + Languages _languages; + + class Inner; + QPointer _inner; }; diff --git a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp new file mode 100644 index 000000000..a3163e837 --- /dev/null +++ b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp @@ -0,0 +1,123 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#include "lang/lang_cloud_manager.h" + +#include "lang/lang_instance.h" +#include "mtproto/mtp_instance.h" +#include "storage/localstorage.h" +#include "messenger.h" +#include "apiwrap.h" +#include "auth_session.h" + +namespace Lang { + +CloudManager::CloudManager(Instance &langpack, gsl::not_null mtproto) : MTP::Sender(mtproto) +, _langpack(langpack) { + requestLangPackDifference(); +} + +void CloudManager::requestLangPackDifference() { + auto &langpack = Lang::Current(); + if (langpack.isCustom() || _langPackRequestId) { + return; + } + + auto version = langpack.version(); + if (version > 0) { + _langPackRequestId = request(MTPlangpack_GetDifference(MTP_int(version))).done([this](const MTPLangPackDifference &result) { + _langPackRequestId = 0; + applyLangPackDifference(result); + }).fail([this](const RPCError &error) { + _langPackRequestId = 0; + }).send(); + } else { + _langPackRequestId = request(MTPlangpack_GetLangPack()).done([this](const MTPLangPackDifference &result) { + _langPackRequestId = 0; + applyLangPackDifference(result); + }).fail([this](const RPCError &error) { + _langPackRequestId = 0; + }).send(); + } +} + +void CloudManager::applyLangPackDifference(const MTPLangPackDifference &difference) { + Expects(difference.type() == mtpc_langPackDifference); + auto ¤t = Lang::Current(); + if (current.isCustom()) { + return; + } + + auto &langpack = difference.c_langPackDifference(); + switchLangPackId(qs(langpack.vlang_code)); + if (current.version() < langpack.vfrom_version.v) { + requestLangPackDifference(); + } else if (!langpack.vstrings.v.isEmpty()) { + current.applyDifference(langpack); + Local::writeLangPack(); + auto fullLangPackUpdated = (langpack.vfrom_version.v == 0); + if (fullLangPackUpdated) { + Lang::Current().updated().notify(); + } + } else { + LOG(("Lang Info: Up to date.")); + } +} + +void CloudManager::requestLanguageList() { + _languagesRequestId = request(MTPlangpack_GetLanguages()).done([this](const MTPVector &result) { + auto languages = Languages(); + for_const (auto &langData, result.v) { + t_assert(langData.type() == mtpc_langPackLanguage); + auto &language = langData.c_langPackLanguage(); + languages.push_back({ qs(language.vlang_code), qs(language.vname) }); + } + if (_languages != languages) { + _languages = languages; + _languagesChanged.notify(); + } + _languagesRequestId = 0; + }).fail([this](const RPCError &error) { + _languagesRequestId = 0; + }).send(); +} + +void CloudManager::switchToLanguage(const QString &id) { + switchLangPackId(id); + requestLangPackDifference(); +} + +void CloudManager::switchLangPackId(const QString &id) { + auto ¤t = Lang::Current(); + if (current.id() != id) { + current.switchToId(id); + + auto mtproto = requestMTP(); + mtproto->reInitConnection(mtproto->mainDcId()); + } +} + +CloudManager &CurrentCloudManager() { + auto result = Messenger::Instance().langCloudManager(); + t_assert(result != nullptr); + return *result; +} + +} // namespace Lang diff --git a/Telegram/SourceFiles/lang/lang_cloud_manager.h b/Telegram/SourceFiles/lang/lang_cloud_manager.h new file mode 100644 index 000000000..b1850fc83 --- /dev/null +++ b/Telegram/SourceFiles/lang/lang_cloud_manager.h @@ -0,0 +1,77 @@ +/* +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-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "mtproto/sender.h" + +namespace MTP { +class Instance; +} // namespace MTP + +namespace Lang { + +class Instance; + +class CloudManager : private MTP::Sender { +public: + CloudManager(Instance &langpack, gsl::not_null mtproto); + + struct Language { + QString id; + QString name; + }; + using Languages = QVector; + + void requestLanguageList(); + Languages languageList() const { + return _languages; + } + base::Observable &languageListChanged() { + return _languagesChanged; + } + void requestLangPackDifference(); + void applyLangPackDifference(const MTPLangPackDifference &difference); + + void switchToLanguage(const QString &id); + +private: + void applyLangPack(const MTPUpdates &updates); + void switchLangPackId(const QString &id); + + Instance &_langpack; + Languages _languages; + base::Observable _languagesChanged; + mtpRequestId _langPackRequestId = 0; + mtpRequestId _languagesRequestId = 0; + +}; + +inline bool operator==(const CloudManager::Language &a, const CloudManager::Language &b) { + return (a.id == b.id) && (a.name == b.name); +} + +inline bool operator!=(const CloudManager::Language &a, const CloudManager::Language &b) { + return !(a == b); +} + +CloudManager &CurrentCloudManager(); + +} // namespace Lang diff --git a/Telegram/SourceFiles/lang/lang_instance.cpp b/Telegram/SourceFiles/lang/lang_instance.cpp index b745d64e7..1f7f1ed65 100644 --- a/Telegram/SourceFiles/lang/lang_instance.cpp +++ b/Telegram/SourceFiles/lang/lang_instance.cpp @@ -22,9 +22,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "messenger.h" #include "lang/lang_file_parser.h" -#include "platform/platform_specific.h" #include "storage/serialize_common.h" #include "storage/localstorage.h" +#include "platform/platform_specific.h" namespace Lang { namespace { @@ -32,6 +32,16 @@ namespace { constexpr auto kDefaultLanguage = str_const("en"); constexpr auto kLangValuesLimit = 20000; +constexpr str_const kLegacyLanguages[] = { + "en", + "it", + "es", + "de", + "nl", + "pt_BR", + "ko", +}; + class ValueParser { public: ValueParser(const QByteArray &key, LangKey keyIndex, const QByteArray &value); @@ -220,14 +230,38 @@ bool ValueParser::parse() { } // namespace -void Instance::fillDefaults() { +void Instance::switchToId(const QString &id) { + reset(); + _id = id; +} + +void Instance::switchToCustomFile(const QString &filePath) { + reset(); + fillFromCustomFile(filePath); +} + +void Instance::reset() { _values.clear(); + _nonDefaultValues.clear(); + _legacyId = kLegacyLanguageNone; + _customFilePathAbsolute = QString(); + _customFilePathRelative = QString(); + _customFileContent = QByteArray(); + _version = 0; + + fillDefaults(); +} + +void Instance::fillDefaults() { + Expects(_values.empty()); _values.reserve(kLangKeysCount); for (auto i = 0; i != kLangKeysCount; ++i) { _values.emplace_back(GetOriginalValue(LangKey(i))); } - _id = str_const_toString(kDefaultLanguage); - _legacyId = kLegacyDefaultLanguage; +} + +QString Instance::DefaultLanguageId() { + return str_const_toString(kDefaultLanguage); } QString Instance::cloudLangCode() const { @@ -235,7 +269,7 @@ QString Instance::cloudLangCode() const { if (_systemLanguage.isEmpty()) { _systemLanguage = Platform::SystemLanguage(); if (_systemLanguage.isEmpty()) { - _systemLanguage = str_const_toString(kDefaultLanguage); + _systemLanguage = Instance::DefaultLanguageId(); } } return _systemLanguage; diff --git a/Telegram/SourceFiles/lang/lang_instance.h b/Telegram/SourceFiles/lang/lang_instance.h index dc6ab770d..db2eff7ab 100644 --- a/Telegram/SourceFiles/lang/lang_instance.h +++ b/Telegram/SourceFiles/lang/lang_instance.h @@ -27,36 +27,23 @@ namespace Lang { constexpr auto kLegacyLanguageNone = -2; constexpr auto kLegacyCustomLanguage = -1; constexpr auto kLegacyDefaultLanguage = 0; -constexpr str_const kLegacyLanguages[] = { - "en", - "it", - "es", - "de", - "nl", - "pt_BR", - "ko", -}; class Instance { public: Instance() { fillDefaults(); } - struct CreateFromIdTag {}; - Instance(const QString &id, CreateFromIdTag) { - fillDefaults(); - _id = id; - } - struct CreateFromCustomFileTag {}; - Instance(const QString &filePath, CreateFromCustomFileTag) { - fillDefaults(); - fillFromCustomFile(filePath); - } + void switchToId(const QString &id); + void switchToCustomFile(const QString &filePath); + Instance(const Instance &other) = delete; Instance &operator=(const Instance &other) = delete; Instance(Instance &&other) = default; Instance &operator=(Instance &&other) = default; + static QString DefaultLanguageId(); + QString cloudLangCode() const; + QString id() const { return _id; } @@ -66,13 +53,15 @@ public: int version() const { return _version; } - QString cloudLangCode() const; QByteArray serialize() const; void fillFromSerialized(const QByteArray &data); void fillFromLegacy(int legacyId, const QString &legacyPath); void applyDifference(const MTPDlangPackDifference &difference); + base::Observable &updated() { + return _updated; + } QString getValue(LangKey key) { Expects(key >= 0 && key < kLangKeysCount); @@ -83,6 +72,7 @@ public: private: void applyValue(const QByteArray &key, const QByteArray &value); void resetValue(const QByteArray &key); + void reset(); void fillDefaults(); void fillFromCustomFile(const QString &filePath); void loadFromContent(const QByteArray &content); @@ -94,6 +84,8 @@ private: QString _customFilePathRelative; QByteArray _customFileContent; int _version = 0; + base::Observable _updated; + mutable QString _systemLanguage; std::vector _values; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 81a52abaf..b1aad6897 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "history/history_service_layout.h" #include "overviewwidget.h" #include "lang/lang_keys.h" +#include "lang/lang_cloud_manager.h" #include "boxes/add_contact_box.h" #include "storage/file_upload.h" #include "messenger.h" @@ -5689,11 +5690,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { ////// Cloud langpacks case mtpc_updateLangPack: { auto &langpack = update.c_updateLangPack(); - Messenger::Instance().mtp()->applyLangPackDifference(langpack.vdifference); + Messenger::Instance().langCloudManager()->applyLangPackDifference(langpack.vdifference); } break; case mtpc_updateLangPackTooLong: { - Messenger::Instance().mtp()->requestLangPackDifference(); + Messenger::Instance().langCloudManager()->requestLangPackDifference(); } break; } diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 4a4c352a4..0117bda99 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "calls/calls_instance.h" #include "lang/lang_file_parser.h" #include "lang/lang_translator.h" +#include "lang/lang_cloud_manager.h" #include "observer_peer.h" #include "storage/file_upload.h" #include "mainwidget.h" @@ -318,6 +319,8 @@ void Messenger::startMtp() { } _private->storedAuthSession.reset(); } + + _langCloudManager = std::make_unique(langpack(), mtp()); } void Messenger::destroyMtpKeys(MTP::AuthKeysList &&keys) { diff --git a/Telegram/SourceFiles/messenger.h b/Telegram/SourceFiles/messenger.h index 7b2aaa601..c5a8410a5 100644 --- a/Telegram/SourceFiles/messenger.h +++ b/Telegram/SourceFiles/messenger.h @@ -50,6 +50,7 @@ class Instance; namespace Lang { class Instance; class Translator; +class CloudManager; } // namespace Lang class Messenger final : public QObject, public RPCSender, private base::Subscriber { @@ -109,6 +110,9 @@ public: Lang::Instance &langpack() { return *_langpack; } + Lang::CloudManager *langCloudManager() { + return _langCloudManager.get(); + } void authSessionCreate(UserId userId); void authSessionDestroy(); base::Observable &authSessionChanged() { @@ -197,6 +201,7 @@ private: FileUploader *_uploader = nullptr; std::unique_ptr _langpack; + std::unique_ptr _langCloudManager; std::unique_ptr _translator; std::unique_ptr _dcOptions; std::unique_ptr _mtproto; diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index 50ec31e64..22fa43982 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -33,7 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace MTP { -class Instance::Private : public Sender { +class Instance::Private : private Sender { public: Private(Instance *instance, DcOptions *options, Instance::Mode mode); @@ -51,8 +51,6 @@ public: void requestConfig(); void requestCDNConfig(); - void requestLangPackDifference(); - void applyLangPackDifference(const MTPLangPackDifference &difference); void restart(); void restart(ShiftedDcId shiftedDcId); @@ -64,6 +62,7 @@ public: void killSession(ShiftedDcId shiftedDcId); void killSession(std::unique_ptr session); void stopSession(ShiftedDcId shiftedDcId); + void reInitConnection(DcId dcId); void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail); internal::DcenterPtr getDcById(ShiftedDcId shiftedDcId); @@ -129,8 +128,6 @@ private: void checkDelayedRequests(); - void switchLangPackId(const QString &id); - Instance *_instance = nullptr; DcOptions *_dcOptions = nullptr; Instance::Mode _mode = Instance::Mode::Normal; @@ -183,8 +180,6 @@ private: base::Timer _checkDelayedTimer; - mtpRequestId _langPackRequestId = 0; - // Debug flag to find out how we end up crashing. bool MustNotCreateSessions = false; @@ -246,7 +241,6 @@ void Instance::Private::start(Config &&config) { t_assert((_mainDcId == Config::kNoneMainDc) == isKeysDestroyer()); if (!isKeysDestroyer()) { requestConfig(); - requestLangPackDifference(); } } @@ -303,58 +297,6 @@ void Instance::Private::requestCDNConfig() { }).send(); } - -void Instance::Private::requestLangPackDifference() { - auto &langpack = Lang::Current(); - if (langpack.isCustom() || _langPackRequestId) { - return; - } - - auto version = langpack.version(); - if (version > 0) { - _langPackRequestId = request(MTPlangpack_GetDifference(MTP_int(version))).done([this](const MTPLangPackDifference &result) { - _langPackRequestId = 0; - applyLangPackDifference(result); - }).fail([this](const RPCError &error) { - _langPackRequestId = 0; - }).send(); - } else { - _langPackRequestId = request(MTPlangpack_GetLangPack()).done([this](const MTPLangPackDifference &result) { - _langPackRequestId = 0; - applyLangPackDifference(result); - }).fail([this](const RPCError &error) { - _langPackRequestId = 0; - }).send(); - } -} - -void Instance::Private::applyLangPackDifference(const MTPLangPackDifference &difference) { - Expects(difference.type() == mtpc_langPackDifference); - auto ¤t = Lang::Current(); - if (current.isCustom()) { - return; - } - - auto &langpack = difference.c_langPackDifference(); - switchLangPackId(qs(langpack.vlang_code)); - if (current.version() < langpack.vfrom_version.v) { - requestLangPackDifference(); - } else if (!langpack.vstrings.v.isEmpty()) { - current.applyDifference(langpack); - Local::writeLangPack(); - } else { - LOG(("Lang Info: Up to date.")); - } -} - -void Instance::Private::switchLangPackId(const QString &id) { - auto ¤t = Lang::Current(); - if (current.id() != id) { - current = Lang::Instance(id, Lang::Instance::CreateFromIdTag()); - restart(maindc()); - } -} - void Instance::Private::restart() { for (auto &session : _sessions) { session.second->restart(); @@ -477,7 +419,9 @@ void Instance::Private::killSession(ShiftedDcId shiftedDcId) { _sessions.emplace(_mainDcId, std::move(main)); _mainSession->start(); } - QMetaObject::invokeMethod(_instance, "onClearKilledSessions", Qt::QueuedConnection); + InvokeQueued(_instance, [this] { + clearKilledSessions(); + }); } void Instance::Private::clearKilledSessions() { @@ -493,6 +437,11 @@ void Instance::Private::stopSession(ShiftedDcId shiftedDcId) { } } +void Instance::Private::reInitConnection(DcId dcId) { + killSession(dcId); + getSession(dcId)->notifyLayerInited(false); +} + void Instance::Private::logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) { _instance->send(MTPauth_LogOut(), onDone, onFail); @@ -1333,14 +1282,6 @@ void Instance::requestCDNConfig() { _private->requestCDNConfig(); } -void Instance::requestLangPackDifference() { - _private->requestLangPackDifference(); -} - -void Instance::applyLangPackDifference(const MTPLangPackDifference &difference) { - _private->applyLangPackDifference(difference); -} - void Instance::connectionFinished(internal::Connection *connection) { _private->connectionFinished(connection); } @@ -1381,6 +1322,10 @@ void Instance::stopSession(ShiftedDcId shiftedDcId) { _private->stopSession(shiftedDcId); } +void Instance::reInitConnection(DcId dcId) { + _private->reInitConnection(dcId); +} + void Instance::logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) { _private->logout(onDone, onFail); } @@ -1489,10 +1434,6 @@ void Instance::onKeyDestroyed(qint32 shiftedDcId) { _private->completedKeyDestroy(shiftedDcId); } -void Instance::onClearKilledSessions() { - _private->clearKilledSessions(); -} - Instance::~Instance() { _private->prepareToDestroy(); } diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.h b/Telegram/SourceFiles/mtproto/mtp_instance.h index 26ffeb899..139942e78 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.h +++ b/Telegram/SourceFiles/mtproto/mtp_instance.h @@ -89,6 +89,7 @@ public: int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms void killSession(ShiftedDcId shiftedDcId); void stopSession(ShiftedDcId shiftedDcId); + void reInitConnection(DcId dcId); void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail); internal::DcenterPtr getDcById(ShiftedDcId shiftedDcId); @@ -122,8 +123,6 @@ public: void requestConfig(); void requestCDNConfig(); - void requestLangPackDifference(); - void applyLangPackDifference(const MTPLangPackDifference &difference); ~Instance(); @@ -138,7 +137,6 @@ signals: private slots: void onKeyDestroyed(qint32 shiftedDcId); - void onClearKilledSessions(); private: internal::Session *getSession(ShiftedDcId shiftedDcId); diff --git a/Telegram/SourceFiles/mtproto/sender.h b/Telegram/SourceFiles/mtproto/sender.h index 9eb13297a..14f9e0f45 100644 --- a/Telegram/SourceFiles/mtproto/sender.h +++ b/Telegram/SourceFiles/mtproto/sender.h @@ -288,13 +288,16 @@ public: SentRequestWrap request(mtpRequestId requestId) noexcept WARN_UNUSED_RESULT; void requestSendDelayed() { - MTP::sendAnything(); + _instance->sendAnything(); } void requestCancellingDiscard() { for (auto &request : _requests) { request.handled(); } } + gsl::not_null requestMTP() const { + return _instance; + } private: class RequestWrap { diff --git a/Telegram/SourceFiles/settings/settings_general_widget.cpp b/Telegram/SourceFiles/settings/settings_general_widget.cpp index f364cde1e..728e54b47 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_general_widget.cpp @@ -34,6 +34,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/about_box.h" #include "core/file_utilities.h" #include "lang/lang_file_parser.h" +#include "lang/lang_cloud_manager.h" +#include "messenger.h" #include "autoupdater.h" namespace Settings { @@ -220,7 +222,7 @@ void GeneralWidget::chooseCustomLang() { save = result.value(lng_box_ok, Lang::GetOriginalValue(lng_box_ok)), cancel = result.value(lng_cancel, Lang::GetOriginalValue(lng_cancel)); Ui::show(Box(text, save, cancel, base::lambda_guarded(this, [this, filePath] { - Lang::Current() = Lang::Instance(filePath, Lang::Instance::CreateFromCustomFileTag()); + Lang::Current().switchToCustomFile(filePath); Local::writeLangPack(); onRestart(); }))); @@ -233,9 +235,19 @@ void GeneralWidget::chooseCustomLang() { void GeneralWidget::onChangeLanguage() { if ((_changeLanguage->clickModifiers() & Qt::ShiftModifier) && (_changeLanguage->clickModifiers() & Qt::AltModifier)) { chooseCustomLang(); + return; + } + auto manager = Messenger::Instance().langCloudManager(); + if (manager->languageList().isEmpty()) { + _languagesLoadedSubscription = subscribe(manager->languageListChanged(), [this] { + unsubscribe(base::take(_languagesLoadedSubscription)); + Ui::show(Box()); + }); } else { + unsubscribe(base::take(_languagesLoadedSubscription)); Ui::show(Box()); } + manager->requestLanguageList(); } void GeneralWidget::onRestart() { diff --git a/Telegram/SourceFiles/settings/settings_general_widget.h b/Telegram/SourceFiles/settings/settings_general_widget.h index 1c1d0942c..04f9c54ad 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.h +++ b/Telegram/SourceFiles/settings/settings_general_widget.h @@ -117,6 +117,8 @@ private: object_ptr> _startMinimized = { nullptr }; object_ptr _addInSendTo = { nullptr }; + int _languagesLoadedSubscription = 0; + }; } // namespace Settings diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index dc574336a..13b24dc59 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -177,6 +177,8 @@ <(src_loc)/intro/introsignup.h <(src_loc)/intro/introstart.cpp <(src_loc)/intro/introstart.h +<(src_loc)/lang/lang_cloud_manager.cpp +<(src_loc)/lang/lang_cloud_manager.h <(src_loc)/lang/lang_file_parser.cpp <(src_loc)/lang/lang_file_parser.h <(src_loc)/lang/lang_instance.cpp