init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
This commit is contained in:
382
Telegram/SourceFiles/ui/boxes/choose_language_box.cpp
Normal file
382
Telegram/SourceFiles/ui/boxes/choose_language_box.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
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::on_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::on_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
|
||||
Reference in New Issue
Block a user