Add translation bar dropdown menu.

This commit is contained in:
John Preston 2023-01-30 14:10:42 +04:00
parent 1689c1a597
commit f5be551ff8
27 changed files with 700 additions and 384 deletions

View File

@ -12,9 +12,7 @@ add_subdirectory(lib_crl)
add_subdirectory(lib_base)
add_subdirectory(lib_ui)
add_subdirectory(lib_tl)
if (NOT DESKTOP_APP_DISABLE_SPELLCHECK)
add_subdirectory(lib_spellcheck)
endif()
add_subdirectory(lib_spellcheck)
add_subdirectory(lib_storage)
add_subdirectory(lib_lottie)
add_subdirectory(lib_qr)
@ -72,6 +70,7 @@ PRIVATE
desktop-app::lib_crl
desktop-app::lib_ui
desktop-app::lib_tl
desktop-app::lib_spellcheck
desktop-app::lib_storage
desktop-app::lib_lottie
desktop-app::lib_qr

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/language_box.h"
#include "lang/lang_keys.h"
#include "ui/boxes/choose_language_box.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
@ -44,16 +45,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QClipboard>
namespace {
namespace {
[[nodiscard]] std::vector<QLocale> SkipLocalesFromSettings() {
const auto list = Core::App().settings().skipTranslationLanguages();
return list
| ranges::views::transform(&LanguageId::locale)
| ranges::to_vector;
}
} // namespace
using Language = Lang::Language;
using Languages = Lang::CloudManager::Languages;
@ -1128,8 +1119,7 @@ void LanguageBox::prepare() {
Core::App().saveSettingsDelayed();
}, translateEnabled->lifetime());
using Locales = std::vector<QLocale>;
const auto label = lifetime().make_state<rpl::event_stream<Locales>>();
using Languages = std::vector<LanguageId>;
const auto translateSkipWrap = topContainer->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
topContainer,
@ -1141,28 +1131,16 @@ void LanguageBox::prepare() {
const auto translateSkip = Settings::AddButtonWithLabel(
translateSkipWrap->entity(),
tr::lng_translate_settings_choose(),
label->events(
) | rpl::map([](const Locales &locales) {
return (locales.size() > 1)
? tr::lng_languages_count(tr::now, lt_count, locales.size())
: Ui::LanguageName(locales.front());
Core::App().settings().skipTranslationLanguagesValue(
) | rpl::map([](const Languages &list) {
return (list.size() > 1)
? tr::lng_languages_count(tr::now, lt_count, list.size())
: Ui::LanguageName(list.front());
}),
st::settingsButtonNoIcon);
label->fire(SkipLocalesFromSettings());
translateSkip->setClickedCallback([=] {
Ui::BoxShow(this).showBox(
Box(Ui::ChooseLanguageBox, [=](Locales locales) {
label->fire_copy(locales);
using namespace ranges::views;
Core::App().settings().setSkipTranslationLanguages(all(
locales
) | transform([](const QLocale &l) {
return LanguageId{ l.language() };
}) | ranges::to_vector);
Core::App().saveSettingsDelayed();
}, SkipLocalesFromSettings()),
Ui::LayerOption::KeepOther);
Ui::BoxShow(this).showBox(Ui::EditSkipTranslationLanguages());
});
Settings::AddSkip(topContainer);
Settings::AddDividerText(

View File

@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
#include "base/binary_guard.h"
struct LanguageId;
namespace Ui {
class MultiSelect;
struct ScrollToRequest;

View File

@ -114,6 +114,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
return tr::lng_premium_summary_subtitle_profile_badge();
case PremiumPreview::AnimatedUserpics:
return tr::lng_premium_summary_subtitle_animated_userpics();
case PremiumPreview::RealTimeTranslation:
return tr::lng_premium_summary_subtitle_translation();
}
Unexpected("PremiumPreview in SectionTitle.");
}
@ -142,6 +144,8 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
return tr::lng_premium_summary_about_profile_badge();
case PremiumPreview::AnimatedUserpics:
return tr::lng_premium_summary_about_animated_userpics();
case PremiumPreview::RealTimeTranslation:
return tr::lng_premium_summary_about_translation();
}
Unexpected("PremiumPreview in SectionTitle.");
}
@ -453,6 +457,7 @@ struct VideoPreviewDocument {
case PremiumPreview::InfiniteReactions: return "infinite_reactions";
case PremiumPreview::ProfileBadge: return "profile_badge";
case PremiumPreview::AnimatedUserpics: return "animated_userpics";
case PremiumPreview::RealTimeTranslation: return "translations";
}
return "";
}();

View File

@ -49,6 +49,7 @@ enum class PremiumPreview {
AdvancedChatManagement,
ProfileBadge,
AnimatedUserpics,
RealTimeTranslation,
kCount,
};

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/sender.h"
#include "settings/settings_common.h"
#include "spellcheck/platform/platform_language.h"
#include "ui/boxes/choose_language_box.h"
#include "ui/effects/loading_element.h"
#include "ui/layers/generic_box.h"
#include "ui/painter.h"
@ -36,171 +37,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
namespace {
[[nodiscard]] std::vector<QLocale::Language> Languages() {
return std::vector<QLocale::Language>{
QLocale::English,
QLocale::Afrikaans,
QLocale::Albanian,
QLocale::Amharic,
QLocale::Arabic,
QLocale::Armenian,
QLocale::Azerbaijani,
QLocale::Basque,
QLocale::Belarusian,
QLocale::Bosnian,
QLocale::Bulgarian,
QLocale::Burmese,
QLocale::Catalan,
QLocale::Chinese,
QLocale::Croatian,
QLocale::Czech,
QLocale::Danish,
QLocale::Dutch,
QLocale::Esperanto,
QLocale::Estonian,
QLocale::Finnish,
QLocale::French,
QLocale::Gaelic,
QLocale::Galician,
QLocale::Georgian,
QLocale::German,
QLocale::Greek,
QLocale::Gusii,
QLocale::Hausa,
QLocale::Hebrew,
QLocale::Hungarian,
QLocale::Icelandic,
QLocale::Igbo,
QLocale::Indonesian,
QLocale::Irish,
QLocale::Italian,
QLocale::Japanese,
QLocale::Kazakh,
QLocale::Kinyarwanda,
QLocale::Korean,
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::Polish,
QLocale::Portuguese,
QLocale::Romanian,
QLocale::Russian,
QLocale::Serbian,
QLocale::Shona,
QLocale::Sindhi,
QLocale::Sinhala,
QLocale::Slovak,
QLocale::Slovenian,
QLocale::Somali,
QLocale::Spanish,
QLocale::Sundanese,
QLocale::Swahili,
QLocale::Swedish,
QLocale::Tajik,
QLocale::Tatar,
QLocale::Teso,
QLocale::Thai,
QLocale::Turkish,
QLocale::Turkmen,
QLocale::Ukrainian,
QLocale::Urdu,
QLocale::Uzbek,
QLocale::Vietnamese,
QLocale::Welsh,
QLocale::WesternFrisian,
QLocale::Xhosa,
QLocale::Yiddish,
};
}
class Row final : public Ui::SettingsButton {
public:
Row(not_null<Ui::RpWidget*> parent, const QLocale &locale);
[[nodiscard]] bool filtered(const QString &query) const;
[[nodiscard]] QLocale locale() const;
int resizeGetHeight(int newWidth) override;
protected:
void paintEvent(QPaintEvent *e) override;
private:
const style::PeerListItem &_st;
const QLocale _locale;
const QString _status;
const QString _titleText;
Ui::Text::String _title;
};
Row::Row(not_null<Ui::RpWidget*> parent, const QLocale &locale)
: SettingsButton(parent, rpl::never<QString>())
, _st(st::inviteLinkListItem)
, _locale(locale)
, _status(QLocale::languageToString(locale.language()))
, _titleText(LanguageName(locale))
, _title(_st.nameStyle, _titleText) {
}
QLocale Row::locale() const {
return _locale;
}
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();
Ui::SettingsButton::paintBg(p, e->rect(), paintOver);
Ui::SettingsButton::paintRipple(p, 0, 0);
Ui::SettingsButton::paintToggle(p, width());
const auto &color = st::windowSubTextFg;
p.setPen(Qt::NoPen);
p.setBrush(color);
const auto left = st::settingsSubsectionTitlePadding.left();
const auto toggleRect = Ui::SettingsButton::maybeToggleRect();
const auto right = left
+ (toggleRect.isEmpty() ? 0 : (width() - toggleRect.x()));
p.setPen(_st.nameFg);
_title.drawLeft(
p,
left,
_st.namePosition.y(),
width() - left - right,
width() - left - right);
p.setPen(paintOver ? _st.statusFgOver : _st.statusFg);
p.setFont(st::contactsStatusFont);
p.drawTextLeft(
left,
_st.statusPosition.y(),
width() - left - right,
_status);
}
class ShowButton final : public RpWidget {
public:
ShowButton(not_null<Ui::RpWidget*> parent);
@ -250,19 +86,6 @@ rpl::producer<Qt::MouseButton> ShowButton::clicks() const {
} // namespace
QString LanguageName(const QLocale &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);
}
}
void TranslateBox(
not_null<Ui::GenericBox*> box,
not_null<PeerData*> peer,
@ -272,14 +95,10 @@ void TranslateBox(
box->setWidth(st::boxWideWidth);
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
const auto container = box->verticalLayout();
const auto translateTo = Core::App().settings().translateTo().locale();
auto id = Core::App().settings().translateToValue();
const auto api = box->lifetime().make_state<MTP::Sender>(
&peer->session().mtp());
struct State {
rpl::event_stream<QLocale> locale;
};
const auto state = box->lifetime().make_state<State>();
text.entities = ranges::views::all(
text.entities
@ -355,11 +174,10 @@ void TranslateBox(
const auto padding = st::settingsSubsectionTitlePadding;
const auto subtitle = Settings::AddSubsectionTitle(
container,
state->locale.events() | rpl::map(LanguageName));
rpl::duplicate(id) | rpl::map(LanguageName));
// Workaround.
state->locale.events(
) | rpl::start_with_next([=] {
rpl::duplicate(id) | rpl::start_with_next([=] {
subtitle->resizeToWidth(container->width()
- padding.left()
- padding.right());
@ -370,7 +188,6 @@ void TranslateBox(
box,
object_ptr<FlatLabel>(box, stLabel)));
translated->entity()->setSelectable(!hasCopyRestriction);
translated->hide(anim::type::instant);
constexpr auto kMaxLines = 3;
container->resizeToWidth(box->width());
@ -380,10 +197,9 @@ void TranslateBox(
box,
st::aboutLabel,
std::min(original->entity()->height() / lineHeight, kMaxLines),
state->locale.events() | rpl::map([=](const QLocale &locale) {
return locale.textDirection() == Qt::RightToLeft;
rpl::duplicate(id) | rpl::map([=](LanguageId id) {
return id.locale().textDirection() == Qt::RightToLeft;
}))));
loading->show(anim::type::instant);
const auto showText = [=](const QString &text) {
translated->entity()->setText(text);
@ -391,7 +207,9 @@ void TranslateBox(
loading->hide(anim::type::instant);
};
const auto send = [=](const QString &toLang) {
const auto send = [=](LanguageId to) {
loading->show(anim::type::instant);
translated->hide(anim::type::instant);
api->request(MTPmessages_TranslateText(
MTP_flags(flags),
msgId ? peer->input : MTP_inputPeerEmpty(),
@ -403,7 +221,7 @@ void TranslateBox(
: MTP_vector<MTPTextWithEntities>(1, MTP_textWithEntities(
MTP_string(text.text),
MTP_vector<MTPMessageEntity>()))),
MTP_string(toLang.mid(0, 2))
MTP_string(to.locale().name().mid(0, 2))
)).done([=](const MTPmessages_TranslatedText &result) {
const auto &data = result.data();
const auto &list = data.vresult().v;
@ -414,117 +232,16 @@ void TranslateBox(
showText(tr::lng_translate_box_error(tr::now));
}).send();
};
send(translateTo.name());
state->locale.fire_copy(translateTo);
std::move(id) | rpl::start_with_next(send, box->lifetime());
box->addLeftButton(tr::lng_settings_language(), [=] {
if (loading->toggled()) {
return;
}
Ui::BoxShow(box).showBox(Box(ChooseLanguageBox, [=](
std::vector<QLocale> locales) {
const auto &locale = locales.front();
send(locale.name());
state->locale.fire_copy(locale);
loading->show(anim::type::instant);
translated->hide(anim::type::instant);
}, std::vector<QLocale>()));
Ui::BoxShow(box).showBox(ChooseTranslateToBox());
});
}
void ChooseLanguageBox(
not_null<Ui::GenericBox*> box,
Fn<void(std::vector<QLocale>)> callback,
std::vector<QLocale> toggled) {
box->setMinHeight(st::boxWidth);
box->setMaxHeight(st::boxWidth);
box->setTitle(tr::lng_languages());
const auto hasToggled = !toggled.empty();
const auto multiSelect = box->setPinnedToTopContent(
object_ptr<Ui::MultiSelect>(
box,
st::defaultMultiSelect,
tr::lng_participant_filter()));
box->setFocusCallback([=] { multiSelect->setInnerFocus(); });
const auto container = box->verticalLayout();
const auto langs = [&] {
auto langs = Languages();
const auto current = QLocale(
Lang::LanguageIdOrDefault(Lang::Id())).language();
if (const auto it = ranges::find(langs, current); it != end(langs)) {
base::reorder(langs, std::distance(begin(langs), it), 0);
}
return langs;
}();
auto rows = std::vector<not_null<Ui::SlideWrap<Row>*>>();
rows.reserve(langs.size());
for (const auto &lang : langs) {
const auto locale = QLocale(lang);
const auto button = container->add(
object_ptr<Ui::SlideWrap<Row>>(
container,
object_ptr<Row>(container, locale)));
if (hasToggled) {
button->entity()->toggleOn(
rpl::single(ranges::contains(toggled, locale)),
false);
} else {
button->entity()->setClickedCallback([=] {
callback({ locale });
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 = Ui::CreateChild<Ui::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 (hasToggled) {
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()->locale();
}) | ranges::to_vector;
if (!result.empty()) {
callback(std::move(result));
}
box->closeBox();
});
}
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
bool SkipTranslate(TextWithEntities textWithEntities) {
const auto &text = textWithEntities.text;
if (text.isEmpty()) {
@ -557,4 +274,24 @@ bool SkipTranslate(TextWithEntities textWithEntities) {
#endif
}
object_ptr<BoxContent> EditSkipTranslationLanguages() {
auto title = tr::lng_translate_settings_choose();
return Box(ChooseLanguageBox, std::move(title), [=](
std::vector<LanguageId> &&list) {
Core::App().settings().setSkipTranslationLanguages(
std::move(list));
Core::App().saveSettingsDelayed();
}, Core::App().settings().skipTranslationLanguages());
}
object_ptr<BoxContent> ChooseTranslateToBox() {
return Box(ChooseLanguageBox, tr::lng_languages(), [=](
const std::vector<LanguageId> &ids) {
Expects(!ids.empty());
Core::App().settings().setTranslateTo(ids.front());
Core::App().saveSettingsDelayed();
}, std::nullopt);
}
} // namespace Ui

View File

@ -7,16 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/object_ptr.h"
class PeerData;
struct LanguageId;
namespace Ui {
class BoxContent;
class GenericBox;
[[nodiscard]] QString LanguageName(const QLocale &locale);
void TranslateBox(
not_null<Ui::GenericBox*> box,
not_null<GenericBox*> box,
not_null<PeerData*> peer,
MsgId msgId,
TextWithEntities text,
@ -24,9 +26,7 @@ void TranslateBox(
[[nodiscard]] bool SkipTranslate(TextWithEntities textWithEntities);
void ChooseLanguageBox(
not_null<Ui::GenericBox*> box,
Fn<void(std::vector<QLocale>)> callback,
std::vector<QLocale> toggled);
[[nodiscard]] object_ptr<BoxContent> EditSkipTranslationLanguages();
[[nodiscard]] object_ptr<BoxContent> ChooseTranslateToBox();
} // namespace Ui

View File

@ -1447,6 +1447,7 @@ void StickersListFooter::paintSetIconToCache(
p.restore();
} else {
paintOne(0, [&] {
const auto selected = (info.index == _iconState.selected);
if (icon.setId == Data::Stickers::FeaturedSetId) {
const auto &stickers = _session->data().stickers();
return stickers.featuredSetsUnreadCount()
@ -1457,9 +1458,9 @@ void StickersListFooter::paintSetIconToCache(
} else if (icon.setId == AllEmojiSectionSetId()) {
return &st::emojiPeople;
} else if (const auto section = SetIdEmojiSection(icon.setId)) {
return sectionIcon(*section, false);
return sectionIcon(*section, selected);
}
return &st::emojiRecent;
return sectionIcon(Section::Recent, selected);
}());
}
}

View File

@ -78,9 +78,9 @@ constexpr auto kPinnedMessageTextLimit = 16;
using ItemPreview = HistoryView::ItemPreview;
[[nodiscard]] bool IsOnlyEmojiAndSpaces(const QString &text) {
[[nodiscard]] bool HasNotEmojiAndSpaces(const QString &text) {
if (text.isEmpty()) {
return true;
return false;
}
auto emoji = 0;
auto start = text.data();
@ -91,10 +91,10 @@ using ItemPreview = HistoryView::ItemPreview;
} else if (Ui::Emoji::Find(start, end, &emoji)) {
start += emoji;
} else {
return false;
return true;
}
}
return true;
return false;
}
} // namespace
@ -4682,7 +4682,7 @@ void HistoryItem::cacheOnlyEmojiAndSpaces(bool only) {
bool HistoryItem::isOnlyEmojiAndSpaces() const {
if (!(_flags & MessageFlag::OnlyEmojiAndSpacesSet)) {
const_cast<HistoryItem*>(this)->cacheOnlyEmojiAndSpaces(
IsOnlyEmojiAndSpaces(_text.text));
!HasNotEmojiAndSpaces(_text.text));
}
return (_flags & MessageFlag::OnlyEmojiAndSpaces);
}

View File

@ -6254,6 +6254,7 @@ void HistoryWidget::setupTranslateBar() {
_translateBar = std::make_unique<HistoryView::TranslateBar>(
this,
controller(),
_history);
controller()->adaptive().oneColumnValue(

View File

@ -655,10 +655,12 @@ const Ui::Text::String &Element::text() const {
OnlyEmojiAndSpaces Element::isOnlyEmojiAndSpaces() const {
if (data()->Has<HistoryMessageTranslation>()) {
return OnlyEmojiAndSpaces::No;
} else if (!_text.isEmpty() || data()->originalText().empty()) {
return _text.isOnlyEmojiAndSpaces()
? OnlyEmojiAndSpaces::Yes
: OnlyEmojiAndSpaces::No;
} else if (!_text.isEmpty()) {
return _text.hasNotEmojiAndSpaces()
? OnlyEmojiAndSpaces::No
: OnlyEmojiAndSpaces::Yes;
} else if (data()->originalText().empty()) {
return OnlyEmojiAndSpaces::Yes;
} else {
return OnlyEmojiAndSpaces::Unknown;
}

View File

@ -7,26 +7,42 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_translate_bar.h"
#include "boxes/translate_box.h" // Ui::LanguageName.
#include "boxes/translate_box.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "data/data_changes.h"
#include "history/history.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "spellcheck/spellcheck_types.h"
#include "ui/boxes/choose_language_box.h" // EditSkipTranslationLanguages.
#include "ui/layers/box_content.h"
#include "ui/text/text_utilities.h"
#include "ui/toast/toast.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/popup_menu.h"
#include "ui/widgets/shadow.h"
#include "window/window_session_controller.h"
#include "styles/style_chat.h"
#include "styles/style_menu_icons.h"
#include <QtGui/QtEvents>
namespace HistoryView {
namespace {
constexpr auto kToastDuration = 4 * crl::time(1000);
} // namespace
TranslateBar::TranslateBar(
not_null<QWidget*> parent,
not_null<Window::SessionController*> controller,
not_null<History*> history)
: _wrap(parent, object_ptr<Ui::FlatButton>(
: _controller(controller)
, _history(history)
, _wrap(parent, object_ptr<Ui::FlatButton>(
parent,
QString(),
st::historyComposeButton))
@ -95,6 +111,8 @@ void TranslateBar::setup(not_null<History*> history) {
const auto settings = Ui::CreateChild<Ui::IconButton>(
button,
st::historyTranslateSettings);
settings->setClickedCallback([=] { showMenu(createMenu(settings)); });
const auto updateLabelGeometry = [=] {
const auto full = _wrap.width() - icon->width();
const auto skip = st::semiboldFont->spacew * 2;
@ -125,14 +143,23 @@ void TranslateBar::setup(not_null<History*> history) {
history->session().changes().historyFlagsValue(
history,
(Data::HistoryUpdate::Flag::TranslatedTo
| Data::HistoryUpdate::Flag::TranslateFrom))
) | rpl::map([=](LanguageId to, const auto&) {
return history->translatedTo()
? u"Show Original"_q
| Data::HistoryUpdate::Flag::TranslateFrom)),
history->session().changes().peerFlagsValue(
history->peer,
Data::PeerUpdate::Flag::TranslationDisabled)
) | rpl::map([=](LanguageId to, const auto&, const auto&) {
using Flag = PeerData::TranslationFlag;
return (history->peer->translationFlag() != Flag::Enabled)
? rpl::single(QString())
: history->translatedTo()
? tr::lng_translate_show_original()
: history->translateOfferedFrom()
? u"Translate to "_q + Ui::LanguageName(to.locale())
: QString();
}) | rpl::distinct_until_changed(
? tr::lng_translate_bar_to(
lt_name,
rpl::single(Ui::LanguageName(to)))
: rpl::single(QString());
}) | rpl::flatten_latest(
) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](QString phrase) {
_shouldBeShown = !phrase.isEmpty();
if (_shouldBeShown) {
@ -145,6 +172,181 @@ void TranslateBar::setup(not_null<History*> history) {
}, lifetime());
}
base::unique_qptr<Ui::PopupMenu> TranslateBar::createMenu(
not_null<Ui::IconButton*> button) {
if (_menu) {
return nullptr;
}
auto result = base::make_unique_q<Ui::PopupMenu>(
&_wrap,
st::popupMenuExpandedSeparator);
result->setDestroyedCallback([
this,
weak = Ui::MakeWeak(&_wrap),
weakButton = Ui::MakeWeak(button),
menu = result.get()
] {
if (weak && _menu == menu) {
if (weakButton) {
weakButton->setForceRippled(false);
}
}
});
button->setForceRippled(true);
return result;
}
void TranslateBar::showMenu(base::unique_qptr<Ui::PopupMenu> menu) {
if (!menu) {
return;
}
_menu = std::move(menu);
_menu->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
const auto weak = base::make_weak(_controller);
_menu->addAction(tr::lng_translate_menu_to(tr::now), [=] {
if (const auto strong = weak.get()) {
strong->show(Ui::ChooseTranslateToBox());
}
}, &st::menuIconTranslate);
_menu->addSeparator();
const auto history = _history;
if (const auto translateOfferedFrom = _history->translateOfferedFrom()) {
const auto name = Ui::LanguageName(translateOfferedFrom);
const auto addToIgnoreList = [=] {
showSettingsToast(history->peer, translateOfferedFrom);
history->peer->saveTranslationDisabled(true);
auto &settings = Core::App().settings();
auto skip = settings.skipTranslationLanguages();
if (!ranges::contains(skip, translateOfferedFrom)) {
skip.push_back(translateOfferedFrom);
}
settings.setSkipTranslationLanguages(std::move(skip));
Core::App().saveSettingsDelayed();
};
_menu->addAction(
tr::lng_translate_menu_dont(tr::now, lt_name, name),
addToIgnoreList,
&st::menuIconBlock);
}
const auto hideBar = [=] {
showHiddenToast(history->peer);
history->peer->saveTranslationDisabled(true);
};
_menu->addAction(
tr::lng_translate_menu_hide(tr::now),
hideBar,
&st::menuIconCancel);
_menu->popup(_wrap.mapToGlobal(
QPoint(_wrap.width(), 0) + st::historyTranslateMenuPosition));
}
void TranslateBar::showSettingsToast(
not_null<PeerData*> peer,
LanguageId ignored) {
const auto weak = base::make_weak(_controller);
const auto text = tr::lng_translate_dont_added(
tr::now,
lt_name,
Ui::Text::Bold(Ui::LanguageName(ignored)),
Ui::Text::WithEntities);
showToast(text, tr::lng_translate_settings(tr::now), [=] {
if (const auto strong = weak.get()) {
const auto box = strong->show(
Ui::EditSkipTranslationLanguages());
if (box) {
box->boxClosing() | rpl::start_with_next([=] {
const auto in = ranges::contains(
Core::App().settings().skipTranslationLanguages(),
ignored);
if (!in && weak) {
peer->saveTranslationDisabled(false);
}
}, box->lifetime());
}
}
});
}
void TranslateBar::showHiddenToast(not_null<PeerData*> peer) {
const auto &phrase = peer->isUser()
? tr::lng_translate_hidden_user
: peer->isBroadcast()
? tr::lng_translate_hidden_channel
: tr::lng_translate_hidden_group;
const auto proj = Ui::Text::WithEntities;
showToast(phrase(tr::now, proj), tr::lng_translate_undo(tr::now), [=] {
peer->saveTranslationDisabled(false);
});
}
void TranslateBar::showToast(
TextWithEntities text,
const QString &buttonText,
Fn<void()> buttonCallback) {
const auto st = std::make_shared<style::Toast>(st::historyPremiumToast);
const auto skip = st->padding.top();
st->padding.setRight(st::historyPremiumViewSet.font->width(buttonText)
- st::historyPremiumViewSet.width);
const auto weak = Ui::Toast::Show(_wrap.window(), Ui::Toast::Config{
.text = std::move(text),
.st = st.get(),
.durationMs = kToastDuration,
.multiline = true,
.dark = true,
.slideSide = RectPart::Bottom,
});
const auto strong = weak.get();
if (!strong) {
return;
}
strong->setInputUsed(true);
const auto widget = strong->widget();
widget->lifetime().add([st] {});
const auto hideToast = [weak] {
if (const auto strong = weak.get()) {
strong->hideAnimated();
}
};
const auto clickableBackground = Ui::CreateChild<Ui::AbstractButton>(
widget.get());
clickableBackground->setPointerCursor(false);
clickableBackground->setAcceptBoth();
clickableBackground->show();
clickableBackground->addClickHandler([=](Qt::MouseButton button) {
if (button == Qt::RightButton) {
hideToast();
}
});
const auto button = Ui::CreateChild<Ui::RoundButton>(
widget.get(),
rpl::single(buttonText),
st::historyPremiumViewSet);
button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
button->show();
rpl::combine(
widget->sizeValue(),
button->sizeValue()
) | rpl::start_with_next([=](QSize outer, QSize inner) {
button->moveToRight(
0,
(outer.height() - inner.height()) / 2,
outer.width());
clickableBackground->resize(outer);
}, widget->lifetime());
button->setClickedCallback([=] {
buttonCallback();
hideToast();
});
}
void TranslateBar::show() {
if (!_forceHidden) {
return;

View File

@ -14,13 +14,22 @@ struct LanguageId;
namespace Ui {
class PlainShadow;
class PopupMenu;
class IconButton;
} // namespace Ui
namespace Window {
class SessionController;
} // namespace Window
namespace HistoryView {
class TranslateBar final {
public:
TranslateBar(not_null<QWidget*> parent, not_null<History*> history);
TranslateBar(
not_null<QWidget*> parent,
not_null<Window::SessionController*> controller,
not_null<History*> history);
~TranslateBar();
void show();
@ -43,10 +52,23 @@ private:
void setup(not_null<History*> history);
void updateShadowGeometry(QRect wrapGeometry);
void updateControlsGeometry(QRect wrapGeometry);
[[nodiscard]] base::unique_qptr<Ui::PopupMenu> createMenu(
not_null<Ui::IconButton*> button);
void showMenu(base::unique_qptr<Ui::PopupMenu> menu);
void showHiddenToast(not_null<PeerData*> peer);
void showSettingsToast(not_null<PeerData*> peer, LanguageId ignored);
void showToast(
TextWithEntities text,
const QString &buttonText,
Fn<void()> buttonCallback);
const not_null<Window::SessionController*> _controller;
const not_null<History*> _history;
Ui::SlideWrap<> _wrap;
std::unique_ptr<Ui::PlainShadow> _shadow;
Fn<QRect(QRect)> _shadowGeometryPostprocess;
base::unique_qptr<Ui::PopupMenu> _menu;
bool _shouldBeShown = false;
bool _forceHidden = false;

View File

@ -57,13 +57,6 @@ void TranslateTracker::setup() {
const auto session = &_history->session();
peer->updateFull();
auto translationEnabled = session->changes().peerFlagsValue(
peer,
Data::PeerUpdate::Flag::TranslationDisabled
) | rpl::map([=] {
return peer->translationFlag() == PeerData::TranslationFlag::Enabled;
}) | rpl::distinct_until_changed();
_trackingLanguage = Data::AmPremiumValue(&_history->session());
_trackingLanguage.value(
@ -340,7 +333,14 @@ void TranslateTracker::checkRecognized(const std::vector<LanguageId> &skip) {
: _allLoaded
? std::min(count, kEnoughForTranslation)
: kEnoughForTranslation;
if (ranges::accumulate(languages, 0, ranges::plus(), p) >= threshold) {
const auto translatable = ranges::accumulate(
languages,
0,
ranges::plus(),
p);
if (count < kEnoughForTranslation) {
// Don't change offer by small amount of messages.
} else if (translatable >= threshold) {
_history->translateOfferFrom(
ranges::max_element(languages, ranges::less(), p)->first);
} else {

View File

@ -121,7 +121,9 @@ TextWithEntities AddTimestampLinks(
return text;
}
static const auto expression = QRegularExpression(
"(?<![^\\s\\(\\)\"\\,\\.\\-])(?:(?:(\\d{1,2}):)?(\\d))?(\\d):(\\d\\d)(?![^\\s\\(\\)\",\\.\\-])");
"(?<![^\\s\\(\\)\"\\,\\.\\-])"
"(?:(?:(\\d{1,2}):)?(\\d))?(\\d):(\\d\\d)"
"(?![^\\s\\(\\)\",\\.\\-\\+])");
const auto &string = text.text;
auto offset = 0;
while (true) {

View File

@ -21,7 +21,6 @@ namespace {
const auto kSerializeVersionTag = u"#new"_q;
constexpr auto kSerializeVersion = 1;
constexpr auto kDefaultLanguage = "en"_cs;
constexpr auto kCloudLangPackName = "tdesktop"_cs;
constexpr auto kCustomLanguage = "#custom"_cs;
constexpr auto kLangValuesLimit = 20000;
@ -213,14 +212,6 @@ void ParseKeyValue(
} // namespace
QString DefaultLanguageId() {
return kDefaultLanguage.utf16();
}
QString LanguageIdOrDefault(const QString &id) {
return !id.isEmpty() ? id : DefaultLanguageId();
}
QString CloudLangPackName() {
return kCloudLangPackName.utf16();
}

View File

@ -7,8 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/producer.h>
#include "lang_auto.h"
#include "base/const_string.h"
#include "base/weak_ptr.h"
namespace Lang {
@ -31,8 +31,6 @@ inline bool operator!=(const Language &a, const Language &b) {
return !(a == b);
}
QString DefaultLanguageId();
QString LanguageIdOrDefault(const QString &id);
QString CloudLangPackName();
QString CustomLanguageId();
Language DefaultLanguage();

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "lang/lang_keys.h"
#include "base/const_string.h"
#include "lang/lang_file_parser.h"
#include "ui/integration.h"
@ -14,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kDefaultLanguage = "en"_cs;
template <typename WithYear, typename WithoutYear>
inline QString langDateMaybeWithYear(
QDate date,
@ -231,3 +234,15 @@ QString langDateTimeFull(const QDateTime &date) {
lt_time,
QLocale().toString(date.time(), QLocale::ShortFormat));
}
namespace Lang {
QString DefaultLanguageId() {
return kDefaultLanguage.utf16();
}
QString LanguageIdOrDefault(const QString &id) {
return !id.isEmpty() ? id : DefaultLanguageId();
}
} // namespace Lang

View File

@ -34,5 +34,7 @@ namespace Lang {
[[nodiscard]] QString Id();
[[nodiscard]] rpl::producer<> Updated();
[[nodiscard]] QString GetNonDefaultValue(const QByteArray &key);
[[nodiscard]] QString DefaultLanguageId();
[[nodiscard]] QString LanguageIdOrDefault(const QString &id);
} // namespace Lang

View File

@ -119,6 +119,7 @@ settingsPremiumIconSpeed: icon {{ "settings/premium/speed", settingsIconFg }};
settingsPremiumIconStar: icon {{ "settings/premium/star", settingsIconFg }};
settingsPremiumIconVoice: icon {{ "settings/premium/voice", settingsIconFg }};
settingsPremiumIconFiles: icon {{ "settings/premium/files", settingsIconFg }};
settingsPremiumIconTranslations: icon {{ "settings/premium/translations", settingsIconFg }};
settingsTTLChatsOff: icon {{ "settings/ttl/autodelete_off", windowSubTextFg }};
settingsTTLChatsOn: icon {{ "settings/ttl/autodelete_on", windowActiveTextFg }};

View File

@ -221,6 +221,7 @@ using Order = std::vector<QString>;
u"advanced_chat_management"_q,
u"profile_badge"_q,
u"animated_userpics"_q,
u"translations"_q,
};
}
@ -333,6 +334,15 @@ using Order = std::vector<QString>;
PremiumPreview::AnimatedUserpics,
},
},
{
u"translations"_q,
Entry{
&st::settingsPremiumIconTranslations,
tr::lng_premium_summary_subtitle_translation(),
tr::lng_premium_summary_about_translation(),
PremiumPreview::RealTimeTranslation,
},
},
};
}
@ -1887,6 +1897,8 @@ not_null<Ui::GradientButton*> CreateSubscribeButton(
return PremiumPreview::ProfileBadge;
} else if (s == u"animated_userpics"_q) {
return PremiumPreview::AnimatedUserpics;
} else if (s == u"translations"_q) {
return PremiumPreview::RealTimeTranslation;
}
return PremiumPreview::kCount;
}) | ranges::views::filter([](PremiumPreview type) {

View File

@ -0,0 +1,321 @@
/*
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 "styles/style_info.h"
#include "styles/style_layers.h"
#include "styles/style_settings.h"
namespace Ui {
namespace {
const auto kLanguageNamePrefix = "cloud_lng_passport_in_";
[[nodiscard]] std::vector<LanguageId> TranslationLanguagesList() {
return {
{ QLocale::English },
{ QLocale::Afrikaans },
{ QLocale::Albanian },
{ QLocale::Amharic },
{ QLocale::Arabic },
{ QLocale::Armenian },
{ QLocale::Azerbaijani },
{ QLocale::Basque },
{ QLocale::Belarusian },
{ QLocale::Bosnian },
{ QLocale::Bulgarian },
{ QLocale::Burmese },
{ QLocale::Catalan },
{ QLocale::Chinese },
{ QLocale::Croatian },
{ QLocale::Czech },
{ QLocale::Danish },
{ QLocale::Dutch },
{ QLocale::Esperanto },
{ QLocale::Estonian },
{ QLocale::Finnish },
{ QLocale::French },
{ QLocale::Gaelic },
{ QLocale::Galician },
{ QLocale::Georgian },
{ QLocale::German },
{ QLocale::Greek },
{ QLocale::Gusii },
{ QLocale::Hausa },
{ QLocale::Hebrew },
{ QLocale::Hungarian },
{ QLocale::Icelandic },
{ QLocale::Igbo },
{ QLocale::Indonesian },
{ QLocale::Irish },
{ QLocale::Italian },
{ QLocale::Japanese },
{ QLocale::Kazakh },
{ QLocale::Kinyarwanda },
{ QLocale::Korean },
{ 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::Polish },
{ QLocale::Portuguese },
{ QLocale::Romanian },
{ QLocale::Russian },
{ QLocale::Serbian },
{ QLocale::Shona },
{ QLocale::Sindhi },
{ QLocale::Sinhala },
{ QLocale::Slovak },
{ QLocale::Slovenian },
{ QLocale::Somali },
{ QLocale::Spanish },
{ QLocale::Sundanese },
{ QLocale::Swahili },
{ QLocale::Swedish },
{ QLocale::Tajik },
{ QLocale::Tatar },
{ QLocale::Teso },
{ QLocale::Thai },
{ QLocale::Turkish },
{ QLocale::Turkmen },
{ QLocale::Ukrainian },
{ 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::settingsSubsectionTitlePadding.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 LanguageName(LanguageId id) {
const auto code = id.locale().name().toLower().mid(0, 2);
const auto translated = LanguageNameTranslated(code);
return translated.isEmpty()
? QLocale::languageToString(id.locale().language())
: 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);
}
}
void ChooseLanguageBox(
not_null<GenericBox*> box,
rpl::producer<QString> title,
Fn<void(std::vector<LanguageId>)> callback,
std::optional<std::vector<LanguageId>> toggled) {
box->setMinHeight(st::boxWidth);
box->setMaxHeight(st::boxWidth);
box->setTitle(std::move(title));
const auto hasToggles = toggled.has_value();
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();
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);
}
if (hasToggles) {
ranges::stable_partition(list, [&](LanguageId id) {
return ranges::contains(*toggled, id);
});
}
return list;
}();
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 (hasToggles) {
button->entity()->toggleOn(
rpl::single(ranges::contains(*toggled, id)),
false);
} 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 (hasToggles) {
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

View File

@ -0,0 +1,26 @@
/*
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
*/
#pragma once
struct LanguageId;
namespace Ui {
class GenericBox;
[[nodiscard]] QString LanguageNameTranslated(const QString &twoLetterCode);
[[nodiscard]] QString LanguageName(LanguageId id);
[[nodiscard]] QString LanguageNameNative(LanguageId id);
void ChooseLanguageBox(
not_null<GenericBox*> box,
rpl::producer<QString> title,
Fn<void(std::vector<LanguageId>)> callback,
std::optional<std::vector<LanguageId>> toggled);
} // namespace Ui

View File

@ -1273,3 +1273,4 @@ historyTranslateSettings: IconButton(defaultIconButton) {
rippleAreaSize: 38px;
ripple: defaultRippleAnimation;
}
historyTranslateMenuPosition: point(-6px, 40px);

View File

@ -156,6 +156,8 @@ PRIVATE
ui/boxes/calendar_box.h
ui/boxes/choose_date_time.cpp
ui/boxes/choose_date_time.h
ui/boxes/choose_language_box.cpp
ui/boxes/choose_language_box.h
ui/boxes/choose_time.cpp
ui/boxes/choose_time.h
ui/boxes/confirm_box.cpp
@ -326,6 +328,7 @@ PRIVATE
desktop-app::lib_ffmpeg
desktop-app::lib_webview
desktop-app::lib_webrtc
desktop-app::lib_spellcheck
desktop-app::lib_stripe
desktop-app::external_kcoreaddons
)

View File

@ -36,12 +36,6 @@ if (TDESKTOP_API_ID STREQUAL "0" OR TDESKTOP_API_HASH STREQUAL "")
" ")
endif()
if (DESKTOP_APP_DISABLE_SPELLCHECK)
target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_SPELLCHECK)
else()
target_link_libraries(Telegram PRIVATE desktop-app::lib_spellcheck)
endif()
if (DESKTOP_APP_DISABLE_AUTOUPDATE)
target_compile_definitions(Telegram PRIVATE TDESKTOP_DISABLE_AUTOUPDATE)
endif()

@ -1 +1 @@
Subproject commit f2e698f2209a86c133261196275ca98273c7a4dc
Subproject commit 7bcca23bfe9f95bf9fd10a2e803734baccc517b4