| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "ui/boxes/choose_language_box.h"
- #include "lang/lang_keys.h"
- #include "spellcheck/spellcheck_types.h"
- #include "ui/layers/generic_box.h"
- #include "ui/widgets/buttons.h"
- #include "ui/widgets/multi_select.h"
- #include "ui/wrap/slide_wrap.h"
- #include "ui/painter.h"
- #include "base/debug_log.h"
- #include "styles/style_info.h"
- #include "styles/style_layers.h"
- namespace Ui {
- namespace {
- const auto kLanguageNamePrefix = "cloud_lng_language_";
- const auto kTranslateToPrefix = "cloud_lng_translate_to_";
- [[nodiscard]] std::vector<LanguageId> TranslationLanguagesList() {
- // If adding some languages here you need to check that it is
- // supported on the server. Right now server supports those:
- //
- // 'af', 'sq', 'am', 'ar', 'hy', 'az', 'eu', 'be', 'bn', 'bs', 'bg',
- // 'ca', 'ceb', 'zh-CN', 'zh', 'zh-TW', 'co', 'hr', 'cs', 'da', 'nl',
- // 'en', 'eo', 'et', 'fi', 'fr', 'fy', 'gl', 'ka', 'de', 'el', 'gu',
- // 'ht', 'ha', 'haw', 'he', 'iw', 'hi', 'hmn', 'hu', 'is', 'ig', 'id',
- // 'ga', 'it', 'ja', 'jv', 'kn', 'kk', 'km', 'rw', 'ko', 'ku', 'ky',
- // 'lo', 'la', 'lv', 'lt', 'lb', 'mk', 'mg', 'ms', 'ml', 'mt', 'mi',
- // 'mr', 'mn', 'my', 'ne', 'no', 'ny', 'or', 'ps', 'fa', 'pl', 'pt',
- // 'pa', 'ro', 'ru', 'sm', 'gd', 'sr', 'st', 'sn', 'sd', 'si', 'sk',
- // 'sl', 'so', 'es', 'su', 'sw', 'sv', 'tl', 'tg', 'ta', 'tt', 'te',
- // 'th', 'tr', 'tk', 'uk', 'ur', 'ug', 'uz', 'vi', 'cy', 'xh', 'yi',
- // 'yo', 'zu',
- return {
- { QLocale::English },
- { QLocale::Arabic },
- { QLocale::Belarusian },
- { QLocale::Catalan },
- { QLocale::Chinese },
- { QLocale::Dutch },
- { QLocale::French },
- { QLocale::German },
- { QLocale::Indonesian },
- { QLocale::Italian },
- { QLocale::Japanese },
- { QLocale::Korean },
- { QLocale::Polish },
- { QLocale::Portuguese },
- { QLocale::Russian },
- { QLocale::Spanish },
- { QLocale::Ukrainian },
- { QLocale::Afrikaans },
- { QLocale::Albanian },
- { QLocale::Amharic },
- { QLocale::Armenian },
- { QLocale::Azerbaijani },
- { QLocale::Basque },
- { QLocale::Bosnian },
- { QLocale::Bulgarian },
- { QLocale::Burmese },
- { QLocale::Croatian },
- { QLocale::Czech },
- { QLocale::Danish },
- { QLocale::Esperanto },
- { QLocale::Estonian },
- { QLocale::Finnish },
- { QLocale::Gaelic },
- { QLocale::Galician },
- { QLocale::Georgian },
- { QLocale::Greek },
- { QLocale::Gusii },
- { QLocale::Hausa },
- { QLocale::Hebrew },
- { QLocale::Hungarian },
- { QLocale::Icelandic },
- { QLocale::Igbo },
- { QLocale::Irish },
- { QLocale::Kazakh },
- { QLocale::Kinyarwanda },
- { QLocale::Kurdish },
- { QLocale::Lao },
- { QLocale::Latvian },
- { QLocale::Lithuanian },
- { QLocale::Luxembourgish },
- { QLocale::Macedonian },
- { QLocale::Malagasy },
- { QLocale::Malay },
- { QLocale::Maltese },
- { QLocale::Maori },
- { QLocale::Mongolian },
- { QLocale::Nepali },
- { QLocale::Pashto },
- { QLocale::Persian },
- { QLocale::Romanian },
- { QLocale::Serbian },
- { QLocale::Shona },
- { QLocale::Sindhi },
- { QLocale::Sinhala },
- { QLocale::Slovak },
- { QLocale::Slovenian },
- { QLocale::Somali },
- { QLocale::Sundanese },
- { QLocale::Swahili },
- { QLocale::Swedish },
- { QLocale::Tajik },
- { QLocale::Tatar },
- { QLocale::Teso },
- { QLocale::Thai },
- { QLocale::Turkish },
- { QLocale::Turkmen },
- { QLocale::Urdu },
- { QLocale::Uzbek },
- { QLocale::Vietnamese },
- { QLocale::Welsh },
- { QLocale::WesternFrisian },
- { QLocale::Xhosa },
- { QLocale::Yiddish },
- };
- }
- class Row final : public SettingsButton {
- public:
- Row(not_null<RpWidget*> parent, LanguageId id);
- [[nodiscard]] bool filtered(const QString &query) const;
- [[nodiscard]] LanguageId id() const;
- int resizeGetHeight(int newWidth) override;
- protected:
- void paintEvent(QPaintEvent *e) override;
- private:
- const style::PeerListItem &_st;
- const LanguageId _id;
- const QString _status;
- const QString _titleText;
- Text::String _title;
- };
- Row::Row(not_null<RpWidget*> parent, LanguageId id)
- : SettingsButton(parent, rpl::never<QString>())
- , _st(st::inviteLinkListItem)
- , _id(id)
- , _status(LanguageName(id))
- , _titleText(LanguageNameNative(id))
- , _title(_st.nameStyle, _titleText) {
- }
- LanguageId Row::id() const {
- return _id;
- }
- bool Row::filtered(const QString &query) const {
- return _status.startsWith(query, Qt::CaseInsensitive)
- || _titleText.startsWith(query, Qt::CaseInsensitive);
- }
- int Row::resizeGetHeight(int newWidth) {
- return _st.height;
- }
- void Row::paintEvent(QPaintEvent *e) {
- auto p = Painter(this);
- const auto paintOver = (isOver() || isDown()) && !isDisabled();
- SettingsButton::paintBg(p, e->rect(), paintOver);
- SettingsButton::paintRipple(p, 0, 0);
- SettingsButton::paintToggle(p, width());
- const auto &color = st::windowSubTextFg;
- p.setPen(Qt::NoPen);
- p.setBrush(color);
- const auto left = st::defaultSubsectionTitlePadding.left();
- const auto toggleRect = SettingsButton::maybeToggleRect();
- const auto right = left
- + (toggleRect.isEmpty() ? 0 : (width() - toggleRect.x()));
- const auto availableWidth = std::min(
- _title.maxWidth(),
- width() - left - right);
- p.setPen(_st.nameFg);
- _title.drawLeft(
- p,
- left,
- _st.namePosition.y(),
- availableWidth,
- width() - left - right);
- p.setPen(paintOver ? _st.statusFgOver : _st.statusFg);
- p.setFont(st::contactsStatusFont);
- p.drawTextLeft(
- left,
- _st.statusPosition.y(),
- width() - left - right,
- _status);
- }
- } // namespace
- QString LanguageNameTranslated(const QString &twoLetterCode) {
- return Lang::GetNonDefaultValue(
- kLanguageNamePrefix + twoLetterCode.toUtf8());
- }
- QString LanguageNameLocal(LanguageId id) {
- return QLocale::languageToString(id.language());
- }
- QString LanguageName(LanguageId id) {
- const auto translated = LanguageNameTranslated(id.twoLetterCode());
- return translated.isEmpty() ? LanguageNameLocal(id) : translated;
- }
- QString LanguageNameNative(LanguageId id) {
- const auto locale = id.locale();
- if (locale.language() == QLocale::English
- && (locale.country() == QLocale::UnitedStates
- || locale.country() == QLocale::AnyCountry)) {
- return u"English"_q;
- } else if (locale.language() == QLocale::Spanish) {
- return QString::fromUtf8("\x45\x73\x70\x61\xc3\xb1\x6f\x6c");
- } else {
- const auto name = locale.nativeLanguageName();
- return name.left(1).toUpper() + name.mid(1);
- }
- }
- rpl::producer<QString> TranslateBarTo(LanguageId id) {
- const auto translated = Lang::GetNonDefaultValue(
- kTranslateToPrefix + id.twoLetterCode().toUtf8());
- return (translated.isEmpty()
- ? tr::lng_translate_bar_to_other
- : tr::lng_translate_bar_to)(
- lt_name,
- rpl::single(translated.isEmpty()
- ? LanguageNameLocal(id)
- : translated));
- }
- QString TranslateMenuDont(tr::now_t, LanguageId id) {
- const auto translated = Lang::GetNonDefaultValue(
- kTranslateToPrefix + id.twoLetterCode().toUtf8());
- return (translated.isEmpty()
- ? tr::lng_translate_menu_dont_other
- : tr::lng_translate_menu_dont)(
- tr::now,
- lt_name,
- translated.isEmpty() ? LanguageNameLocal(id) : translated);
- }
- void ChooseLanguageBox(
- not_null<GenericBox*> box,
- rpl::producer<QString> title,
- Fn<void(std::vector<LanguageId>)> callback,
- std::vector<LanguageId> selected,
- bool multiselect,
- Fn<bool(LanguageId)> toggleCheck) {
- box->setMinHeight(st::boxWidth);
- box->setMaxHeight(st::boxWidth);
- box->setTitle(std::move(title));
- const auto multiSelect = box->setPinnedToTopContent(
- object_ptr<MultiSelect>(
- box,
- st::defaultMultiSelect,
- tr::lng_participant_filter()));
- box->setFocusCallback([=] { multiSelect->setInnerFocus(); });
- const auto container = box->verticalLayout();
- const auto langs = [&] {
- auto list = TranslationLanguagesList();
- for (const auto id : list) {
- LOG(("cloud_lng_language_%1").arg(id.twoLetterCode()));
- }
- const auto current = LanguageId{ QLocale(
- Lang::LanguageIdOrDefault(Lang::Id())).language() };
- if (const auto i = ranges::find(list, current); i != end(list)) {
- base::reorder(list, std::distance(begin(list), i), 0);
- }
- ranges::stable_partition(list, [&](LanguageId id) {
- return ranges::contains(selected, id);
- });
- return list;
- }();
- struct ToggleOne {
- LanguageId id;
- bool selected = false;
- };
- struct State {
- rpl::event_stream<ToggleOne> toggles;
- };
- const auto state = box->lifetime().make_state<State>();
- auto rows = std::vector<not_null<SlideWrap<Row>*>>();
- rows.reserve(langs.size());
- for (const auto &id : langs) {
- const auto button = container->add(
- object_ptr<SlideWrap<Row>>(
- container,
- object_ptr<Row>(container, id)));
- if (multiselect) {
- button->entity()->toggleOn(rpl::single(
- ranges::contains(selected, id)
- ) | rpl::then(state->toggles.events(
- ) | rpl::filter([=](ToggleOne one) {
- return one.id == id;
- }) | rpl::map([=](ToggleOne one) {
- return one.selected;
- })));
- button->entity()->toggledChanges(
- ) | rpl::start_with_next([=](bool value) {
- if (toggleCheck && !toggleCheck(id)) {
- state->toggles.fire({ .id = id, .selected = !value });
- }
- }, button->lifetime());
- } else {
- button->entity()->setClickedCallback([=] {
- callback({ id });
- box->closeBox();
- });
- }
- rows.push_back(button);
- }
- multiSelect->setQueryChangedCallback([=](const QString &query) {
- for (const auto &row : rows) {
- const auto toggled = row->entity()->filtered(query);
- if (toggled != row->toggled()) {
- row->toggle(toggled, anim::type::instant);
- }
- }
- });
- {
- const auto label = CreateChild<FlatLabel>(
- box.get(),
- tr::lng_languages_none(),
- st::membersAbout);
- box->verticalLayout()->geometryValue(
- ) | rpl::start_with_next([=](const QRect &geometry) {
- const auto shown = (geometry.height() <= 0);
- label->setVisible(shown);
- if (shown) {
- label->moveToLeft(
- (geometry.width() - label->width()) / 2,
- geometry.y() + st::membersAbout.style.font->height * 4);
- label->stackUnder(box->verticalLayout());
- }
- }, label->lifetime());
- }
- if (multiselect) {
- box->addButton(tr::lng_settings_save(), [=] {
- auto result = ranges::views::all(
- rows
- ) | ranges::views::filter([](const auto &row) {
- return row->entity()->toggled();
- }) | ranges::views::transform([](const auto &row) {
- return row->entity()->id();
- }) | ranges::to_vector;
- if (!result.empty()) {
- callback(std::move(result));
- }
- box->closeBox();
- });
- }
- box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
- }
- } // namespace Ui
|