From 3f0b57ec1174a8db6e0030e252e48c5ab5e1dd4b Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 18 Apr 2017 20:37:14 +0300 Subject: [PATCH] Retranslate Settings when language is changed. Also suggest user to change language from 'en' to his for one time. --- Telegram/SourceFiles/boxes/language_box.cpp | 6 +- Telegram/SourceFiles/boxes/language_box.h | 2 +- .../SourceFiles/lang/lang_cloud_manager.cpp | 119 ++++++++++++++---- .../SourceFiles/lang/lang_cloud_manager.h | 13 +- Telegram/SourceFiles/lang/lang_instance.cpp | 14 ++- Telegram/SourceFiles/lang/lang_instance.h | 8 +- Telegram/SourceFiles/mainwidget.cpp | 4 +- .../settings_chat_settings_widget.cpp | 4 - .../settings/settings_chat_settings_widget.h | 2 - .../settings/settings_inner_widget.cpp | 6 +- .../settings/settings_inner_widget.h | 2 +- .../settings/settings_privacy_widget.cpp | 16 ++- .../settings/settings_privacy_widget.h | 4 + .../SourceFiles/settings/settings_widget.cpp | 12 +- .../SourceFiles/settings/settings_widget.h | 4 +- Telegram/SourceFiles/ui/widgets/checkbox.cpp | 22 +++- Telegram/SourceFiles/ui/widgets/checkbox.h | 4 + 17 files changed, 183 insertions(+), 59 deletions(-) diff --git a/Telegram/SourceFiles/boxes/language_box.cpp b/Telegram/SourceFiles/boxes/language_box.cpp index 7009b9829..5c0c56b3e 100644 --- a/Telegram/SourceFiles/boxes/language_box.cpp +++ b/Telegram/SourceFiles/boxes/language_box.cpp @@ -87,9 +87,9 @@ void LanguageBox::Inner::languageChanged(int languageIndex) { } void LanguageBox::prepare() { - refreshLangItems(); + refreshLang(); subscribe(Lang::Current().updated(), [this] { - refreshLangItems(); + refreshLang(); }); _inner = setInnerWidget(object_ptr(this, &_languages), st::boxLayerScroll); @@ -100,7 +100,7 @@ void LanguageBox::prepare() { }); } -void LanguageBox::refreshLangItems() { +void LanguageBox::refreshLang() { clearButtons(); addButton(lang(lng_box_ok), [this] { closeBox(); }); diff --git a/Telegram/SourceFiles/boxes/language_box.h b/Telegram/SourceFiles/boxes/language_box.h index 6407a7730..d7f1e3879 100644 --- a/Telegram/SourceFiles/boxes/language_box.h +++ b/Telegram/SourceFiles/boxes/language_box.h @@ -42,7 +42,7 @@ private: void refresh(); void refreshLanguages(); - void refreshLangItems(); + void refreshLang(); Languages _languages; diff --git a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp index a3163e837..feb893607 100644 --- a/Telegram/SourceFiles/lang/lang_cloud_manager.cpp +++ b/Telegram/SourceFiles/lang/lang_cloud_manager.cpp @@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "messenger.h" #include "apiwrap.h" #include "auth_session.h" +#include "boxes/confirm_box.h" namespace Lang { @@ -35,12 +36,11 @@ CloudManager::CloudManager(Instance &langpack, gsl::not_null mtp } void CloudManager::requestLangPackDifference() { - auto &langpack = Lang::Current(); - if (langpack.isCustom() || _langPackRequestId) { + if (_langpack.isCustom() || _langPackRequestId) { return; } - auto version = langpack.version(); + auto version = _langpack.version(); if (version > 0) { _langPackRequestId = request(MTPlangpack_GetDifference(MTP_int(version))).done([this](const MTPLangPackDifference &result) { _langPackRequestId = 0; @@ -60,24 +60,24 @@ void CloudManager::requestLangPackDifference() { void CloudManager::applyLangPackDifference(const MTPLangPackDifference &difference) { Expects(difference.type() == mtpc_langPackDifference); - auto ¤t = Lang::Current(); - if (current.isCustom()) { + if (_langpack.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(); + auto langpackId = qs(langpack.vlang_code); + if (needToApplyLangPack(langpackId)) { + applyLangPackData(langpack); + } else if (_langpack.id().isEmpty()) { + _offerSwitchToId = langpackId; + if (langpack.vfrom_version.v == 0) { + _offerSwitchToData = std::make_unique(difference); + } else { + _offerSwitchToData.reset(); } + offerSwitchLangPack(); } else { - LOG(("Lang Info: Up to date.")); + LOG(("Lang Warning: Ignoring update for '%1' because our language is '%2'").arg(langpackId).arg(_langpack.id())); } } @@ -99,21 +99,98 @@ void CloudManager::requestLanguageList() { }).send(); } +bool CloudManager::needToApplyLangPack(const QString &id) { + auto currentId = _langpack.id(); + if (currentId == id) { + return true; + } else if (currentId.isEmpty() && id == DefaultLanguageId()) { + return true; + } + return false; +} + +void CloudManager::offerSwitchLangPack() { + Expects(!_offerSwitchToId.isEmpty()); + Expects(_offerSwitchToId != DefaultLanguageId()); + + if (!showOfferSwitchBox()) { + subscribe(languageListChanged(), [this] { + showOfferSwitchBox(); + }); + requestLanguageList(); + } +} + +QString CloudManager::findOfferedLanguageName() { + for_const (auto &language, _languages) { + if (language.id == _offerSwitchToId) { + return language.name; + } + } + return QString(); +} + +bool CloudManager::showOfferSwitchBox() { + auto name = findOfferedLanguageName(); + if (name.isEmpty()) { + return false; + } + + Ui::show(Box("Do you want to switch your language to " + name + "? You can always change your language in Settings.", "Change", lang(lng_cancel), [this] { + Ui::hideLayer(); + if (_offerSwitchToId.isEmpty()) { + return; + } + if (_offerSwitchToData) { + t_assert(_offerSwitchToData->type() == mtpc_langPackDifference); + applyLangPackData(base::take(_offerSwitchToData)->c_langPackDifference()); + } else { + switchToLanguage(_offerSwitchToId); + } + }, [this] { + Ui::hideLayer(); + changeIdAndReInitConnection(DefaultLanguageId()); + Local::writeLangPack(); + })); + return true; +} + +void CloudManager::applyLangPackData(const MTPDlangPackDifference &data) { + switchLangPackId(qs(data.vlang_code)); + if (_langpack.version() < data.vfrom_version.v) { + requestLangPackDifference(); + } 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.")); + } +} + 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()); + auto currentId = _langpack.id(); + auto notChanged = (currentId == id) || (currentId.isEmpty() && id == DefaultLanguageId()); + if (!notChanged) { + changeIdAndReInitConnection(id); } } +void CloudManager::changeIdAndReInitConnection(const QString &id) { + _langpack.switchToId(id); + + auto mtproto = requestMTP(); + mtproto->reInitConnection(mtproto->mainDcId()); +} + CloudManager &CurrentCloudManager() { auto result = Messenger::Instance().langCloudManager(); t_assert(result != nullptr); diff --git a/Telegram/SourceFiles/lang/lang_cloud_manager.h b/Telegram/SourceFiles/lang/lang_cloud_manager.h index b1850fc83..0d19cbad9 100644 --- a/Telegram/SourceFiles/lang/lang_cloud_manager.h +++ b/Telegram/SourceFiles/lang/lang_cloud_manager.h @@ -30,7 +30,7 @@ namespace Lang { class Instance; -class CloudManager : private MTP::Sender { +class CloudManager : private MTP::Sender, private base::Subscriber { public: CloudManager(Instance &langpack, gsl::not_null mtproto); @@ -53,8 +53,14 @@ public: void switchToLanguage(const QString &id); private: - void applyLangPack(const MTPUpdates &updates); + void offerSwitchLangPack(); + bool showOfferSwitchBox(); + QString findOfferedLanguageName(); + + bool needToApplyLangPack(const QString &id); + void applyLangPackData(const MTPDlangPackDifference &data); void switchLangPackId(const QString &id); + void changeIdAndReInitConnection(const QString &id); Instance &_langpack; Languages _languages; @@ -62,6 +68,9 @@ private: mtpRequestId _langPackRequestId = 0; mtpRequestId _languagesRequestId = 0; + QString _offerSwitchToId; + std::unique_ptr _offerSwitchToData; + }; inline bool operator==(const CloudManager::Language &a, const CloudManager::Language &b) { diff --git a/Telegram/SourceFiles/lang/lang_instance.cpp b/Telegram/SourceFiles/lang/lang_instance.cpp index 1f7f1ed65..f7fe4216f 100644 --- a/Telegram/SourceFiles/lang/lang_instance.cpp +++ b/Telegram/SourceFiles/lang/lang_instance.cpp @@ -230,6 +230,10 @@ bool ValueParser::parse() { } // namespace +QString DefaultLanguageId() { + return str_const_toString(kDefaultLanguage); +} + void Instance::switchToId(const QString &id) { reset(); _id = id; @@ -260,16 +264,12 @@ void Instance::fillDefaults() { } } -QString Instance::DefaultLanguageId() { - return str_const_toString(kDefaultLanguage); -} - QString Instance::cloudLangCode() const { if (isCustom() || id().isEmpty()) { if (_systemLanguage.isEmpty()) { _systemLanguage = Platform::SystemLanguage(); if (_systemLanguage.isEmpty()) { - _systemLanguage = Instance::DefaultLanguageId(); + _systemLanguage = DefaultLanguageId(); } } return _systemLanguage; @@ -410,7 +410,9 @@ void Instance::fillFromLegacy(int legacyId, const QString &legacyPath) { } void Instance::applyDifference(const MTPDlangPackDifference &difference) { - Expects(qs(difference.vlang_code) == _id); + auto updateLanguageId = qs(difference.vlang_code); + auto isValidUpdate = (updateLanguageId == _id) || (_id.isEmpty() && updateLanguageId == DefaultLanguageId()); + Expects(isValidUpdate); Expects(difference.vfrom_version.v <= _version); _version = difference.vversion.v; diff --git a/Telegram/SourceFiles/lang/lang_instance.h b/Telegram/SourceFiles/lang/lang_instance.h index db2eff7ab..3b4bd8c00 100644 --- a/Telegram/SourceFiles/lang/lang_instance.h +++ b/Telegram/SourceFiles/lang/lang_instance.h @@ -28,6 +28,11 @@ constexpr auto kLegacyLanguageNone = -2; constexpr auto kLegacyCustomLanguage = -1; constexpr auto kLegacyDefaultLanguage = 0; +QString DefaultLanguageId(); + +class Instance; +Instance &Current(); + class Instance { public: Instance() { @@ -41,7 +46,6 @@ public: Instance(Instance &&other) = default; Instance &operator=(Instance &&other) = default; - static QString DefaultLanguageId(); QString cloudLangCode() const; QString id() const { @@ -93,6 +97,4 @@ private: }; -Instance &Current(); - } // namespace Lang diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index b1aad6897..f099f6a3c 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -5690,11 +5690,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { ////// Cloud langpacks case mtpc_updateLangPack: { auto &langpack = update.c_updateLangPack(); - Messenger::Instance().langCloudManager()->applyLangPackDifference(langpack.vdifference); + Lang::CurrentCloudManager().applyLangPackDifference(langpack.vdifference); } break; case mtpc_updateLangPackTooLong: { - Messenger::Instance().langCloudManager()->requestLangPackDifference(); + Lang::CurrentCloudManager().requestLangPackDifference(); } break; } diff --git a/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp b/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp index 9904b9422..d8aeaa592 100644 --- a/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp @@ -43,10 +43,6 @@ LabeledLink::LabeledLink(QWidget *parent, const QString &label, const QString &t connect(_link, SIGNAL(clicked()), parent, slot); } -void LabeledLink::setLink(const QString &text) { - _link.create(this, text); -} - Ui::LinkButton *LabeledLink::link() const { return _link; } diff --git a/Telegram/SourceFiles/settings/settings_chat_settings_widget.h b/Telegram/SourceFiles/settings/settings_chat_settings_widget.h index 33a71a63b..d7e4f9d5d 100644 --- a/Telegram/SourceFiles/settings/settings_chat_settings_widget.h +++ b/Telegram/SourceFiles/settings/settings_chat_settings_widget.h @@ -36,8 +36,6 @@ public: }; LabeledLink(QWidget *parent, const QString &label, const QString &text, Type type, const char *slot); - void setLink(const QString &text); - Ui::LinkButton *link() const; int naturalWidth() const override; diff --git a/Telegram/SourceFiles/settings/settings_inner_widget.cpp b/Telegram/SourceFiles/settings/settings_inner_widget.cpp index bc8b4f80a..7a3d7f3f2 100644 --- a/Telegram/SourceFiles/settings/settings_inner_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_inner_widget.cpp @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "settings/settings_inner_widget.h" +#include "lang/lang_instance.h" #include "styles/style_settings.h" #include "settings/settings_cover.h" #include "settings/settings_block_widget.h" @@ -37,10 +38,11 @@ namespace Settings { InnerWidget::InnerWidget(QWidget *parent) : LayerInner(parent) , _self(App::self()) { refreshBlocks(); - subscribe(Global::RefSelfChanged(), [this]() { selfUpdated(); }); + subscribe(Global::RefSelfChanged(), [this] { fullRebuild(); }); + subscribe(Lang::Current().updated(), [this] { fullRebuild(); }); } -void InnerWidget::selfUpdated() { +void InnerWidget::fullRebuild() { _self = App::self(); refreshBlocks(); diff --git a/Telegram/SourceFiles/settings/settings_inner_widget.h b/Telegram/SourceFiles/settings/settings_inner_widget.h index ecc7f5fa1..e61dd1258 100644 --- a/Telegram/SourceFiles/settings/settings_inner_widget.h +++ b/Telegram/SourceFiles/settings/settings_inner_widget.h @@ -52,7 +52,7 @@ protected: int resizeGetHeight(int newWidth) override; private: - void selfUpdated(); + void fullRebuild(); void refreshBlocks(); // Returns the new height value. diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp index ca5f61af5..86843f16b 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.cpp @@ -37,7 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Settings { LocalPasscodeState::LocalPasscodeState(QWidget *parent) : TWidget(parent) -, _edit(this, lang(Global::LocalPasscode() ? lng_passcode_change : lng_passcode_turn_on), st::boxLinkButton) +, _edit(this, GetEditPasscodeText(), st::boxLinkButton) , _turnOff(this, lang(lng_passcode_turn_off), st::boxLinkButton) { updateControls(); connect(_edit, SIGNAL(clicked()), this, SLOT(onEdit())); @@ -60,11 +60,15 @@ void LocalPasscodeState::onTurnOff() { } void LocalPasscodeState::updateControls() { - _edit->setText(lang(Global::LocalPasscode() ? lng_passcode_change : lng_passcode_turn_on)); + _edit->setText(GetEditPasscodeText()); _edit->moveToLeft(0, 0); _turnOff->setVisible(Global::LocalPasscode()); } +QString LocalPasscodeState::GetEditPasscodeText() { + return lang(Global::LocalPasscode() ? lng_passcode_change : lng_passcode_turn_on); +} + CloudPasswordState::CloudPasswordState(QWidget *parent) : TWidget(parent) , _edit(this, lang(lng_cloud_password_set), st::boxLinkButton) , _turnOff(this, lang(lng_passcode_turn_off), st::boxLinkButton) { @@ -169,6 +173,10 @@ PrivacyWidget::PrivacyWidget(QWidget *parent, UserData *self) : BlockWidget(pare subscribe(Global::RefLocalPasscodeChanged(), [this]() { autoLockUpdated(); }); } +QString PrivacyWidget::GetAutoLockText() { + return (Global::AutoLock() % 3600) ? lng_passcode_autolock_minutes(lt_count, Global::AutoLock() / 60) : lng_passcode_autolock_hours(lt_count, Global::AutoLock() / 3600); +} + void PrivacyWidget::createControls() { style::margins marginSmall(0, 0, 0, st::settingsSmallSkip); style::margins marginSkip(0, 0, 0, st::settingsSkip); @@ -180,7 +188,7 @@ void PrivacyWidget::createControls() { addChildRow(_groupsInvitePrivacy, marginSmall, lang(lng_settings_groups_invite_privacy), SLOT(onGroupsInvitePrivacy())); addChildRow(_localPasscodeState, marginSmall); auto label = lang(psIdleSupported() ? lng_passcode_autolock_away : lng_passcode_autolock_inactive); - auto value = (Global::AutoLock() % 3600) ? lng_passcode_autolock_minutes(lt_count, Global::AutoLock() / 60) : lng_passcode_autolock_hours(lt_count, Global::AutoLock() / 3600); + auto value = GetAutoLockText(); addChildRow(_autoLock, marginSmall, slidedPadding, label, value, LabeledLink::Type::Primary, SLOT(onAutoLock())); if (!Global::LocalPasscode()) { _autoLock->hideFast(); @@ -192,7 +200,7 @@ void PrivacyWidget::createControls() { void PrivacyWidget::autoLockUpdated() { if (Global::LocalPasscode()) { - auto value = (Global::AutoLock() % 3600) ? lng_passcode_autolock_minutes(lt_count, Global::AutoLock() / 60) : lng_passcode_autolock_hours(lt_count, Global::AutoLock() / 3600); + auto value = GetAutoLockText(); _autoLock->entity()->link()->setText(value); resizeToWidth(width()); } diff --git a/Telegram/SourceFiles/settings/settings_privacy_widget.h b/Telegram/SourceFiles/settings/settings_privacy_widget.h index 2af6c689b..89a1c7941 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_widget.h +++ b/Telegram/SourceFiles/settings/settings_privacy_widget.h @@ -39,6 +39,8 @@ private slots: void onTurnOff(); private: + static QString GetEditPasscodeText(); + void updateControls(); object_ptr _edit; @@ -94,6 +96,8 @@ private slots: void onSelfDestruction(); private: + static QString GetAutoLockText(); + void createControls(); void autoLockUpdated(); diff --git a/Telegram/SourceFiles/settings/settings_widget.cpp b/Telegram/SourceFiles/settings/settings_widget.cpp index 5f46a0298..1d995c93b 100644 --- a/Telegram/SourceFiles/settings/settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_widget.cpp @@ -197,13 +197,23 @@ void codesFeedString(const QString &text) { } // namespace Widget::Widget(QWidget *parent) { - setTitle(lang(lng_menu_settings)); + refreshLang(); + subscribe(Lang::Current().updated(), [this] { + refreshLang(); + }); + _inner = setInnerWidget(object_ptr(this)); setCloseClickHandler([]() { Ui::hideSettingsAndLayer(); }); } +void Widget::refreshLang() { + setTitle(lang(lng_menu_settings)); + + update(); +} + void Widget::showFinished() { _inner->showFinished(); } diff --git a/Telegram/SourceFiles/settings/settings_widget.h b/Telegram/SourceFiles/settings/settings_widget.h index 6a5c760ea..b10b2caf5 100644 --- a/Telegram/SourceFiles/settings/settings_widget.h +++ b/Telegram/SourceFiles/settings/settings_widget.h @@ -26,12 +26,14 @@ namespace Settings { class InnerWidget; -class Widget : public Layer { +class Widget : public Layer, private base::Subscriber { Q_OBJECT public: Widget(QWidget*); + void refreshLang(); + void showFinished() override; void parentResized() override; diff --git a/Telegram/SourceFiles/ui/widgets/checkbox.cpp b/Telegram/SourceFiles/ui/widgets/checkbox.cpp index 9a9a762ce..c9c5ac356 100644 --- a/Telegram/SourceFiles/ui/widgets/checkbox.cpp +++ b/Telegram/SourceFiles/ui/widgets/checkbox.cpp @@ -39,22 +39,32 @@ Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const sty , _st(st) , _text(_st.style, text, _checkboxOptions) , _checked(checked) { - if (_st.width <= 0) { - resizeToWidth(_text.maxWidth() - _st.width); - } else { - resizeToWidth(_st.width); - } - _checkRect = myrtlrect(_st.margin.left(), _st.margin.top(), _st.diameter, _st.diameter); + resizeToText(); connect(this, SIGNAL(clicked()), this, SLOT(onClicked())); setCursor(style::cur_pointer); } +void Checkbox::setText(const QString &text) { + _text.setText(_st.style, text, _checkboxOptions); + resizeToText(); + update(); +} + bool Checkbox::checked() const { return _checked; } +void Checkbox::resizeToText() { + if (_st.width <= 0) { + resizeToWidth(_text.maxWidth() - _st.width); + } else { + resizeToWidth(_st.width); + } + _checkRect = myrtlrect(_st.margin.left(), _st.margin.top(), _st.diameter, _st.diameter); +} + void Checkbox::setChecked(bool checked, NotifyAboutChange notify) { if (_checked != checked) { _checked = checked; diff --git a/Telegram/SourceFiles/ui/widgets/checkbox.h b/Telegram/SourceFiles/ui/widgets/checkbox.h index 0d90a5fb0..d9807c451 100644 --- a/Telegram/SourceFiles/ui/widgets/checkbox.h +++ b/Telegram/SourceFiles/ui/widgets/checkbox.h @@ -31,6 +31,8 @@ class Checkbox : public RippleButton { public: Checkbox(QWidget *parent, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox); + void setText(const QString &text); + bool checked() const; enum class NotifyAboutChange { Notify, @@ -61,6 +63,8 @@ signals: void changed(); private: + void resizeToText(); + const style::Checkbox &_st; Text _text;