mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-11 01:10:13 +00:00
Save embedded themes accent colors.
This commit is contained in:
parent
7de28fc4bd
commit
c2117e7722
@ -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) {
|
||||
|
@ -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> _private;
|
||||
|
||||
QWidget _globalShortcutParent;
|
||||
Settings _settings;
|
||||
|
||||
const std::unique_ptr<Storage::Databases> _databases;
|
||||
const std::unique_ptr<Ui::Animations::Manager> _animationsManager;
|
||||
@ -276,6 +281,7 @@ private:
|
||||
std::unique_ptr<Window::TermsLock> _termsLock;
|
||||
|
||||
base::DelayedCallTimer _callDelayedTimer;
|
||||
base::Timer _saveSettingsTimer;
|
||||
|
||||
struct LeaveSubscription {
|
||||
LeaveSubscription(
|
||||
|
51
Telegram/SourceFiles/core/core_settings.cpp
Normal file
51
Telegram/SourceFiles/core/core_settings.cpp
Normal file
@ -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
|
40
Telegram/SourceFiles/core/core_settings.h
Normal file
40
Telegram/SourceFiles/core/core_settings.h
Normal file
@ -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
|
@ -1587,7 +1587,7 @@ void UpdateApplication() {
|
||||
Window::SectionShow());
|
||||
} else {
|
||||
window->showSpecialLayer(
|
||||
Box<Settings::LayerWidget>(),
|
||||
Box<::Settings::LayerWidget>(),
|
||||
anim::type::normal);
|
||||
}
|
||||
window->showFromTray();
|
||||
|
@ -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<qint32>(_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<qint32>(ChatHelpers::SelectorTab::Emoji);
|
||||
qint32 lastSeenWarningSeen = 0;
|
||||
qint32 tabbedSelectorSectionEnabled = 1;
|
||||
qint32 tabbedSelectorSectionTooltipShown = 0;
|
||||
qint32 floatPlayerColumn = static_cast<qint32>(Window::Column::Second);
|
||||
qint32 floatPlayerCorner = static_cast<qint32>(RectPart::TopRight);
|
||||
QMap<QString, QString> soundOverrides;
|
||||
base::flat_set<PeerId> 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<qint32>(_variables.sendFilesWay);
|
||||
qint32 legacyCallsPeerToPeer = qint32(0);
|
||||
qint32 sendSubmitWay = static_cast<qint32>(_variables.sendSubmitWay);
|
||||
qint32 supportSwitch = static_cast<qint32>(_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<ChatHelpers::SelectorTab>(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<Window::Column>(floatPlayerColumn);
|
||||
switch (uncheckedColumn) {
|
||||
case Window::Column::First:
|
||||
case Window::Column::Second:
|
||||
case Window::Column::Third: _variables.floatPlayerColumn = uncheckedColumn; break;
|
||||
}
|
||||
auto uncheckedCorner = static_cast<RectPart>(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>(sendFilesWay);
|
||||
switch (uncheckedSendFilesWay) {
|
||||
case SendFilesWay::Album:
|
||||
case SendFilesWay::Photos:
|
||||
case SendFilesWay::Files: _variables.sendFilesWay = uncheckedSendFilesWay; break;
|
||||
}
|
||||
auto uncheckedSendSubmitWay = static_cast<Ui::InputSubmitSettings>(
|
||||
sendSubmitWay);
|
||||
switch (uncheckedSendSubmitWay) {
|
||||
case Ui::InputSubmitSettings::Enter:
|
||||
case Ui::InputSubmitSettings::CtrlEnter: _variables.sendSubmitWay = uncheckedSendSubmitWay; break;
|
||||
}
|
||||
auto uncheckedSupportSwitch = static_cast<Support::SwitchSettings>(
|
||||
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<int> 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<bool> Settings::supportAllSearchResultsValue() const {
|
||||
return _variables.supportAllSearchResults.value();
|
||||
}
|
||||
|
||||
void Settings::setTabbedSelectorSectionEnabled(bool enabled) {
|
||||
_variables.tabbedSelectorSectionEnabled = enabled;
|
||||
if (enabled) {
|
||||
setThirdSectionInfoEnabled(false);
|
||||
}
|
||||
setTabbedReplacedWithInfo(false);
|
||||
}
|
||||
|
||||
rpl::producer<bool> 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<bool> 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<float64> 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<int> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> Settings::largeEmojiValue() const {
|
||||
return _variables.largeEmoji.value();
|
||||
}
|
||||
|
||||
rpl::producer<bool> 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<bool> Settings::replaceEmojiValue() const {
|
||||
return _variables.replaceEmoji.value();
|
||||
}
|
||||
|
||||
rpl::producer<bool> Settings::replaceEmojiChanges() const {
|
||||
return _variables.replaceEmoji.changes();
|
||||
}
|
||||
|
||||
Session::Session(
|
||||
not_null<Main::Account*> account,
|
||||
const MTPUser &user)
|
||||
: _account(account)
|
||||
, _saveSettingsTimer([=] { Local::writeUserSettings(); })
|
||||
, _autoLockTimer([=] { checkAutoLock(); })
|
||||
, _api(std::make_unique<ApiWrap>(this))
|
||||
, _appConfig(std::make_unique<AppConfig>(this))
|
||||
@ -522,9 +52,6 @@ Session::Session(
|
||||
, _emojiStickersPack(std::make_unique<Stickers::EmojiPack>(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<MTP::Instance*> Session::mtp() {
|
||||
|
@ -10,18 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include <rpl/event_stream.h>
|
||||
#include <rpl/filter.h>
|
||||
#include <rpl/variable.h>
|
||||
#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<int> supportChatsTimeSliceValue() const;
|
||||
void setSupportAllSearchResults(bool all);
|
||||
[[nodiscard]] bool supportAllSearchResults() const;
|
||||
[[nodiscard]] rpl::producer<bool> 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<bool> 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<bool> 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<float64> dialogsWidthRatioChanges() const;
|
||||
void setThirdColumnWidth(int width);
|
||||
[[nodiscard]] int thirdColumnWidth() const;
|
||||
[[nodiscard]] rpl::producer<int> 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<bool> archiveCollapsedChanges() const;
|
||||
|
||||
void setArchiveInMainMenu(bool inMainMenu);
|
||||
[[nodiscard]] bool archiveInMainMenu() const;
|
||||
[[nodiscard]] rpl::producer<bool> archiveInMainMenuChanges() const;
|
||||
|
||||
void setNotifyAboutPinned(bool notify);
|
||||
[[nodiscard]] bool notifyAboutPinned() const;
|
||||
[[nodiscard]] rpl::producer<bool> notifyAboutPinnedChanges() const;
|
||||
|
||||
void setSkipArchiveInSearch(bool skip);
|
||||
[[nodiscard]] bool skipArchiveInSearch() const;
|
||||
[[nodiscard]] rpl::producer<bool> 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<bool> largeEmojiValue() const;
|
||||
[[nodiscard]] rpl::producer<bool> largeEmojiChanges() const;
|
||||
void setReplaceEmoji(bool value);
|
||||
[[nodiscard]] bool replaceEmoji() const;
|
||||
[[nodiscard]] rpl::producer<bool> replaceEmojiValue() const;
|
||||
[[nodiscard]] rpl::producer<bool> 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<QString, QString> soundOverrides;
|
||||
Window::Column floatPlayerColumn; // per-window
|
||||
RectPart floatPlayerCorner; // per-window
|
||||
base::flat_set<PeerId> groupStickersSectionHidden;
|
||||
bool thirdSectionInfoEnabled = true; // per-window
|
||||
bool smallDialogsList = false; // per-window
|
||||
int thirdSectionExtendedBy = -1; // per-window
|
||||
rpl::variable<float64> dialogsWidthRatio
|
||||
= kDefaultDialogsWidthRatio; // per-window
|
||||
rpl::variable<int> 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<bool> archiveCollapsed = false;
|
||||
rpl::variable<bool> archiveInMainMenu = false;
|
||||
rpl::variable<bool> notifyAboutPinned = true;
|
||||
rpl::variable<bool> skipArchiveInSearch = false;
|
||||
bool autoplayGifs = true;
|
||||
bool loopAnimatedStickers = true;
|
||||
rpl::variable<bool> largeEmoji = true;
|
||||
rpl::variable<bool> 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<int> supportChatsTimeSlice
|
||||
= kDefaultSupportChatsLimitSlice;
|
||||
rpl::variable<bool> supportAllSearchResults = false;
|
||||
};
|
||||
|
||||
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
|
||||
bool _tabbedReplacedWithInfo = false;
|
||||
rpl::event_stream<bool> _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<UserData*> user() const {
|
||||
[[nodiscard]] UserId userId() const;
|
||||
[[nodiscard]] PeerId userPeerId() const;
|
||||
[[nodiscard]] not_null<UserData*> 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<void> &downloaderTaskFinished();
|
||||
[[nodiscard]] base::Observable<void> &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::Instance*> mtp();
|
||||
ApiWrap &api() {
|
||||
[[nodiscard]] not_null<MTP::Instance*> 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<Main::Account*> _account;
|
||||
|
||||
Settings _settings;
|
||||
base::Timer _saveDataTimer;
|
||||
base::Timer _saveSettingsTimer;
|
||||
|
||||
crl::time _shouldLockAt = 0;
|
||||
base::Timer _autoLockTimer;
|
||||
|
490
Telegram/SourceFiles/main/main_settings.cpp
Normal file
490
Telegram/SourceFiles/main/main_settings.cpp
Normal file
@ -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<qint32>(_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<qint32>(ChatHelpers::SelectorTab::Emoji);
|
||||
qint32 lastSeenWarningSeen = 0;
|
||||
qint32 tabbedSelectorSectionEnabled = 1;
|
||||
qint32 tabbedSelectorSectionTooltipShown = 0;
|
||||
qint32 floatPlayerColumn = static_cast<qint32>(Window::Column::Second);
|
||||
qint32 floatPlayerCorner = static_cast<qint32>(RectPart::TopRight);
|
||||
QMap<QString, QString> soundOverrides;
|
||||
base::flat_set<PeerId> 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<qint32>(_variables.sendFilesWay);
|
||||
qint32 legacyCallsPeerToPeer = qint32(0);
|
||||
qint32 sendSubmitWay = static_cast<qint32>(_variables.sendSubmitWay);
|
||||
qint32 supportSwitch = static_cast<qint32>(_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<ChatHelpers::SelectorTab>(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<Window::Column>(floatPlayerColumn);
|
||||
switch (uncheckedColumn) {
|
||||
case Window::Column::First:
|
||||
case Window::Column::Second:
|
||||
case Window::Column::Third: _variables.floatPlayerColumn = uncheckedColumn; break;
|
||||
}
|
||||
auto uncheckedCorner = static_cast<RectPart>(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>(sendFilesWay);
|
||||
switch (uncheckedSendFilesWay) {
|
||||
case SendFilesWay::Album:
|
||||
case SendFilesWay::Photos:
|
||||
case SendFilesWay::Files: _variables.sendFilesWay = uncheckedSendFilesWay; break;
|
||||
}
|
||||
auto uncheckedSendSubmitWay = static_cast<Ui::InputSubmitSettings>(
|
||||
sendSubmitWay);
|
||||
switch (uncheckedSendSubmitWay) {
|
||||
case Ui::InputSubmitSettings::Enter:
|
||||
case Ui::InputSubmitSettings::CtrlEnter: _variables.sendSubmitWay = uncheckedSendSubmitWay; break;
|
||||
}
|
||||
auto uncheckedSupportSwitch = static_cast<Support::SwitchSettings>(
|
||||
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<int> 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<bool> Settings::supportAllSearchResultsValue() const {
|
||||
return _variables.supportAllSearchResults.value();
|
||||
}
|
||||
|
||||
void Settings::setTabbedSelectorSectionEnabled(bool enabled) {
|
||||
_variables.tabbedSelectorSectionEnabled = enabled;
|
||||
if (enabled) {
|
||||
setThirdSectionInfoEnabled(false);
|
||||
}
|
||||
setTabbedReplacedWithInfo(false);
|
||||
}
|
||||
|
||||
rpl::producer<bool> 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<bool> 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<float64> 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<int> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> Settings::largeEmojiValue() const {
|
||||
return _variables.largeEmoji.value();
|
||||
}
|
||||
|
||||
rpl::producer<bool> 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<bool> Settings::replaceEmojiValue() const {
|
||||
return _variables.replaceEmoji.value();
|
||||
}
|
||||
|
||||
rpl::producer<bool> Settings::replaceEmojiChanges() const {
|
||||
return _variables.replaceEmoji.changes();
|
||||
}
|
||||
|
||||
} // namespace Main
|
295
Telegram/SourceFiles/main/main_settings.h
Normal file
295
Telegram/SourceFiles/main/main_settings.h
Normal file
@ -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<int> supportChatsTimeSliceValue() const;
|
||||
void setSupportAllSearchResults(bool all);
|
||||
[[nodiscard]] bool supportAllSearchResults() const;
|
||||
[[nodiscard]] rpl::producer<bool> 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<bool> 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<bool> 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<float64> dialogsWidthRatioChanges() const;
|
||||
void setThirdColumnWidth(int width);
|
||||
[[nodiscard]] int thirdColumnWidth() const;
|
||||
[[nodiscard]] rpl::producer<int> 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<bool> archiveCollapsedChanges() const;
|
||||
|
||||
void setArchiveInMainMenu(bool inMainMenu);
|
||||
[[nodiscard]] bool archiveInMainMenu() const;
|
||||
[[nodiscard]] rpl::producer<bool> archiveInMainMenuChanges() const;
|
||||
|
||||
void setNotifyAboutPinned(bool notify);
|
||||
[[nodiscard]] bool notifyAboutPinned() const;
|
||||
[[nodiscard]] rpl::producer<bool> notifyAboutPinnedChanges() const;
|
||||
|
||||
void setSkipArchiveInSearch(bool skip);
|
||||
[[nodiscard]] bool skipArchiveInSearch() const;
|
||||
[[nodiscard]] rpl::producer<bool> 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<bool> largeEmojiValue() const;
|
||||
[[nodiscard]] rpl::producer<bool> largeEmojiChanges() const;
|
||||
void setReplaceEmoji(bool value);
|
||||
[[nodiscard]] bool replaceEmoji() const;
|
||||
[[nodiscard]] rpl::producer<bool> replaceEmojiValue() const;
|
||||
[[nodiscard]] rpl::producer<bool> 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<QString, QString> soundOverrides;
|
||||
Window::Column floatPlayerColumn; // per-window
|
||||
RectPart floatPlayerCorner; // per-window
|
||||
base::flat_set<PeerId> groupStickersSectionHidden;
|
||||
bool thirdSectionInfoEnabled = true; // per-window
|
||||
bool smallDialogsList = false; // per-window
|
||||
int thirdSectionExtendedBy = -1; // per-window
|
||||
rpl::variable<float64> dialogsWidthRatio
|
||||
= kDefaultDialogsWidthRatio; // per-window
|
||||
rpl::variable<int> 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<bool> archiveCollapsed = false;
|
||||
rpl::variable<bool> archiveInMainMenu = false;
|
||||
rpl::variable<bool> notifyAboutPinned = true;
|
||||
rpl::variable<bool> skipArchiveInSearch = false;
|
||||
bool autoplayGifs = true;
|
||||
bool loopAnimatedStickers = true;
|
||||
rpl::variable<bool> largeEmoji = true;
|
||||
rpl::variable<bool> 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<int> supportChatsTimeSlice
|
||||
= kDefaultSupportChatsLimitSlice;
|
||||
rpl::variable<bool> supportAllSearchResults = false;
|
||||
};
|
||||
|
||||
rpl::event_stream<bool> _thirdSectionInfoEnabledValue;
|
||||
bool _tabbedReplacedWithInfo = false;
|
||||
rpl::event_stream<bool> _tabbedReplacedWithInfoValue;
|
||||
|
||||
Variables _variables;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Main
|
@ -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<QLatin1String>{ {
|
||||
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<Ui::VerticalLayout*> container) {
|
||||
using Scheme = DefaultTheme::Scheme;
|
||||
const auto block = container->add(object_ptr<Ui::FixedHeightWidget>(
|
||||
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<Ui::VerticalLayout*> 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<EditColorBox>(
|
||||
"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<Ui::VerticalLayout*> 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<Type,not_null<DefaultTheme*>>();
|
||||
auto buttons = ranges::view::all(
|
||||
schemes
|
||||
SchemesList
|
||||
) | ranges::view::transform([&](const Scheme &scheme) {
|
||||
auto check = std::make_unique<DefaultTheme>(scheme, false);
|
||||
const auto weak = check.get();
|
||||
@ -967,9 +858,30 @@ void SetupDefaultThemes(not_null<Ui::VerticalLayout*> 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<Ui::VerticalLayout*> 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<Ui::VerticalLayout*> container) {
|
||||
}
|
||||
}, block->lifetime());
|
||||
|
||||
const auto colors = container->add(
|
||||
object_ptr<Ui::SlideWrap<>>(
|
||||
container,
|
||||
object_ptr<Ui::FixedHeightWidget>(
|
||||
container)));
|
||||
|
||||
AddSkip(container);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -21,6 +21,23 @@ constexpr auto kModernImageLocationTag = std::numeric_limits<qint32>::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<StorageImageLocation> readLegacyStorageImageLocationOrTag(
|
||||
int streamAppVersion,
|
||||
QDataStream &stream) {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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<const Colorizer*> 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<const Colorizer*> colorizer) {
|
||||
const auto chars = reinterpret_cast<uchar*>(&pixel);
|
||||
Colorize(
|
||||
chars[2],
|
||||
chars[1],
|
||||
chars[0],
|
||||
colorizer);
|
||||
}
|
||||
|
||||
void Colorize(QImage &image, not_null<const Colorizer*> 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<uint32*>(
|
||||
bytes + line * bytesPerLine);
|
||||
const auto end = ints + image.width();
|
||||
for (auto p = ints; p != end; ++p) {
|
||||
Colorize(*p, colorizer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class SetResult {
|
||||
Ok,
|
||||
Bad,
|
||||
|
@ -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<QLatin1String> ignoreKeys;
|
||||
};
|
||||
|
||||
bool Apply(const QString &filepath);
|
||||
bool Apply(std::unique_ptr<Preview> preview);
|
||||
void ApplyDefaultWithPath(
|
||||
|
365
Telegram/SourceFiles/window/themes/window_themes_embedded.cpp
Normal file
365
Telegram/SourceFiles/window/themes/window_themes_embedded.cpp
Normal file
@ -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<QLatin1String>{ {
|
||||
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<const Colorizer*> 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<const Colorizer*> colorizer) {
|
||||
const auto chars = reinterpret_cast<uchar*>(&pixel);
|
||||
Colorize(
|
||||
chars[2],
|
||||
chars[1],
|
||||
chars[0],
|
||||
colorizer);
|
||||
}
|
||||
|
||||
void Colorize(QColor &color, not_null<const Colorizer*> 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<const Colorizer*> 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<uint32*>(
|
||||
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<const Colorizer*> 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<EmbeddedScheme> 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<QColor> 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<qint32>(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<EmbeddedType, QColor>();
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
auto type = qint32();
|
||||
stream >> type;
|
||||
const auto color = Serialize::readColor(stream);
|
||||
const auto uncheckedType = static_cast<EmbeddedType>(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<QColor> 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
|
77
Telegram/SourceFiles/window/themes/window_themes_embedded.h
Normal file
77
Telegram/SourceFiles/window/themes/window_themes_embedded.h
Normal file
@ -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<QColor> get(EmbeddedType type) const;
|
||||
|
||||
private:
|
||||
base::flat_map<EmbeddedType, QColor> _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<QLatin1String> ignoreKeys;
|
||||
};
|
||||
|
||||
[[nodiscard]] Colorizer ColorizerFrom(
|
||||
const EmbeddedScheme &scheme,
|
||||
const QColor &color);
|
||||
|
||||
void Colorize(
|
||||
uchar &r,
|
||||
uchar &g,
|
||||
uchar &b,
|
||||
not_null<const Colorizer*> colorizer);
|
||||
void Colorize(QImage &image, not_null<const Colorizer*> colorizer);
|
||||
void Colorize(EmbeddedScheme &scheme, not_null<const Colorizer*> colorizer);
|
||||
|
||||
[[nodiscard]] std::vector<EmbeddedScheme> EmbeddedThemes();
|
||||
[[nodiscard]] std::vector<QColor> DefaultAccentColors(EmbeddedType type);
|
||||
|
||||
} // namespace Theme
|
||||
} // namespace Window
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user