From c2117e77223a91dda2f5a03b816c6f7c24a2d69e Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 23 Aug 2019 16:52:59 +0300 Subject: [PATCH] Save embedded themes accent colors. --- Telegram/SourceFiles/core/application.cpp | 5 + Telegram/SourceFiles/core/application.h | 20 +- Telegram/SourceFiles/core/core_settings.cpp | 51 ++ Telegram/SourceFiles/core/core_settings.h | 40 ++ Telegram/SourceFiles/core/update_checker.cpp | 2 +- Telegram/SourceFiles/main/main_session.cpp | 481 +---------------- Telegram/SourceFiles/main/main_session.h | 314 +---------- Telegram/SourceFiles/main/main_settings.cpp | 490 ++++++++++++++++++ Telegram/SourceFiles/main/main_settings.h | 295 +++++++++++ .../SourceFiles/settings/settings_chat.cpp | 235 +++------ Telegram/SourceFiles/storage/localstorage.cpp | 14 +- .../SourceFiles/storage/serialize_common.cpp | 17 + .../SourceFiles/storage/serialize_common.h | 7 + .../window/themes/window_theme.cpp | 71 +-- .../SourceFiles/window/themes/window_theme.h | 13 +- .../window/themes/window_themes_embedded.cpp | 365 +++++++++++++ .../window/themes/window_themes_embedded.h | 77 +++ Telegram/gyp/telegram_sources.txt | 6 + 18 files changed, 1484 insertions(+), 1019 deletions(-) create mode 100644 Telegram/SourceFiles/core/core_settings.cpp create mode 100644 Telegram/SourceFiles/core/core_settings.h create mode 100644 Telegram/SourceFiles/main/main_settings.cpp create mode 100644 Telegram/SourceFiles/main/main_settings.h create mode 100644 Telegram/SourceFiles/window/themes/window_themes_embedded.cpp create mode 100644 Telegram/SourceFiles/window/themes/window_themes_embedded.h diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index c88dc5ab5d..4ebb149a03 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -336,6 +336,10 @@ bool Application::eventFilter(QObject *object, QEvent *e) { return QObject::eventFilter(object, e); } +void Application::saveSettingsDelayed(crl::time delay) { + _saveSettingsTimer.callOnce(delay); +} + void Application::setCurrentProxy( const ProxyData &proxy, ProxyData::Settings settings) { @@ -381,6 +385,7 @@ void Application::startLocalStorage() { } } }); + _saveSettingsTimer.setCallback([=] { Local::writeSettings(); }); } void Application::forceLogOut(const TextWithEntities &explanation) { diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index 10fc5c8ea1..65dd47e5a3 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -7,8 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "base/observer.h" +#include "core/core_settings.h" #include "mtproto/auth_key.h" +#include "base/observer.h" #include "base/timer.h" class MainWindow; @@ -94,9 +95,6 @@ public: bool closeActiveWindow(); bool minimizeActiveWindow(); QWidget *getFileDialogParent(); - QWidget *getGlobalShortcutParent() { - return &_globalShortcutParent; - } // Media view interface. void checkMediaViewActivation(); @@ -115,7 +113,13 @@ public: return _logoNoMargin; } - // MTProto components. + [[nodiscard]] Settings &settings() { + return _settings; + } + void moveSettingsFrom(Settings &&other); + void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay); + + // Dc options and proxy. MTP::DcOptions *dcOptions() { return _dcOptions.get(); } @@ -221,6 +225,8 @@ protected: bool eventFilter(QObject *object, QEvent *event) override; private: + static constexpr auto kDefaultSaveDelay = crl::time(1000); + friend bool IsAppLaunched(); friend Application &App(); @@ -251,8 +257,7 @@ private: // Some fields are just moved from the declaration. struct Private; const std::unique_ptr _private; - - QWidget _globalShortcutParent; + Settings _settings; const std::unique_ptr _databases; const std::unique_ptr _animationsManager; @@ -276,6 +281,7 @@ private: std::unique_ptr _termsLock; base::DelayedCallTimer _callDelayedTimer; + base::Timer _saveSettingsTimer; struct LeaveSubscription { LeaveSubscription( diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp new file mode 100644 index 0000000000..a9c577cf27 --- /dev/null +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -0,0 +1,51 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "core/core_settings.h" + +#include "storage/serialize_common.h" + +namespace Core { + +Settings::Variables::Variables() { +} + +QByteArray Settings::serialize() const { + const auto themesAccentColors = _variables.themesAccentColors.serialize(); + auto size = Serialize::bytearraySize(themesAccentColors); + + auto result = QByteArray(); + result.reserve(size); + { + QDataStream stream(&result, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_1); + stream << themesAccentColors; + } + return result; +} + +void Settings::constructFromSerialized(const QByteArray &serialized) { + if (serialized.isEmpty()) { + return; + } + + QDataStream stream(serialized); + stream.setVersion(QDataStream::Qt_5_1); + QByteArray themesAccentColors; + + stream >> themesAccentColors; + if (stream.status() != QDataStream::Ok) { + LOG(("App Error: " + "Bad data for Core::Settings::constructFromSerialized()")); + return; + } + if (!_variables.themesAccentColors.setFromSerialized(themesAccentColors)) { + return; + } +} + +} // namespace Core diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h new file mode 100644 index 0000000000..a3bcbdd89b --- /dev/null +++ b/Telegram/SourceFiles/core/core_settings.h @@ -0,0 +1,40 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "window/themes/window_themes_embedded.h" + +namespace Core { + +class Settings final { +public: + void moveFrom(Settings &&other) { + _variables = std::move(other._variables); + } + [[nodiscard]] QByteArray serialize() const; + void constructFromSerialized(const QByteArray &serialized); + + void setThemesAccentColors(Window::Theme::AccentColors &&colors) { + _variables.themesAccentColors = std::move(colors); + } + [[nodiscard]] Window::Theme::AccentColors &themesAccentColors() { + return _variables.themesAccentColors; + } + +private: + struct Variables { + Variables(); + + Window::Theme::AccentColors themesAccentColors; + }; + + Variables _variables; + +}; + +} // namespace Core diff --git a/Telegram/SourceFiles/core/update_checker.cpp b/Telegram/SourceFiles/core/update_checker.cpp index bff6dcd77d..ad19757109 100644 --- a/Telegram/SourceFiles/core/update_checker.cpp +++ b/Telegram/SourceFiles/core/update_checker.cpp @@ -1587,7 +1587,7 @@ void UpdateApplication() { Window::SectionShow()); } else { window->showSpecialLayer( - Box(), + Box<::Settings::LayerWidget>(), anim::type::normal); } window->showFromTray(); diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 3ea70b537e..43d7fd9712 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -12,23 +12,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/changelogs.h" #include "main/main_account.h" #include "main/main_app_config.h" +#include "chat_helpers/stickers_emoji_pack.h" #include "storage/file_download.h" #include "storage/file_upload.h" #include "storage/localstorage.h" #include "storage/storage_facade.h" -#include "storage/serialize_common.h" #include "data/data_session.h" #include "data/data_user.h" #include "window/notifications_manager.h" #include "window/themes/window_theme.h" -#include "platform/platform_specific.h" +//#include "platform/platform_specific.h" #include "calls/calls_instance.h" -#include "window/section_widget.h" -#include "chat_helpers/tabbed_selector.h" -#include "chat_helpers/stickers_emoji_pack.h" -#include "boxes/send_files_box.h" -#include "ui/widgets/input_fields.h" -#include "support/support_common.h" #include "support/support_helper.h" #include "observer_peer.h" @@ -40,475 +34,11 @@ constexpr auto kLegacyCallsPeerToPeerNobody = 4; } // namespace -Settings::Variables::Variables() -: sendFilesWay(SendFilesWay::Album) -, selectorTab(ChatHelpers::SelectorTab::Emoji) -, floatPlayerColumn(Window::Column::Second) -, floatPlayerCorner(RectPart::TopRight) -, sendSubmitWay(Ui::InputSubmitSettings::Enter) -, supportSwitch(Support::SwitchSettings::Next) { -} - -QByteArray Settings::serialize() const { - const auto autoDownload = _variables.autoDownload.serialize(); - auto size = sizeof(qint32) * 30; - for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) { - size += Serialize::stringSize(i.key()) + Serialize::stringSize(i.value()); - } - size += _variables.groupStickersSectionHidden.size() * sizeof(quint64); - size += Serialize::bytearraySize(autoDownload); - - auto result = QByteArray(); - result.reserve(size); - { - QDataStream stream(&result, QIODevice::WriteOnly); - stream.setVersion(QDataStream::Qt_5_1); - stream << static_cast(_variables.selectorTab); - stream << qint32(_variables.lastSeenWarningSeen ? 1 : 0); - stream << qint32(_variables.tabbedSelectorSectionEnabled ? 1 : 0); - stream << qint32(_variables.soundOverrides.size()); - for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) { - stream << i.key() << i.value(); - } - stream << qint32(_variables.tabbedSelectorSectionTooltipShown); - stream << qint32(_variables.floatPlayerColumn); - stream << qint32(_variables.floatPlayerCorner); - stream << qint32(_variables.groupStickersSectionHidden.size()); - for (auto peerId : _variables.groupStickersSectionHidden) { - stream << quint64(peerId); - } - stream << qint32(_variables.thirdSectionInfoEnabled ? 1 : 0); - stream << qint32(_variables.smallDialogsList ? 1 : 0); - stream << qint32(snap( - qRound(_variables.dialogsWidthRatio.current() * 1000000), - 0, - 1000000)); - stream << qint32(_variables.thirdColumnWidth.current()); - stream << qint32(_variables.thirdSectionExtendedBy); - stream << qint32(_variables.sendFilesWay); - stream << qint32(0);// LEGACY _variables.callsPeerToPeer.current()); - stream << qint32(_variables.sendSubmitWay); - stream << qint32(_variables.supportSwitch); - stream << qint32(_variables.supportFixChatsOrder ? 1 : 0); - stream << qint32(_variables.supportTemplatesAutocomplete ? 1 : 0); - stream << qint32(_variables.supportChatsTimeSlice.current()); - stream << qint32(_variables.includeMutedCounter ? 1 : 0); - stream << qint32(_variables.countUnreadMessages ? 1 : 0); - stream << qint32(_variables.exeLaunchWarning ? 1 : 0); - stream << autoDownload; - stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0); - stream << qint32(_variables.archiveCollapsed.current() ? 1 : 0); - stream << qint32(_variables.notifyAboutPinned.current() ? 1 : 0); - stream << qint32(_variables.archiveInMainMenu.current() ? 1 : 0); - stream << qint32(_variables.skipArchiveInSearch.current() ? 1 : 0); - stream << qint32(_variables.autoplayGifs ? 1 : 0); - stream << qint32(_variables.loopAnimatedStickers ? 1 : 0); - stream << qint32(_variables.largeEmoji.current() ? 1 : 0); - stream << qint32(_variables.replaceEmoji.current() ? 1 : 0); - stream << qint32(_variables.suggestEmoji ? 1 : 0); - stream << qint32(_variables.suggestStickersByEmoji ? 1 : 0); - } - return result; -} - -void Settings::constructFromSerialized(const QByteArray &serialized) { - if (serialized.isEmpty()) { - return; - } - - QDataStream stream(serialized); - stream.setVersion(QDataStream::Qt_5_1); - qint32 selectorTab = static_cast(ChatHelpers::SelectorTab::Emoji); - qint32 lastSeenWarningSeen = 0; - qint32 tabbedSelectorSectionEnabled = 1; - qint32 tabbedSelectorSectionTooltipShown = 0; - qint32 floatPlayerColumn = static_cast(Window::Column::Second); - qint32 floatPlayerCorner = static_cast(RectPart::TopRight); - QMap soundOverrides; - base::flat_set groupStickersSectionHidden; - qint32 thirdSectionInfoEnabled = 0; - qint32 smallDialogsList = 0; - float64 dialogsWidthRatio = _variables.dialogsWidthRatio.current(); - int thirdColumnWidth = _variables.thirdColumnWidth.current(); - int thirdSectionExtendedBy = _variables.thirdSectionExtendedBy; - qint32 sendFilesWay = static_cast(_variables.sendFilesWay); - qint32 legacyCallsPeerToPeer = qint32(0); - qint32 sendSubmitWay = static_cast(_variables.sendSubmitWay); - qint32 supportSwitch = static_cast(_variables.supportSwitch); - qint32 supportFixChatsOrder = _variables.supportFixChatsOrder ? 1 : 0; - qint32 supportTemplatesAutocomplete = _variables.supportTemplatesAutocomplete ? 1 : 0; - qint32 supportChatsTimeSlice = _variables.supportChatsTimeSlice.current(); - qint32 includeMutedCounter = _variables.includeMutedCounter ? 1 : 0; - qint32 countUnreadMessages = _variables.countUnreadMessages ? 1 : 0; - qint32 exeLaunchWarning = _variables.exeLaunchWarning ? 1 : 0; - QByteArray autoDownload; - qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0; - qint32 archiveCollapsed = _variables.archiveCollapsed.current() ? 1 : 0; - qint32 notifyAboutPinned = _variables.notifyAboutPinned.current() ? 1 : 0; - qint32 archiveInMainMenu = _variables.archiveInMainMenu.current() ? 1 : 0; - qint32 skipArchiveInSearch = _variables.skipArchiveInSearch.current() ? 1 : 0; - qint32 autoplayGifs = _variables.autoplayGifs ? 1 : 0; - qint32 loopAnimatedStickers = _variables.loopAnimatedStickers ? 1 : 0; - qint32 largeEmoji = _variables.largeEmoji.current() ? 1 : 0; - qint32 replaceEmoji = _variables.replaceEmoji.current() ? 1 : 0; - qint32 suggestEmoji = _variables.suggestEmoji ? 1 : 0; - qint32 suggestStickersByEmoji = _variables.suggestStickersByEmoji ? 1 : 0; - - stream >> selectorTab; - stream >> lastSeenWarningSeen; - if (!stream.atEnd()) { - stream >> tabbedSelectorSectionEnabled; - } - if (!stream.atEnd()) { - auto count = qint32(0); - stream >> count; - if (stream.status() == QDataStream::Ok) { - for (auto i = 0; i != count; ++i) { - QString key, value; - stream >> key >> value; - soundOverrides[key] = value; - } - } - } - if (!stream.atEnd()) { - stream >> tabbedSelectorSectionTooltipShown; - } - if (!stream.atEnd()) { - stream >> floatPlayerColumn >> floatPlayerCorner; - } - if (!stream.atEnd()) { - auto count = qint32(0); - stream >> count; - if (stream.status() == QDataStream::Ok) { - for (auto i = 0; i != count; ++i) { - quint64 peerId; - stream >> peerId; - groupStickersSectionHidden.insert(peerId); - } - } - } - if (!stream.atEnd()) { - stream >> thirdSectionInfoEnabled; - stream >> smallDialogsList; - } - if (!stream.atEnd()) { - qint32 value = 0; - stream >> value; - dialogsWidthRatio = snap(value / 1000000., 0., 1.); - - stream >> value; - thirdColumnWidth = value; - - stream >> value; - thirdSectionExtendedBy = value; - } - if (!stream.atEnd()) { - stream >> sendFilesWay; - } - if (!stream.atEnd()) { - stream >> legacyCallsPeerToPeer; - } - if (!stream.atEnd()) { - stream >> sendSubmitWay; - stream >> supportSwitch; - stream >> supportFixChatsOrder; - } - if (!stream.atEnd()) { - stream >> supportTemplatesAutocomplete; - } - if (!stream.atEnd()) { - stream >> supportChatsTimeSlice; - } - if (!stream.atEnd()) { - stream >> includeMutedCounter; - stream >> countUnreadMessages; - } - if (!stream.atEnd()) { - stream >> exeLaunchWarning; - } - if (!stream.atEnd()) { - stream >> autoDownload; - } - if (!stream.atEnd()) { - stream >> supportAllSearchResults; - } - if (!stream.atEnd()) { - stream >> archiveCollapsed; - } - if (!stream.atEnd()) { - stream >> notifyAboutPinned; - } - if (!stream.atEnd()) { - stream >> archiveInMainMenu; - } - if (!stream.atEnd()) { - stream >> skipArchiveInSearch; - } - if (!stream.atEnd()) { - stream >> autoplayGifs; - stream >> loopAnimatedStickers; - stream >> largeEmoji; - stream >> replaceEmoji; - stream >> suggestEmoji; - stream >> suggestStickersByEmoji; - } - if (stream.status() != QDataStream::Ok) { - LOG(("App Error: " - "Bad data for Settings::constructFromSerialized()")); - return; - } - if (!autoDownload.isEmpty() - && !_variables.autoDownload.setFromSerialized(autoDownload)) { - return; - } - - auto uncheckedTab = static_cast(selectorTab); - switch (uncheckedTab) { - case ChatHelpers::SelectorTab::Emoji: - case ChatHelpers::SelectorTab::Stickers: - case ChatHelpers::SelectorTab::Gifs: _variables.selectorTab = uncheckedTab; break; - } - _variables.lastSeenWarningSeen = (lastSeenWarningSeen == 1); - _variables.tabbedSelectorSectionEnabled = (tabbedSelectorSectionEnabled == 1); - _variables.soundOverrides = std::move(soundOverrides); - _variables.tabbedSelectorSectionTooltipShown = tabbedSelectorSectionTooltipShown; - auto uncheckedColumn = static_cast(floatPlayerColumn); - switch (uncheckedColumn) { - case Window::Column::First: - case Window::Column::Second: - case Window::Column::Third: _variables.floatPlayerColumn = uncheckedColumn; break; - } - auto uncheckedCorner = static_cast(floatPlayerCorner); - switch (uncheckedCorner) { - case RectPart::TopLeft: - case RectPart::TopRight: - case RectPart::BottomLeft: - case RectPart::BottomRight: _variables.floatPlayerCorner = uncheckedCorner; break; - } - _variables.groupStickersSectionHidden = std::move(groupStickersSectionHidden); - _variables.thirdSectionInfoEnabled = thirdSectionInfoEnabled; - _variables.smallDialogsList = smallDialogsList; - _variables.dialogsWidthRatio = dialogsWidthRatio; - _variables.thirdColumnWidth = thirdColumnWidth; - _variables.thirdSectionExtendedBy = thirdSectionExtendedBy; - if (_variables.thirdSectionInfoEnabled) { - _variables.tabbedSelectorSectionEnabled = false; - } - auto uncheckedSendFilesWay = static_cast(sendFilesWay); - switch (uncheckedSendFilesWay) { - case SendFilesWay::Album: - case SendFilesWay::Photos: - case SendFilesWay::Files: _variables.sendFilesWay = uncheckedSendFilesWay; break; - } - auto uncheckedSendSubmitWay = static_cast( - sendSubmitWay); - switch (uncheckedSendSubmitWay) { - case Ui::InputSubmitSettings::Enter: - case Ui::InputSubmitSettings::CtrlEnter: _variables.sendSubmitWay = uncheckedSendSubmitWay; break; - } - auto uncheckedSupportSwitch = static_cast( - supportSwitch); - switch (uncheckedSupportSwitch) { - case Support::SwitchSettings::None: - case Support::SwitchSettings::Next: - case Support::SwitchSettings::Previous: _variables.supportSwitch = uncheckedSupportSwitch; break; - } - _variables.supportFixChatsOrder = (supportFixChatsOrder == 1); - _variables.supportTemplatesAutocomplete = (supportTemplatesAutocomplete == 1); - _variables.supportChatsTimeSlice = supportChatsTimeSlice; - _variables.hadLegacyCallsPeerToPeerNobody = (legacyCallsPeerToPeer == kLegacyCallsPeerToPeerNobody); - _variables.includeMutedCounter = (includeMutedCounter == 1); - _variables.countUnreadMessages = (countUnreadMessages == 1); - _variables.exeLaunchWarning = (exeLaunchWarning == 1); - _variables.supportAllSearchResults = (supportAllSearchResults == 1); - _variables.archiveCollapsed = (archiveCollapsed == 1); - _variables.notifyAboutPinned = (notifyAboutPinned == 1); - _variables.archiveInMainMenu = (archiveInMainMenu == 1); - _variables.skipArchiveInSearch = (skipArchiveInSearch == 1); - _variables.autoplayGifs = (autoplayGifs == 1); - _variables.loopAnimatedStickers = (loopAnimatedStickers == 1); - _variables.largeEmoji = (largeEmoji == 1); - _variables.replaceEmoji = (replaceEmoji == 1); - _variables.suggestEmoji = (suggestEmoji == 1); - _variables.suggestStickersByEmoji = (suggestStickersByEmoji == 1); -} - -void Settings::setSupportChatsTimeSlice(int slice) { - _variables.supportChatsTimeSlice = slice; -} - -int Settings::supportChatsTimeSlice() const { - return _variables.supportChatsTimeSlice.current(); -} - -rpl::producer Settings::supportChatsTimeSliceValue() const { - return _variables.supportChatsTimeSlice.value(); -} - -void Settings::setSupportAllSearchResults(bool all) { - _variables.supportAllSearchResults = all; -} - -bool Settings::supportAllSearchResults() const { - return _variables.supportAllSearchResults.current(); -} - -rpl::producer Settings::supportAllSearchResultsValue() const { - return _variables.supportAllSearchResults.value(); -} - -void Settings::setTabbedSelectorSectionEnabled(bool enabled) { - _variables.tabbedSelectorSectionEnabled = enabled; - if (enabled) { - setThirdSectionInfoEnabled(false); - } - setTabbedReplacedWithInfo(false); -} - -rpl::producer Settings::tabbedReplacedWithInfoValue() const { - return _tabbedReplacedWithInfoValue.events_starting_with( - tabbedReplacedWithInfo()); -} - -void Settings::setThirdSectionInfoEnabled(bool enabled) { - if (_variables.thirdSectionInfoEnabled != enabled) { - _variables.thirdSectionInfoEnabled = enabled; - if (enabled) { - setTabbedSelectorSectionEnabled(false); - } - setTabbedReplacedWithInfo(false); - _thirdSectionInfoEnabledValue.fire_copy(enabled); - } -} - -rpl::producer Settings::thirdSectionInfoEnabledValue() const { - return _thirdSectionInfoEnabledValue.events_starting_with( - thirdSectionInfoEnabled()); -} - -void Settings::setTabbedReplacedWithInfo(bool enabled) { - if (_tabbedReplacedWithInfo != enabled) { - _tabbedReplacedWithInfo = enabled; - _tabbedReplacedWithInfoValue.fire_copy(enabled); - } -} - -QString Settings::getSoundPath(const QString &key) const { - auto it = _variables.soundOverrides.constFind(key); - if (it != _variables.soundOverrides.end()) { - return it.value(); - } - return qsl(":/sounds/") + key + qsl(".mp3"); -} - -void Settings::setDialogsWidthRatio(float64 ratio) { - _variables.dialogsWidthRatio = ratio; -} - -float64 Settings::dialogsWidthRatio() const { - return _variables.dialogsWidthRatio.current(); -} - -rpl::producer Settings::dialogsWidthRatioChanges() const { - return _variables.dialogsWidthRatio.changes(); -} - -void Settings::setThirdColumnWidth(int width) { - _variables.thirdColumnWidth = width; -} - -int Settings::thirdColumnWidth() const { - return _variables.thirdColumnWidth.current(); -} - -rpl::producer Settings::thirdColumnWidthChanges() const { - return _variables.thirdColumnWidth.changes(); -} - -void Settings::setArchiveCollapsed(bool collapsed) { - _variables.archiveCollapsed = collapsed; -} - -bool Settings::archiveCollapsed() const { - return _variables.archiveCollapsed.current(); -} - -rpl::producer Settings::archiveCollapsedChanges() const { - return _variables.archiveCollapsed.changes(); -} - -void Settings::setArchiveInMainMenu(bool inMainMenu) { - _variables.archiveInMainMenu = inMainMenu; -} - -bool Settings::archiveInMainMenu() const { - return _variables.archiveInMainMenu.current(); -} - -rpl::producer Settings::archiveInMainMenuChanges() const { - return _variables.archiveInMainMenu.changes(); -} - -void Settings::setNotifyAboutPinned(bool notify) { - _variables.notifyAboutPinned = notify; -} - -bool Settings::notifyAboutPinned() const { - return _variables.notifyAboutPinned.current(); -} - -rpl::producer Settings::notifyAboutPinnedChanges() const { - return _variables.notifyAboutPinned.changes(); -} - -void Settings::setSkipArchiveInSearch(bool skip) { - _variables.skipArchiveInSearch = skip; -} - -bool Settings::skipArchiveInSearch() const { - return _variables.skipArchiveInSearch.current(); -} - -rpl::producer Settings::skipArchiveInSearchChanges() const { - return _variables.skipArchiveInSearch.changes(); -} - -void Settings::setLargeEmoji(bool value) { - _variables.largeEmoji = value; -} - -bool Settings::largeEmoji() const { - return _variables.largeEmoji.current(); -} - -rpl::producer Settings::largeEmojiValue() const { - return _variables.largeEmoji.value(); -} - -rpl::producer Settings::largeEmojiChanges() const { - return _variables.largeEmoji.changes(); -} - -void Settings::setReplaceEmoji(bool value) { - _variables.replaceEmoji = value; -} - -bool Settings::replaceEmoji() const { - return _variables.replaceEmoji.current(); -} - -rpl::producer Settings::replaceEmojiValue() const { - return _variables.replaceEmoji.value(); -} - -rpl::producer Settings::replaceEmojiChanges() const { - return _variables.replaceEmoji.changes(); -} - Session::Session( not_null account, const MTPUser &user) : _account(account) +, _saveSettingsTimer([=] { Local::writeUserSettings(); }) , _autoLockTimer([=] { checkAutoLock(); }) , _api(std::make_unique(this)) , _appConfig(std::make_unique(this)) @@ -522,9 +52,6 @@ Session::Session( , _emojiStickersPack(std::make_unique(this)) , _changelogs(Core::Changelogs::Create(this)) , _supportHelper(Support::Helper::Create(this)) { - _saveDataTimer.setCallback([=] { - Local::writeUserSettings(); - }); Core::App().passcodeLockChanges( ) | rpl::start_with_next([=] { _shouldLockAt = 0; @@ -614,7 +141,7 @@ void Session::moveSettingsFrom(Settings &&other) { void Session::saveSettingsDelayed(crl::time delay) { Expects(this == &Auth()); - _saveDataTimer.callOnce(delay); + _saveSettingsTimer.callOnce(delay); } not_null Session::mtp() { diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 7f6afc3dd6..5cb8ee69ba 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -10,18 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include +#include "main/main_settings.h" #include "base/timer.h" -#include "data/data_auto_download.h" class ApiWrap; -enum class SendFilesWay; - -namespace Ui { -enum class InputSubmitSettings; -} // namespace Ui namespace Support { -enum class SwitchSettings; class Helper; class Templates; } // namespace Support @@ -40,17 +34,12 @@ namespace Window { namespace Notifications { class System; } // namespace Notifications -enum class Column; } // namespace Window namespace Calls { class Instance; } // namespace Calls -namespace ChatHelpers { -enum class SelectorTab; -} // namespace ChatHelpers - namespace Stickers { class EmojiPack; } // namespace Stickers; @@ -64,269 +53,6 @@ namespace Main { class Account; class AppConfig; -class Settings final { -public: - void moveFrom(Settings &&other) { - _variables = std::move(other._variables); - } - [[nodiscard]] QByteArray serialize() const; - void constructFromSerialized(const QByteArray &serialized); - - void setLastSeenWarningSeen(bool lastSeenWarningSeen) { - _variables.lastSeenWarningSeen = lastSeenWarningSeen; - } - [[nodiscard]] bool lastSeenWarningSeen() const { - return _variables.lastSeenWarningSeen; - } - void setSendFilesWay(SendFilesWay way) { - _variables.sendFilesWay = way; - } - [[nodiscard]] SendFilesWay sendFilesWay() const { - return _variables.sendFilesWay; - } - void setSendSubmitWay(Ui::InputSubmitSettings value) { - _variables.sendSubmitWay = value; - } - [[nodiscard]] Ui::InputSubmitSettings sendSubmitWay() const { - return _variables.sendSubmitWay; - } - - void setSupportSwitch(Support::SwitchSettings value) { - _variables.supportSwitch = value; - } - [[nodiscard]] Support::SwitchSettings supportSwitch() const { - return _variables.supportSwitch; - } - void setSupportFixChatsOrder(bool fix) { - _variables.supportFixChatsOrder = fix; - } - [[nodiscard]] bool supportFixChatsOrder() const { - return _variables.supportFixChatsOrder; - } - void setSupportTemplatesAutocomplete(bool enabled) { - _variables.supportTemplatesAutocomplete = enabled; - } - [[nodiscard]] bool supportTemplatesAutocomplete() const { - return _variables.supportTemplatesAutocomplete; - } - void setSupportChatsTimeSlice(int slice); - [[nodiscard]] int supportChatsTimeSlice() const; - [[nodiscard]] rpl::producer supportChatsTimeSliceValue() const; - void setSupportAllSearchResults(bool all); - [[nodiscard]] bool supportAllSearchResults() const; - [[nodiscard]] rpl::producer supportAllSearchResultsValue() const; - - [[nodiscard]] ChatHelpers::SelectorTab selectorTab() const { - return _variables.selectorTab; - } - void setSelectorTab(ChatHelpers::SelectorTab tab) { - _variables.selectorTab = tab; - } - [[nodiscard]] bool tabbedSelectorSectionEnabled() const { - return _variables.tabbedSelectorSectionEnabled; - } - void setTabbedSelectorSectionEnabled(bool enabled); - [[nodiscard]] bool thirdSectionInfoEnabled() const { - return _variables.thirdSectionInfoEnabled; - } - void setThirdSectionInfoEnabled(bool enabled); - [[nodiscard]] rpl::producer thirdSectionInfoEnabledValue() const; - [[nodiscard]] int thirdSectionExtendedBy() const { - return _variables.thirdSectionExtendedBy; - } - void setThirdSectionExtendedBy(int savedValue) { - _variables.thirdSectionExtendedBy = savedValue; - } - [[nodiscard]] bool tabbedReplacedWithInfo() const { - return _tabbedReplacedWithInfo; - } - void setTabbedReplacedWithInfo(bool enabled); - [[nodiscard]] rpl::producer tabbedReplacedWithInfoValue() const; - void setSmallDialogsList(bool enabled) { - _variables.smallDialogsList = enabled; - } - [[nodiscard]] bool smallDialogsList() const { - return _variables.smallDialogsList; - } - void setSoundOverride(const QString &key, const QString &path) { - _variables.soundOverrides.insert(key, path); - } - void clearSoundOverrides() { - _variables.soundOverrides.clear(); - } - [[nodiscard]] QString getSoundPath(const QString &key) const; - void setTabbedSelectorSectionTooltipShown(int shown) { - _variables.tabbedSelectorSectionTooltipShown = shown; - } - [[nodiscard]] int tabbedSelectorSectionTooltipShown() const { - return _variables.tabbedSelectorSectionTooltipShown; - } - void setFloatPlayerColumn(Window::Column column) { - _variables.floatPlayerColumn = column; - } - [[nodiscard]] Window::Column floatPlayerColumn() const { - return _variables.floatPlayerColumn; - } - void setFloatPlayerCorner(RectPart corner) { - _variables.floatPlayerCorner = corner; - } - [[nodiscard]] RectPart floatPlayerCorner() const { - return _variables.floatPlayerCorner; - } - void setDialogsWidthRatio(float64 ratio); - [[nodiscard]] float64 dialogsWidthRatio() const; - [[nodiscard]] rpl::producer dialogsWidthRatioChanges() const; - void setThirdColumnWidth(int width); - [[nodiscard]] int thirdColumnWidth() const; - [[nodiscard]] rpl::producer thirdColumnWidthChanges() const; - - void setGroupStickersSectionHidden(PeerId peerId) { - _variables.groupStickersSectionHidden.insert(peerId); - } - [[nodiscard]] bool isGroupStickersSectionHidden(PeerId peerId) const { - return _variables.groupStickersSectionHidden.contains(peerId); - } - void removeGroupStickersSectionHidden(PeerId peerId) { - _variables.groupStickersSectionHidden.remove(peerId); - } - - [[nodiscard]] Data::AutoDownload::Full &autoDownload() { - return _variables.autoDownload; - } - [[nodiscard]] const Data::AutoDownload::Full &autoDownload() const { - return _variables.autoDownload; - } - - void setArchiveCollapsed(bool collapsed); - [[nodiscard]] bool archiveCollapsed() const; - [[nodiscard]] rpl::producer archiveCollapsedChanges() const; - - void setArchiveInMainMenu(bool inMainMenu); - [[nodiscard]] bool archiveInMainMenu() const; - [[nodiscard]] rpl::producer archiveInMainMenuChanges() const; - - void setNotifyAboutPinned(bool notify); - [[nodiscard]] bool notifyAboutPinned() const; - [[nodiscard]] rpl::producer notifyAboutPinnedChanges() const; - - void setSkipArchiveInSearch(bool skip); - [[nodiscard]] bool skipArchiveInSearch() const; - [[nodiscard]] rpl::producer skipArchiveInSearchChanges() const; - - [[nodiscard]] bool hadLegacyCallsPeerToPeerNobody() const { - return _variables.hadLegacyCallsPeerToPeerNobody; - } - - [[nodiscard]] bool includeMutedCounter() const { - return _variables.includeMutedCounter; - } - void setIncludeMutedCounter(bool value) { - _variables.includeMutedCounter = value; - } - [[nodiscard]] bool countUnreadMessages() const { - return _variables.countUnreadMessages; - } - void setCountUnreadMessages(bool value) { - _variables.countUnreadMessages = value; - } - [[nodiscard]] bool exeLaunchWarning() const { - return _variables.exeLaunchWarning; - } - void setExeLaunchWarning(bool warning) { - _variables.exeLaunchWarning = warning; - } - [[nodiscard]] bool autoplayGifs() const { - return _variables.autoplayGifs; - } - void setAutoplayGifs(bool value) { - _variables.autoplayGifs = value; - } - [[nodiscard]] bool loopAnimatedStickers() const { - return _variables.loopAnimatedStickers; - } - void setLoopAnimatedStickers(bool value) { - _variables.loopAnimatedStickers = value; - } - void setLargeEmoji(bool value); - [[nodiscard]] bool largeEmoji() const; - [[nodiscard]] rpl::producer largeEmojiValue() const; - [[nodiscard]] rpl::producer largeEmojiChanges() const; - void setReplaceEmoji(bool value); - [[nodiscard]] bool replaceEmoji() const; - [[nodiscard]] rpl::producer replaceEmojiValue() const; - [[nodiscard]] rpl::producer replaceEmojiChanges() const; - [[nodiscard]] bool suggestEmoji() const { - return _variables.suggestEmoji; - } - void setSuggestEmoji(bool value) { - _variables.suggestEmoji = value; - } - [[nodiscard]] bool suggestStickersByEmoji() const { - return _variables.suggestStickersByEmoji; - } - void setSuggestStickersByEmoji(bool value) { - _variables.suggestStickersByEmoji = value; - } - -private: - struct Variables { - Variables(); - - static constexpr auto kDefaultDialogsWidthRatio = 5. / 14; - static constexpr auto kDefaultThirdColumnWidth = 0; - - bool lastSeenWarningSeen = false; - SendFilesWay sendFilesWay; - ChatHelpers::SelectorTab selectorTab; // per-window - bool tabbedSelectorSectionEnabled = false; // per-window - int tabbedSelectorSectionTooltipShown = 0; - QMap soundOverrides; - Window::Column floatPlayerColumn; // per-window - RectPart floatPlayerCorner; // per-window - base::flat_set groupStickersSectionHidden; - bool thirdSectionInfoEnabled = true; // per-window - bool smallDialogsList = false; // per-window - int thirdSectionExtendedBy = -1; // per-window - rpl::variable dialogsWidthRatio - = kDefaultDialogsWidthRatio; // per-window - rpl::variable thirdColumnWidth - = kDefaultThirdColumnWidth; // per-window - Ui::InputSubmitSettings sendSubmitWay; - bool hadLegacyCallsPeerToPeerNobody = false; - bool includeMutedCounter = true; - bool countUnreadMessages = true; - bool exeLaunchWarning = true; - Data::AutoDownload::Full autoDownload; - rpl::variable archiveCollapsed = false; - rpl::variable archiveInMainMenu = false; - rpl::variable notifyAboutPinned = true; - rpl::variable skipArchiveInSearch = false; - bool autoplayGifs = true; - bool loopAnimatedStickers = true; - rpl::variable largeEmoji = true; - rpl::variable replaceEmoji = true; - bool suggestEmoji = true; - bool suggestStickersByEmoji = true; - - static constexpr auto kDefaultSupportChatsLimitSlice - = 7 * 24 * 60 * 60; - - Support::SwitchSettings supportSwitch; - bool supportFixChatsOrder = true; - bool supportTemplatesAutocomplete = true; - rpl::variable supportChatsTimeSlice - = kDefaultSupportChatsLimitSlice; - rpl::variable supportAllSearchResults = false; - }; - - rpl::event_stream _thirdSectionInfoEnabledValue; - bool _tabbedReplacedWithInfo = false; - rpl::event_stream _tabbedReplacedWithInfoValue; - - Variables _variables; - -}; - class Session final : public base::has_weak_ptr , private base::Subscriber { @@ -337,54 +63,54 @@ public: Session(const Session &other) = delete; Session &operator=(const Session &other) = delete; - static bool Exists(); + [[nodiscard]] static bool Exists(); - Main::Account &account() const; + [[nodiscard]] Main::Account &account() const; - UserId userId() const; - PeerId userPeerId() const; - not_null user() const { + [[nodiscard]] UserId userId() const; + [[nodiscard]] PeerId userPeerId() const; + [[nodiscard]] not_null user() const { return _user; } bool validateSelf(const MTPUser &user); - Storage::Downloader &downloader() { + [[nodiscard]] Storage::Downloader &downloader() { return *_downloader; } - Storage::Uploader &uploader() { + [[nodiscard]] Storage::Uploader &uploader() { return *_uploader; } - Storage::Facade &storage() { + [[nodiscard]] Storage::Facade &storage() { return *_storage; } - Stickers::EmojiPack &emojiStickersPack() { + [[nodiscard]] Stickers::EmojiPack &emojiStickersPack() { return *_emojiStickersPack; } - AppConfig &appConfig() { + [[nodiscard]] AppConfig &appConfig() { return *_appConfig; } - base::Observable &downloaderTaskFinished(); + [[nodiscard]] base::Observable &downloaderTaskFinished(); - Window::Notifications::System ¬ifications() { + [[nodiscard]] Window::Notifications::System ¬ifications() { return *_notifications; } - Data::Session &data() { + [[nodiscard]] Data::Session &data() { return *_data; } - Settings &settings() { + [[nodiscard]] Settings &settings() { return _settings; } void moveSettingsFrom(Settings &&other); void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay); - not_null mtp(); - ApiWrap &api() { + [[nodiscard]] not_null mtp(); + [[nodiscard]] ApiWrap &api() { return *_api; } - Calls::Instance &calls() { + [[nodiscard]] Calls::Instance &calls() { return *_calls; } @@ -393,7 +119,7 @@ public: void localPasscodeChanged(); void termsDeleteNow(); - rpl::lifetime &lifetime() { + [[nodiscard]] rpl::lifetime &lifetime() { return _lifetime; } @@ -410,7 +136,7 @@ private: const not_null _account; Settings _settings; - base::Timer _saveDataTimer; + base::Timer _saveSettingsTimer; crl::time _shouldLockAt = 0; base::Timer _autoLockTimer; diff --git a/Telegram/SourceFiles/main/main_settings.cpp b/Telegram/SourceFiles/main/main_settings.cpp new file mode 100644 index 0000000000..52b719711f --- /dev/null +++ b/Telegram/SourceFiles/main/main_settings.cpp @@ -0,0 +1,490 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "main/main_settings.h" + +#include "chat_helpers/tabbed_selector.h" +#include "window/section_widget.h" +#include "ui/widgets/input_fields.h" +#include "support/support_common.h" +#include "storage/serialize_common.h" +#include "boxes/send_files_box.h" + +namespace Main { +namespace { + +constexpr auto kAutoLockTimeoutLateMs = crl::time(3000); +constexpr auto kLegacyCallsPeerToPeerNobody = 4; + +} // namespace + +Settings::Variables::Variables() +: sendFilesWay(SendFilesWay::Album) +, selectorTab(ChatHelpers::SelectorTab::Emoji) +, floatPlayerColumn(Window::Column::Second) +, floatPlayerCorner(RectPart::TopRight) +, sendSubmitWay(Ui::InputSubmitSettings::Enter) +, supportSwitch(Support::SwitchSettings::Next) { +} + +QByteArray Settings::serialize() const { + const auto autoDownload = _variables.autoDownload.serialize(); + auto size = sizeof(qint32) * 30; + for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) { + size += Serialize::stringSize(i.key()) + Serialize::stringSize(i.value()); + } + size += _variables.groupStickersSectionHidden.size() * sizeof(quint64); + size += Serialize::bytearraySize(autoDownload); + + auto result = QByteArray(); + result.reserve(size); + { + QDataStream stream(&result, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_1); + stream << static_cast(_variables.selectorTab); + stream << qint32(_variables.lastSeenWarningSeen ? 1 : 0); + stream << qint32(_variables.tabbedSelectorSectionEnabled ? 1 : 0); + stream << qint32(_variables.soundOverrides.size()); + for (auto i = _variables.soundOverrides.cbegin(), e = _variables.soundOverrides.cend(); i != e; ++i) { + stream << i.key() << i.value(); + } + stream << qint32(_variables.tabbedSelectorSectionTooltipShown); + stream << qint32(_variables.floatPlayerColumn); + stream << qint32(_variables.floatPlayerCorner); + stream << qint32(_variables.groupStickersSectionHidden.size()); + for (auto peerId : _variables.groupStickersSectionHidden) { + stream << quint64(peerId); + } + stream << qint32(_variables.thirdSectionInfoEnabled ? 1 : 0); + stream << qint32(_variables.smallDialogsList ? 1 : 0); + stream << qint32(snap( + qRound(_variables.dialogsWidthRatio.current() * 1000000), + 0, + 1000000)); + stream << qint32(_variables.thirdColumnWidth.current()); + stream << qint32(_variables.thirdSectionExtendedBy); + stream << qint32(_variables.sendFilesWay); + stream << qint32(0);// LEGACY _variables.callsPeerToPeer.current()); + stream << qint32(_variables.sendSubmitWay); + stream << qint32(_variables.supportSwitch); + stream << qint32(_variables.supportFixChatsOrder ? 1 : 0); + stream << qint32(_variables.supportTemplatesAutocomplete ? 1 : 0); + stream << qint32(_variables.supportChatsTimeSlice.current()); + stream << qint32(_variables.includeMutedCounter ? 1 : 0); + stream << qint32(_variables.countUnreadMessages ? 1 : 0); + stream << qint32(_variables.exeLaunchWarning ? 1 : 0); + stream << autoDownload; + stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0); + stream << qint32(_variables.archiveCollapsed.current() ? 1 : 0); + stream << qint32(_variables.notifyAboutPinned.current() ? 1 : 0); + stream << qint32(_variables.archiveInMainMenu.current() ? 1 : 0); + stream << qint32(_variables.skipArchiveInSearch.current() ? 1 : 0); + stream << qint32(_variables.autoplayGifs ? 1 : 0); + stream << qint32(_variables.loopAnimatedStickers ? 1 : 0); + stream << qint32(_variables.largeEmoji.current() ? 1 : 0); + stream << qint32(_variables.replaceEmoji.current() ? 1 : 0); + stream << qint32(_variables.suggestEmoji ? 1 : 0); + stream << qint32(_variables.suggestStickersByEmoji ? 1 : 0); + } + return result; +} + +void Settings::constructFromSerialized(const QByteArray &serialized) { + if (serialized.isEmpty()) { + return; + } + + QDataStream stream(serialized); + stream.setVersion(QDataStream::Qt_5_1); + qint32 selectorTab = static_cast(ChatHelpers::SelectorTab::Emoji); + qint32 lastSeenWarningSeen = 0; + qint32 tabbedSelectorSectionEnabled = 1; + qint32 tabbedSelectorSectionTooltipShown = 0; + qint32 floatPlayerColumn = static_cast(Window::Column::Second); + qint32 floatPlayerCorner = static_cast(RectPart::TopRight); + QMap soundOverrides; + base::flat_set groupStickersSectionHidden; + qint32 thirdSectionInfoEnabled = 0; + qint32 smallDialogsList = 0; + float64 dialogsWidthRatio = _variables.dialogsWidthRatio.current(); + int thirdColumnWidth = _variables.thirdColumnWidth.current(); + int thirdSectionExtendedBy = _variables.thirdSectionExtendedBy; + qint32 sendFilesWay = static_cast(_variables.sendFilesWay); + qint32 legacyCallsPeerToPeer = qint32(0); + qint32 sendSubmitWay = static_cast(_variables.sendSubmitWay); + qint32 supportSwitch = static_cast(_variables.supportSwitch); + qint32 supportFixChatsOrder = _variables.supportFixChatsOrder ? 1 : 0; + qint32 supportTemplatesAutocomplete = _variables.supportTemplatesAutocomplete ? 1 : 0; + qint32 supportChatsTimeSlice = _variables.supportChatsTimeSlice.current(); + qint32 includeMutedCounter = _variables.includeMutedCounter ? 1 : 0; + qint32 countUnreadMessages = _variables.countUnreadMessages ? 1 : 0; + qint32 exeLaunchWarning = _variables.exeLaunchWarning ? 1 : 0; + QByteArray autoDownload; + qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0; + qint32 archiveCollapsed = _variables.archiveCollapsed.current() ? 1 : 0; + qint32 notifyAboutPinned = _variables.notifyAboutPinned.current() ? 1 : 0; + qint32 archiveInMainMenu = _variables.archiveInMainMenu.current() ? 1 : 0; + qint32 skipArchiveInSearch = _variables.skipArchiveInSearch.current() ? 1 : 0; + qint32 autoplayGifs = _variables.autoplayGifs ? 1 : 0; + qint32 loopAnimatedStickers = _variables.loopAnimatedStickers ? 1 : 0; + qint32 largeEmoji = _variables.largeEmoji.current() ? 1 : 0; + qint32 replaceEmoji = _variables.replaceEmoji.current() ? 1 : 0; + qint32 suggestEmoji = _variables.suggestEmoji ? 1 : 0; + qint32 suggestStickersByEmoji = _variables.suggestStickersByEmoji ? 1 : 0; + + stream >> selectorTab; + stream >> lastSeenWarningSeen; + if (!stream.atEnd()) { + stream >> tabbedSelectorSectionEnabled; + } + if (!stream.atEnd()) { + auto count = qint32(0); + stream >> count; + if (stream.status() == QDataStream::Ok) { + for (auto i = 0; i != count; ++i) { + QString key, value; + stream >> key >> value; + soundOverrides[key] = value; + } + } + } + if (!stream.atEnd()) { + stream >> tabbedSelectorSectionTooltipShown; + } + if (!stream.atEnd()) { + stream >> floatPlayerColumn >> floatPlayerCorner; + } + if (!stream.atEnd()) { + auto count = qint32(0); + stream >> count; + if (stream.status() == QDataStream::Ok) { + for (auto i = 0; i != count; ++i) { + quint64 peerId; + stream >> peerId; + groupStickersSectionHidden.insert(peerId); + } + } + } + if (!stream.atEnd()) { + stream >> thirdSectionInfoEnabled; + stream >> smallDialogsList; + } + if (!stream.atEnd()) { + qint32 value = 0; + stream >> value; + dialogsWidthRatio = snap(value / 1000000., 0., 1.); + + stream >> value; + thirdColumnWidth = value; + + stream >> value; + thirdSectionExtendedBy = value; + } + if (!stream.atEnd()) { + stream >> sendFilesWay; + } + if (!stream.atEnd()) { + stream >> legacyCallsPeerToPeer; + } + if (!stream.atEnd()) { + stream >> sendSubmitWay; + stream >> supportSwitch; + stream >> supportFixChatsOrder; + } + if (!stream.atEnd()) { + stream >> supportTemplatesAutocomplete; + } + if (!stream.atEnd()) { + stream >> supportChatsTimeSlice; + } + if (!stream.atEnd()) { + stream >> includeMutedCounter; + stream >> countUnreadMessages; + } + if (!stream.atEnd()) { + stream >> exeLaunchWarning; + } + if (!stream.atEnd()) { + stream >> autoDownload; + } + if (!stream.atEnd()) { + stream >> supportAllSearchResults; + } + if (!stream.atEnd()) { + stream >> archiveCollapsed; + } + if (!stream.atEnd()) { + stream >> notifyAboutPinned; + } + if (!stream.atEnd()) { + stream >> archiveInMainMenu; + } + if (!stream.atEnd()) { + stream >> skipArchiveInSearch; + } + if (!stream.atEnd()) { + stream >> autoplayGifs; + stream >> loopAnimatedStickers; + stream >> largeEmoji; + stream >> replaceEmoji; + stream >> suggestEmoji; + stream >> suggestStickersByEmoji; + } + if (stream.status() != QDataStream::Ok) { + LOG(("App Error: " + "Bad data for Main::Settings::constructFromSerialized()")); + return; + } + if (!autoDownload.isEmpty() + && !_variables.autoDownload.setFromSerialized(autoDownload)) { + return; + } + + auto uncheckedTab = static_cast(selectorTab); + switch (uncheckedTab) { + case ChatHelpers::SelectorTab::Emoji: + case ChatHelpers::SelectorTab::Stickers: + case ChatHelpers::SelectorTab::Gifs: _variables.selectorTab = uncheckedTab; break; + } + _variables.lastSeenWarningSeen = (lastSeenWarningSeen == 1); + _variables.tabbedSelectorSectionEnabled = (tabbedSelectorSectionEnabled == 1); + _variables.soundOverrides = std::move(soundOverrides); + _variables.tabbedSelectorSectionTooltipShown = tabbedSelectorSectionTooltipShown; + auto uncheckedColumn = static_cast(floatPlayerColumn); + switch (uncheckedColumn) { + case Window::Column::First: + case Window::Column::Second: + case Window::Column::Third: _variables.floatPlayerColumn = uncheckedColumn; break; + } + auto uncheckedCorner = static_cast(floatPlayerCorner); + switch (uncheckedCorner) { + case RectPart::TopLeft: + case RectPart::TopRight: + case RectPart::BottomLeft: + case RectPart::BottomRight: _variables.floatPlayerCorner = uncheckedCorner; break; + } + _variables.groupStickersSectionHidden = std::move(groupStickersSectionHidden); + _variables.thirdSectionInfoEnabled = thirdSectionInfoEnabled; + _variables.smallDialogsList = smallDialogsList; + _variables.dialogsWidthRatio = dialogsWidthRatio; + _variables.thirdColumnWidth = thirdColumnWidth; + _variables.thirdSectionExtendedBy = thirdSectionExtendedBy; + if (_variables.thirdSectionInfoEnabled) { + _variables.tabbedSelectorSectionEnabled = false; + } + auto uncheckedSendFilesWay = static_cast(sendFilesWay); + switch (uncheckedSendFilesWay) { + case SendFilesWay::Album: + case SendFilesWay::Photos: + case SendFilesWay::Files: _variables.sendFilesWay = uncheckedSendFilesWay; break; + } + auto uncheckedSendSubmitWay = static_cast( + sendSubmitWay); + switch (uncheckedSendSubmitWay) { + case Ui::InputSubmitSettings::Enter: + case Ui::InputSubmitSettings::CtrlEnter: _variables.sendSubmitWay = uncheckedSendSubmitWay; break; + } + auto uncheckedSupportSwitch = static_cast( + supportSwitch); + switch (uncheckedSupportSwitch) { + case Support::SwitchSettings::None: + case Support::SwitchSettings::Next: + case Support::SwitchSettings::Previous: _variables.supportSwitch = uncheckedSupportSwitch; break; + } + _variables.supportFixChatsOrder = (supportFixChatsOrder == 1); + _variables.supportTemplatesAutocomplete = (supportTemplatesAutocomplete == 1); + _variables.supportChatsTimeSlice = supportChatsTimeSlice; + _variables.hadLegacyCallsPeerToPeerNobody = (legacyCallsPeerToPeer == kLegacyCallsPeerToPeerNobody); + _variables.includeMutedCounter = (includeMutedCounter == 1); + _variables.countUnreadMessages = (countUnreadMessages == 1); + _variables.exeLaunchWarning = (exeLaunchWarning == 1); + _variables.supportAllSearchResults = (supportAllSearchResults == 1); + _variables.archiveCollapsed = (archiveCollapsed == 1); + _variables.notifyAboutPinned = (notifyAboutPinned == 1); + _variables.archiveInMainMenu = (archiveInMainMenu == 1); + _variables.skipArchiveInSearch = (skipArchiveInSearch == 1); + _variables.autoplayGifs = (autoplayGifs == 1); + _variables.loopAnimatedStickers = (loopAnimatedStickers == 1); + _variables.largeEmoji = (largeEmoji == 1); + _variables.replaceEmoji = (replaceEmoji == 1); + _variables.suggestEmoji = (suggestEmoji == 1); + _variables.suggestStickersByEmoji = (suggestStickersByEmoji == 1); +} + +void Settings::setSupportChatsTimeSlice(int slice) { + _variables.supportChatsTimeSlice = slice; +} + +int Settings::supportChatsTimeSlice() const { + return _variables.supportChatsTimeSlice.current(); +} + +rpl::producer Settings::supportChatsTimeSliceValue() const { + return _variables.supportChatsTimeSlice.value(); +} + +void Settings::setSupportAllSearchResults(bool all) { + _variables.supportAllSearchResults = all; +} + +bool Settings::supportAllSearchResults() const { + return _variables.supportAllSearchResults.current(); +} + +rpl::producer Settings::supportAllSearchResultsValue() const { + return _variables.supportAllSearchResults.value(); +} + +void Settings::setTabbedSelectorSectionEnabled(bool enabled) { + _variables.tabbedSelectorSectionEnabled = enabled; + if (enabled) { + setThirdSectionInfoEnabled(false); + } + setTabbedReplacedWithInfo(false); +} + +rpl::producer Settings::tabbedReplacedWithInfoValue() const { + return _tabbedReplacedWithInfoValue.events_starting_with( + tabbedReplacedWithInfo()); +} + +void Settings::setThirdSectionInfoEnabled(bool enabled) { + if (_variables.thirdSectionInfoEnabled != enabled) { + _variables.thirdSectionInfoEnabled = enabled; + if (enabled) { + setTabbedSelectorSectionEnabled(false); + } + setTabbedReplacedWithInfo(false); + _thirdSectionInfoEnabledValue.fire_copy(enabled); + } +} + +rpl::producer Settings::thirdSectionInfoEnabledValue() const { + return _thirdSectionInfoEnabledValue.events_starting_with( + thirdSectionInfoEnabled()); +} + +void Settings::setTabbedReplacedWithInfo(bool enabled) { + if (_tabbedReplacedWithInfo != enabled) { + _tabbedReplacedWithInfo = enabled; + _tabbedReplacedWithInfoValue.fire_copy(enabled); + } +} + +QString Settings::getSoundPath(const QString &key) const { + auto it = _variables.soundOverrides.constFind(key); + if (it != _variables.soundOverrides.end()) { + return it.value(); + } + return qsl(":/sounds/") + key + qsl(".mp3"); +} + +void Settings::setDialogsWidthRatio(float64 ratio) { + _variables.dialogsWidthRatio = ratio; +} + +float64 Settings::dialogsWidthRatio() const { + return _variables.dialogsWidthRatio.current(); +} + +rpl::producer Settings::dialogsWidthRatioChanges() const { + return _variables.dialogsWidthRatio.changes(); +} + +void Settings::setThirdColumnWidth(int width) { + _variables.thirdColumnWidth = width; +} + +int Settings::thirdColumnWidth() const { + return _variables.thirdColumnWidth.current(); +} + +rpl::producer Settings::thirdColumnWidthChanges() const { + return _variables.thirdColumnWidth.changes(); +} + +void Settings::setArchiveCollapsed(bool collapsed) { + _variables.archiveCollapsed = collapsed; +} + +bool Settings::archiveCollapsed() const { + return _variables.archiveCollapsed.current(); +} + +rpl::producer Settings::archiveCollapsedChanges() const { + return _variables.archiveCollapsed.changes(); +} + +void Settings::setArchiveInMainMenu(bool inMainMenu) { + _variables.archiveInMainMenu = inMainMenu; +} + +bool Settings::archiveInMainMenu() const { + return _variables.archiveInMainMenu.current(); +} + +rpl::producer Settings::archiveInMainMenuChanges() const { + return _variables.archiveInMainMenu.changes(); +} + +void Settings::setNotifyAboutPinned(bool notify) { + _variables.notifyAboutPinned = notify; +} + +bool Settings::notifyAboutPinned() const { + return _variables.notifyAboutPinned.current(); +} + +rpl::producer Settings::notifyAboutPinnedChanges() const { + return _variables.notifyAboutPinned.changes(); +} + +void Settings::setSkipArchiveInSearch(bool skip) { + _variables.skipArchiveInSearch = skip; +} + +bool Settings::skipArchiveInSearch() const { + return _variables.skipArchiveInSearch.current(); +} + +rpl::producer Settings::skipArchiveInSearchChanges() const { + return _variables.skipArchiveInSearch.changes(); +} + +void Settings::setLargeEmoji(bool value) { + _variables.largeEmoji = value; +} + +bool Settings::largeEmoji() const { + return _variables.largeEmoji.current(); +} + +rpl::producer Settings::largeEmojiValue() const { + return _variables.largeEmoji.value(); +} + +rpl::producer Settings::largeEmojiChanges() const { + return _variables.largeEmoji.changes(); +} + +void Settings::setReplaceEmoji(bool value) { + _variables.replaceEmoji = value; +} + +bool Settings::replaceEmoji() const { + return _variables.replaceEmoji.current(); +} + +rpl::producer Settings::replaceEmojiValue() const { + return _variables.replaceEmoji.value(); +} + +rpl::producer Settings::replaceEmojiChanges() const { + return _variables.replaceEmoji.changes(); +} + +} // namespace Main diff --git a/Telegram/SourceFiles/main/main_settings.h b/Telegram/SourceFiles/main/main_settings.h new file mode 100644 index 0000000000..3ba716653a --- /dev/null +++ b/Telegram/SourceFiles/main/main_settings.h @@ -0,0 +1,295 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "data/data_auto_download.h" + +enum class SendFilesWay; + +namespace Ui { +enum class InputSubmitSettings; +} // namespace Ui + +namespace Support { +enum class SwitchSettings; +} // namespace Support + +namespace Window { +enum class Column; +} // namespace Window + +namespace ChatHelpers { +enum class SelectorTab; +} // namespace ChatHelpers + +namespace Main { + +class Settings final { +public: + void moveFrom(Settings &&other) { + _variables = std::move(other._variables); + } + [[nodiscard]] QByteArray serialize() const; + void constructFromSerialized(const QByteArray &serialized); + + void setLastSeenWarningSeen(bool lastSeenWarningSeen) { + _variables.lastSeenWarningSeen = lastSeenWarningSeen; + } + [[nodiscard]] bool lastSeenWarningSeen() const { + return _variables.lastSeenWarningSeen; + } + void setSendFilesWay(SendFilesWay way) { + _variables.sendFilesWay = way; + } + [[nodiscard]] SendFilesWay sendFilesWay() const { + return _variables.sendFilesWay; + } + void setSendSubmitWay(Ui::InputSubmitSettings value) { + _variables.sendSubmitWay = value; + } + [[nodiscard]] Ui::InputSubmitSettings sendSubmitWay() const { + return _variables.sendSubmitWay; + } + + void setSupportSwitch(Support::SwitchSettings value) { + _variables.supportSwitch = value; + } + [[nodiscard]] Support::SwitchSettings supportSwitch() const { + return _variables.supportSwitch; + } + void setSupportFixChatsOrder(bool fix) { + _variables.supportFixChatsOrder = fix; + } + [[nodiscard]] bool supportFixChatsOrder() const { + return _variables.supportFixChatsOrder; + } + void setSupportTemplatesAutocomplete(bool enabled) { + _variables.supportTemplatesAutocomplete = enabled; + } + [[nodiscard]] bool supportTemplatesAutocomplete() const { + return _variables.supportTemplatesAutocomplete; + } + void setSupportChatsTimeSlice(int slice); + [[nodiscard]] int supportChatsTimeSlice() const; + [[nodiscard]] rpl::producer supportChatsTimeSliceValue() const; + void setSupportAllSearchResults(bool all); + [[nodiscard]] bool supportAllSearchResults() const; + [[nodiscard]] rpl::producer supportAllSearchResultsValue() const; + + [[nodiscard]] ChatHelpers::SelectorTab selectorTab() const { + return _variables.selectorTab; + } + void setSelectorTab(ChatHelpers::SelectorTab tab) { + _variables.selectorTab = tab; + } + [[nodiscard]] bool tabbedSelectorSectionEnabled() const { + return _variables.tabbedSelectorSectionEnabled; + } + void setTabbedSelectorSectionEnabled(bool enabled); + [[nodiscard]] bool thirdSectionInfoEnabled() const { + return _variables.thirdSectionInfoEnabled; + } + void setThirdSectionInfoEnabled(bool enabled); + [[nodiscard]] rpl::producer thirdSectionInfoEnabledValue() const; + [[nodiscard]] int thirdSectionExtendedBy() const { + return _variables.thirdSectionExtendedBy; + } + void setThirdSectionExtendedBy(int savedValue) { + _variables.thirdSectionExtendedBy = savedValue; + } + [[nodiscard]] bool tabbedReplacedWithInfo() const { + return _tabbedReplacedWithInfo; + } + void setTabbedReplacedWithInfo(bool enabled); + [[nodiscard]] rpl::producer tabbedReplacedWithInfoValue() const; + void setSmallDialogsList(bool enabled) { + _variables.smallDialogsList = enabled; + } + [[nodiscard]] bool smallDialogsList() const { + return _variables.smallDialogsList; + } + void setSoundOverride(const QString &key, const QString &path) { + _variables.soundOverrides.insert(key, path); + } + void clearSoundOverrides() { + _variables.soundOverrides.clear(); + } + [[nodiscard]] QString getSoundPath(const QString &key) const; + void setTabbedSelectorSectionTooltipShown(int shown) { + _variables.tabbedSelectorSectionTooltipShown = shown; + } + [[nodiscard]] int tabbedSelectorSectionTooltipShown() const { + return _variables.tabbedSelectorSectionTooltipShown; + } + void setFloatPlayerColumn(Window::Column column) { + _variables.floatPlayerColumn = column; + } + [[nodiscard]] Window::Column floatPlayerColumn() const { + return _variables.floatPlayerColumn; + } + void setFloatPlayerCorner(RectPart corner) { + _variables.floatPlayerCorner = corner; + } + [[nodiscard]] RectPart floatPlayerCorner() const { + return _variables.floatPlayerCorner; + } + void setDialogsWidthRatio(float64 ratio); + [[nodiscard]] float64 dialogsWidthRatio() const; + [[nodiscard]] rpl::producer dialogsWidthRatioChanges() const; + void setThirdColumnWidth(int width); + [[nodiscard]] int thirdColumnWidth() const; + [[nodiscard]] rpl::producer thirdColumnWidthChanges() const; + + void setGroupStickersSectionHidden(PeerId peerId) { + _variables.groupStickersSectionHidden.insert(peerId); + } + [[nodiscard]] bool isGroupStickersSectionHidden(PeerId peerId) const { + return _variables.groupStickersSectionHidden.contains(peerId); + } + void removeGroupStickersSectionHidden(PeerId peerId) { + _variables.groupStickersSectionHidden.remove(peerId); + } + + [[nodiscard]] Data::AutoDownload::Full &autoDownload() { + return _variables.autoDownload; + } + [[nodiscard]] const Data::AutoDownload::Full &autoDownload() const { + return _variables.autoDownload; + } + + void setArchiveCollapsed(bool collapsed); + [[nodiscard]] bool archiveCollapsed() const; + [[nodiscard]] rpl::producer archiveCollapsedChanges() const; + + void setArchiveInMainMenu(bool inMainMenu); + [[nodiscard]] bool archiveInMainMenu() const; + [[nodiscard]] rpl::producer archiveInMainMenuChanges() const; + + void setNotifyAboutPinned(bool notify); + [[nodiscard]] bool notifyAboutPinned() const; + [[nodiscard]] rpl::producer notifyAboutPinnedChanges() const; + + void setSkipArchiveInSearch(bool skip); + [[nodiscard]] bool skipArchiveInSearch() const; + [[nodiscard]] rpl::producer skipArchiveInSearchChanges() const; + + [[nodiscard]] bool hadLegacyCallsPeerToPeerNobody() const { + return _variables.hadLegacyCallsPeerToPeerNobody; + } + + [[nodiscard]] bool includeMutedCounter() const { + return _variables.includeMutedCounter; + } + void setIncludeMutedCounter(bool value) { + _variables.includeMutedCounter = value; + } + [[nodiscard]] bool countUnreadMessages() const { + return _variables.countUnreadMessages; + } + void setCountUnreadMessages(bool value) { + _variables.countUnreadMessages = value; + } + [[nodiscard]] bool exeLaunchWarning() const { + return _variables.exeLaunchWarning; + } + void setExeLaunchWarning(bool warning) { + _variables.exeLaunchWarning = warning; + } + [[nodiscard]] bool autoplayGifs() const { + return _variables.autoplayGifs; + } + void setAutoplayGifs(bool value) { + _variables.autoplayGifs = value; + } + [[nodiscard]] bool loopAnimatedStickers() const { + return _variables.loopAnimatedStickers; + } + void setLoopAnimatedStickers(bool value) { + _variables.loopAnimatedStickers = value; + } + void setLargeEmoji(bool value); + [[nodiscard]] bool largeEmoji() const; + [[nodiscard]] rpl::producer largeEmojiValue() const; + [[nodiscard]] rpl::producer largeEmojiChanges() const; + void setReplaceEmoji(bool value); + [[nodiscard]] bool replaceEmoji() const; + [[nodiscard]] rpl::producer replaceEmojiValue() const; + [[nodiscard]] rpl::producer replaceEmojiChanges() const; + [[nodiscard]] bool suggestEmoji() const { + return _variables.suggestEmoji; + } + void setSuggestEmoji(bool value) { + _variables.suggestEmoji = value; + } + [[nodiscard]] bool suggestStickersByEmoji() const { + return _variables.suggestStickersByEmoji; + } + void setSuggestStickersByEmoji(bool value) { + _variables.suggestStickersByEmoji = value; + } + +private: + struct Variables { + Variables(); + + static constexpr auto kDefaultDialogsWidthRatio = 5. / 14; + static constexpr auto kDefaultThirdColumnWidth = 0; + + bool lastSeenWarningSeen = false; + SendFilesWay sendFilesWay; + ChatHelpers::SelectorTab selectorTab; // per-window + bool tabbedSelectorSectionEnabled = false; // per-window + int tabbedSelectorSectionTooltipShown = 0; + QMap soundOverrides; + Window::Column floatPlayerColumn; // per-window + RectPart floatPlayerCorner; // per-window + base::flat_set groupStickersSectionHidden; + bool thirdSectionInfoEnabled = true; // per-window + bool smallDialogsList = false; // per-window + int thirdSectionExtendedBy = -1; // per-window + rpl::variable dialogsWidthRatio + = kDefaultDialogsWidthRatio; // per-window + rpl::variable thirdColumnWidth + = kDefaultThirdColumnWidth; // per-window + Ui::InputSubmitSettings sendSubmitWay; + bool hadLegacyCallsPeerToPeerNobody = false; + bool includeMutedCounter = true; + bool countUnreadMessages = true; + bool exeLaunchWarning = true; + Data::AutoDownload::Full autoDownload; + rpl::variable archiveCollapsed = false; + rpl::variable archiveInMainMenu = false; + rpl::variable notifyAboutPinned = true; + rpl::variable skipArchiveInSearch = false; + bool autoplayGifs = true; + bool loopAnimatedStickers = true; + rpl::variable largeEmoji = true; + rpl::variable replaceEmoji = true; + bool suggestEmoji = true; + bool suggestStickersByEmoji = true; + + static constexpr auto kDefaultSupportChatsLimitSlice + = 7 * 24 * 60 * 60; + + Support::SwitchSettings supportSwitch; + bool supportFixChatsOrder = true; + bool supportTemplatesAutocomplete = true; + rpl::variable supportChatsTimeSlice + = kDefaultSupportChatsLimitSlice; + rpl::variable supportAllSearchResults = false; + }; + + rpl::event_stream _thirdSectionInfoEnabledValue; + bool _tabbedReplacedWithInfo = false; + rpl::event_stream _tabbedReplacedWithInfoValue; + + Variables _variables; + +}; + +} // namespace Main diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 39bc72618d..34739decb8 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -28,10 +28,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "window/themes/window_theme_editor.h" #include "window/themes/window_theme.h" +#include "window/themes/window_themes_embedded.h" #include "window/window_session_controller.h" #include "info/profile/info_profile_button.h" #include "storage/localstorage.h" #include "core/file_utilities.h" +#include "core/application.h" #include "data/data_session.h" #include "chat_helpers/emoji_sets_manager.h" #include "platform/platform_info.h" @@ -43,58 +45,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_boxes.h" namespace Settings { -namespace { - -const auto kColorizeIgnoredKeys = base::flat_set{ { - qstr("boxTextFgGood"), - qstr("boxTextFgError"), - qstr("historyPeer1NameFg"), - qstr("historyPeer1NameFgSelected"), - qstr("historyPeer1UserpicBg"), - qstr("historyPeer2NameFg"), - qstr("historyPeer2NameFgSelected"), - qstr("historyPeer2UserpicBg"), - qstr("historyPeer3NameFg"), - qstr("historyPeer3NameFgSelected"), - qstr("historyPeer3UserpicBg"), - qstr("historyPeer4NameFg"), - qstr("historyPeer4NameFgSelected"), - qstr("historyPeer4UserpicBg"), - qstr("historyPeer5NameFg"), - qstr("historyPeer5NameFgSelected"), - qstr("historyPeer5UserpicBg"), - qstr("historyPeer6NameFg"), - qstr("historyPeer6NameFgSelected"), - qstr("historyPeer6UserpicBg"), - qstr("historyPeer7NameFg"), - qstr("historyPeer7NameFgSelected"), - qstr("historyPeer7UserpicBg"), - qstr("historyPeer8NameFg"), - qstr("historyPeer8NameFgSelected"), - qstr("historyPeer8UserpicBg"), - qstr("msgFile1Bg"), - qstr("msgFile1BgDark"), - qstr("msgFile1BgOver"), - qstr("msgFile1BgSelected"), - qstr("msgFile2Bg"), - qstr("msgFile2BgDark"), - qstr("msgFile2BgOver"), - qstr("msgFile2BgSelected"), - qstr("msgFile3Bg"), - qstr("msgFile3BgDark"), - qstr("msgFile3BgOver"), - qstr("msgFile3BgSelected"), - qstr("msgFile4Bg"), - qstr("msgFile4BgDark"), - qstr("msgFile4BgOver"), - qstr("msgFile4BgSelected"), - qstr("mediaviewFileRedCornerFg"), - qstr("mediaviewFileYellowCornerFg"), - qstr("mediaviewFileGreenCornerFg"), - qstr("mediaviewFileBlueCornerFg"), -} }; - -} // namespace class BackgroundRow : public Ui::RpWidget { public: @@ -127,23 +77,9 @@ private: class DefaultTheme final : public Ui::AbstractCheckView { public: - enum class Type { - DayBlue, - Default, - Night, - NightGreen, - }; - struct Scheme { - Type type = Type(); - QColor background; - QColor sent; - QColor received; - QColor radiobuttonInactive; - QColor radiobuttonActive; - tr::phrase<> name; - QString path; - QColor accentColor; - }; + using Type = Window::Theme::EmbeddedType; + using Scheme = Window::Theme::EmbeddedScheme; + DefaultTheme(Scheme scheme, bool checked); QSize getSize() const override; @@ -155,10 +91,13 @@ public: QImage prepareRippleMask() const override; bool checkRippleStartPosition(QPoint position) const override; + void setColorizer(const Window::Theme::Colorizer *colorizer); + private: void checkedChangedHook(anim::type animated) override; Scheme _scheme; + Scheme _colorized; Ui::RadioView _radio; }; @@ -369,8 +308,17 @@ DefaultTheme::DefaultTheme(Scheme scheme, bool checked) : AbstractCheckView(st::defaultRadio.duration, checked, nullptr) , _scheme(scheme) , _radio(st::defaultRadio, checked, [=] { update(); }) { - _radio.setToggledOverride(_scheme.radiobuttonActive); - _radio.setUntoggledOverride(_scheme.radiobuttonInactive); + setColorizer(nullptr); +} + +void DefaultTheme::setColorizer(const Window::Theme::Colorizer *colorizer) { + _colorized = _scheme; + if (colorizer) { + Window::Theme::Colorize(_colorized, colorizer); + } + _radio.setToggledOverride(_colorized.radiobuttonActive); + _radio.setUntoggledOverride(_colorized.radiobuttonInactive); + update(); } QSize DefaultTheme::getSize() const { @@ -394,13 +342,13 @@ void DefaultTheme::paint( p.fillRect( QRect(QPoint(), st::settingsThemePreviewSize), - _scheme.background); + _colorized.background); PainterHighQualityEnabler hq(p); p.setPen(Qt::NoPen); - p.setBrush(_scheme.received); + p.setBrush(_colorized.received); p.drawRoundedRect(rtlrect(received, outerWidth), radius, radius); - p.setBrush(_scheme.sent); + p.setBrush(_colorized.sent); p.drawRoundedRect(rtlrect(sent, outerWidth), radius, radius); const auto radio = _radio.getSize(); @@ -824,79 +772,13 @@ void SetupDefaultThemes(not_null container) { using Scheme = DefaultTheme::Scheme; const auto block = container->add(object_ptr( container)); - const auto scheme = DefaultTheme::Scheme(); - const auto color = [](str_const hex) { - Expects(hex.size() == 6); - - const auto component = [](char a, char b) { - const auto convert = [](char ch) { - Expects((ch >= '0' && ch <= '9') - || (ch >= 'A' && ch <= 'F') - || (ch >= 'a' && ch <= 'f')); - - return (ch >= '0' && ch <= '9') - ? int(ch - '0') - : int(ch - ((ch >= 'A' && ch <= 'F') ? 'A' : 'a') + 10); - }; - return convert(a) * 16 + convert(b); - }; - - return QColor( - component(hex[0], hex[1]), - component(hex[2], hex[3]), - component(hex[4], hex[5])); - }; - static const auto schemes = { - Scheme{ - Type::DayBlue, - color("7ec4ea"), - color("d7f0ff"), - color("ffffff"), - color("d7f0ff"), - color("ffffff"), - tr::lng_settings_theme_blue, - ":/gui/day-blue.tdesktop-theme", - color("40a7e3") - }, - Scheme{ - Type::Default, - color("90ce89"), - color("eaffdc"), - color("ffffff"), - color("eaffdc"), - color("ffffff"), - tr::lng_settings_theme_classic, - QString() - }, - Scheme{ - Type::Night, - color("485761"), - color("5ca7d4"), - color("6b808d"), - color("6b808d"), - color("5ca7d4"), - tr::lng_settings_theme_midnight, - ":/gui/night.tdesktop-theme", - color("5288c1") - }, - Scheme{ - Type::NightGreen, - color("485761"), - color("74bf93"), - color("6b808d"), - color("6b808d"), - color("74bf93"), - tr::lng_settings_theme_matrix, - ":/gui/night-green.tdesktop-theme", - color("3fc1b0") - }, - }; - const auto chosen = [&] { + static const auto SchemesList = Window::Theme::EmbeddedThemes(); + const auto chosen = [] { if (Window::Theme::IsNonDefaultBackground()) { return Type(-1); } const auto path = Window::Theme::Background()->themeAbsolutePath(); - for (const auto &scheme : schemes) { + for (const auto &scheme : SchemesList) { if (path == scheme.path) { return scheme.type; } @@ -922,23 +804,26 @@ void SetupDefaultThemes(not_null container) { Window::Theme::KeepApplied(); } }; + const auto applyWithColor = [=]( + const Scheme &scheme, + const QColor &color) { + const auto colorizer = Window::Theme::ColorizerFrom( + scheme, + color); + apply(scheme, &colorizer); + }; const auto applyWithColorize = [=](const Scheme &scheme) { + const auto &colors = Core::App().settings().themesAccentColors(); + const auto color = colors.get(scheme.type); const auto box = Ui::show(Box( "Choose accent color", - scheme.accentColor)); + color.value_or(scheme.accentColor))); box->setSaveCallback([=](QColor result) { - auto colorizer = Window::Theme::Colorizer(); - colorizer.ignoreKeys = kColorizeIgnoredKeys; - colorizer.hueThreshold = 10; - scheme.accentColor.getHsv( - &colorizer.wasHue, - &colorizer.wasSaturation, - &colorizer.wasValue); - result.getHsv( - &colorizer.nowHue, - &colorizer.nowSaturation, - &colorizer.nowValue); - apply(scheme, &colorizer); + Core::App().settings().themesAccentColors().set( + scheme.type, + result); + Core::App().saveSettingsDelayed(); + applyWithColor(scheme, result); }); }; const auto schemeClicked = [=]( @@ -947,12 +832,18 @@ void SetupDefaultThemes(not_null container) { if (scheme.accentColor.hue() && (modifiers & Qt::ControlModifier)) { applyWithColorize(scheme); } else { - apply(scheme); + const auto &colors = Core::App().settings().themesAccentColors(); + if (const auto color = colors.get(scheme.type)) { + applyWithColor(scheme, *color); + } else { + apply(scheme); + } } }; + auto checks = base::flat_map>(); auto buttons = ranges::view::all( - schemes + SchemesList ) | ranges::view::transform([&](const Scheme &scheme) { auto check = std::make_unique(scheme, false); const auto weak = check.get(); @@ -967,9 +858,30 @@ void SetupDefaultThemes(not_null container) { schemeClicked(scheme, result->clickModifiers()); }); weak->setUpdateCallback([=] { result->update(); }); + checks.emplace(scheme.type, weak); return result; }) | ranges::to_vector; + const auto refreshColorizer = [=](Type type) { + const auto &colors = Core::App().settings().themesAccentColors(); + const auto i = checks.find(type); + const auto scheme = ranges::find(SchemesList, type, &Scheme::type); + if (i != end(checks) && scheme != end(SchemesList)) { + if (const auto color = colors.get(type)) { + const auto colorizer = Window::Theme::ColorizerFrom( + *scheme, + *color); + i->second->setColorizer(&colorizer); + } else { + i->second->setColorizer(nullptr); + } + } + }; + + for (const auto &scheme : SchemesList) { + refreshColorizer(scheme.type); + } + using Update = const Window::Theme::BackgroundUpdate; base::ObservableViewer( *Window::Theme::Background() @@ -979,6 +891,7 @@ void SetupDefaultThemes(not_null container) { }) | rpl::map([=] { return chosen(); }) | rpl::start_with_next([=](Type type) { + refreshColorizer(type); group->setValue(type); }, container->lifetime()); @@ -1025,6 +938,12 @@ void SetupDefaultThemes(not_null container) { } }, block->lifetime()); + const auto colors = container->add( + object_ptr>( + container, + object_ptr( + container))); + AddSkip(container); } diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 478747694e..eb86cd2f1a 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -616,6 +616,7 @@ enum { dbiCallSettings = 0x5b, dbiCacheSettings = 0x5c, dbiTxtDomainString = 0x5d, + dbiApplicationSettings = 0x5e, dbiEncryptedWithSalt = 333, dbiEncrypted = 444, @@ -927,6 +928,14 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting context.dcOptions.constructFromSerialized(serialized); } break; + case dbiApplicationSettings: { + auto serialized = QByteArray(); + stream >> serialized; + if (!_checkStreamStatus(stream)) return false; + + Core::App().settings().constructFromSerialized(serialized); + } break; + case dbiChatSizeMax: { qint32 maxSize; stream >> maxSize; @@ -2618,10 +2627,12 @@ void writeSettings() { } settings.writeData(_settingsSalt); - auto dcOptionsSerialized = Core::App().dcOptions()->serialize(); + const auto dcOptionsSerialized = Core::App().dcOptions()->serialize(); + const auto applicationSettings = Core::App().settings().serialize(); quint32 size = 12 * (sizeof(quint32) + sizeof(qint32)); size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized); + size += sizeof(quint32) + Serialize::bytearraySize(applicationSettings); size += sizeof(quint32) + Serialize::stringSize(cLoggedPhoneNumber()); size += sizeof(quint32) + Serialize::stringSize(Global::TxtDomainString()); @@ -2660,6 +2671,7 @@ void writeSettings() { data.stream << quint32(dbiLastUpdateCheck) << qint32(cLastUpdateCheck()); data.stream << quint32(dbiScalePercent) << qint32(cConfigScale()); data.stream << quint32(dbiDcOptions) << dcOptionsSerialized; + data.stream << quint32(dbiApplicationSettings) << applicationSettings; data.stream << quint32(dbiLoggedPhoneNumber) << cLoggedPhoneNumber(); data.stream << quint32(dbiTxtDomainString) << Global::TxtDomainString(); data.stream << quint32(dbiAnimationsDisabled) << qint32(anim::Disabled() ? 1 : 0); diff --git a/Telegram/SourceFiles/storage/serialize_common.cpp b/Telegram/SourceFiles/storage/serialize_common.cpp index 3da99d45fd..00ed57147f 100644 --- a/Telegram/SourceFiles/storage/serialize_common.cpp +++ b/Telegram/SourceFiles/storage/serialize_common.cpp @@ -21,6 +21,23 @@ constexpr auto kModernImageLocationTag = std::numeric_limits::min(); } // namespace +void writeColor(QDataStream &stream, const QColor &color) { + stream << (quint32(uchar(color.red())) + | (quint32(uchar(color.green())) << 8) + | (quint32(uchar(color.blue())) << 16) + | (quint32(uchar(color.alpha())) << 24)); +} + +QColor readColor(QDataStream &stream) { + auto value = quint32(); + stream >> value; + return QColor( + int(value & 0xFFU), + int((value >> 8) & 0xFFU), + int((value >> 16) & 0xFFU), + int((value >> 24) & 0xFFU)); +} + std::optional readLegacyStorageImageLocationOrTag( int streamAppVersion, QDataStream &stream) { diff --git a/Telegram/SourceFiles/storage/serialize_common.h b/Telegram/SourceFiles/storage/serialize_common.h index 9b6eaed1c4..679c0fece4 100644 --- a/Telegram/SourceFiles/storage/serialize_common.h +++ b/Telegram/SourceFiles/storage/serialize_common.h @@ -23,6 +23,13 @@ inline int bytesSize(bytes::const_span bytes) { return sizeof(quint32) + bytes.size(); } +inline int colorSize() { + return sizeof(quint32); +} + +void writeColor(QDataStream &stream, const QColor &color); +QColor readColor(QDataStream &stream); + struct ReadBytesVectorWrap { bytes::vector &bytes; }; diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp index 89fad322f6..a8472a6b38 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/themes/window_theme.h" #include "window/themes/window_theme_preview.h" +#include "window/themes/window_themes_embedded.h" #include "mainwidget.h" #include "main/main_session.h" #include "apiwrap.h" @@ -33,6 +34,7 @@ constexpr auto kThemeBackgroundSizeLimit = 4 * 1024 * 1024; constexpr auto kBackgroundSizeLimit = 25 * 1024 * 1024; constexpr auto kThemeSchemeSizeLimit = 1024 * 1024; constexpr auto kNightThemeFile = str_const(":/gui/night.tdesktop-theme"); +constexpr auto kMinimumTiledSize = 512; struct Applying { QString pathRelative; @@ -143,75 +145,6 @@ bool readNameAndValue(const char *&from, const char *end, QLatin1String *outName return true; } -void Colorize( - uchar &r, - uchar &g, - uchar &b, - not_null colorizer) { - auto color = QColor(int(r), int(g), int(b)); - auto hue = 0; - auto saturation = 0; - auto value = 0; - color.getHsv(&hue, &saturation, &value); - const auto changeColor = std::abs(hue - colorizer->wasHue) - <= colorizer->hueThreshold; - const auto nowHue = hue + (colorizer->nowHue - colorizer->wasHue); - const auto nowSaturation = ((saturation > colorizer->wasSaturation) - && (colorizer->nowSaturation > colorizer->wasSaturation)) - ? (((colorizer->nowSaturation * (255 - colorizer->wasSaturation)) - + ((saturation - colorizer->wasSaturation) - * (255 - colorizer->nowSaturation))) - / (255 - colorizer->wasSaturation)) - : ((saturation != colorizer->wasSaturation) - && (colorizer->wasSaturation != 0)) - ? ((saturation * colorizer->nowSaturation) - / colorizer->wasSaturation) - : colorizer->nowSaturation; - const auto nowValue = (value > colorizer->wasValue) - ? (((colorizer->nowValue * (255 - colorizer->wasValue)) - + ((value - colorizer->wasValue) - * (255 - colorizer->nowValue))) - / (255 - colorizer->wasValue)) - : (value < colorizer->wasValue) - ? ((value * colorizer->nowValue) - / colorizer->wasValue) - : colorizer->nowValue; - auto nowR = 0; - auto nowG = 0; - auto nowB = 0; - QColor::fromHsv( - changeColor ? ((nowHue + 360) % 360) : hue, - changeColor ? nowSaturation : saturation, - nowValue - ).getRgb(&nowR, &nowG, &nowB); - r = uchar(nowR); - g = uchar(nowG); - b = uchar(nowB); -} - -void Colorize(uint32 &pixel, not_null colorizer) { - const auto chars = reinterpret_cast(&pixel); - Colorize( - chars[2], - chars[1], - chars[0], - colorizer); -} - -void Colorize(QImage &image, not_null colorizer) { - image = std::move(image).convertToFormat(QImage::Format_ARGB32); - const auto bytes = image.bits(); - const auto bytesPerLine = image.bytesPerLine(); - for (auto line = 0; line != image.height(); ++line) { - const auto ints = reinterpret_cast( - bytes + line * bytesPerLine); - const auto end = ints + image.width(); - for (auto p = ints; p != end; ++p) { - Colorize(*p, colorizer); - } - } -} - enum class SetResult { Ok, Bad, diff --git a/Telegram/SourceFiles/window/themes/window_theme.h b/Telegram/SourceFiles/window/themes/window_theme.h index ee3e3a8c34..1865e56a17 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.h +++ b/Telegram/SourceFiles/window/themes/window_theme.h @@ -16,7 +16,7 @@ class Session; namespace Window { namespace Theme { -constexpr auto kMinimumTiledSize = 512; +struct Colorizer; struct Cached { QByteArray colors; @@ -49,17 +49,6 @@ struct Preview { QImage preview; }; -struct Colorizer { - int wasHue = 0; - int wasSaturation = 0; - int wasValue = 0; - int nowHue = 0; - int nowSaturation = 0; - int nowValue = 0; - int hueThreshold = 0; - base::flat_set ignoreKeys; -}; - bool Apply(const QString &filepath); bool Apply(std::unique_ptr preview); void ApplyDefaultWithPath( diff --git a/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp b/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp new file mode 100644 index 0000000000..5cf6b522e1 --- /dev/null +++ b/Telegram/SourceFiles/window/themes/window_themes_embedded.cpp @@ -0,0 +1,365 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "window/themes/window_themes_embedded.h" + +#include "window/themes/window_theme.h" +#include "storage/serialize_common.h" + +namespace Window { +namespace Theme { +namespace { + +constexpr auto kMaxAccentColors = 3; + +const auto kColorizeIgnoredKeys = base::flat_set{ { + qstr("boxTextFgGood"), + qstr("boxTextFgError"), + qstr("historyPeer1NameFg"), + qstr("historyPeer1NameFgSelected"), + qstr("historyPeer1UserpicBg"), + qstr("historyPeer2NameFg"), + qstr("historyPeer2NameFgSelected"), + qstr("historyPeer2UserpicBg"), + qstr("historyPeer3NameFg"), + qstr("historyPeer3NameFgSelected"), + qstr("historyPeer3UserpicBg"), + qstr("historyPeer4NameFg"), + qstr("historyPeer4NameFgSelected"), + qstr("historyPeer4UserpicBg"), + qstr("historyPeer5NameFg"), + qstr("historyPeer5NameFgSelected"), + qstr("historyPeer5UserpicBg"), + qstr("historyPeer6NameFg"), + qstr("historyPeer6NameFgSelected"), + qstr("historyPeer6UserpicBg"), + qstr("historyPeer7NameFg"), + qstr("historyPeer7NameFgSelected"), + qstr("historyPeer7UserpicBg"), + qstr("historyPeer8NameFg"), + qstr("historyPeer8NameFgSelected"), + qstr("historyPeer8UserpicBg"), + qstr("msgFile1Bg"), + qstr("msgFile1BgDark"), + qstr("msgFile1BgOver"), + qstr("msgFile1BgSelected"), + qstr("msgFile2Bg"), + qstr("msgFile2BgDark"), + qstr("msgFile2BgOver"), + qstr("msgFile2BgSelected"), + qstr("msgFile3Bg"), + qstr("msgFile3BgDark"), + qstr("msgFile3BgOver"), + qstr("msgFile3BgSelected"), + qstr("msgFile4Bg"), + qstr("msgFile4BgDark"), + qstr("msgFile4BgOver"), + qstr("msgFile4BgSelected"), + qstr("mediaviewFileRedCornerFg"), + qstr("mediaviewFileYellowCornerFg"), + qstr("mediaviewFileGreenCornerFg"), + qstr("mediaviewFileBlueCornerFg"), +} }; + +QColor Color(str_const hex) { + Expects(hex.size() == 6); + + const auto component = [](char a, char b) { + const auto convert = [](char ch) { + Expects((ch >= '0' && ch <= '9') + || (ch >= 'A' && ch <= 'F') + || (ch >= 'a' && ch <= 'f')); + + return (ch >= '0' && ch <= '9') + ? int(ch - '0') + : int(ch - ((ch >= 'A' && ch <= 'F') ? 'A' : 'a') + 10); + }; + return convert(a) * 16 + convert(b); + }; + + return QColor( + component(hex[0], hex[1]), + component(hex[2], hex[3]), + component(hex[4], hex[5])); +}; + +} // namespace + +Colorizer ColorizerFrom(const EmbeddedScheme &scheme, const QColor &color) { + auto result = Colorizer(); + result.ignoreKeys = kColorizeIgnoredKeys; + result.hueThreshold = 10; + scheme.accentColor.getHsv( + &result.wasHue, + &result.wasSaturation, + &result.wasValue); + color.getHsv( + &result.nowHue, + &result.nowSaturation, + &result.nowValue); + return result; +} + +void Colorize( + uchar &r, + uchar &g, + uchar &b, + not_null colorizer) { + auto color = QColor(int(r), int(g), int(b)); + auto hue = 0; + auto saturation = 0; + auto value = 0; + color.getHsv(&hue, &saturation, &value); + const auto changeColor = std::abs(hue - colorizer->wasHue) + <= colorizer->hueThreshold; + const auto nowHue = hue + (colorizer->nowHue - colorizer->wasHue); + const auto nowSaturation = ((saturation > colorizer->wasSaturation) + && (colorizer->nowSaturation > colorizer->wasSaturation)) + ? (((colorizer->nowSaturation * (255 - colorizer->wasSaturation)) + + ((saturation - colorizer->wasSaturation) + * (255 - colorizer->nowSaturation))) + / (255 - colorizer->wasSaturation)) + : ((saturation != colorizer->wasSaturation) + && (colorizer->wasSaturation != 0)) + ? ((saturation * colorizer->nowSaturation) + / colorizer->wasSaturation) + : colorizer->nowSaturation; + const auto nowValue = (value > colorizer->wasValue) + ? (((colorizer->nowValue * (255 - colorizer->wasValue)) + + ((value - colorizer->wasValue) + * (255 - colorizer->nowValue))) + / (255 - colorizer->wasValue)) + : (value < colorizer->wasValue) + ? ((value * colorizer->nowValue) + / colorizer->wasValue) + : colorizer->nowValue; + auto nowR = 0; + auto nowG = 0; + auto nowB = 0; + QColor::fromHsv( + changeColor ? ((nowHue + 360) % 360) : hue, + changeColor ? nowSaturation : saturation, + nowValue + ).getRgb(&nowR, &nowG, &nowB); + r = uchar(nowR); + g = uchar(nowG); + b = uchar(nowB); +} + +void Colorize(uint32 &pixel, not_null colorizer) { + const auto chars = reinterpret_cast(&pixel); + Colorize( + chars[2], + chars[1], + chars[0], + colorizer); +} + +void Colorize(QColor &color, not_null colorizer) { + auto r = uchar(color.red()); + auto g = uchar(color.green()); + auto b = uchar(color.blue()); + Colorize(r, g, b, colorizer); + color = QColor(r, g, b, color.alpha()); +} + +void Colorize(QImage &image, not_null colorizer) { + image = std::move(image).convertToFormat(QImage::Format_ARGB32); + const auto bytes = image.bits(); + const auto bytesPerLine = image.bytesPerLine(); + for (auto line = 0; line != image.height(); ++line) { + const auto ints = reinterpret_cast( + bytes + line * bytesPerLine); + const auto end = ints + image.width(); + for (auto p = ints; p != end; ++p) { + Colorize(*p, colorizer); + } + } +} + +void Colorize(EmbeddedScheme &scheme, not_null colorizer) { + const auto colors = { + &EmbeddedScheme::background, + &EmbeddedScheme::sent, + &EmbeddedScheme::received, + &EmbeddedScheme::radiobuttonActive, + &EmbeddedScheme::radiobuttonInactive + }; + for (const auto color : colors) { + Colorize(scheme.*color, colorizer); + } +} + +std::vector EmbeddedThemes() { + return { + EmbeddedScheme{ + EmbeddedType::DayBlue, + Color("7ec4ea"), + Color("d7f0ff"), + Color("ffffff"), + Color("d7f0ff"), + Color("ffffff"), + tr::lng_settings_theme_blue, + ":/gui/day-blue.tdesktop-theme", + Color("40a7e3") + }, + EmbeddedScheme{ + EmbeddedType::Default, + Color("90ce89"), + Color("eaffdc"), + Color("ffffff"), + Color("eaffdc"), + Color("ffffff"), + tr::lng_settings_theme_classic, + QString() + }, + EmbeddedScheme{ + EmbeddedType::Night, + Color("485761"), + Color("5ca7d4"), + Color("6b808d"), + Color("6b808d"), + Color("5ca7d4"), + tr::lng_settings_theme_midnight, + ":/gui/night.tdesktop-theme", + Color("5288c1") + }, + EmbeddedScheme{ + EmbeddedType::NightGreen, + Color("485761"), + Color("75bfab"), + Color("6b808d"), + Color("6b808d"), + Color("75bfab"), + tr::lng_settings_theme_matrix, + ":/gui/night-green.tdesktop-theme", + Color("3fc1b0") + }, + }; +} + +std::vector AccentColors(EmbeddedType type) { + switch (type) { + case EmbeddedType::DayBlue: + return { + //Color("3478f5"), + Color("58bfe8"), + Color("58b040"), + Color("da73a2"), + Color("e28830"), + Color("9073e7"), + Color("9073e7"), + Color("e3b63e"), + Color("71829c") + }; + case EmbeddedType::Default: + return {}; + case EmbeddedType::Night: + return { + //Color("3478f5"), + Color("58bfe8"), + Color("58b040"), + Color("da73a2"), + Color("e28830"), + Color("9073e7"), + Color("9073e7"), + Color("e3b63e"), + Color("71829c") + }; + case EmbeddedType::NightGreen: + return { + Color("3478f5"), + //Color("58bfe8"), + Color("58b040"), + Color("da73a2"), + Color("e28830"), + Color("9073e7"), + Color("9073e7"), + Color("e3b63e"), + Color("71829c") + }; + } + Unexpected("Type in Window::Theme::AccentColors."); +} + +QByteArray AccentColors::serialize() const { + auto result = QByteArray(); + if (_data.empty()) { + return result; + } + + const auto count = _data.size(); + auto size = sizeof(qint32) * (count + 1) + + Serialize::colorSize() * count; + result.reserve(size); + + auto stream = QDataStream(&result, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_1); + stream << qint32(_data.size()); + for (const auto &[type, color] : _data) { + stream << static_cast(type); + Serialize::writeColor(stream, color); + } + stream.device()->close(); + + return result; +} + +bool AccentColors::setFromSerialized(const QByteArray &serialized) { + if (serialized.isEmpty()) { + _data.clear(); + return true; + } + auto copy = QByteArray(serialized); + auto stream = QDataStream(©, QIODevice::ReadOnly); + stream.setVersion(QDataStream::Qt_5_1); + + auto count = qint32(); + stream >> count; + if (stream.status() != QDataStream::Ok) { + return false; + } else if (count <= 0 || count > kMaxAccentColors) { + return false; + } + auto data = base::flat_map(); + for (auto i = 0; i != count; ++i) { + auto type = qint32(); + stream >> type; + const auto color = Serialize::readColor(stream); + const auto uncheckedType = static_cast(type); + switch (uncheckedType) { + case EmbeddedType::DayBlue: + case EmbeddedType::Night: + case EmbeddedType::NightGreen: + data.emplace(uncheckedType, color); + break; + default: + return false; + } + } + if (stream.status() != QDataStream::Ok) { + return false; + } + _data = std::move(data); + return true; +} + +void AccentColors::set(EmbeddedType type, const QColor &value) { + _data.emplace_or_assign(type, value); +} + +void AccentColors::clear(EmbeddedType type) { + _data.remove(type); +} + +std::optional AccentColors::get(EmbeddedType type) const { + const auto i = _data.find(type); + return (i != end(_data)) ? std::make_optional(i->second) : std::nullopt; +} + +} // namespace Theme +} // namespace Window diff --git a/Telegram/SourceFiles/window/themes/window_themes_embedded.h b/Telegram/SourceFiles/window/themes/window_themes_embedded.h new file mode 100644 index 0000000000..b0d7d5a428 --- /dev/null +++ b/Telegram/SourceFiles/window/themes/window_themes_embedded.h @@ -0,0 +1,77 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "lang/lang_keys.h" + +class QImage; + +namespace Window { +namespace Theme { + +enum class EmbeddedType { + DayBlue, + Default, + Night, + NightGreen, +}; + +struct EmbeddedScheme { + EmbeddedType type = EmbeddedType(); + QColor background; + QColor sent; + QColor received; + QColor radiobuttonInactive; + QColor radiobuttonActive; + tr::phrase<> name; + QString path; + QColor accentColor; +}; + +class AccentColors final { +public: + [[nodiscard]] QByteArray serialize() const; + bool setFromSerialized(const QByteArray &serialized); + + void set(EmbeddedType type, const QColor &value); + void clear(EmbeddedType type); + [[nodiscard]] std::optional get(EmbeddedType type) const; + +private: + base::flat_map _data; + +}; + +struct Colorizer { + int wasHue = 0; + int wasSaturation = 0; + int wasValue = 0; + int nowHue = 0; + int nowSaturation = 0; + int nowValue = 0; + int hueThreshold = 0; + base::flat_set ignoreKeys; +}; + +[[nodiscard]] Colorizer ColorizerFrom( + const EmbeddedScheme &scheme, + const QColor &color); + +void Colorize( + uchar &r, + uchar &g, + uchar &b, + not_null colorizer); +void Colorize(QImage &image, not_null colorizer); +void Colorize(EmbeddedScheme &scheme, not_null colorizer); + +[[nodiscard]] std::vector EmbeddedThemes(); +[[nodiscard]] std::vector DefaultAccentColors(EmbeddedType type); + +} // namespace Theme +} // namespace Window \ No newline at end of file diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index ce1e5f5704..2e50658faf 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -145,6 +145,8 @@ <(src_loc)/core/click_handler_types.h <(src_loc)/core/core_cloud_password.cpp <(src_loc)/core/core_cloud_password.h +<(src_loc)/core/core_settings.cpp +<(src_loc)/core/core_settings.h <(src_loc)/core/crash_report_window.cpp <(src_loc)/core/crash_report_window.h <(src_loc)/core/crash_reports.cpp @@ -467,6 +469,8 @@ <(src_loc)/main/main_app_config.h <(src_loc)/main/main_session.cpp <(src_loc)/main/main_session.h +<(src_loc)/main/main_settings.cpp +<(src_loc)/main/main_settings.h <(src_loc)/media/audio/media_audio.cpp <(src_loc)/media/audio/media_audio.h <(src_loc)/media/audio/media_audio_capture.cpp @@ -893,6 +897,8 @@ <(src_loc)/window/themes/window_theme_preview.h <(src_loc)/window/themes/window_theme_warning.cpp <(src_loc)/window/themes/window_theme_warning.h +<(src_loc)/window/themes/window_themes_embedded.cpp +<(src_loc)/window/themes/window_themes_embedded.h <(src_loc)/apiwrap.cpp <(src_loc)/apiwrap.h <(src_loc)/app.cpp