| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101 |
- /*
- 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 "settings/settings_advanced.h"
- #include "api/api_global_privacy.h"
- #include "apiwrap.h"
- #include "settings/settings_chat.h"
- #include "settings/settings_power_saving.h"
- #include "settings/settings_privacy_security.h"
- #include "ui/wrap/vertical_layout.h"
- #include "ui/wrap/slide_wrap.h"
- #include "ui/widgets/labels.h"
- #include "ui/widgets/checkbox.h"
- #include "ui/widgets/buttons.h"
- #include "ui/gl/gl_detection.h"
- #include "ui/layers/generic_box.h"
- #include "ui/text/format_values.h"
- #include "ui/boxes/single_choice_box.h"
- #include "ui/painter.h"
- #include "ui/vertical_list.h"
- #include "ui/ui_utility.h"
- #include "boxes/connection_box.h"
- #include "boxes/about_box.h"
- #include "ui/boxes/confirm_box.h"
- #include "platform/platform_specific.h"
- #include "ui/platform/ui_platform_window.h"
- #include "base/platform/base_platform_custom_app_icon.h"
- #include "base/platform/base_platform_info.h"
- #include "window/window_controller.h"
- #include "window/window_session_controller.h"
- #include "lang/lang_keys.h"
- #include "core/update_checker.h"
- #include "core/launcher.h"
- #include "core/application.h"
- #include "tray.h"
- #include "storage/localstorage.h"
- #include "storage/storage_domain.h"
- #include "data/data_session.h"
- #include "main/main_account.h"
- #include "main/main_domain.h"
- #include "main/main_session.h"
- #include "mtproto/facade.h"
- #include "styles/style_layers.h"
- #include "styles/style_menu_icons.h"
- #include "styles/style_settings.h"
- #ifdef Q_OS_MAC
- #include "base/platform/mac/base_confirm_quit.h"
- #endif // Q_OS_MAC
- #ifndef TDESKTOP_DISABLE_SPELLCHECK
- #include "boxes/dictionaries_manager.h"
- #include "chat_helpers/spellchecker_common.h"
- #include "spellcheck/platform/platform_spellcheck.h"
- #endif // !TDESKTOP_DISABLE_SPELLCHECK
- namespace Settings {
- namespace {
- #if defined Q_OS_MAC && !defined OS_MAC_STORE
- [[nodiscard]] const QImage &IconMacRound() {
- static const auto result = QImage(u":/gui/art/icon_round512@2x.png"_q);
- return result;
- }
- #endif // Q_OS_MAC && !OS_MAC_STORE
- } // namespace
- void SetupConnectionType(
- not_null<Window::Controller*> controller,
- not_null<Main::Account*> account,
- not_null<Ui::VerticalLayout*> container) {
- const auto connectionType = [=] {
- const auto transport = account->mtp().dctransport();
- if (!Core::App().settings().proxy().isEnabled()) {
- return transport.isEmpty()
- ? tr::lng_connection_auto_connecting(tr::now)
- : tr::lng_connection_auto(tr::now, lt_transport, transport);
- } else {
- return transport.isEmpty()
- ? tr::lng_connection_proxy_connecting(tr::now)
- : tr::lng_connection_proxy(tr::now, lt_transport, transport);
- }
- };
- const auto button = AddButtonWithLabel(
- container,
- tr::lng_settings_connection_type(),
- rpl::merge(
- Core::App().settings().proxy().connectionTypeChanges(),
- // Handle language switch.
- tr::lng_connection_auto_connecting() | rpl::to_empty
- ) | rpl::map(connectionType),
- st::settingsButton,
- { &st::menuIconNetwork });
- button->addClickHandler([=] {
- controller->show(ProxiesBoxController::CreateOwningBox(account));
- });
- }
- bool HasUpdate() {
- return !Core::UpdaterDisabled();
- }
- void SetupUpdate(not_null<Ui::VerticalLayout*> container) {
- if (!HasUpdate()) {
- return;
- }
- const auto texts = Ui::CreateChild<rpl::event_stream<QString>>(
- container.get());
- const auto downloading = Ui::CreateChild<rpl::event_stream<bool>>(
- container.get());
- const auto version = tr::lng_settings_current_version(
- tr::now,
- lt_version,
- currentVersionText());
- const auto toggle = container->add(object_ptr<Button>(
- container,
- tr::lng_settings_update_automatically(),
- st::settingsUpdateToggle));
- const auto label = Ui::CreateChild<Ui::FlatLabel>(
- toggle,
- texts->events(),
- st::settingsUpdateState);
- const auto options = container->add(
- object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
- container,
- object_ptr<Ui::VerticalLayout>(container)));
- const auto inner = options->entity();
- const auto install = cAlphaVersion()
- ? nullptr
- : inner->add(object_ptr<Button>(
- inner,
- tr::lng_settings_install_beta(),
- st::settingsButtonNoIcon));
- const auto check = inner->add(object_ptr<Button>(
- inner,
- tr::lng_settings_check_now(),
- st::settingsButtonNoIcon));
- const auto update = Ui::CreateChild<Button>(
- check,
- tr::lng_update_telegram(),
- st::settingsUpdate);
- update->hide();
- check->widthValue() | rpl::start_with_next([=](int width) {
- update->resizeToWidth(width);
- update->moveToLeft(0, 0);
- }, update->lifetime());
- rpl::combine(
- toggle->widthValue(),
- label->widthValue()
- ) | rpl::start_with_next([=] {
- label->moveToLeft(
- st::settingsUpdateStatePosition.x(),
- st::settingsUpdateStatePosition.y());
- }, label->lifetime());
- label->setAttribute(Qt::WA_TransparentForMouseEvents);
- const auto showDownloadProgress = [=](int64 ready, int64 total) {
- texts->fire(tr::lng_settings_downloading_update(
- tr::now,
- lt_progress,
- Ui::FormatDownloadText(ready, total)));
- downloading->fire(true);
- };
- const auto setDefaultStatus = [=](const Core::UpdateChecker &checker) {
- using State = Core::UpdateChecker::State;
- const auto state = checker.state();
- switch (state) {
- case State::Download:
- showDownloadProgress(checker.already(), checker.size());
- break;
- case State::Ready:
- texts->fire(tr::lng_settings_update_ready(tr::now));
- update->show();
- break;
- default:
- texts->fire_copy(version);
- break;
- }
- };
- toggle->toggleOn(rpl::single(cAutoUpdate()));
- toggle->toggledValue(
- ) | rpl::filter([](bool toggled) {
- return (toggled != cAutoUpdate());
- }) | rpl::start_with_next([=](bool toggled) {
- cSetAutoUpdate(toggled);
- Local::writeSettings();
- Core::UpdateChecker checker;
- if (cAutoUpdate()) {
- checker.start();
- } else {
- checker.stop();
- setDefaultStatus(checker);
- }
- }, toggle->lifetime());
- if (install) {
- install->toggleOn(rpl::single(cInstallBetaVersion()));
- install->toggledValue(
- ) | rpl::filter([](bool toggled) {
- return (toggled != cInstallBetaVersion());
- }) | rpl::start_with_next([=](bool toggled) {
- cSetInstallBetaVersion(toggled);
- Core::Launcher::Instance().writeInstallBetaVersionsSetting();
- Core::UpdateChecker checker;
- checker.stop();
- if (toggled) {
- cSetLastUpdateCheck(0);
- }
- checker.start();
- }, toggle->lifetime());
- }
- Core::UpdateChecker checker;
- options->toggleOn(rpl::combine(
- toggle->toggledValue(),
- downloading->events_starting_with(
- checker.state() == Core::UpdateChecker::State::Download)
- ) | rpl::map([](bool check, bool downloading) {
- return check && !downloading;
- }));
- checker.checking() | rpl::start_with_next([=] {
- options->setAttribute(Qt::WA_TransparentForMouseEvents);
- texts->fire(tr::lng_settings_update_checking(tr::now));
- downloading->fire(false);
- }, options->lifetime());
- checker.isLatest() | rpl::start_with_next([=] {
- options->setAttribute(Qt::WA_TransparentForMouseEvents, false);
- texts->fire(tr::lng_settings_latest_installed(tr::now));
- downloading->fire(false);
- }, options->lifetime());
- checker.progress(
- ) | rpl::start_with_next([=](Core::UpdateChecker::Progress progress) {
- showDownloadProgress(progress.already, progress.size);
- }, options->lifetime());
- checker.failed() | rpl::start_with_next([=] {
- options->setAttribute(Qt::WA_TransparentForMouseEvents, false);
- texts->fire(tr::lng_settings_update_fail(tr::now));
- downloading->fire(false);
- }, options->lifetime());
- checker.ready() | rpl::start_with_next([=] {
- options->setAttribute(Qt::WA_TransparentForMouseEvents, false);
- texts->fire(tr::lng_settings_update_ready(tr::now));
- update->show();
- downloading->fire(false);
- }, options->lifetime());
- setDefaultStatus(checker);
- check->addClickHandler([] {
- Core::UpdateChecker checker;
- cSetLastUpdateCheck(0);
- checker.start();
- });
- update->addClickHandler([] {
- if (!Core::UpdaterDisabled()) {
- Core::checkReadyUpdate();
- }
- Core::Restart();
- });
- }
- bool HasSystemSpellchecker() {
- #ifdef TDESKTOP_DISABLE_SPELLCHECK
- return false;
- #endif // TDESKTOP_DISABLE_SPELLCHECK
- return true;
- }
- void SetupSpellchecker(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- #ifndef TDESKTOP_DISABLE_SPELLCHECK
- const auto session = &controller->session();
- const auto settings = &Core::App().settings();
- const auto isSystem = Platform::Spellchecker::IsSystemSpellchecker();
- const auto button = container->add(object_ptr<Button>(
- container,
- isSystem
- ? tr::lng_settings_system_spellchecker()
- : tr::lng_settings_custom_spellchecker(),
- st::settingsButtonNoIcon
- ))->toggleOn(
- rpl::single(settings->spellcheckerEnabled())
- );
- button->toggledValue(
- ) | rpl::filter([=](bool enabled) {
- return (enabled != settings->spellcheckerEnabled());
- }) | rpl::start_with_next([=](bool enabled) {
- settings->setSpellcheckerEnabled(enabled);
- Core::App().saveSettingsDelayed();
- }, container->lifetime());
- if (isSystem) {
- return;
- }
- const auto sliding = container->add(
- object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
- container,
- object_ptr<Ui::VerticalLayout>(container)));
- sliding->entity()->add(object_ptr<Button>(
- sliding->entity(),
- tr::lng_settings_auto_download_dictionaries(),
- st::settingsButtonNoIcon
- ))->toggleOn(
- rpl::single(settings->autoDownloadDictionaries())
- )->toggledValue(
- ) | rpl::filter([=](bool enabled) {
- return (enabled != settings->autoDownloadDictionaries());
- }) | rpl::start_with_next([=](bool enabled) {
- settings->setAutoDownloadDictionaries(enabled);
- Core::App().saveSettingsDelayed();
- }, sliding->entity()->lifetime());
- AddButtonWithLabel(
- sliding->entity(),
- tr::lng_settings_manage_dictionaries(),
- Spellchecker::ButtonManageDictsState(session),
- st::settingsButtonNoIcon
- )->addClickHandler([=] {
- controller->show(
- Box<Ui::ManageDictionariesBox>(&controller->session()));
- });
- button->toggledValue(
- ) | rpl::start_with_next([=](bool enabled) {
- sliding->toggle(enabled, anim::type::normal);
- }, container->lifetime());
- #endif // !TDESKTOP_DISABLE_SPELLCHECK
- }
- void SetupWindowTitleContent(
- Window::SessionController *controller,
- not_null<Ui::VerticalLayout*> container) {
- const auto checkbox = [&](rpl::producer<QString> &&label, bool checked) {
- return object_ptr<Ui::Checkbox>(
- container,
- std::move(label),
- checked,
- st::settingsCheckbox);
- };
- const auto addCheckbox = [&](
- rpl::producer<QString> &&label,
- bool checked) {
- return container->add(
- checkbox(std::move(label), checked),
- st::settingsCheckboxPadding);
- };
- const auto settings = &Core::App().settings();
- if (controller) {
- const auto content = [=] {
- return settings->windowTitleContent();
- };
- const auto showChatName = addCheckbox(
- tr::lng_settings_title_chat_name(),
- !content().hideChatName);
- showChatName->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked == content().hideChatName);
- }) | rpl::start_with_next([=](bool checked) {
- auto updated = content();
- updated.hideChatName = !checked;
- settings->setWindowTitleContent(updated);
- Core::App().saveSettingsDelayed();
- }, showChatName->lifetime());
- if (Core::App().domain().accountsAuthedCount() > 1) {
- const auto showAccountName = addCheckbox(
- tr::lng_settings_title_account_name(),
- !content().hideAccountName);
- showAccountName->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked == content().hideAccountName);
- }) | rpl::start_with_next([=](bool checked) {
- auto updated = content();
- updated.hideAccountName = !checked;
- settings->setWindowTitleContent(updated);
- Core::App().saveSettingsDelayed();
- }, showAccountName->lifetime());
- }
- const auto showTotalUnread = addCheckbox(
- tr::lng_settings_title_total_count(),
- !content().hideTotalUnread);
- showTotalUnread->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked == content().hideTotalUnread);
- }) | rpl::start_with_next([=](bool checked) {
- auto updated = content();
- updated.hideTotalUnread = !checked;
- settings->setWindowTitleContent(updated);
- Core::App().saveSettingsDelayed();
- }, showTotalUnread->lifetime());
- }
- if (Ui::Platform::NativeWindowFrameSupported()) {
- const auto nativeFrame = addCheckbox(
- Platform::IsWayland()
- ? tr::lng_settings_qt_frame()
- : tr::lng_settings_native_frame(),
- Core::App().settings().nativeWindowFrame());
- nativeFrame->checkedChanges(
- ) | rpl::filter([](bool checked) {
- return (checked != Core::App().settings().nativeWindowFrame());
- }) | rpl::start_with_next([=](bool checked) {
- Core::App().settings().setNativeWindowFrame(checked);
- Core::App().saveSettingsDelayed();
- }, nativeFrame->lifetime());
- }
- }
- void SetupSystemIntegrationContent(
- Window::SessionController *controller,
- not_null<Ui::VerticalLayout*> container) {
- using WorkMode = Core::Settings::WorkMode;
- const auto checkbox = [&](rpl::producer<QString> &&label, bool checked) {
- return object_ptr<Ui::Checkbox>(
- container,
- std::move(label),
- checked,
- st::settingsCheckbox);
- };
- const auto addCheckbox = [&](
- rpl::producer<QString> &&label,
- bool checked) {
- return container->add(
- checkbox(std::move(label), checked),
- st::settingsCheckboxPadding);
- };
- const auto addSlidingCheckbox = [&](
- rpl::producer<QString> &&label,
- bool checked) {
- return container->add(
- object_ptr<Ui::SlideWrap<Ui::Checkbox>>(
- container,
- checkbox(std::move(label), checked),
- st::settingsCheckboxPadding));
- };
- const auto settings = &Core::App().settings();
- if (Platform::TrayIconSupported()) {
- const auto trayEnabled = [=] {
- const auto workMode = settings->workMode();
- return (workMode == WorkMode::TrayOnly)
- || (workMode == WorkMode::WindowAndTray);
- };
- const auto tray = addCheckbox(
- tr::lng_settings_workmode_tray(),
- trayEnabled());
- const auto monochrome = Platform::HasMonochromeSetting()
- ? addSlidingCheckbox(
- tr::lng_settings_monochrome_icon(),
- settings->trayIconMonochrome())
- : nullptr;
- if (monochrome) {
- monochrome->toggle(tray->checked(), anim::type::instant);
- monochrome->entity()->checkedChanges(
- ) | rpl::filter([=](bool value) {
- return (value != settings->trayIconMonochrome());
- }) | rpl::start_with_next([=](bool value) {
- settings->setTrayIconMonochrome(value);
- Core::App().saveSettingsDelayed();
- }, monochrome->lifetime());
- }
- const auto taskbarEnabled = [=] {
- const auto workMode = settings->workMode();
- return (workMode == WorkMode::WindowOnly)
- || (workMode == WorkMode::WindowAndTray);
- };
- const auto taskbar = Platform::SkipTaskbarSupported()
- ? addCheckbox(
- tr::lng_settings_workmode_window(),
- taskbarEnabled())
- : nullptr;
- const auto updateWorkmode = [=] {
- const auto newMode = tray->checked()
- ? ((!taskbar || taskbar->checked())
- ? WorkMode::WindowAndTray
- : WorkMode::TrayOnly)
- : WorkMode::WindowOnly;
- if ((newMode == WorkMode::WindowAndTray
- || newMode == WorkMode::TrayOnly)
- && settings->workMode() != newMode) {
- cSetSeenTrayTooltip(false);
- }
- settings->setWorkMode(newMode);
- Core::App().saveSettingsDelayed();
- };
- tray->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked != trayEnabled());
- }) | rpl::start_with_next([=](bool checked) {
- if (!checked && taskbar && !taskbar->checked()) {
- taskbar->setChecked(true);
- } else {
- updateWorkmode();
- }
- if (monochrome) {
- monochrome->toggle(checked, anim::type::normal);
- }
- }, tray->lifetime());
- if (taskbar) {
- taskbar->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked != taskbarEnabled());
- }) | rpl::start_with_next([=](bool checked) {
- if (!checked && !tray->checked()) {
- tray->setChecked(true);
- } else {
- updateWorkmode();
- }
- }, taskbar->lifetime());
- }
- }
- #ifdef Q_OS_MAC
- const auto warnBeforeQuit = addCheckbox(
- tr::lng_settings_mac_warn_before_quit(
- lt_text,
- rpl::single(Platform::ConfirmQuit::QuitKeysString())),
- settings->macWarnBeforeQuit());
- warnBeforeQuit->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked != settings->macWarnBeforeQuit());
- }) | rpl::start_with_next([=](bool checked) {
- settings->setMacWarnBeforeQuit(checked);
- Core::App().saveSettingsDelayed();
- }, warnBeforeQuit->lifetime());
- #ifndef OS_MAC_STORE
- const auto enabled = [=] {
- const auto digest = base::Platform::CurrentCustomAppIconDigest();
- return digest && (settings->macRoundIconDigest() == digest);
- };
- const auto roundIcon = addCheckbox(
- tr::lng_settings_mac_round_icon(),
- enabled());
- roundIcon->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked != enabled());
- }) | rpl::start_with_next([=](bool checked) {
- const auto digest = checked
- ? base::Platform::SetCustomAppIcon(IconMacRound())
- : std::optional<uint64>();
- if (!checked) {
- base::Platform::ClearCustomAppIcon();
- }
- Window::OverrideApplicationIcon(checked ? IconMacRound() : QImage());
- Core::App().refreshApplicationIcon();
- settings->setMacRoundIconDigest(digest);
- Core::App().saveSettings();
- }, roundIcon->lifetime());
- #endif // OS_MAC_STORE
- #elif defined Q_OS_WIN // Q_OS_MAC
- using Behavior = Core::Settings::CloseBehavior;
- const auto closeToTaskbar = addSlidingCheckbox(
- tr::lng_settings_close_to_taskbar(),
- settings->closeBehavior() == Behavior::CloseToTaskbar);
- const auto closeToTaskbarShown = std::make_shared<
- rpl::variable<bool>
- >(false);
- settings->workModeValue(
- ) | rpl::start_with_next([=](WorkMode workMode) {
- *closeToTaskbarShown = !Core::App().tray().has();
- }, closeToTaskbar->lifetime());
- closeToTaskbar->toggleOn(closeToTaskbarShown->value());
- closeToTaskbar->entity()->checkedChanges(
- ) | rpl::map([=](bool checked) {
- return checked ? Behavior::CloseToTaskbar : Behavior::Quit;
- }) | rpl::filter([=](Behavior value) {
- return (settings->closeBehavior() != value);
- }) | rpl::start_with_next([=](Behavior value) {
- settings->setCloseBehavior(value);
- Local::writeSettings();
- }, closeToTaskbar->lifetime());
- #endif // Q_OS_MAC || Q_OS_WIN
- if (Platform::AutostartSupported() && controller) {
- const auto minimizedToggled = [=] {
- return cStartMinimized()
- && !controller->session().domain().local().hasLocalPasscode();
- };
- const auto autostart = addCheckbox(
- tr::lng_settings_auto_start(),
- cAutoStart());
- const auto minimized = addSlidingCheckbox(
- tr::lng_settings_start_min(),
- minimizedToggled());
- autostart->checkedChanges(
- ) | rpl::filter([](bool checked) {
- return (checked != cAutoStart());
- }) | rpl::start_with_next([=](bool checked) {
- const auto weak = base::make_weak(controller);
- cSetAutoStart(checked);
- Platform::AutostartToggle(checked, crl::guard(autostart, [=](
- bool enabled) {
- if (checked && !enabled && weak) {
- weak->window().showToast(
- Lang::Hard::AutostartEnableError());
- }
- Ui::PostponeCall(autostart, [=] {
- autostart->setChecked(enabled);
- });
- if (enabled || !minimized->entity()->checked()) {
- Local::writeSettings();
- } else {
- minimized->entity()->setChecked(false);
- }
- }));
- }, autostart->lifetime());
- Platform::AutostartRequestStateFromSystem(crl::guard(
- controller,
- [=](bool enabled) { autostart->setChecked(enabled); }));
- minimized->toggleOn(autostart->checkedValue());
- minimized->entity()->checkedChanges(
- ) | rpl::filter([=](bool checked) {
- return (checked != minimizedToggled());
- }) | rpl::start_with_next([=](bool checked) {
- if (controller->session().domain().local().hasLocalPasscode()) {
- minimized->entity()->setChecked(false);
- controller->show(Ui::MakeInformBox(
- tr::lng_error_start_minimized_passcoded()));
- } else {
- cSetStartMinimized(checked);
- Local::writeSettings();
- }
- }, minimized->lifetime());
- controller->session().domain().local().localPasscodeChanged(
- ) | rpl::start_with_next([=] {
- minimized->entity()->setChecked(minimizedToggled());
- }, minimized->lifetime());
- }
- if (Platform::IsWindows() && !Platform::IsWindowsStoreBuild()) {
- const auto sendto = addCheckbox(
- tr::lng_settings_add_sendto(),
- cSendToMenu());
- sendto->checkedChanges(
- ) | rpl::filter([](bool checked) {
- return (checked != cSendToMenu());
- }) | rpl::start_with_next([](bool checked) {
- cSetSendToMenu(checked);
- psSendToMenu(checked);
- Local::writeSettings();
- }, sendto->lifetime());
- }
- }
- template <typename Fill>
- void CheckNonEmptyOptions(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container,
- Fill fill) {
- auto wrap = object_ptr<Ui::VerticalLayout>(container);
- fill(controller, wrap.data());
- if (wrap->count() > 0) {
- container->add(object_ptr<Ui::OverrideMargins>(
- container,
- std::move(wrap)));
- Ui::AddSkip(container, st::settingsCheckboxesSkip);
- }
- }
- void SetupSystemIntegrationOptions(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- CheckNonEmptyOptions(
- controller,
- container,
- SetupSystemIntegrationContent);
- }
- void SetupWindowTitleOptions(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- CheckNonEmptyOptions(
- controller,
- container,
- SetupWindowTitleContent);
- }
- void SetupAnimations(
- not_null<Window::Controller*> window,
- not_null<Ui::VerticalLayout*> container) {
- container->add(object_ptr<Button>(
- container,
- tr::lng_settings_power_menu(),
- st::settingsButtonNoIcon
- ))->setClickedCallback([=] { window->show(Box(PowerSavingBox)); });
- }
- void ArchiveSettingsBox(
- not_null<Ui::GenericBox*> box,
- not_null<Window::SessionController*> controller) {
- box->setTitle(tr::lng_settings_archive_title());
- box->setWidth(st::boxWideWidth);
- box->addButton(tr::lng_about_done(), [=] { box->closeBox(); });
- PreloadArchiveSettings(&controller->session());
- struct State {
- Ui::SlideWrap<Ui::VerticalLayout> *foldersWrap = nullptr;
- Ui::SettingsButton *folders = nullptr;
- };
- const auto state = box->lifetime().make_state<State>();
- const auto privacy = &controller->session().api().globalPrivacy();
- const auto container = box->verticalLayout();
- AddSkip(container);
- AddSubsectionTitle(container, tr::lng_settings_unmuted_chats());
- using Unarchive = Api::UnarchiveOnNewMessage;
- container->add(object_ptr<Button>(
- container,
- tr::lng_settings_always_in_archive(),
- st::settingsButtonNoIcon
- ))->toggleOn(privacy->unarchiveOnNewMessage(
- ) | rpl::map(
- rpl::mappers::_1 == Unarchive::None
- ))->toggledChanges(
- ) | rpl::filter([=](bool toggled) {
- const auto current = privacy->unarchiveOnNewMessageCurrent();
- state->foldersWrap->toggle(!toggled, anim::type::normal);
- return toggled != (current == Unarchive::None);
- }) | rpl::start_with_next([=](bool toggled) {
- privacy->updateUnarchiveOnNewMessage(toggled
- ? Unarchive::None
- : state->folders->toggled()
- ? Unarchive::NotInFoldersUnmuted
- : Unarchive::AnyUnmuted);
- }, container->lifetime());
- AddSkip(container);
- AddDividerText(container, tr::lng_settings_unmuted_chats_about());
- state->foldersWrap = container->add(
- object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
- container,
- object_ptr<Ui::VerticalLayout>(container)));
- const auto inner = state->foldersWrap->entity();
- AddSkip(inner);
- AddSubsectionTitle(inner, tr::lng_settings_chats_from_folders());
- state->folders = inner->add(object_ptr<Button>(
- inner,
- tr::lng_settings_always_in_archive(),
- st::settingsButtonNoIcon
- ))->toggleOn(privacy->unarchiveOnNewMessage(
- ) | rpl::map(
- rpl::mappers::_1 != Unarchive::AnyUnmuted
- ));
- state->folders->toggledChanges(
- ) | rpl::filter([=](bool toggled) {
- const auto current = privacy->unarchiveOnNewMessageCurrent();
- return toggled != (current != Unarchive::AnyUnmuted);
- }) | rpl::start_with_next([=](bool toggled) {
- const auto current = privacy->unarchiveOnNewMessageCurrent();
- privacy->updateUnarchiveOnNewMessage(!toggled
- ? Unarchive::AnyUnmuted
- : (current == Unarchive::AnyUnmuted)
- ? Unarchive::NotInFoldersUnmuted
- : current);
- }, inner->lifetime());
- AddSkip(inner);
- AddDividerText(inner, tr::lng_settings_chats_from_folders_about());
- state->foldersWrap->toggle(
- privacy->unarchiveOnNewMessageCurrent() != Unarchive::None,
- anim::type::instant);
- SetupArchiveAndMute(controller, box->verticalLayout());
- }
- void PreloadArchiveSettings(not_null<::Main::Session*> session) {
- session->api().globalPrivacy().reload();
- }
- void SetupHardwareAcceleration(not_null<Ui::VerticalLayout*> container) {
- const auto settings = &Core::App().settings();
- container->add(object_ptr<Button>(
- container,
- tr::lng_settings_enable_hwaccel(),
- st::settingsButtonNoIcon
- ))->toggleOn(
- rpl::single(settings->hardwareAcceleratedVideo())
- )->toggledValue(
- ) | rpl::filter([=](bool enabled) {
- return (enabled != settings->hardwareAcceleratedVideo());
- }) | rpl::start_with_next([=](bool enabled) {
- settings->setHardwareAcceleratedVideo(enabled);
- Core::App().saveSettingsDelayed();
- }, container->lifetime());
- }
- #ifdef DESKTOP_APP_USE_ANGLE
- void SetupANGLE(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- using ANGLE = Ui::GL::ANGLE;
- const auto options = std::vector{
- tr::lng_settings_angle_backend_auto(tr::now),
- tr::lng_settings_angle_backend_d3d11(tr::now),
- tr::lng_settings_angle_backend_d3d9(tr::now),
- tr::lng_settings_angle_backend_d3d11on12(tr::now),
- //tr::lng_settings_angle_backend_opengl(tr::now),
- tr::lng_settings_angle_backend_disabled(tr::now),
- };
- const auto disabled = int(options.size()) - 1;
- const auto backendIndex = [=] {
- if (Core::App().settings().disableOpenGL()) {
- return disabled;
- } else switch (Ui::GL::CurrentANGLE()) {
- case ANGLE::Auto: return 0;
- case ANGLE::D3D11: return 1;
- case ANGLE::D3D9: return 2;
- case ANGLE::D3D11on12: return 3;
- //case ANGLE::OpenGL: return 4;
- }
- Unexpected("Ui::GL::CurrentANGLE value in SetupANGLE.");
- }();
- const auto button = AddButtonWithLabel(
- container,
- tr::lng_settings_angle_backend(),
- rpl::single(options[backendIndex]),
- st::settingsButtonNoIcon);
- button->addClickHandler([=] {
- controller->show(Box([=](not_null<Ui::GenericBox*> box) {
- const auto save = [=](int index) {
- if (index == backendIndex) {
- return;
- }
- const auto confirmed = crl::guard(button, [=] {
- const auto nowDisabled = (index == disabled);
- if (!nowDisabled) {
- Ui::GL::ChangeANGLE([&] {
- switch (index) {
- case 0: return ANGLE::Auto;
- case 1: return ANGLE::D3D11;
- case 2: return ANGLE::D3D9;
- case 3: return ANGLE::D3D11on12;
- //case 4: return ANGLE::OpenGL;
- }
- Unexpected("Index in SetupANGLE.");
- }());
- }
- const auto wasDisabled = (backendIndex == disabled);
- if (nowDisabled != wasDisabled) {
- Core::App().settings().setDisableOpenGL(nowDisabled);
- Local::writeSettings();
- }
- Core::Restart();
- });
- controller->show(Ui::MakeConfirmBox({
- .text = tr::lng_settings_need_restart(),
- .confirmed = confirmed,
- .confirmText = tr::lng_settings_restart_now(),
- }));
- };
- SingleChoiceBox(box, {
- .title = tr::lng_settings_angle_backend(),
- .options = options,
- .initialSelection = backendIndex,
- .callback = save,
- });
- }));
- });
- }
- #endif // DESKTOP_APP_USE_ANGLE
- void SetupOpenGL(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- const auto toggles = container->lifetime().make_state<
- rpl::event_stream<bool>
- >();
- const auto button = container->add(object_ptr<Button>(
- container,
- tr::lng_settings_enable_opengl(),
- st::settingsButtonNoIcon
- ))->toggleOn(
- toggles->events_starting_with_copy(
- !Core::App().settings().disableOpenGL())
- );
- button->toggledValue(
- ) | rpl::filter([](bool enabled) {
- return (enabled == Core::App().settings().disableOpenGL());
- }) | rpl::start_with_next([=](bool enabled) {
- const auto confirmed = crl::guard(button, [=] {
- Core::App().settings().setDisableOpenGL(!enabled);
- Local::writeSettings();
- Core::Restart();
- });
- const auto cancelled = crl::guard(button, [=](Fn<void()> close) {
- toggles->fire(!enabled);
- close();
- });
- controller->show(Ui::MakeConfirmBox({
- .text = tr::lng_settings_need_restart(),
- .confirmed = confirmed,
- .cancelled = cancelled,
- .confirmText = tr::lng_settings_restart_now(),
- }));
- }, container->lifetime());
- }
- void SetupPerformance(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- SetupAnimations(&controller->window(), container);
- SetupHardwareAcceleration(container);
- #ifdef DESKTOP_APP_USE_ANGLE
- SetupANGLE(controller, container);
- #else // DESKTOP_APP_USE_ANGLE
- if constexpr (!Platform::IsMac()) {
- SetupOpenGL(controller, container);
- }
- #endif // DESKTOP_APP_USE_ANGLE
- }
- void SetupWindowTitle(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- AddDivider(container);
- AddSkip(container);
- AddSubsectionTitle(container, tr::lng_settings_window_system());
- SetupWindowTitleOptions(controller, container);
- AddSkip(container);
- }
- void SetupWindowCloseBehavior(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- #if !defined Q_OS_WIN && !defined Q_OS_MAC
- const auto wrap = container->add(
- object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
- container,
- object_ptr<Ui::VerticalLayout>(container)));
- const auto inner = wrap->entity();
- AddDivider(inner);
- AddSkip(inner);
- AddSubsectionTitle(inner, tr::lng_settings_window_close());
- const auto settings = &Core::App().settings();
- using Behavior = Core::Settings::CloseBehavior;
- const auto group = std::make_shared<Ui::RadioenumGroup<Behavior>>(
- settings->closeBehavior());
- const auto add = [&](Behavior value, const QString &label) {
- inner->add(
- object_ptr<Ui::Radioenum<Behavior>>(
- inner,
- group,
- value,
- label,
- st::settingsSendType),
- st::settingsSendTypePadding);
- };
- add(
- Behavior::RunInBackground,
- tr::lng_settings_run_in_background(tr::now));
- add(
- Behavior::CloseToTaskbar,
- tr::lng_settings_close_to_taskbar(tr::now));
- add(
- Behavior::Quit,
- tr::lng_settings_quit_on_close(tr::now));
- group->value() | rpl::filter([=](Behavior value) {
- return (value != settings->closeBehavior());
- }) | rpl::start_with_next([=](Behavior value) {
- settings->setCloseBehavior(value);
- Local::writeSettings();
- }, inner->lifetime());
- AddSkip(inner);
- if (!Platform::TrayIconSupported()) {
- wrap->toggle(true, anim::type::instant);
- } else {
- wrap->toggleOn(Core::App().settings().workModeValue(
- ) | rpl::map([=](Core::Settings::WorkMode mode) {
- return (mode == Core::Settings::WorkMode::WindowOnly);
- }) | rpl::distinct_until_changed(), anim::type::normal);
- wrap->finishAnimating();
- }
- #endif
- }
- void SetupSystemIntegration(
- not_null<Window::SessionController*> controller,
- not_null<Ui::VerticalLayout*> container) {
- AddDivider(container);
- AddSkip(container);
- AddSubsectionTitle(container, tr::lng_settings_system_integration());
- SetupSystemIntegrationOptions(controller, container);
- AddSkip(container);
- }
- Advanced::Advanced(
- QWidget *parent,
- not_null<Window::SessionController*> controller)
- : Section(parent) {
- setupContent(controller);
- }
- rpl::producer<QString> Advanced::title() {
- return tr::lng_settings_advanced();
- }
- void Advanced::setupContent(not_null<Window::SessionController*> controller) {
- const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
- auto empty = true;
- const auto addDivider = [&] {
- if (empty) {
- empty = false;
- } else {
- AddDivider(content);
- }
- };
- const auto addUpdate = [&] {
- if (HasUpdate()) {
- addDivider();
- AddSkip(content);
- AddSubsectionTitle(content, tr::lng_settings_version_info());
- SetupUpdate(content);
- AddSkip(content);
- }
- };
- if (!cAutoUpdate()) {
- addUpdate();
- }
- addDivider();
- SetupDataStorage(controller, content);
- SetupAutoDownload(controller, content);
- SetupWindowTitle(controller, content);
- SetupWindowCloseBehavior(controller, content);
- SetupSystemIntegration(controller, content);
- empty = false;
- AddDivider(content);
- AddSkip(content);
- AddSubsectionTitle(content, tr::lng_settings_performance());
- SetupPerformance(controller, content);
- AddSkip(content);
- if (HasSystemSpellchecker()) {
- AddDivider(content);
- AddSkip(content);
- AddSubsectionTitle(content, tr::lng_settings_spellchecker());
- SetupSpellchecker(controller, content);
- AddSkip(content);
- }
- if (cAutoUpdate()) {
- addUpdate();
- }
- AddSkip(content);
- AddDivider(content);
- AddSkip(content);
- SetupExport(controller, content, showOtherMethod());
- Ui::ResizeFitChild(this, content);
- }
- } // namespace Settings
|