mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Support cloud languages list and switching.
Add Lang::Current().updated() observable for retranslating the UI.
This commit is contained in:
parent
139d4e72b5
commit
f5dfeb0c50
@ -357,9 +357,9 @@ class Observable : public internal::BaseObservable<EventType, Handler, base::typ
|
||||
public:
|
||||
Observable() = default;
|
||||
Observable(const Observable &other) = delete;
|
||||
Observable(Observable &&other) = default;
|
||||
Observable(Observable &&other) = delete;
|
||||
Observable &operator=(const Observable &other) = delete;
|
||||
Observable &operator=(Observable &&other) = default;
|
||||
Observable &operator=(Observable &&other) = delete;
|
||||
|
||||
};
|
||||
|
||||
|
@ -28,81 +28,119 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "lang/lang_cloud_manager.h"
|
||||
#include "styles/style_boxes.h"
|
||||
|
||||
class LanguageBox::Inner : public TWidget {
|
||||
public:
|
||||
Inner(QWidget *parent, gsl::not_null<Languages*> languages);
|
||||
|
||||
void setSelected(int index);
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
void languageChanged(int languageIndex);
|
||||
|
||||
gsl::not_null<Languages*> _languages;
|
||||
std::shared_ptr<Ui::RadiobuttonGroup> _group;
|
||||
std::vector<object_ptr<Ui::Radiobutton>> _buttons;
|
||||
|
||||
};
|
||||
|
||||
LanguageBox::Inner::Inner(QWidget *parent, gsl::not_null<Languages*> languages) : TWidget(parent)
|
||||
, _languages(languages) {
|
||||
_group = std::make_shared<Ui::RadiobuttonGroup>(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<Inner>(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<MTPLangPackLanguage> &result) {
|
||||
auto currentId = Lang::Current().id();
|
||||
auto currentFound = false;
|
||||
std::vector<QString> languageIds = { qsl("en") };
|
||||
std::vector<QString> 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<Ui::RadiobuttonGroup>(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<ConfirmBox>(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);
|
||||
}
|
||||
|
@ -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<Ui::RadiobuttonGroup> _langGroup;
|
||||
std::vector<object_ptr<Ui::Radiobutton>> _langs;
|
||||
void refresh();
|
||||
void refreshLanguages();
|
||||
void refreshLangItems();
|
||||
|
||||
Languages _languages;
|
||||
|
||||
class Inner;
|
||||
QPointer<Inner> _inner;
|
||||
|
||||
};
|
||||
|
123
Telegram/SourceFiles/lang/lang_cloud_manager.cpp
Normal file
123
Telegram/SourceFiles/lang/lang_cloud_manager.cpp
Normal file
@ -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<MTP::Instance*> 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<MTPLangPackLanguage> &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
|
77
Telegram/SourceFiles/lang/lang_cloud_manager.h
Normal file
77
Telegram/SourceFiles/lang/lang_cloud_manager.h
Normal file
@ -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<MTP::Instance*> mtproto);
|
||||
|
||||
struct Language {
|
||||
QString id;
|
||||
QString name;
|
||||
};
|
||||
using Languages = QVector<Language>;
|
||||
|
||||
void requestLanguageList();
|
||||
Languages languageList() const {
|
||||
return _languages;
|
||||
}
|
||||
base::Observable<void> &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<void> _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
|
@ -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;
|
||||
|
@ -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<void> &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<void> _updated;
|
||||
|
||||
mutable QString _systemLanguage;
|
||||
|
||||
std::vector<QString> _values;
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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<Lang::CloudManager>(langpack(), mtp());
|
||||
}
|
||||
|
||||
void Messenger::destroyMtpKeys(MTP::AuthKeysList &&keys) {
|
||||
|
@ -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<void> &authSessionChanged() {
|
||||
@ -197,6 +201,7 @@ private:
|
||||
FileUploader *_uploader = nullptr;
|
||||
|
||||
std::unique_ptr<Lang::Instance> _langpack;
|
||||
std::unique_ptr<Lang::CloudManager> _langCloudManager;
|
||||
std::unique_ptr<Lang::Translator> _translator;
|
||||
std::unique_ptr<MTP::DcOptions> _dcOptions;
|
||||
std::unique_ptr<MTP::Instance> _mtproto;
|
||||
|
@ -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<internal::Session> 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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<Instance*> requestMTP() const {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
private:
|
||||
class RequestWrap {
|
||||
|
@ -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<ConfirmBox>(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<LanguageBox>());
|
||||
});
|
||||
} else {
|
||||
unsubscribe(base::take(_languagesLoadedSubscription));
|
||||
Ui::show(Box<LanguageBox>());
|
||||
}
|
||||
manager->requestLanguageList();
|
||||
}
|
||||
|
||||
void GeneralWidget::onRestart() {
|
||||
|
@ -117,6 +117,8 @@ private:
|
||||
object_ptr<Ui::WidgetSlideWrap<Ui::Checkbox>> _startMinimized = { nullptr };
|
||||
object_ptr<Ui::Checkbox> _addInSendTo = { nullptr };
|
||||
|
||||
int _languagesLoadedSubscription = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user