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_disable_filtering" = "Disable filtering";
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices."; "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_spellchecker" = "Spell checker";
"lng_settings_system_spellchecker" = "Use system spell checker"; "lng_settings_system_spellchecker" = "Use system spell checker";
"lng_settings_custom_spellchecker" = "Use spell checker"; "lng_settings_custom_spellchecker" = "Use spell checker";

View File

@ -212,25 +212,9 @@ void Application::run() {
Ui::InitTextOptions(); Ui::InitTextOptions();
Ui::Emoji::Init(); Ui::Emoji::Init();
startEmojiImageLoader(); startEmojiImageLoader();
startSystemDarkModeViewer();
Media::Player::start(_audio.get()); 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( style::ShortAnimationPlaying(
) | rpl::start_with_next([=](bool playing) { ) | rpl::start_with_next([=](bool playing) {
if (playing) { if (playing) {
@ -250,10 +234,10 @@ void Application::run() {
QMimeDatabase().mimeTypeForName(qsl("text/plain")); QMimeDatabase().mimeTypeForName(qsl("text/plain"));
_window = std::make_unique<Window::Controller>(); _window = std::make_unique<Window::Controller>();
_domain->activeChanges( _domain->activeChanges(
) | rpl::start_with_next([=](not_null<Main::Account*> account) { ) | rpl::start_with_next([=](not_null<Main::Account*> account) {
_window->showAccount(account); _window->showAccount(account);
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
}, _window->widget()->lifetime()); }, _window->widget()->lifetime());
QCoreApplication::instance()->installEventFilter(this); QCoreApplication::instance()->installEventFilter(this);
@ -267,16 +251,8 @@ void Application::run() {
// Depend on activeWindow() for now :( // Depend on activeWindow() for now :(
startShortcuts(); startShortcuts();
App::initMedia(); App::initMedia();
startDomain();
const auto state = _domain->start(QByteArray());
if (state == Storage::StartResult::IncorrectPasscode) {
Global::SetLocalPasscode(true);
Global::RefLocalPasscodeChanged().notify();
lockByPasscode();
DEBUG_LOG(("Application Info: passcode needed..."));
}
_window->widget()->show(); _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() auto Application::prepareEmojiSourceImages()
-> std::shared_ptr<Ui::Emoji::UniversalImages> { -> std::shared_ptr<Ui::Emoji::UniversalImages> {
const auto &images = Ui::Emoji::SourceImages(); const auto &images = Ui::Emoji::SourceImages();

View File

@ -140,6 +140,7 @@ public:
[[nodiscard]] QWidget *getFileDialogParent(); [[nodiscard]] QWidget *getFileDialogParent();
void notifyFileDialogShown(bool shown); void notifyFileDialogShown(bool shown);
[[nodiscard]] QWidget *getModalParent(); [[nodiscard]] QWidget *getModalParent();
void checkSystemDarkMode();
// Media view interface. // Media view interface.
void checkMediaViewActivation(); void checkMediaViewActivation();
@ -161,6 +162,7 @@ public:
return _logoNoMargin; return _logoNoMargin;
} }
void startSettingsAndBackground();
[[nodiscard]] Settings &settings() { [[nodiscard]] Settings &settings() {
return _settings; return _settings;
} }
@ -290,7 +292,9 @@ private:
-> std::shared_ptr<Ui::Emoji::UniversalImages>; -> std::shared_ptr<Ui::Emoji::UniversalImages>;
void startLocalStorage(); void startLocalStorage();
void startShortcuts(); void startShortcuts();
void startDomain();
void startEmojiImageLoader(); void startEmojiImageLoader();
void startSystemDarkModeViewer();
void stateChanged(Qt::ApplicationState state); void stateChanged(Qt::ApplicationState state);

View File

@ -31,7 +31,9 @@ Domain::Domain(const QString &dataName)
, _local(std::make_unique<Storage::Domain>(this, dataName)) { , _local(std::make_unique<Storage::Domain>(this, dataName)) {
_active.changes( _active.changes(
) | rpl::take(1) | rpl::start_with_next([] { ) | 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(); Core::App().notifications().createManager();
}, _lifetime); }, _lifetime);

View File

@ -426,7 +426,7 @@ void MainWindow::initHook() {
|| QSystemTrayIcon::isSystemTrayAvailable(); || QSystemTrayIcon::isSystemTrayAvailable();
LOG(("System tray available: %1").arg(Logs::b(trayAvailable))); LOG(("System tray available: %1").arg(Logs::b(trayAvailable)));
cSetSupportTray(trayAvailable); Platform::SetTrayIconSupported(trayAvailable);
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
auto sniWatcher = new QDBusServiceWatcher( auto sniWatcher = new QDBusServiceWatcher(
@ -591,9 +591,9 @@ void MainWindow::onSNIOwnerChanged(
const auto trayAvailable = SNIAvailable const auto trayAvailable = SNIAvailable
|| QSystemTrayIcon::isSystemTrayAvailable(); || QSystemTrayIcon::isSystemTrayAvailable();
cSetSupportTray(trayAvailable); Platform::SetTrayIconSupported(trayAvailable);
if (cSupportTray()) { if (trayAvailable) {
psSetupTrayIcon(); psSetupTrayIcon();
} else { } else {
LOG(("System tray is not available.")); LOG(("System tray is not available."));
@ -654,9 +654,9 @@ void MainWindow::psSetupTrayIcon() {
} }
void MainWindow::workmodeUpdated(DBIWorkMode mode) { void MainWindow::workmodeUpdated(DBIWorkMode mode) {
if (!cSupportTray()) return; if (!Platform::TrayIconSupported()) {
return;
if (mode == dbiwmWindowOnly) { } else if (mode == dbiwmWindowOnly) {
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
if (_sniTrayIcon) { if (_sniTrayIcon) {
_sniTrayIcon->setContextMenu(0); _sniTrayIcon->setContextMenu(0);

View File

@ -69,6 +69,8 @@ constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs;
QStringList PlatformThemes; QStringList PlatformThemes;
bool IsTrayIconSupported = true;
#ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION #ifndef TDESKTOP_DISABLE_DBUS_INTEGRATION
void PortalAutostart(bool autostart, bool silent = false) { void PortalAutostart(bool autostart, bool silent = false) {
QVariantMap options; QVariantMap options;
@ -871,8 +873,7 @@ std::optional<crl::time> LastUserInputTime() {
std::optional<bool> IsDarkMode() { std::optional<bool> IsDarkMode() {
#ifndef TDESKTOP_DISABLE_GTK_INTEGRATION #ifndef TDESKTOP_DISABLE_GTK_INTEGRATION
if (Libs::GtkSettingSupported() if (Libs::GtkSettingSupported() && Libs::GtkLoaded()) {
&& Libs::GtkLoaded()) {
if (Libs::gtk_check_version != nullptr if (Libs::gtk_check_version != nullptr
&& !Libs::gtk_check_version(3, 0, 0) && !Libs::gtk_check_version(3, 0, 0)
&& Libs::GtkSetting<gboolean>("gtk-application-prefer-dark-theme")) { && Libs::GtkSetting<gboolean>("gtk-application-prefer-dark-theme")) {
@ -897,6 +898,14 @@ bool AutostartSupported() {
return !InSnap(); return !InSnap();
} }
bool TrayIconSupported() {
return IsTrayIconSupported;
}
void SetTrayIconSupported(bool supported) {
IsTrayIconSupported = supported;
}
void FallbackFontConfigCheckBegin() { void FallbackFontConfigCheckBegin() {
if (!CheckFontConfigCrash()) { if (!CheckFontConfigCrash()) {
return; return;

View File

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

View File

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

View File

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

View File

@ -48,6 +48,7 @@ bool OpenSystemSettings(SystemSettingsType type);
void IgnoreApplicationActivationRightNow(); void IgnoreApplicationActivationRightNow();
bool AutostartSupported(); bool AutostartSupported();
bool TrayIconSupported();
QImage GetImageFromClipboard(); QImage GetImageFromClipboard();
bool StartSystemMove(QWindow *window); bool StartSystemMove(QWindow *window);
bool StartSystemResize(QWindow *window, Qt::Edges edges); bool StartSystemResize(QWindow *window, Qt::Edges edges);

View File

@ -384,27 +384,34 @@ std::optional<crl::time> LastUserInputTime() {
} }
std::optional<bool> IsDarkMode() { std::optional<bool> IsDarkMode() {
if (QOperatingSystemVersion::current() static const auto kSystemVersion = QOperatingSystemVersion::current();
< QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763)) { static const auto kDarkModeAddedVersion = QOperatingSystemVersion(
QOperatingSystemVersion::Windows,
10,
0,
17763);
static const auto kSupported = (kSystemVersion >= kDarkModeAddedVersion);
if (!kSupported) {
return std::nullopt; return std::nullopt;
} }
LPCWSTR lpKeyName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; const auto keyName = L""
LPCWSTR lpValueName = L"AppsUseLightTheme"; "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
HKEY key; const auto valueName = L"AppsUseLightTheme";
auto result = RegOpenKeyEx(HKEY_CURRENT_USER, lpKeyName, 0, KEY_READ, &key); auto key = HKEY();
auto result = RegOpenKeyEx(HKEY_CURRENT_USER, keyName, 0, KEY_READ, &key);
if (result != ERROR_SUCCESS) { if (result != ERROR_SUCCESS) {
return std::nullopt; return std::nullopt;
} }
DWORD value = 0, type = 0, size = sizeof(value); 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); RegCloseKey(key);
if (result != ERROR_SUCCESS) { if (result != ERROR_SUCCESS) {
return std::nullopt; return std::nullopt;
} }
return value == 0; return (value == 0);
} }
bool AutostartSupported() { bool AutostartSupported() {

View File

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

View File

@ -42,7 +42,6 @@ bool gUseFreeType = false;
bool gAutoUpdate = true; bool gAutoUpdate = true;
TWindowPos gWindowPos; TWindowPos gWindowPos;
LaunchMode gLaunchMode = LaunchModeNormal; LaunchMode gLaunchMode = LaunchModeNormal;
bool gSupportTray = true;
bool gSeenTrayTooltip = false; bool gSeenTrayTooltip = false;
bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false; bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = false, gWriteProtected = false;
int32 gLastUpdateCheck = 0; int32 gLastUpdateCheck = 0;

View File

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

View File

@ -325,11 +325,7 @@ void SetupSpellchecker(
#endif // !TDESKTOP_DISABLE_SPELLCHECK #endif // !TDESKTOP_DISABLE_SPELLCHECK
} }
bool HasTray() { void SetupSystemIntegrationContent(not_null<Ui::VerticalLayout*> container) {
return cSupportTray() || Platform::IsWindows();
}
void SetupTrayContent(not_null<Ui::VerticalLayout*> container) {
const auto checkbox = [&](const QString &label, bool checked) { const auto checkbox = [&](const QString &label, bool checked) {
return object_ptr<Ui::Checkbox>( return object_ptr<Ui::Checkbox>(
container, container,
@ -349,65 +345,65 @@ void SetupTrayContent(not_null<Ui::VerticalLayout*> container) {
checkbox(label, checked), checkbox(label, checked),
st::settingsCheckboxPadding)); 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 taskbarEnabled = [] {
const auto workMode = Global::WorkMode().value(); const auto workMode = Global::WorkMode().value();
return (workMode == dbiwmTrayOnly) return (workMode == dbiwmWindowOnly)
|| (workMode == dbiwmWindowAndTray); || (workMode == dbiwmWindowAndTray);
}; };
const auto tray = addCheckbox( const auto taskbar = Platform::IsWindows()
tr::lng_settings_workmode_tray(tr::now), ? addCheckbox(
trayEnabled()); tr::lng_settings_workmode_window(tr::now),
taskbarEnabled())
: nullptr;
const auto taskbarEnabled = [] { const auto updateWorkmode = [=] {
const auto workMode = Global::WorkMode().value(); const auto newMode = tray->checked()
return (workMode == dbiwmWindowOnly) ? ((!taskbar || taskbar->checked())
|| (workMode == dbiwmWindowAndTray); ? dbiwmWindowAndTray
}; : dbiwmTrayOnly)
const auto taskbar = Platform::IsWindows() : dbiwmWindowOnly;
? addCheckbox( if ((newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)
tr::lng_settings_workmode_window(tr::now), && Global::WorkMode().value() != newMode) {
taskbarEnabled()) cSetSeenTrayTooltip(false);
: nullptr; }
Global::RefWorkMode().set(newMode);
Local::writeSettings();
};
const auto updateWorkmode = [=] { tray->checkedChanges(
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(
) | rpl::filter([=](bool checked) { ) | rpl::filter([=](bool checked) {
return (checked != taskbarEnabled()); return (checked != trayEnabled());
}) | rpl::start_with_next([=](bool checked) { }) | rpl::start_with_next([=](bool checked) {
if (!checked && !tray->checked()) { if (!checked && taskbar && !taskbar->checked()) {
tray->setChecked(true); taskbar->setChecked(true);
} else { } else {
updateWorkmode(); 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()) { if (Platform::AllowNativeWindowFrameToggle()) {
const auto nativeFrame = addCheckbox( const auto nativeFrame = addCheckbox(
tr::lng_settings_native_frame(tr::now), tr::lng_settings_native_frame(tr::now),
@ -421,7 +417,6 @@ void SetupTrayContent(not_null<Ui::VerticalLayout*> container) {
Core::App().saveSettingsDelayed(); Core::App().saveSettingsDelayed();
}, nativeFrame->lifetime()); }, nativeFrame->lifetime());
} }
if (Platform::AutostartSupported()) { if (Platform::AutostartSupported()) {
const auto minimizedToggled = [] { const auto minimizedToggled = [] {
return cStartMinimized() && !Global::LocalPasscode(); return cStartMinimized() && !Global::LocalPasscode();
@ -471,8 +466,7 @@ void SetupTrayContent(not_null<Ui::VerticalLayout*> container) {
}, minimized->lifetime()); }, minimized->lifetime());
} }
#ifndef OS_WIN_STORE if (Platform::IsWindows() && !Platform::IsWindowsStoreBuild()) {
if (Platform::IsWindows()) {
const auto sendto = addCheckbox( const auto sendto = addCheckbox(
tr::lng_settings_add_sendto(tr::now), tr::lng_settings_add_sendto(tr::now),
cSendToMenu()); cSendToMenu());
@ -486,22 +480,18 @@ void SetupTrayContent(not_null<Ui::VerticalLayout*> container) {
Local::writeSettings(); Local::writeSettings();
}, sendto->lifetime()); }, sendto->lifetime());
} }
#endif // OS_WIN_STORE
} }
void SetupTray(not_null<Ui::VerticalLayout*> container) { void SetupSystemIntegrationOptions(not_null<Ui::VerticalLayout*> container) {
if (!HasTray()) {
return;
}
auto wrap = object_ptr<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>( AddSkip(container, st::settingsCheckboxesSkip);
container, }
std::move(wrap)));
AddSkip(container, st::settingsCheckboxesSkip);
} }
void SetupAnimations(not_null<Ui::VerticalLayout*> container) { void SetupAnimations(not_null<Ui::VerticalLayout*> container) {
@ -539,7 +529,7 @@ void SetupSystemIntegration(
)->addClickHandler([=] { )->addClickHandler([=] {
showOther(Type::Calls); showOther(Type::Calls);
}); });
SetupTray(container); SetupSystemIntegrationOptions(container);
AddSkip(container); AddSkip(container);
} }

View File

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

View File

@ -982,7 +982,9 @@ void SetupChatBackground(
}, adaptive->lifetime()); }, 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 Type = Window::Theme::EmbeddedType;
using Scheme = Window::Theme::EmbeddedScheme; using Scheme = Window::Theme::EmbeddedScheme;
using Check = Window::Theme::CloudListCheck; using Check = Window::Theme::CloudListCheck;
@ -1015,13 +1017,18 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
}; };
const auto currentlyIsCustom = (chosen() == Type(-1)) const auto currentlyIsCustom = (chosen() == Type(-1))
&& !Background()->themeObject().cloud.id; && !Background()->themeObject().cloud.id;
const auto keep = [=] {
if (!currentlyIsCustom) {
KeepApplied();
}
};
if (IsNightMode() == isNight(scheme)) { if (IsNightMode() == isNight(scheme)) {
ApplyDefaultWithPath(scheme.path); ApplyDefaultWithPath(scheme.path);
keep();
} else { } else {
ToggleNightMode(scheme.path); Window::Theme::ToggleNightModeWithConfirmation(
} window,
if (!currentlyIsCustom) { [=, path = scheme.path] { ToggleNightMode(path); keep();});
KeepApplied();
} }
}; };
const auto schemeClicked = [=]( const auto schemeClicked = [=](
@ -1163,7 +1170,7 @@ void SetupThemeOptions(
AddSubsectionTitle(container, tr::lng_settings_themes()); AddSubsectionTitle(container, tr::lng_settings_themes());
AddSkip(container, st::settingsThemesTopSkip); AddSkip(container, st::settingsThemesTopSkip);
SetupDefaultThemes(container); SetupDefaultThemes(&controller->window(), container);
AddSkip(container); AddSkip(container);
} }
@ -1260,6 +1267,47 @@ void SetupCloudThemes(
wrap->setDuration(0)->toggleOn(list->empty() | rpl::map(!_1)); 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( void SetupSupportSwitchSettings(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) { 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); const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
SetupThemeOptions(controller, content); SetupThemeOptions(controller, content);
SetupAutoNightMode(content);
SetupCloudThemes(controller, content); SetupCloudThemes(controller, content);
SetupChatBackground(controller, content); SetupChatBackground(controller, content);
SetupStickersEmoji(controller, content); SetupStickersEmoji(controller, content);

View File

@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_common.h" #include "settings/settings_common.h"
namespace Window {
class Controller;
} // namespace Window
namespace Settings { namespace Settings {
void SetupDataStorage( void SetupDataStorage(
@ -17,7 +21,9 @@ void SetupDataStorage(
void SetupAutoDownload( void SetupAutoDownload(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container); 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( void SetupSupport(
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container); not_null<Ui::VerticalLayout*> container);

View File

@ -75,16 +75,14 @@ object_ptr<Ui::RpWidget> CreateIntroSettings(
SetupUpdate(result); SetupUpdate(result);
AddSkip(result); AddSkip(result);
} }
if (HasTray()) { AddDivider(result);
AddDivider(result); AddSkip(result);
AddSkip(result); SetupSystemIntegrationContent(result);
SetupTray(result); AddSkip(result);
AddSkip(result);
}
AddDivider(result); AddDivider(result);
AddSkip(result); AddSkip(result);
SetupInterfaceScale(result, false); SetupInterfaceScale(result, false);
SetupDefaultThemes(result); SetupDefaultThemes(window, result);
AddSkip(result); AddSkip(result);
if (anim::Disabled()) { if (anim::Disabled()) {

View File

@ -140,8 +140,9 @@ void FileLoader::finishWithBytes(const QByteArray &data) {
Platform::File::PostprocessDownloaded( Platform::File::PostprocessDownloaded(
QFileInfo(_file).absoluteFilePath()); QFileInfo(_file).absoluteFilePath());
} }
_session->notifyDownloaderTaskFinished(); const auto session = _session;
_updates.fire_done(); _updates.fire_done();
session->notifyDownloaderTaskFinished();
} }
QByteArray FileLoader::imageFormat(const QSize &shrinkBox) const { QByteArray FileLoader::imageFormat(const QSize &shrinkBox) const {

View File

@ -134,7 +134,7 @@ StartResult Account::legacyStart(const QByteArray &passcode) {
if (result == ReadMapResult::Failed) { if (result == ReadMapResult::Failed) {
Assert(_localKey == nullptr); Assert(_localKey == nullptr);
} else if (result == ReadMapResult::IncorrectPasscode) { } else if (result == ReadMapResult::IncorrectPasscode) {
return StartResult::IncorrectPasscode; return StartResult::IncorrectPasscodeLegacy;
} }
clearLegacyFiles(); clearLegacyFiles();
return StartResult::Success; return StartResult::Success;

View File

@ -23,6 +23,7 @@ namespace Storage {
enum class StartResult : uchar { enum class StartResult : uchar {
Success, Success,
IncorrectPasscode, IncorrectPasscode,
IncorrectPasscodeLegacy,
}; };
class Domain final { 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_theme_preview.h"
#include "window/themes/window_themes_embedded.h" #include "window/themes/window_themes_embedded.h"
#include "window/themes/window_theme_editor.h" #include "window/themes/window_theme_editor.h"
#include "window/window_controller.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "apiwrap.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_account.h" // Account::local.
#include "main/main_domain.h" // Domain::activeSessionValue. #include "main/main_domain.h" // Domain::activeSessionValue.
#include "ui/image/image.h" #include "ui/image/image.h"
#include "boxes/confirm_box.h"
#include "boxes/background_box.h" #include "boxes/background_box.h"
#include "core/application.h" #include "core/application.h"
#include "app.h" #include "app.h"
@ -560,6 +562,8 @@ void ChatBackground::start() {
_session = session; _session = session;
checkUploadWallPaper(); checkUploadWallPaper();
}, _lifetime); }, _lifetime);
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
} }
void ChatBackground::checkUploadWallPaper() { void ChatBackground::checkUploadWallPaper() {
@ -1074,6 +1078,14 @@ bool ChatBackground::nightMode() const {
void ChatBackground::reapplyWithNightMode( void ChatBackground::reapplyWithNightMode(
std::optional<QString> themePath, std::optional<QString> themePath,
bool newNightMode) { 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 settingExactTheme = themePath.has_value();
const auto nightModeChanged = (newNightMode != _nightMode); const auto nightModeChanged = (newNightMode != _nightMode);
const auto oldNightMode = _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) { void ChatBackground::toggleNightMode(std::optional<QString> themePath) {
reapplyWithNightMode(themePath, !_nightMode); reapplyWithNightMode(themePath, !_nightMode);
} }
@ -1293,6 +1313,28 @@ void ToggleNightMode(const QString &path) {
Background()->toggleNightMode(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() { void ResetToSomeDefault() {
Background()->reapplyWithNightMode( Background()->reapplyWithNightMode(
IsNightMode() ? NightThemePath() : QString(), IsNightMode() ? NightThemePath() : QString(),

View File

@ -14,6 +14,10 @@ namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
namespace Window {
class Controller;
} // namespace Window
namespace Window { namespace Window {
namespace Theme { namespace Theme {
@ -76,6 +80,9 @@ QString NightThemePath();
void SetNightModeValue(bool nightMode); void SetNightModeValue(bool nightMode);
void ToggleNightMode(); void ToggleNightMode();
void ToggleNightMode(const QString &themePath); void ToggleNightMode(const QString &themePath);
void ToggleNightModeWithConfirmation(
not_null<Controller*> window,
Fn<void()> toggle);
void ResetToSomeDefault(); void ResetToSomeDefault();
[[nodiscard]] bool IsNonDefaultBackground(); [[nodiscard]] bool IsNonDefaultBackground();
void Revert(); void Revert();
@ -169,6 +176,7 @@ public:
[[nodiscard]] bool tileDay() const; [[nodiscard]] bool tileDay() const;
[[nodiscard]] bool tileNight() const; [[nodiscard]] bool tileNight() const;
[[nodiscard]] bool isMonoColorImage() const; [[nodiscard]] bool isMonoColorImage() const;
[[nodiscard]] bool nightModeChangeAllowed() const;
private: private:
struct AdjustableColor { struct AdjustableColor {

View File

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

View File

@ -894,10 +894,19 @@ void MainMenu::refreshMenu() {
_nightThemeAction = std::make_shared<QPointer<QAction>>(); _nightThemeAction = std::make_shared<QPointer<QAction>>();
auto action = _menu->addAction(tr::lng_menu_night_mode(tr::now), [=] { auto action = _menu->addAction(tr::lng_menu_night_mode(tr::now), [=] {
if (auto action = *_nightThemeAction) { const auto weak = MakeWeak(this);
action->setChecked(!action->isChecked()); const auto toggle = [=] {
_nightThemeSwitch.callOnce(st::mainMenu.itemToggle.duration); 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); }, &st::mainMenuNightMode, &st::mainMenuNightModeOver);
*_nightThemeAction = action; *_nightThemeAction = action;
action->setCheckable(true); action->setCheckable(true);
@ -908,12 +917,6 @@ void MainMenu::refreshMenu() {
if (darkModeEnabled && darkMode.has_value()) { if (darkModeEnabled && darkMode.has_value()) {
action->setChecked(*darkMode); 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()); }, lifetime());
_menu->finishAnimating(); _menu->finishAnimating();