diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 2d6126197a..db08ef19f9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -425,6 +425,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_custom_spellchecker" = "Use spell checker"; "lng_settings_manage_dictionaries" = "Manage dictionaries"; "lng_settings_manage_enabled_dictionary" = "Dictionary is enabled"; +"lng_settings_manage_remove_dictionary" = "Remove Dictionary"; "lng_backgrounds_header" = "Choose your new chat background"; "lng_theme_sure_keep" = "Keep this theme?"; diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp index 98ba77e1a0..cd8957ce59 100644 --- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp +++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #ifndef TDESKTOP_DISABLE_SPELLCHECK +#include "base/event_filter.h" #include "chat_helpers/spellchecker_common.h" #include "core/application.h" #include "main/main_account.h" @@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/wrap/vertical_layout.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" +#include "ui/widgets/popup_menu.h" #include "ui/wrap/slide_wrap.h" #include "ui/effects/animations.h" @@ -68,6 +70,12 @@ inline auto DictExists(int langId) { return Spellchecker::DictionaryExists(langId); } +inline auto FilterEnabledDict(Dictionaries dicts) { + return dicts | ranges::views::filter( + DictExists + ) | ranges::to_vector; +} + DictState ComputeState(int id, bool enabled) { const auto result = enabled ? DictState(Active()) : DictState(Ready()); if (DictExists(id)) { @@ -151,6 +159,8 @@ auto AddButtonWithLoader( const auto buttonState = button->lifetime() .make_state>(); + const auto dictionaryRemoved = button->lifetime() + .make_state>(); const auto label = Ui::CreateChild( button, @@ -188,10 +198,15 @@ auto AddButtonWithLoader( rpl::single( buttonEnabled ) | rpl::then( - buttonState->value( - ) | rpl::filter([](const DictState &state) { - return state.is(); - }) | rpl::map([](const auto &state) { + rpl::merge( + dictionaryRemoved->events(), + buttonState->value( + ) | rpl::filter([](const DictState &state) { + return state.is(); + }) | rpl::map([] { + return rpl::empty_value(); + }) + ) | rpl::map([]() { return false; }) ) @@ -205,7 +220,13 @@ auto AddButtonWithLoader( : rpl::single( buttonEnabled ) | rpl::then( - button->toggledValue() + rpl::merge( + dictionaryRemoved->events( + ) | rpl::map([] { + return false; + }), + button->toggledValue() + ) ) | rpl::map([=](auto enabled) { return ComputeState(id, enabled); }); @@ -233,6 +254,29 @@ auto AddButtonWithLoader( } }, button->lifetime()); + const auto contextMenu = button->lifetime() + .make_state>(); + const auto showMenu = [=] { + if (!DictExists(id)) { + return false; + } + *contextMenu = base::make_unique_q(button); + contextMenu->get()->addAction( + tr::lng_settings_manage_remove_dictionary(tr::now), [=] { + Spellchecker::RemoveDictionary(id); + dictionaryRemoved->fire({}); + }); + contextMenu->get()->popup(QCursor::pos()); + return true; + }; + + base::install_event_filter(button, [=](not_null e) { + if (e->type() == QEvent::ContextMenu && showMenu()) { + return base::EventFilterResult::Cancel; + } + return base::EventFilterResult::Continue; + }); + return button; } @@ -281,11 +325,8 @@ void ManageDictionariesBox::prepare() { setTitle(tr::lng_settings_manage_dictionaries()); addButton(tr::lng_settings_save(), [=] { - auto enabledRows = inner->enabledRows(); _session->settings().setDictionariesEnabled( - enabledRows | ranges::views::filter( - DictExists - ) | ranges::to_vector); + FilterEnabledDict(inner->enabledRows())); _session->saveSettingsDelayed(); // Ignore boxClosing() when the Save button was pressed. lifetime().destroy(); @@ -294,7 +335,8 @@ void ManageDictionariesBox::prepare() { addButton(tr::lng_close(), [=] { closeBox(); }); boxClosing() | rpl::start_with_next([=] { - _session->settings().setDictionariesEnabled(initialEnabledRows); + _session->settings().setDictionariesEnabled( + FilterEnabledDict(initialEnabledRows)); _session->saveSettingsDelayed(); }, lifetime()); diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp index a589f39c30..07e6ef0127 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.cpp @@ -134,6 +134,17 @@ bool DictionaryExists(int langId) { return (bad == end(kDictExtensions)); } +bool RemoveDictionary(int langId) { + if (!langId) { + return true; + } + const auto fileName = Spellchecker::LocaleFromLangId(langId).name(); + const auto folder = qsl("%1/%2/") + .arg(DictionariesPath()) + .arg(fileName); + return QDir(folder).removeRecursively(); +} + bool WriteDefaultDictionary() { // This is an unused function. const auto en = QLocale::English; diff --git a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h index 0c3a09c4df..db486ebde2 100644 --- a/Telegram/SourceFiles/chat_helpers/spellchecker_common.h +++ b/Telegram/SourceFiles/chat_helpers/spellchecker_common.h @@ -27,6 +27,8 @@ MTP::DedicatedLoader::Location GetDownloadLocation(int id); [[nodiscard]] QString DictPathByLangId(int langId); bool UnpackDictionary(const QString &path, int langId); [[nodiscard]] bool DictionaryExists(int langId); +bool RemoveDictionary(int langId); +[[nodiscard]] bool IsEn(int langId); bool WriteDefaultDictionary(); std::vector Dictionaries();