Add 'respect system dark mode' checkbox.

This commit is contained in:
John Preston 2020-07-22 16:10:17 +04:00
parent c24da4c3df
commit 8c4e8212cd
26 changed files with 298 additions and 151 deletions

View File

@ -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";

View File

@ -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<Window::Controller>();
_domain->activeChanges(
) | rpl::start_with_next([=](not_null<Main::Account*> 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<Ui::Emoji::UniversalImages> {
const auto &images = Ui::Emoji::SourceImages();

View File

@ -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<Ui::Emoji::UniversalImages>;
void startLocalStorage();
void startShortcuts();
void startDomain();
void startEmojiImageLoader();
void startSystemDarkModeViewer();
void stateChanged(Qt::ApplicationState state);

View File

@ -31,7 +31,9 @@ Domain::Domain(const QString &dataName)
, _local(std::make_unique<Storage::Domain>(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);

View File

@ -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);

View File

@ -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<crl::time> LastUserInputTime() {
std::optional<bool> 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<gboolean>("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;

View File

@ -47,6 +47,7 @@ void FallbackFontConfigCheckBegin();
void FallbackFontConfigCheckEnd();
bool GtkClipboardSupported();
void SetTrayIconSupported(bool supported);
} // namespace Platform

View File

@ -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() {

View File

@ -263,10 +263,6 @@ void IgnoreApplicationActivationRightNow() {
objc_ignoreApplicationActivationRightNow();
}
bool AutostartSupported() {
return false;
}
} // namespace Platform
void psNewVersion() {

View File

@ -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);

View File

@ -384,27 +384,34 @@ std::optional<crl::time> LastUserInputTime() {
}
std::optional<bool> 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() {

View File

@ -40,6 +40,10 @@ inline bool StartSystemResize(QWindow *window, Qt::Edges edges) {
return false;
}
inline bool TrayIconSupported() {
return true;
}
namespace ThirdParty {
void start();

View File

@ -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;

View File

@ -79,7 +79,6 @@ struct TWindowPos {
int h = 0;
};
DeclareSetting(TWindowPos, WindowPos);
DeclareSetting(bool, SupportTray);
DeclareSetting(bool, SeenTrayTooltip);
DeclareSetting(bool, RestartingUpdate);
DeclareSetting(bool, Restarting);

View File

@ -325,11 +325,7 @@ void SetupSpellchecker(
#endif // !TDESKTOP_DISABLE_SPELLCHECK
}
bool HasTray() {
return cSupportTray() || Platform::IsWindows();
}
void SetupTrayContent(not_null<Ui::VerticalLayout*> container) {
void SetupSystemIntegrationContent(not_null<Ui::VerticalLayout*> container) {
const auto checkbox = [&](const QString &label, bool checked) {
return object_ptr<Ui::Checkbox>(
container,
@ -349,65 +345,65 @@ void SetupTrayContent(not_null<Ui::VerticalLayout*> 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<Ui::VerticalLayout*> container) {
Core::App().saveSettingsDelayed();
}, nativeFrame->lifetime());
}
if (Platform::AutostartSupported()) {
const auto minimizedToggled = [] {
return cStartMinimized() && !Global::LocalPasscode();
@ -471,8 +466,7 @@ void SetupTrayContent(not_null<Ui::VerticalLayout*> 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<Ui::VerticalLayout*> container) {
Local::writeSettings();
}, sendto->lifetime());
}
#endif // OS_WIN_STORE
}
void SetupTray(not_null<Ui::VerticalLayout*> container) {
if (!HasTray()) {
return;
}
void SetupSystemIntegrationOptions(not_null<Ui::VerticalLayout*> container) {
auto wrap = object_ptr<Ui::VerticalLayout>(container);
SetupTrayContent(wrap.data());
SetupSystemIntegrationContent(wrap.data());
if (wrap->count() > 0) {
container->add(object_ptr<Ui::OverrideMargins>(
container,
std::move(wrap)));
container->add(object_ptr<Ui::OverrideMargins>(
container,
std::move(wrap)));
AddSkip(container, st::settingsCheckboxesSkip);
AddSkip(container, st::settingsCheckboxesSkip);
}
}
void SetupAnimations(not_null<Ui::VerticalLayout*> container) {
@ -539,7 +529,7 @@ void SetupSystemIntegration(
)->addClickHandler([=] {
showOther(Type::Calls);
});
SetupTray(container);
SetupSystemIntegrationOptions(container);
AddSkip(container);
}

View File

@ -21,8 +21,7 @@ void SetupConnectionType(
not_null<Ui::VerticalLayout*> container);
bool HasUpdate();
void SetupUpdate(not_null<Ui::VerticalLayout*> container);
bool HasTray();
void SetupTray(not_null<Ui::VerticalLayout*> container);
void SetupSystemIntegrationContent(not_null<Ui::VerticalLayout*> container);
void SetupAnimations(not_null<Ui::VerticalLayout*> container);
class Advanced : public Section {

View File

@ -982,7 +982,9 @@ void SetupChatBackground(
}, adaptive->lifetime());
}
void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
void SetupDefaultThemes(
not_null<Window::Controller*> window,
not_null<Ui::VerticalLayout*> container) {
using Type = Window::Theme::EmbeddedType;
using Scheme = Window::Theme::EmbeddedScheme;
using Check = Window::Theme::CloudListCheck;
@ -1015,13 +1017,18 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> 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<Ui::VerticalLayout*> container) {
if (!Platform::IsDarkModeSupported()) {
return;
}
AddDivider(container);
AddSkip(container, st::settingsPrivacySkip);
AddSubsectionTitle(container, tr::lng_settings_auto_night_mode());
auto wrap = object_ptr<Ui::VerticalLayout>(container);
const auto autoNight = wrap->add(
object_ptr<Ui::Checkbox>(
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<Ui::OverrideMargins>(
container,
std::move(wrap)));
AddSkip(container, st::settingsCheckboxesSkip);
}
void SetupSupportSwitchSettings(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) {
@ -1381,6 +1429,7 @@ void Chat::setupContent(not_null<Window::SessionController*> controller) {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
SetupThemeOptions(controller, content);
SetupAutoNightMode(content);
SetupCloudThemes(controller, content);
SetupChatBackground(controller, content);
SetupStickersEmoji(controller, content);

View File

@ -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<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container);
void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container);
void SetupDefaultThemes(
not_null<Window::Controller*> window,
not_null<Ui::VerticalLayout*> container);
void SetupSupport(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container);

View File

@ -75,16 +75,14 @@ object_ptr<Ui::RpWidget> 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()) {

View File

@ -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 {

View File

@ -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;

View File

@ -23,6 +23,7 @@ namespace Storage {
enum class StartResult : uchar {
Success,
IncorrectPasscode,
IncorrectPasscodeLegacy,
};
class Domain final {

View File

@ -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<QString> 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<QString> themePath) {
reapplyWithNightMode(themePath, !_nightMode);
}
@ -1293,6 +1313,28 @@ void ToggleNightMode(const QString &path) {
Background()->toggleNightMode(path);
}
void ToggleNightModeWithConfirmation(
not_null<Controller*> window,
Fn<void()> toggle) {
if (Background()->nightModeChangeAllowed()) {
toggle();
} else {
const auto box = std::make_shared<QPointer<ConfirmBox>>();
const auto disableAndToggle = [=] {
Core::App().settings().setSystemDarkModeEnabled(false);
Core::App().saveSettingsDelayed();
toggle();
if (*box) {
(*box)->closeBox();
}
};
*box = window->show(Box<ConfirmBox>(
tr::lng_settings_auto_night_warning(tr::now),
tr::lng_settings_auto_night_disable(tr::now),
disableAndToggle));
}
}
void ResetToSomeDefault() {
Background()->reapplyWithNightMode(
IsNightMode() ? NightThemePath() : QString(),

View File

@ -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<Controller*> window,
Fn<void()> 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 {

View File

@ -51,8 +51,6 @@ Controller::~Controller() {
}
void Controller::showAccount(not_null<Main::Account*> account) {
Window::Theme::Background()->start();
_accountLifetime.destroy();
_account = account;

View File

@ -894,10 +894,19 @@ void MainMenu::refreshMenu() {
_nightThemeAction = std::make_shared<QPointer<QAction>>();
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();