From 8c4e8212cd5ef6e15de909d98de478e09a6e1a61 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 22 Jul 2020 16:10:17 +0400 Subject: [PATCH] Add 'respect system dark mode' checkbox. --- Telegram/Resources/langs/lang.strings | 5 + Telegram/SourceFiles/core/application.cpp | 71 ++++++---- Telegram/SourceFiles/core/application.h | 4 + Telegram/SourceFiles/main/main_domain.cpp | 4 +- .../platform/linux/main_window_linux.cpp | 12 +- .../platform/linux/specific_linux.cpp | 13 +- .../platform/linux/specific_linux.h | 1 + .../SourceFiles/platform/mac/specific_mac.h | 8 ++ .../SourceFiles/platform/mac/specific_mac.mm | 4 - .../SourceFiles/platform/platform_specific.h | 1 + .../SourceFiles/platform/win/specific_win.cpp | 23 +-- .../SourceFiles/platform/win/specific_win.h | 4 + Telegram/SourceFiles/settings.cpp | 1 - Telegram/SourceFiles/settings.h | 1 - .../settings/settings_advanced.cpp | 132 ++++++++---------- .../SourceFiles/settings/settings_advanced.h | 3 +- .../SourceFiles/settings/settings_chat.cpp | 61 +++++++- Telegram/SourceFiles/settings/settings_chat.h | 8 +- .../SourceFiles/settings/settings_intro.cpp | 12 +- .../SourceFiles/storage/file_download.cpp | 3 +- .../SourceFiles/storage/storage_account.cpp | 2 +- Telegram/SourceFiles/storage/storage_domain.h | 1 + .../window/themes/window_theme.cpp | 42 ++++++ .../SourceFiles/window/themes/window_theme.h | 8 ++ .../SourceFiles/window/window_controller.cpp | 2 - .../SourceFiles/window/window_main_menu.cpp | 23 +-- 26 files changed, 298 insertions(+), 151 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ca96cce888..d104449975 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -434,6 +434,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_sensitive_disable_filtering" = "Disable filtering"; "lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices."; +"lng_settings_auto_night_mode" = "Auto-Night mode"; +"lng_settings_auto_night_enabled" = "Match the system settings"; +"lng_settings_auto_night_warning" = "You have enabled auto-night mode. If you want to change the dark mode settings, you'll need to disable it first."; +"lng_settings_auto_night_disable" = "Disable"; + "lng_settings_spellchecker" = "Spell checker"; "lng_settings_system_spellchecker" = "Use system spell checker"; "lng_settings_custom_spellchecker" = "Use spell checker"; diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 45ebbcb9c0..cda0041f60 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -212,25 +212,9 @@ void Application::run() { Ui::InitTextOptions(); Ui::Emoji::Init(); startEmojiImageLoader(); + startSystemDarkModeViewer(); Media::Player::start(_audio.get()); - const auto darkModeChanged = [] { - const auto darkMode = Core::App().settings().systemDarkMode(); - const auto darkModeEnabled = Core::App().settings().systemDarkModeEnabled(); - if (darkModeEnabled - && darkMode.has_value() - && (*darkMode != Window::Theme::IsNightMode())) { - Window::Theme::ToggleNightMode(); - Window::Theme::KeepApplied(); - } - }; - - Core::App().settings().systemDarkModeChanges( - ) | rpl::start_with_next(darkModeChanged, _lifetime); - - Core::App().settings().systemDarkModeEnabledChanges( - ) | rpl::start_with_next(darkModeChanged, _lifetime); - style::ShortAnimationPlaying( ) | rpl::start_with_next([=](bool playing) { if (playing) { @@ -250,10 +234,10 @@ void Application::run() { QMimeDatabase().mimeTypeForName(qsl("text/plain")); _window = std::make_unique(); + _domain->activeChanges( ) | rpl::start_with_next([=](not_null account) { _window->showAccount(account); - Core::App().settings().setSystemDarkMode(Platform::IsDarkMode()); }, _window->widget()->lifetime()); QCoreApplication::instance()->installEventFilter(this); @@ -267,16 +251,8 @@ void Application::run() { // Depend on activeWindow() for now :( startShortcuts(); - App::initMedia(); - - const auto state = _domain->start(QByteArray()); - if (state == Storage::StartResult::IncorrectPasscode) { - Global::SetLocalPasscode(true); - Global::RefLocalPasscodeChanged().notify(); - lockByPasscode(); - DEBUG_LOG(("Application Info: passcode needed...")); - } + startDomain(); _window->widget()->show(); @@ -298,6 +274,47 @@ void Application::run() { } } +void Application::startDomain() { + const auto state = _domain->start(QByteArray()); + if (state != Storage::StartResult::IncorrectPasscodeLegacy) { + // In case of non-legacy passcoded app all global settings are ready. + startSettingsAndBackground(); + } + if (state != Storage::StartResult::Success) { + Global::SetLocalPasscode(true); + Global::RefLocalPasscodeChanged().notify(); + lockByPasscode(); + DEBUG_LOG(("Application Info: passcode needed...")); + } +} + +void Application::startSettingsAndBackground() { + Local::rewriteSettingsIfNeeded(); + Window::Theme::Background()->start(); + checkSystemDarkMode(); +} + +void Application::checkSystemDarkMode() { + const auto maybeDarkMode = _settings.systemDarkMode(); + const auto darkModeEnabled = _settings.systemDarkModeEnabled(); + const auto needToSwitch = darkModeEnabled + && maybeDarkMode + && (*maybeDarkMode != Window::Theme::IsNightMode()); + if (needToSwitch) { + Window::Theme::ToggleNightMode(); + Window::Theme::KeepApplied(); + } +} + +void Application::startSystemDarkModeViewer() { + rpl::merge( + _settings.systemDarkModeChanges() | rpl::to_empty, + _settings.systemDarkModeEnabledChanges() | rpl::to_empty + ) | rpl::start_with_next([=] { + checkSystemDarkMode(); + }, _lifetime); +} + auto Application::prepareEmojiSourceImages() -> std::shared_ptr { const auto &images = Ui::Emoji::SourceImages(); diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index 4215a98281..aba9460c67 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -140,6 +140,7 @@ public: [[nodiscard]] QWidget *getFileDialogParent(); void notifyFileDialogShown(bool shown); [[nodiscard]] QWidget *getModalParent(); + void checkSystemDarkMode(); // Media view interface. void checkMediaViewActivation(); @@ -161,6 +162,7 @@ public: return _logoNoMargin; } + void startSettingsAndBackground(); [[nodiscard]] Settings &settings() { return _settings; } @@ -290,7 +292,9 @@ private: -> std::shared_ptr; void startLocalStorage(); void startShortcuts(); + void startDomain(); void startEmojiImageLoader(); + void startSystemDarkModeViewer(); void stateChanged(Qt::ApplicationState state); diff --git a/Telegram/SourceFiles/main/main_domain.cpp b/Telegram/SourceFiles/main/main_domain.cpp index 7b9766984e..0501264dd9 100644 --- a/Telegram/SourceFiles/main/main_domain.cpp +++ b/Telegram/SourceFiles/main/main_domain.cpp @@ -31,7 +31,9 @@ Domain::Domain(const QString &dataName) , _local(std::make_unique(this, dataName)) { _active.changes( ) | rpl::take(1) | rpl::start_with_next([] { - Local::rewriteSettingsIfNeeded(); + // In case we had a legacy passcoded app we start settings here. + Core::App().startSettingsAndBackground(); + Core::App().notifications().createManager(); }, _lifetime); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 207503c7f5..fbf7b6ef08 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -426,7 +426,7 @@ void MainWindow::initHook() { || QSystemTrayIcon::isSystemTrayAvailable(); LOG(("System tray available: %1").arg(Logs::b(trayAvailable))); - cSetSupportTray(trayAvailable); + Platform::SetTrayIconSupported(trayAvailable); #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION auto sniWatcher = new QDBusServiceWatcher( @@ -591,9 +591,9 @@ void MainWindow::onSNIOwnerChanged( const auto trayAvailable = SNIAvailable || QSystemTrayIcon::isSystemTrayAvailable(); - cSetSupportTray(trayAvailable); + Platform::SetTrayIconSupported(trayAvailable); - if (cSupportTray()) { + if (trayAvailable) { psSetupTrayIcon(); } else { LOG(("System tray is not available.")); @@ -654,9 +654,9 @@ void MainWindow::psSetupTrayIcon() { } void MainWindow::workmodeUpdated(DBIWorkMode mode) { - if (!cSupportTray()) return; - - if (mode == dbiwmWindowOnly) { + if (!Platform::TrayIconSupported()) { + return; + } else if (mode == dbiwmWindowOnly) { #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION if (_sniTrayIcon) { _sniTrayIcon->setContextMenu(0); diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index 79825ac921..1092ea370a 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -69,6 +69,8 @@ constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs; QStringList PlatformThemes; +bool IsTrayIconSupported = true; + #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION void PortalAutostart(bool autostart, bool silent = false) { QVariantMap options; @@ -871,8 +873,7 @@ std::optional LastUserInputTime() { std::optional IsDarkMode() { #ifndef TDESKTOP_DISABLE_GTK_INTEGRATION - if (Libs::GtkSettingSupported() - && Libs::GtkLoaded()) { + if (Libs::GtkSettingSupported() && Libs::GtkLoaded()) { if (Libs::gtk_check_version != nullptr && !Libs::gtk_check_version(3, 0, 0) && Libs::GtkSetting("gtk-application-prefer-dark-theme")) { @@ -897,6 +898,14 @@ bool AutostartSupported() { return !InSnap(); } +bool TrayIconSupported() { + return IsTrayIconSupported; +} + +void SetTrayIconSupported(bool supported) { + IsTrayIconSupported = supported; +} + void FallbackFontConfigCheckBegin() { if (!CheckFontConfigCrash()) { return; diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.h b/Telegram/SourceFiles/platform/linux/specific_linux.h index 3d9158d285..6960316785 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.h +++ b/Telegram/SourceFiles/platform/linux/specific_linux.h @@ -47,6 +47,7 @@ void FallbackFontConfigCheckBegin(); void FallbackFontConfigCheckEnd(); bool GtkClipboardSupported(); +void SetTrayIconSupported(bool supported); } // namespace Platform diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.h b/Telegram/SourceFiles/platform/mac/specific_mac.h index f749b44a3d..3359066f8a 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.h +++ b/Telegram/SourceFiles/platform/mac/specific_mac.h @@ -40,6 +40,14 @@ inline bool StartSystemResize(QWindow *window, Qt::Edges edges) { return false; } +inline bool AutostartSupported() { + return false; +} + +inline bool TrayIconSupported() { + return true; +} + namespace ThirdParty { inline void start() { diff --git a/Telegram/SourceFiles/platform/mac/specific_mac.mm b/Telegram/SourceFiles/platform/mac/specific_mac.mm index d3668173f5..223ce5dbce 100644 --- a/Telegram/SourceFiles/platform/mac/specific_mac.mm +++ b/Telegram/SourceFiles/platform/mac/specific_mac.mm @@ -263,10 +263,6 @@ void IgnoreApplicationActivationRightNow() { objc_ignoreApplicationActivationRightNow(); } -bool AutostartSupported() { - return false; -} - } // namespace Platform void psNewVersion() { diff --git a/Telegram/SourceFiles/platform/platform_specific.h b/Telegram/SourceFiles/platform/platform_specific.h index 28c73dcb8d..acbb45564c 100644 --- a/Telegram/SourceFiles/platform/platform_specific.h +++ b/Telegram/SourceFiles/platform/platform_specific.h @@ -48,6 +48,7 @@ bool OpenSystemSettings(SystemSettingsType type); void IgnoreApplicationActivationRightNow(); bool AutostartSupported(); +bool TrayIconSupported(); QImage GetImageFromClipboard(); bool StartSystemMove(QWindow *window); bool StartSystemResize(QWindow *window, Qt::Edges edges); diff --git a/Telegram/SourceFiles/platform/win/specific_win.cpp b/Telegram/SourceFiles/platform/win/specific_win.cpp index acfad21538..256fa4204a 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.cpp +++ b/Telegram/SourceFiles/platform/win/specific_win.cpp @@ -384,27 +384,34 @@ std::optional LastUserInputTime() { } std::optional IsDarkMode() { - if (QOperatingSystemVersion::current() - < QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763)) { + static const auto kSystemVersion = QOperatingSystemVersion::current(); + static const auto kDarkModeAddedVersion = QOperatingSystemVersion( + QOperatingSystemVersion::Windows, + 10, + 0, + 17763); + static const auto kSupported = (kSystemVersion >= kDarkModeAddedVersion); + if (!kSupported) { return std::nullopt; } - LPCWSTR lpKeyName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; - LPCWSTR lpValueName = L"AppsUseLightTheme"; - HKEY key; - auto result = RegOpenKeyEx(HKEY_CURRENT_USER, lpKeyName, 0, KEY_READ, &key); + const auto keyName = L"" + "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; + const auto valueName = L"AppsUseLightTheme"; + auto key = HKEY(); + auto result = RegOpenKeyEx(HKEY_CURRENT_USER, keyName, 0, KEY_READ, &key); if (result != ERROR_SUCCESS) { return std::nullopt; } DWORD value = 0, type = 0, size = sizeof(value); - result = RegQueryValueEx(key, lpValueName, 0, &type, (LPBYTE)&value, &size); + result = RegQueryValueEx(key, valueName, 0, &type, (LPBYTE)&value, &size); RegCloseKey(key); if (result != ERROR_SUCCESS) { return std::nullopt; } - return value == 0; + return (value == 0); } bool AutostartSupported() { diff --git a/Telegram/SourceFiles/platform/win/specific_win.h b/Telegram/SourceFiles/platform/win/specific_win.h index b6961100e7..430776e69c 100644 --- a/Telegram/SourceFiles/platform/win/specific_win.h +++ b/Telegram/SourceFiles/platform/win/specific_win.h @@ -40,6 +40,10 @@ inline bool StartSystemResize(QWindow *window, Qt::Edges edges) { return false; } +inline bool TrayIconSupported() { + return true; +} + namespace ThirdParty { void start(); diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp index 64ce493508..2683ad857e 100644 --- a/Telegram/SourceFiles/settings.cpp +++ b/Telegram/SourceFiles/settings.cpp @@ -42,7 +42,6 @@ bool gUseFreeType = false; bool gAutoUpdate = true; TWindowPos gWindowPos; LaunchMode gLaunchMode = LaunchModeNormal; -bool gSupportTray = true; bool gSeenTrayTooltip = false; bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false; int32 gLastUpdateCheck = 0; diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h index 2877f6504e..d5d13e7c51 100644 --- a/Telegram/SourceFiles/settings.h +++ b/Telegram/SourceFiles/settings.h @@ -79,7 +79,6 @@ struct TWindowPos { int h = 0; }; DeclareSetting(TWindowPos, WindowPos); -DeclareSetting(bool, SupportTray); DeclareSetting(bool, SeenTrayTooltip); DeclareSetting(bool, RestartingUpdate); DeclareSetting(bool, Restarting); diff --git a/Telegram/SourceFiles/settings/settings_advanced.cpp b/Telegram/SourceFiles/settings/settings_advanced.cpp index 16a40285d2..c14f712172 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced.cpp @@ -325,11 +325,7 @@ void SetupSpellchecker( #endif // !TDESKTOP_DISABLE_SPELLCHECK } -bool HasTray() { - return cSupportTray() || Platform::IsWindows(); -} - -void SetupTrayContent(not_null container) { +void SetupSystemIntegrationContent(not_null container) { const auto checkbox = [&](const QString &label, bool checked) { return object_ptr( container, @@ -349,65 +345,65 @@ void SetupTrayContent(not_null container) { checkbox(label, checked), st::settingsCheckboxPadding)); }; + if (Platform::TrayIconSupported()) { + const auto trayEnabled = [] { + const auto workMode = Global::WorkMode().value(); + return (workMode == dbiwmTrayOnly) + || (workMode == dbiwmWindowAndTray); + }; + const auto tray = addCheckbox( + tr::lng_settings_workmode_tray(tr::now), + trayEnabled()); - const auto trayEnabled = [] { - const auto workMode = Global::WorkMode().value(); - return (workMode == dbiwmTrayOnly) - || (workMode == dbiwmWindowAndTray); - }; - const auto tray = addCheckbox( - tr::lng_settings_workmode_tray(tr::now), - trayEnabled()); + const auto taskbarEnabled = [] { + const auto workMode = Global::WorkMode().value(); + return (workMode == dbiwmWindowOnly) + || (workMode == dbiwmWindowAndTray); + }; + const auto taskbar = Platform::IsWindows() + ? addCheckbox( + tr::lng_settings_workmode_window(tr::now), + taskbarEnabled()) + : nullptr; - const auto taskbarEnabled = [] { - const auto workMode = Global::WorkMode().value(); - return (workMode == dbiwmWindowOnly) - || (workMode == dbiwmWindowAndTray); - }; - const auto taskbar = Platform::IsWindows() - ? addCheckbox( - tr::lng_settings_workmode_window(tr::now), - taskbarEnabled()) - : nullptr; + const auto updateWorkmode = [=] { + const auto newMode = tray->checked() + ? ((!taskbar || taskbar->checked()) + ? dbiwmWindowAndTray + : dbiwmTrayOnly) + : dbiwmWindowOnly; + if ((newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly) + && Global::WorkMode().value() != newMode) { + cSetSeenTrayTooltip(false); + } + Global::RefWorkMode().set(newMode); + Local::writeSettings(); + }; - const auto updateWorkmode = [=] { - const auto newMode = tray->checked() - ? ((!taskbar || taskbar->checked()) - ? dbiwmWindowAndTray - : dbiwmTrayOnly) - : dbiwmWindowOnly; - if ((newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly) - && Global::WorkMode().value() != newMode) { - cSetSeenTrayTooltip(false); - } - Global::RefWorkMode().set(newMode); - Local::writeSettings(); - }; - - 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(); - } - }, tray->lifetime()); - - if (taskbar) { - taskbar->checkedChanges( + tray->checkedChanges( ) | rpl::filter([=](bool checked) { - return (checked != taskbarEnabled()); + return (checked != trayEnabled()); }) | rpl::start_with_next([=](bool checked) { - if (!checked && !tray->checked()) { - tray->setChecked(true); + if (!checked && taskbar && !taskbar->checked()) { + taskbar->setChecked(true); } else { updateWorkmode(); } - }, taskbar->lifetime()); - } + }, 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()); + } + } if (Platform::AllowNativeWindowFrameToggle()) { const auto nativeFrame = addCheckbox( tr::lng_settings_native_frame(tr::now), @@ -421,7 +417,6 @@ void SetupTrayContent(not_null container) { Core::App().saveSettingsDelayed(); }, nativeFrame->lifetime()); } - if (Platform::AutostartSupported()) { const auto minimizedToggled = [] { return cStartMinimized() && !Global::LocalPasscode(); @@ -471,8 +466,7 @@ void SetupTrayContent(not_null container) { }, minimized->lifetime()); } -#ifndef OS_WIN_STORE - if (Platform::IsWindows()) { + if (Platform::IsWindows() && !Platform::IsWindowsStoreBuild()) { const auto sendto = addCheckbox( tr::lng_settings_add_sendto(tr::now), cSendToMenu()); @@ -486,22 +480,18 @@ void SetupTrayContent(not_null container) { Local::writeSettings(); }, sendto->lifetime()); } -#endif // OS_WIN_STORE } -void SetupTray(not_null container) { - if (!HasTray()) { - return; - } - +void SetupSystemIntegrationOptions(not_null container) { auto wrap = object_ptr(container); - SetupTrayContent(wrap.data()); + SetupSystemIntegrationContent(wrap.data()); + if (wrap->count() > 0) { + container->add(object_ptr( + container, + std::move(wrap))); - container->add(object_ptr( - container, - std::move(wrap))); - - AddSkip(container, st::settingsCheckboxesSkip); + AddSkip(container, st::settingsCheckboxesSkip); + } } void SetupAnimations(not_null container) { @@ -539,7 +529,7 @@ void SetupSystemIntegration( )->addClickHandler([=] { showOther(Type::Calls); }); - SetupTray(container); + SetupSystemIntegrationOptions(container); AddSkip(container); } diff --git a/Telegram/SourceFiles/settings/settings_advanced.h b/Telegram/SourceFiles/settings/settings_advanced.h index d40ad7e956..5b2cf9c3dc 100644 --- a/Telegram/SourceFiles/settings/settings_advanced.h +++ b/Telegram/SourceFiles/settings/settings_advanced.h @@ -21,8 +21,7 @@ void SetupConnectionType( not_null container); bool HasUpdate(); void SetupUpdate(not_null container); -bool HasTray(); -void SetupTray(not_null container); +void SetupSystemIntegrationContent(not_null container); void SetupAnimations(not_null container); class Advanced : public Section { diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index d7eecc043f..70866565d1 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -982,7 +982,9 @@ void SetupChatBackground( }, adaptive->lifetime()); } -void SetupDefaultThemes(not_null container) { +void SetupDefaultThemes( + not_null window, + not_null container) { using Type = Window::Theme::EmbeddedType; using Scheme = Window::Theme::EmbeddedScheme; using Check = Window::Theme::CloudListCheck; @@ -1015,13 +1017,18 @@ void SetupDefaultThemes(not_null container) { }; const auto currentlyIsCustom = (chosen() == Type(-1)) && !Background()->themeObject().cloud.id; + const auto keep = [=] { + if (!currentlyIsCustom) { + KeepApplied(); + } + }; if (IsNightMode() == isNight(scheme)) { ApplyDefaultWithPath(scheme.path); + keep(); } else { - ToggleNightMode(scheme.path); - } - if (!currentlyIsCustom) { - KeepApplied(); + Window::Theme::ToggleNightModeWithConfirmation( + window, + [=, path = scheme.path] { ToggleNightMode(path); keep();}); } }; const auto schemeClicked = [=]( @@ -1163,7 +1170,7 @@ void SetupThemeOptions( AddSubsectionTitle(container, tr::lng_settings_themes()); AddSkip(container, st::settingsThemesTopSkip); - SetupDefaultThemes(container); + SetupDefaultThemes(&controller->window(), container); AddSkip(container); } @@ -1260,6 +1267,47 @@ void SetupCloudThemes( wrap->setDuration(0)->toggleOn(list->empty() | rpl::map(!_1)); } +void SetupAutoNightMode(not_null container) { + if (!Platform::IsDarkModeSupported()) { + return; + } + + AddDivider(container); + AddSkip(container, st::settingsPrivacySkip); + + AddSubsectionTitle(container, tr::lng_settings_auto_night_mode()); + + auto wrap = object_ptr(container); + const auto autoNight = wrap->add( + object_ptr( + wrap, + tr::lng_settings_auto_night_enabled(tr::now), + Core::App().settings().systemDarkModeEnabled(), + st::settingsCheckbox), + st::settingsCheckboxPadding); + + autoNight->checkedChanges( + ) | rpl::filter([=](bool checked) { + return (checked != Core::App().settings().systemDarkModeEnabled()); + }) | rpl::start_with_next([=](bool checked) { + Core::App().settings().setSystemDarkModeEnabled(checked); + Core::App().saveSettingsDelayed(); + }, autoNight->lifetime()); + + Core::App().settings().systemDarkModeEnabledChanges( + ) | rpl::filter([=](bool value) { + return (value != autoNight->checked()); + }) | rpl::start_with_next([=](bool value) { + autoNight->setChecked(value); + }, autoNight->lifetime()); + + container->add(object_ptr( + container, + std::move(wrap))); + + AddSkip(container, st::settingsCheckboxesSkip); +} + void SetupSupportSwitchSettings( not_null controller, not_null container) { @@ -1381,6 +1429,7 @@ void Chat::setupContent(not_null controller) { const auto content = Ui::CreateChild(this); SetupThemeOptions(controller, content); + SetupAutoNightMode(content); SetupCloudThemes(controller, content); SetupChatBackground(controller, content); SetupStickersEmoji(controller, content); diff --git a/Telegram/SourceFiles/settings/settings_chat.h b/Telegram/SourceFiles/settings/settings_chat.h index 578210d77d..a972ca7201 100644 --- a/Telegram/SourceFiles/settings/settings_chat.h +++ b/Telegram/SourceFiles/settings/settings_chat.h @@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_common.h" +namespace Window { +class Controller; +} // namespace Window + namespace Settings { void SetupDataStorage( @@ -17,7 +21,9 @@ void SetupDataStorage( void SetupAutoDownload( not_null controller, not_null container); -void SetupDefaultThemes(not_null container); +void SetupDefaultThemes( + not_null window, + not_null container); void SetupSupport( not_null controller, not_null container); diff --git a/Telegram/SourceFiles/settings/settings_intro.cpp b/Telegram/SourceFiles/settings/settings_intro.cpp index c9b9bae015..5d7a9c29c0 100644 --- a/Telegram/SourceFiles/settings/settings_intro.cpp +++ b/Telegram/SourceFiles/settings/settings_intro.cpp @@ -75,16 +75,14 @@ object_ptr CreateIntroSettings( SetupUpdate(result); AddSkip(result); } - if (HasTray()) { - AddDivider(result); - AddSkip(result); - SetupTray(result); - AddSkip(result); - } + AddDivider(result); + AddSkip(result); + SetupSystemIntegrationContent(result); + AddSkip(result); AddDivider(result); AddSkip(result); SetupInterfaceScale(result, false); - SetupDefaultThemes(result); + SetupDefaultThemes(window, result); AddSkip(result); if (anim::Disabled()) { diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 8164c9690e..a35a790f72 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -140,8 +140,9 @@ void FileLoader::finishWithBytes(const QByteArray &data) { Platform::File::PostprocessDownloaded( QFileInfo(_file).absoluteFilePath()); } - _session->notifyDownloaderTaskFinished(); + const auto session = _session; _updates.fire_done(); + session->notifyDownloaderTaskFinished(); } QByteArray FileLoader::imageFormat(const QSize &shrinkBox) const { diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index 1b0249032a..bdad343602 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -134,7 +134,7 @@ StartResult Account::legacyStart(const QByteArray &passcode) { if (result == ReadMapResult::Failed) { Assert(_localKey == nullptr); } else if (result == ReadMapResult::IncorrectPasscode) { - return StartResult::IncorrectPasscode; + return StartResult::IncorrectPasscodeLegacy; } clearLegacyFiles(); return StartResult::Success; diff --git a/Telegram/SourceFiles/storage/storage_domain.h b/Telegram/SourceFiles/storage/storage_domain.h index 1c78f6e0b8..beb9f11522 100644 --- a/Telegram/SourceFiles/storage/storage_domain.h +++ b/Telegram/SourceFiles/storage/storage_domain.h @@ -23,6 +23,7 @@ namespace Storage { enum class StartResult : uchar { Success, IncorrectPasscode, + IncorrectPasscodeLegacy, }; class Domain final { diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp index 77b9165a5c..164c683b8e 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/themes/window_theme_preview.h" #include "window/themes/window_themes_embedded.h" #include "window/themes/window_theme_editor.h" +#include "window/window_controller.h" #include "mainwidget.h" #include "main/main_session.h" #include "apiwrap.h" @@ -24,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_account.h" // Account::local. #include "main/main_domain.h" // Domain::activeSessionValue. #include "ui/image/image.h" +#include "boxes/confirm_box.h" #include "boxes/background_box.h" #include "core/application.h" #include "app.h" @@ -560,6 +562,8 @@ void ChatBackground::start() { _session = session; checkUploadWallPaper(); }, _lifetime); + + Core::App().settings().setSystemDarkMode(Platform::IsDarkMode()); } void ChatBackground::checkUploadWallPaper() { @@ -1074,6 +1078,14 @@ bool ChatBackground::nightMode() const { void ChatBackground::reapplyWithNightMode( std::optional themePath, bool newNightMode) { + if (!started()) { + // We can get here from legacy passcoded state. + // In this case Background() is not started yet, because + // some settings and the background itself were not read. + return; + } else if (_nightMode != newNightMode && !nightModeChangeAllowed()) { + return; + } const auto settingExactTheme = themePath.has_value(); const auto nightModeChanged = (newNightMode != _nightMode); const auto oldNightMode = _nightMode; @@ -1136,6 +1148,14 @@ void ChatBackground::reapplyWithNightMode( } } +bool ChatBackground::nightModeChangeAllowed() const { + const auto &settings = Core::App().settings(); + const auto allowedToBeAfterChange = settings.systemDarkModeEnabled() + ? settings.systemDarkMode().value_or(!_nightMode) + : !_nightMode; + return (_nightMode != allowedToBeAfterChange); +} + void ChatBackground::toggleNightMode(std::optional themePath) { reapplyWithNightMode(themePath, !_nightMode); } @@ -1293,6 +1313,28 @@ void ToggleNightMode(const QString &path) { Background()->toggleNightMode(path); } +void ToggleNightModeWithConfirmation( + not_null window, + Fn toggle) { + if (Background()->nightModeChangeAllowed()) { + toggle(); + } else { + const auto box = std::make_shared>(); + const auto disableAndToggle = [=] { + Core::App().settings().setSystemDarkModeEnabled(false); + Core::App().saveSettingsDelayed(); + toggle(); + if (*box) { + (*box)->closeBox(); + } + }; + *box = window->show(Box( + tr::lng_settings_auto_night_warning(tr::now), + tr::lng_settings_auto_night_disable(tr::now), + disableAndToggle)); + } +} + void ResetToSomeDefault() { Background()->reapplyWithNightMode( IsNightMode() ? NightThemePath() : QString(), diff --git a/Telegram/SourceFiles/window/themes/window_theme.h b/Telegram/SourceFiles/window/themes/window_theme.h index 3be1b99eb2..ec06f9eb97 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.h +++ b/Telegram/SourceFiles/window/themes/window_theme.h @@ -14,6 +14,10 @@ namespace Main { class Session; } // namespace Main +namespace Window { +class Controller; +} // namespace Window + namespace Window { namespace Theme { @@ -76,6 +80,9 @@ QString NightThemePath(); void SetNightModeValue(bool nightMode); void ToggleNightMode(); void ToggleNightMode(const QString &themePath); +void ToggleNightModeWithConfirmation( + not_null window, + Fn toggle); void ResetToSomeDefault(); [[nodiscard]] bool IsNonDefaultBackground(); void Revert(); @@ -169,6 +176,7 @@ public: [[nodiscard]] bool tileDay() const; [[nodiscard]] bool tileNight() const; [[nodiscard]] bool isMonoColorImage() const; + [[nodiscard]] bool nightModeChangeAllowed() const; private: struct AdjustableColor { diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 479f645536..a9da6ff2aa 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -51,8 +51,6 @@ Controller::~Controller() { } void Controller::showAccount(not_null account) { - Window::Theme::Background()->start(); - _accountLifetime.destroy(); _account = account; diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index c8721e69c3..1485e55129 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -894,10 +894,19 @@ void MainMenu::refreshMenu() { _nightThemeAction = std::make_shared>(); auto action = _menu->addAction(tr::lng_menu_night_mode(tr::now), [=] { - if (auto action = *_nightThemeAction) { - action->setChecked(!action->isChecked()); - _nightThemeSwitch.callOnce(st::mainMenu.itemToggle.duration); - } + const auto weak = MakeWeak(this); + const auto toggle = [=] { + if (!weak) { + Window::Theme::ToggleNightMode(); + Window::Theme::KeepApplied(); + } else if (auto action = *_nightThemeAction) { + action->setChecked(!action->isChecked()); + _nightThemeSwitch.callOnce(st::mainMenu.itemToggle.duration); + } + }; + Window::Theme::ToggleNightModeWithConfirmation( + &_controller->window(), + toggle); }, &st::mainMenuNightMode, &st::mainMenuNightModeOver); *_nightThemeAction = action; action->setCheckable(true); @@ -908,12 +917,6 @@ void MainMenu::refreshMenu() { if (darkModeEnabled && darkMode.has_value()) { action->setChecked(*darkMode); } - action->setEnabled(!darkModeEnabled || !darkMode.has_value()); - }, lifetime()); - Core::App().settings().systemDarkModeEnabledChanges( - ) | rpl::start_with_next([=](bool darkModeEnabled) { - const auto darkMode = Core::App().settings().systemDarkMode(); - action->setEnabled(!darkModeEnabled || !darkMode.has_value()); }, lifetime()); _menu->finishAnimating();