mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Allow independently change default / night themes.
This commit is contained in:
parent
d12bd0824d
commit
cb338e330f
12 changed files with 554 additions and 278 deletions
|
@ -519,6 +519,9 @@ void SetAnnotationHex(const std::string &key, const QString &value) {
|
|||
}
|
||||
|
||||
void SetAnnotationRef(const std::string &key, const QString *valuePtr) {
|
||||
static QMutex mutex;
|
||||
QMutexLocker lock(&mutex);
|
||||
|
||||
if (valuePtr) {
|
||||
ProcessAnnotationRefs[key] = valuePtr;
|
||||
} else {
|
||||
|
|
|
@ -62,13 +62,10 @@ void AdvancedWidget::createControls() {
|
|||
} else {
|
||||
style::margins slidedPadding(0, marginLarge.bottom() / 2, 0, marginLarge.bottom() - (marginLarge.bottom() / 2));
|
||||
createChildRow(_useDefaultTheme, marginLarge, slidedPadding, lang(lng_settings_bg_use_default), SLOT(onUseDefaultTheme()));
|
||||
if (!Window::Theme::IsNonDefaultUsed()) {
|
||||
if (!Window::Theme::SuggestThemeReset()) {
|
||||
_useDefaultTheme->hide(anim::type::instant);
|
||||
}
|
||||
createChildRow(_toggleNightTheme, marginLarge, slidedPadding, getNightThemeToggleText(), SLOT(onToggleNightTheme()));
|
||||
if (Window::Theme::IsNonDefaultUsed()) {
|
||||
_toggleNightTheme->hide(anim::type::instant);
|
||||
}
|
||||
createChildRow(_toggleNightTheme, marginLarge, getNightThemeToggleText(), SLOT(onToggleNightTheme()));
|
||||
}
|
||||
createChildRow(_telegramFAQ, marginLarge, lang(lng_settings_faq), SLOT(onTelegramFAQ()));
|
||||
if (self()) {
|
||||
|
@ -78,14 +75,13 @@ void AdvancedWidget::createControls() {
|
|||
}
|
||||
|
||||
void AdvancedWidget::checkNonDefaultTheme() {
|
||||
if (self()) return;
|
||||
if (self()) {
|
||||
return;
|
||||
}
|
||||
_useDefaultTheme->toggle(
|
||||
Window::Theme::IsNonDefaultUsed(),
|
||||
anim::type::normal);
|
||||
_toggleNightTheme->entity()->setText(getNightThemeToggleText());
|
||||
_toggleNightTheme->toggle(
|
||||
!Window::Theme::IsNonDefaultUsed(),
|
||||
Window::Theme::SuggestThemeReset(),
|
||||
anim::type::normal);
|
||||
_toggleNightTheme->setText(getNightThemeToggleText());
|
||||
}
|
||||
|
||||
void AdvancedWidget::onManageLocalStorage() {
|
||||
|
@ -120,7 +116,7 @@ void AdvancedWidget::onUseDefaultTheme() {
|
|||
}
|
||||
|
||||
void AdvancedWidget::onToggleNightTheme() {
|
||||
Window::Theme::SwitchNightTheme(!Window::Theme::IsNightTheme());
|
||||
Window::Theme::ToggleNightMode();
|
||||
}
|
||||
|
||||
void AdvancedWidget::onAskQuestion() {
|
||||
|
@ -149,7 +145,9 @@ void AdvancedWidget::supportGot(const MTPhelp_Support &support) {
|
|||
}
|
||||
|
||||
QString AdvancedWidget::getNightThemeToggleText() const {
|
||||
return lang(Window::Theme::IsNightTheme() ? lng_settings_disable_night_theme : lng_settings_enable_night_theme);
|
||||
return lang(Window::Theme::IsNightMode()
|
||||
? lng_settings_disable_night_theme
|
||||
: lng_settings_enable_night_theme);
|
||||
}
|
||||
|
||||
void AdvancedWidget::onTelegramFAQ() {
|
||||
|
|
|
@ -44,7 +44,7 @@ private:
|
|||
LabeledLink *_connectionType = nullptr;
|
||||
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
|
||||
Ui::SlideWrap<Ui::LinkButton> *_useDefaultTheme = nullptr;
|
||||
Ui::SlideWrap<Ui::LinkButton> *_toggleNightTheme = nullptr;
|
||||
Ui::LinkButton *_toggleNightTheme = nullptr;
|
||||
Ui::LinkButton *_askQuestion = nullptr;
|
||||
Ui::LinkButton *_telegramFAQ = nullptr;
|
||||
Ui::LinkButton *_logOut = nullptr;
|
||||
|
|
|
@ -33,15 +33,17 @@ BackgroundRow::BackgroundRow(QWidget *parent) : RpWidget(parent)
|
|||
connect(_chooseFromFile, SIGNAL(clicked()), this, SIGNAL(chooseFromFile()));
|
||||
connect(_editTheme, SIGNAL(clicked()), this, SIGNAL(editTheme()));
|
||||
checkNonDefaultTheme();
|
||||
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
|
||||
if (update.type == Window::Theme::BackgroundUpdate::Type::ApplyingTheme) {
|
||||
using Update = const Window::Theme::BackgroundUpdate;
|
||||
subscribe(Window::Theme::Background(), [this](Update &update) {
|
||||
if (update.type == Update::Type::ApplyingTheme
|
||||
|| update.type == Update::Type::New) {
|
||||
checkNonDefaultTheme();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BackgroundRow::checkNonDefaultTheme() {
|
||||
if (Window::Theme::IsNonDefaultUsed()) {
|
||||
if (Window::Theme::SuggestThemeReset()) {
|
||||
if (!_useDefaultTheme) {
|
||||
_useDefaultTheme.create(this, lang(lng_settings_bg_use_default), st::boxLinkButton);
|
||||
_useDefaultTheme->show();
|
||||
|
@ -190,7 +192,8 @@ BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidge
|
|||
subscribe(Window::Theme::Background(), [this](const Update &update) {
|
||||
if (update.type == Update::Type::New) {
|
||||
_background->updateImage();
|
||||
} else if (update.type == Update::Type::Start) {
|
||||
} else if (update.type == Update::Type::Start
|
||||
|| update.type == Update::Type::Changed) {
|
||||
needBackgroundUpdate(update.tiled);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -491,7 +491,7 @@ enum { // Local Storage Keys
|
|||
lskStickerImages = 0x05, // data: StorageKey location
|
||||
lskAudios = 0x06, // data: StorageKey location
|
||||
lskRecentStickersOld = 0x07, // no data
|
||||
lskBackground = 0x08, // no data
|
||||
lskBackgroundOld = 0x08, // no data
|
||||
lskUserSettings = 0x09, // no data
|
||||
lskRecentHashtagsAndBots = 0x0a, // no data
|
||||
lskStickersOld = 0x0b, // no data
|
||||
|
@ -503,6 +503,7 @@ enum { // Local Storage Keys
|
|||
lskTrustedBots = 0x11, // no data
|
||||
lskFavedStickers = 0x12, // no data
|
||||
lskExportSettings = 0x13, // no data
|
||||
lskBackground = 0x14, // no data
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -539,7 +540,7 @@ enum {
|
|||
dbiCompressPastedImage = 0x1e,
|
||||
dbiLangOld = 0x1f,
|
||||
dbiLangFileOld = 0x20,
|
||||
dbiTileBackground = 0x21,
|
||||
dbiTileBackgroundOld = 0x21,
|
||||
dbiAutoLock = 0x22,
|
||||
dbiDialogLastPath = 0x23,
|
||||
dbiRecentEmojiOld = 0x24,
|
||||
|
@ -567,7 +568,7 @@ enum {
|
|||
dbiNativeNotifications = 0x44,
|
||||
dbiNotificationsCount = 0x45,
|
||||
dbiNotificationsCorner = 0x46,
|
||||
dbiThemeKey = 0x47,
|
||||
dbiThemeKeyOld = 0x47,
|
||||
dbiDialogsWidthRatioOld = 0x48,
|
||||
dbiUseExternalVideoPlayer = 0x49,
|
||||
dbiDcOptions = 0x4a,
|
||||
|
@ -580,6 +581,8 @@ enum {
|
|||
dbiSuggestStickersByEmoji = 0x51,
|
||||
dbiSuggestEmoji = 0x52,
|
||||
dbiTxtDomainString = 0x53,
|
||||
dbiThemeKey = 0x54,
|
||||
dbiTileBackground = 0x55,
|
||||
|
||||
dbiEncryptedWithSalt = 333,
|
||||
dbiEncrypted = 444,
|
||||
|
@ -624,13 +627,17 @@ FileKey _recentStickersKeyOld = 0;
|
|||
FileKey _installedStickersKey = 0, _featuredStickersKey = 0, _recentStickersKey = 0, _favedStickersKey = 0, _archivedStickersKey = 0;
|
||||
FileKey _savedGifsKey = 0;
|
||||
|
||||
FileKey _backgroundKey = 0;
|
||||
bool _backgroundWasRead = false;
|
||||
FileKey _backgroundKeyDay = 0;
|
||||
FileKey _backgroundKeyNight = 0;
|
||||
bool _backgroundCanWrite = true;
|
||||
|
||||
FileKey _themeKey = 0;
|
||||
QString _themeAbsolutePath;
|
||||
QString _themePaletteAbsolutePath;
|
||||
FileKey _themeKeyDay = 0;
|
||||
FileKey _themeKeyNight = 0;
|
||||
|
||||
// Theme key legacy may be read in start() with settings.
|
||||
// But it should be moved to keyDay or keyNight inside loadTheme()
|
||||
// and never used after.
|
||||
FileKey _themeKeyLegacy = 0;
|
||||
|
||||
bool _readingUserSettings = false;
|
||||
FileKey _userSettingsKey = 0;
|
||||
|
@ -1277,12 +1284,23 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
|||
Sandbox::refreshGlobalProxy();
|
||||
} break;
|
||||
|
||||
case dbiThemeKey: {
|
||||
quint64 themeKey = 0;
|
||||
stream >> themeKey;
|
||||
case dbiThemeKeyOld: {
|
||||
quint64 key = 0;
|
||||
stream >> key;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
_themeKey = themeKey;
|
||||
_themeKeyLegacy = key;
|
||||
} break;
|
||||
|
||||
case dbiThemeKey: {
|
||||
quint64 keyDay = 0, keyNight = 0;
|
||||
quint32 nightMode = 0;
|
||||
stream >> keyDay >> keyNight >> nightMode;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
_themeKeyDay = keyDay;
|
||||
_themeKeyNight = keyNight;
|
||||
Window::Theme::SetNightModeValue(nightMode == 1);
|
||||
} break;
|
||||
|
||||
case dbiLangPackKey: {
|
||||
|
@ -1413,13 +1431,28 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
|||
if (!_checkStreamStatus(stream)) return false;
|
||||
} break;
|
||||
|
||||
case dbiTileBackground: {
|
||||
case dbiTileBackgroundOld: {
|
||||
qint32 v;
|
||||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
bool tile = (version < 8005 && !_backgroundKey) ? false : (v == 1);
|
||||
Window::Theme::Background()->setTile(tile);
|
||||
bool tile = (version < 8005 && !_backgroundKeyDay)
|
||||
? false
|
||||
: (v == 1);
|
||||
if (Window::Theme::IsNightMode()) {
|
||||
Window::Theme::Background()->setTileNightValue(tile);
|
||||
} else {
|
||||
Window::Theme::Background()->setTileDayValue(tile);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dbiTileBackground: {
|
||||
qint32 tileDay, tileNight;
|
||||
stream >> tileDay >> tileNight;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
Window::Theme::Background()->setTileDayValue(tileDay == 1);
|
||||
Window::Theme::Background()->setTileNightValue(tileNight == 1);
|
||||
} break;
|
||||
|
||||
case dbiAdaptiveForWide: {
|
||||
|
@ -1873,7 +1906,7 @@ void _writeUserSettings() {
|
|||
? userDataInstance->serialize()
|
||||
: QByteArray();
|
||||
|
||||
uint32 size = 23 * (sizeof(quint32) + sizeof(qint32));
|
||||
uint32 size = 22 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
|
||||
|
||||
size += sizeof(quint32) + sizeof(qint32);
|
||||
|
@ -1886,6 +1919,7 @@ void _writeUserSettings() {
|
|||
size += sizeof(quint32) + Serialize::stringSize(cDialogLastPath());
|
||||
size += sizeof(quint32) + 3 * sizeof(qint32);
|
||||
size += sizeof(quint32) + 2 * sizeof(qint32);
|
||||
size += sizeof(quint32) + 2 * sizeof(qint32);
|
||||
if (!Global::HiddenPinnedMessages().isEmpty()) {
|
||||
size += sizeof(quint32) + sizeof(qint32) + Global::HiddenPinnedMessages().size() * (sizeof(PeerId) + sizeof(MsgId));
|
||||
}
|
||||
|
@ -1895,7 +1929,10 @@ void _writeUserSettings() {
|
|||
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << quint32(dbiSendKey) << qint32(cCtrlEnter() ? dbiskCtrlEnter : dbiskEnter);
|
||||
data.stream << quint32(dbiTileBackground) << qint32(Window::Theme::Background()->tileForSave() ? 1 : 0);
|
||||
data.stream
|
||||
<< quint32(dbiTileBackground)
|
||||
<< qint32(Window::Theme::Background()->tileDay() ? 1 : 0)
|
||||
<< qint32(Window::Theme::Background()->tileNight() ? 1 : 0);
|
||||
data.stream << quint32(dbiAdaptiveForWide) << qint32(Global::AdaptiveForWide() ? 1 : 0);
|
||||
data.stream << quint32(dbiAutoLock) << qint32(Global::AutoLock());
|
||||
data.stream << quint32(dbiReplaceEmoji) << qint32(Global::ReplaceEmoji() ? 1 : 0);
|
||||
|
@ -2076,7 +2113,8 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||
quint64 recentStickersKeyOld = 0;
|
||||
quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0;
|
||||
quint64 savedGifsKey = 0;
|
||||
quint64 backgroundKey = 0, userSettingsKey = 0, recentHashtagsAndBotsKey = 0, savedPeersKey = 0, exportSettingsKey = 0;
|
||||
quint64 backgroundKeyDay = 0, backgroundKeyNight = 0;
|
||||
quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, savedPeersKey = 0, exportSettingsKey = 0;
|
||||
while (!map.stream.atEnd()) {
|
||||
quint32 keyType;
|
||||
map.stream >> keyType;
|
||||
|
@ -2150,8 +2188,13 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||
case lskRecentStickersOld: {
|
||||
map.stream >> recentStickersKeyOld;
|
||||
} break;
|
||||
case lskBackgroundOld: {
|
||||
map.stream >> (Window::Theme::IsNightMode()
|
||||
? backgroundKeyNight
|
||||
: backgroundKeyDay);
|
||||
} break;
|
||||
case lskBackground: {
|
||||
map.stream >> backgroundKey;
|
||||
map.stream >> backgroundKeyDay >> backgroundKeyNight;
|
||||
} break;
|
||||
case lskUserSettings: {
|
||||
map.stream >> userSettingsKey;
|
||||
|
@ -2212,7 +2255,8 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||
_archivedStickersKey = archivedStickersKey;
|
||||
_savedGifsKey = savedGifsKey;
|
||||
_savedPeersKey = savedPeersKey;
|
||||
_backgroundKey = backgroundKey;
|
||||
_backgroundKeyDay = backgroundKeyDay;
|
||||
_backgroundKeyNight = backgroundKeyNight;
|
||||
_userSettingsKey = userSettingsKey;
|
||||
_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
|
||||
_exportSettingsKey = exportSettingsKey;
|
||||
|
@ -2291,7 +2335,7 @@ void _writeMap(WriteMapWhen when) {
|
|||
if (_favedStickersKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_savedGifsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_savedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_backgroundKeyDay || _backgroundKeyNight) mapSize += sizeof(quint32) + sizeof(quint64) + sizeof(quint64);
|
||||
if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_recentHashtagsAndBotsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_exportSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
|
@ -2363,8 +2407,11 @@ void _writeMap(WriteMapWhen when) {
|
|||
if (_savedPeersKey) {
|
||||
mapData.stream << quint32(lskSavedPeers) << quint64(_savedPeersKey);
|
||||
}
|
||||
if (_backgroundKey) {
|
||||
mapData.stream << quint32(lskBackground) << quint64(_backgroundKey);
|
||||
if (_backgroundKeyDay || _backgroundKeyNight) {
|
||||
mapData.stream
|
||||
<< quint32(lskBackground)
|
||||
<< quint64(_backgroundKeyDay)
|
||||
<< quint64(_backgroundKeyNight);
|
||||
}
|
||||
if (_userSettingsKey) {
|
||||
mapData.stream << quint32(lskUserSettings) << quint64(_userSettingsKey);
|
||||
|
@ -2396,7 +2443,7 @@ void finish() {
|
|||
}
|
||||
}
|
||||
|
||||
void readTheme();
|
||||
void loadTheme();
|
||||
void readLangPack();
|
||||
|
||||
void start() {
|
||||
|
@ -2454,7 +2501,7 @@ void start() {
|
|||
_oldSettingsVersion = settingsData.version;
|
||||
_settingsSalt = salt;
|
||||
|
||||
readTheme();
|
||||
loadTheme();
|
||||
readLangPack();
|
||||
|
||||
applyReadContext(std::move(context));
|
||||
|
@ -2496,9 +2543,8 @@ void writeSettings() {
|
|||
size += sizeof(qint32) + Serialize::stringSize(proxy.host) + sizeof(qint32) + Serialize::stringSize(proxy.user) + Serialize::stringSize(proxy.password);
|
||||
}
|
||||
|
||||
if (_themeKey) {
|
||||
size += sizeof(quint32) + sizeof(quint64);
|
||||
}
|
||||
// Theme keys and night mode.
|
||||
size += sizeof(quint32) + sizeof(quint64) * 2 + sizeof(quint32);
|
||||
if (_langPackKey) {
|
||||
size += sizeof(quint32) + sizeof(quint64);
|
||||
}
|
||||
|
@ -2534,9 +2580,11 @@ void writeSettings() {
|
|||
}
|
||||
|
||||
data.stream << quint32(dbiTryIPv6) << qint32(Global::TryIPv6());
|
||||
if (_themeKey) {
|
||||
data.stream << quint32(dbiThemeKey) << quint64(_themeKey);
|
||||
}
|
||||
data.stream
|
||||
<< quint32(dbiThemeKey)
|
||||
<< quint64(_themeKeyDay)
|
||||
<< quint64(_themeKeyNight)
|
||||
<< quint32(Window::Theme::IsNightMode() ? 1 : 0);
|
||||
if (_langPackKey) {
|
||||
data.stream << quint32(dbiLangPackKey) << quint64(_langPackKey);
|
||||
}
|
||||
|
@ -2640,7 +2688,8 @@ void reset() {
|
|||
_recentStickersKeyOld = 0;
|
||||
_installedStickersKey = _featuredStickersKey = _recentStickersKey = _favedStickersKey = _archivedStickersKey = 0;
|
||||
_savedGifsKey = 0;
|
||||
_backgroundKey = _userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = _exportSettingsKey = 0;
|
||||
_backgroundKeyDay = _backgroundKeyNight = 0;
|
||||
_userSettingsKey = _recentHashtagsAndBotsKey = _savedPeersKey = _exportSettingsKey = 0;
|
||||
_oldMapVersion = _oldSettingsVersion = 0;
|
||||
StoredAuthSessionCache.reset();
|
||||
_mapChanged = true;
|
||||
|
@ -4102,48 +4151,58 @@ void readSavedGifs() {
|
|||
}
|
||||
|
||||
void writeBackground(int32 id, const QImage &img) {
|
||||
if (!_working() || !_backgroundCanWrite) return;
|
||||
if (!_working() || !_backgroundCanWrite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LocalKey) {
|
||||
LOG(("App Error: localkey not created in writeBackground()"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto &backgroundKey = Window::Theme::IsNightMode()
|
||||
? _backgroundKeyNight
|
||||
: _backgroundKeyDay;
|
||||
QByteArray bmp;
|
||||
if (!img.isNull()) {
|
||||
QBuffer buf(&bmp);
|
||||
if (!img.save(&buf, "BMP")) return;
|
||||
if (!img.save(&buf, "BMP")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!_backgroundKey) {
|
||||
_backgroundKey = genKey();
|
||||
if (!backgroundKey) {
|
||||
backgroundKey = genKey();
|
||||
_mapChanged = true;
|
||||
_writeMap(WriteMapWhen::Fast);
|
||||
}
|
||||
quint32 size = sizeof(qint32) + sizeof(quint32) + (bmp.isEmpty() ? 0 : (sizeof(quint32) + bmp.size()));
|
||||
quint32 size = sizeof(qint32)
|
||||
+ sizeof(quint32)
|
||||
+ (bmp.isEmpty() ? 0 : (sizeof(quint32) + bmp.size()));
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << qint32(id) << bmp;
|
||||
|
||||
FileWriteDescriptor file(_backgroundKey);
|
||||
FileWriteDescriptor file(backgroundKey);
|
||||
file.writeEncrypted(data);
|
||||
}
|
||||
|
||||
bool readBackground() {
|
||||
if (_backgroundWasRead) {
|
||||
return false;
|
||||
}
|
||||
_backgroundWasRead = true;
|
||||
|
||||
FileReadDescriptor bg;
|
||||
if (!readEncryptedFile(bg, _backgroundKey)) {
|
||||
clearKey(_backgroundKey);
|
||||
_backgroundKey = 0;
|
||||
_writeMap();
|
||||
auto &backgroundKey = Window::Theme::IsNightMode()
|
||||
? _backgroundKeyNight
|
||||
: _backgroundKeyDay;
|
||||
if (!readEncryptedFile(bg, backgroundKey)) {
|
||||
if (backgroundKey) {
|
||||
clearKey(backgroundKey);
|
||||
backgroundKey = 0;
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray pngData;
|
||||
QByteArray bmpData;
|
||||
qint32 id;
|
||||
bg.stream >> id >> pngData;
|
||||
bg.stream >> id >> bmpData;
|
||||
auto oldEmptyImage = (bg.stream.status() != QDataStream::Ok);
|
||||
if (oldEmptyImage
|
||||
|| id == Window::Theme::kInitialBackground
|
||||
|
@ -4157,7 +4216,7 @@ bool readBackground() {
|
|||
}
|
||||
_backgroundCanWrite = true;
|
||||
return true;
|
||||
} else if (id == Window::Theme::kThemeBackground && pngData.isEmpty()) {
|
||||
} else if (id == Window::Theme::kThemeBackground && bmpData.isEmpty()) {
|
||||
_backgroundCanWrite = false;
|
||||
Window::Theme::Background()->setImage(id);
|
||||
_backgroundCanWrite = true;
|
||||
|
@ -4165,7 +4224,7 @@ bool readBackground() {
|
|||
}
|
||||
|
||||
QImage image;
|
||||
QBuffer buf(&pngData);
|
||||
QBuffer buf(&bmpData);
|
||||
QImageReader reader(&buf);
|
||||
#ifndef OS_MAC_OLD
|
||||
reader.setAutoTransform(true);
|
||||
|
@ -4179,96 +4238,127 @@ bool readBackground() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool readThemeUsingKey(FileKey key) {
|
||||
Window::Theme::Saved readThemeUsingKey(FileKey key) {
|
||||
FileReadDescriptor theme;
|
||||
if (!readEncryptedFile(theme, key, FileOption::Safe, SettingsKey)) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray themeContent;
|
||||
QString pathRelative, pathAbsolute;
|
||||
Window::Theme::Cached cache;
|
||||
theme.stream >> themeContent;
|
||||
theme.stream >> pathRelative >> pathAbsolute;
|
||||
auto result = Window::Theme::Saved();
|
||||
theme.stream >> result.content;
|
||||
theme.stream >> result.pathRelative >> result.pathAbsolute;
|
||||
if (theme.stream.status() != QDataStream::Ok) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
_themeAbsolutePath = pathAbsolute;
|
||||
_themePaletteAbsolutePath = Window::Theme::IsPaletteTestingPath(pathAbsolute) ? pathAbsolute : QString();
|
||||
|
||||
QFile file(pathRelative);
|
||||
if (pathRelative.isEmpty() || !file.exists()) {
|
||||
file.setFileName(pathAbsolute);
|
||||
QFile file(result.pathRelative);
|
||||
if (result.pathRelative.isEmpty() || !file.exists()) {
|
||||
file.setFileName(result.pathAbsolute);
|
||||
}
|
||||
|
||||
auto changed = false;
|
||||
if (!file.fileName().isEmpty() && file.exists() && file.open(QIODevice::ReadOnly)) {
|
||||
if (!file.fileName().isEmpty()
|
||||
&& file.exists()
|
||||
&& file.open(QIODevice::ReadOnly)) {
|
||||
if (file.size() > kThemeFileSizeLimit) {
|
||||
LOG(("Error: theme file too large: %1 (should be less than 5 MB, got %2)").arg(file.fileName()).arg(file.size()));
|
||||
return false;
|
||||
LOG(("Error: theme file too large: %1 "
|
||||
"(should be less than 5 MB, got %2)"
|
||||
).arg(file.fileName()
|
||||
).arg(file.size()));
|
||||
return {};
|
||||
}
|
||||
auto fileContent = file.readAll();
|
||||
file.close();
|
||||
if (themeContent != fileContent) {
|
||||
themeContent = fileContent;
|
||||
if (result.content != fileContent) {
|
||||
result.content = fileContent;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
quint32 backgroundIsTiled = 0;
|
||||
theme.stream >> cache.paletteChecksum >> cache.contentChecksum >> cache.colors >> cache.background >> backgroundIsTiled;
|
||||
cache.tiled = (backgroundIsTiled == 1);
|
||||
theme.stream
|
||||
>> result.cache.paletteChecksum
|
||||
>> result.cache.contentChecksum
|
||||
>> result.cache.colors
|
||||
>> result.cache.background
|
||||
>> backgroundIsTiled;
|
||||
result.cache.tiled = (backgroundIsTiled == 1);
|
||||
if (theme.stream.status() != QDataStream::Ok) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return Window::Theme::Load(pathRelative, pathAbsolute, themeContent, cache);
|
||||
return result;
|
||||
}
|
||||
|
||||
void writeTheme(const QString &pathRelative, const QString &pathAbsolute, const QByteArray &content, const Window::Theme::Cached &cache) {
|
||||
if (content.isEmpty()) {
|
||||
_themeAbsolutePath = _themePaletteAbsolutePath = QString();
|
||||
if (_themeKey) {
|
||||
clearKey(_themeKey);
|
||||
_themeKey = 0;
|
||||
QString loadThemeUsingKey(FileKey key) {
|
||||
auto read = readThemeUsingKey(key);
|
||||
const auto result = read.pathAbsolute;
|
||||
return (!read.content.isEmpty() && Window::Theme::Load(std::move(read)))
|
||||
? result
|
||||
: QString();
|
||||
}
|
||||
|
||||
void writeTheme(const Window::Theme::Saved &saved) {
|
||||
auto &themeKey = Window::Theme::IsNightMode()
|
||||
? _themeKeyNight
|
||||
: _themeKeyDay;
|
||||
if (saved.content.isEmpty()) {
|
||||
if (themeKey) {
|
||||
clearKey(themeKey);
|
||||
themeKey = 0;
|
||||
writeSettings();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_themeAbsolutePath = pathAbsolute;
|
||||
_themePaletteAbsolutePath = Window::Theme::IsPaletteTestingPath(pathAbsolute) ? pathAbsolute : QString();
|
||||
if (!_themeKey) {
|
||||
_themeKey = genKey(FileOption::Safe);
|
||||
if (!themeKey) {
|
||||
themeKey = genKey(FileOption::Safe);
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
auto backgroundTiled = static_cast<quint32>(cache.tiled ? 1 : 0);
|
||||
quint32 size = Serialize::bytearraySize(content);
|
||||
size += Serialize::stringSize(pathRelative) + Serialize::stringSize(pathAbsolute);
|
||||
size += sizeof(int32) * 2 + Serialize::bytearraySize(cache.colors) + Serialize::bytearraySize(cache.background) + sizeof(quint32);
|
||||
auto backgroundTiled = static_cast<quint32>(saved.cache.tiled ? 1 : 0);
|
||||
quint32 size = Serialize::bytearraySize(saved.content);
|
||||
size += Serialize::stringSize(saved.pathRelative) + Serialize::stringSize(saved.pathAbsolute);
|
||||
size += sizeof(int32) * 2 + Serialize::bytearraySize(saved.cache.colors) + Serialize::bytearraySize(saved.cache.background) + sizeof(quint32);
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << content;
|
||||
data.stream << pathRelative << pathAbsolute;
|
||||
data.stream << cache.paletteChecksum << cache.contentChecksum << cache.colors << cache.background << backgroundTiled;
|
||||
data.stream << saved.content;
|
||||
data.stream << saved.pathRelative << saved.pathAbsolute;
|
||||
data.stream << saved.cache.paletteChecksum << saved.cache.contentChecksum << saved.cache.colors << saved.cache.background << backgroundTiled;
|
||||
|
||||
FileWriteDescriptor file(_themeKey, FileOption::Safe);
|
||||
FileWriteDescriptor file(themeKey, FileOption::Safe);
|
||||
file.writeEncrypted(data, SettingsKey);
|
||||
}
|
||||
|
||||
void clearTheme() {
|
||||
writeTheme(QString(), QString(), QByteArray(), Window::Theme::Cached());
|
||||
writeTheme(Window::Theme::Saved());
|
||||
}
|
||||
|
||||
void readTheme() {
|
||||
if (_themeKey && !readThemeUsingKey(_themeKey)) {
|
||||
void loadTheme() {
|
||||
const auto key = (_themeKeyLegacy != 0)
|
||||
? _themeKeyLegacy
|
||||
: (Window::Theme::IsNightMode()
|
||||
? _themeKeyNight
|
||||
: _themeKeyDay);
|
||||
if (!key) {
|
||||
return;
|
||||
} else if (const auto path = loadThemeUsingKey(key); !path.isEmpty()) {
|
||||
if (_themeKeyLegacy) {
|
||||
Window::Theme::SetNightModeValue(path
|
||||
== Window::Theme::NightThemePath());
|
||||
(Window::Theme::IsNightMode()
|
||||
? _themeKeyNight
|
||||
: _themeKeyDay) = base::take(_themeKeyLegacy);
|
||||
}
|
||||
} else {
|
||||
clearTheme();
|
||||
}
|
||||
}
|
||||
|
||||
bool hasTheme() {
|
||||
return (_themeKey != 0);
|
||||
Window::Theme::Saved readThemeAfterSwitch() {
|
||||
const auto key = Window::Theme::IsNightMode()
|
||||
? _themeKeyNight
|
||||
: _themeKeyDay;
|
||||
return readThemeUsingKey(key);
|
||||
}
|
||||
|
||||
void readLangPack() {
|
||||
|
@ -4297,21 +4387,16 @@ void writeLangPack() {
|
|||
file.writeEncrypted(data, SettingsKey);
|
||||
}
|
||||
|
||||
QString themePaletteAbsolutePath() {
|
||||
return _themePaletteAbsolutePath;
|
||||
}
|
||||
|
||||
QString themeAbsolutePath() {
|
||||
return _themeAbsolutePath;
|
||||
}
|
||||
|
||||
bool copyThemeColorsToPalette(const QString &path) {
|
||||
if (!_themeKey) {
|
||||
auto &themeKey = Window::Theme::IsNightMode()
|
||||
? _themeKeyNight
|
||||
: _themeKeyDay;
|
||||
if (!themeKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FileReadDescriptor theme;
|
||||
if (!readEncryptedFile(theme, _themeKey, FileOption::Safe, SettingsKey)) {
|
||||
if (!readEncryptedFile(theme, themeKey, FileOption::Safe, SettingsKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Window {
|
||||
namespace Theme {
|
||||
struct Cached;
|
||||
struct Saved;
|
||||
} // namespace Theme
|
||||
} // namespace Window
|
||||
|
||||
|
@ -152,12 +152,10 @@ int32 countSavedGifsHash();
|
|||
void writeBackground(int32 id, const QImage &img);
|
||||
bool readBackground();
|
||||
|
||||
void writeTheme(const QString &pathRelative, const QString &pathAbsolute, const QByteArray &content, const Window::Theme::Cached &cache);
|
||||
void writeTheme(const Window::Theme::Saved &saved);
|
||||
void clearTheme();
|
||||
bool hasTheme();
|
||||
QString themeAbsolutePath();
|
||||
QString themePaletteAbsolutePath();
|
||||
bool copyThemeColorsToPalette(const QString &file);
|
||||
Window::Theme::Saved readThemeAfterSwitch();
|
||||
|
||||
void writeLangPack();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "window/themes/window_theme.h"
|
||||
|
||||
#include "window/themes/window_theme_preview.h"
|
||||
#include "mainwidget.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "base/parse_helper.h"
|
||||
|
@ -27,7 +28,8 @@ constexpr auto kNightThemeFile = str_const(":/gui/night.tdesktop-theme");
|
|||
|
||||
struct Data {
|
||||
struct Applying {
|
||||
QString path;
|
||||
QString pathRelative;
|
||||
QString pathAbsolute;
|
||||
QByteArray content;
|
||||
QByteArray paletteForRevert;
|
||||
Cached cached;
|
||||
|
@ -195,7 +197,7 @@ void applyBackground(QImage &&background, bool tiled, Instance *out) {
|
|||
}
|
||||
}
|
||||
|
||||
bool loadThemeFromCache(const QByteArray &content, Cached &cache) {
|
||||
bool loadThemeFromCache(const QByteArray &content, const Cached &cache) {
|
||||
if (cache.paletteChecksum != style::palette::Checksum()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -205,8 +207,8 @@ bool loadThemeFromCache(const QByteArray &content, Cached &cache) {
|
|||
|
||||
QImage background;
|
||||
if (!cache.background.isEmpty()) {
|
||||
QBuffer buffer(&cache.background);
|
||||
QImageReader reader(&buffer);
|
||||
QDataStream stream(cache.background);
|
||||
QImageReader reader(stream.device());
|
||||
#ifndef OS_MAC_OLD
|
||||
reader.setAutoTransform(true);
|
||||
#endif // OS_MAC_OLD
|
||||
|
@ -364,6 +366,24 @@ void adjustColorsUsingBackground(const QImage &img) {
|
|||
adjustColor(st::historyScroll.barBgOver, hue, saturation);
|
||||
}
|
||||
|
||||
void ApplyDefaultWithNightMode(bool nightMode) {
|
||||
if (nightMode) {
|
||||
if (auto preview = PreviewFromFile(NightThemePath())) {
|
||||
Apply(std::move(preview));
|
||||
}
|
||||
} else {
|
||||
instance.createIfNull();
|
||||
instance->applying.pathRelative = QString();
|
||||
instance->applying.pathAbsolute = QString();
|
||||
instance->applying.content = QByteArray();
|
||||
instance->applying.cached = Cached();
|
||||
if (instance->applying.paletteForRevert.isEmpty()) {
|
||||
instance->applying.paletteForRevert = style::main_palette::save();
|
||||
}
|
||||
Background()->setTestingDefaultTheme();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ChatBackground::setThemeData(QImage &&themeImage, bool themeTile) {
|
||||
|
@ -380,7 +400,10 @@ void ChatBackground::start() {
|
|||
}
|
||||
|
||||
void ChatBackground::setImage(int32 id, QImage &&image) {
|
||||
auto resetPalette = (id == kDefaultBackground && _id != kDefaultBackground && !Local::hasTheme());
|
||||
auto resetPalette = (id == kDefaultBackground)
|
||||
&& (_id != kDefaultBackground)
|
||||
&& !nightMode()
|
||||
&& _themeAbsolutePath.isEmpty();
|
||||
if (id == kThemeBackground && _themeImage.isNull()) {
|
||||
id = kDefaultBackground;
|
||||
} else if (resetPalette) {
|
||||
|
@ -392,7 +415,7 @@ void ChatBackground::setImage(int32 id, QImage &&image) {
|
|||
}
|
||||
_id = id;
|
||||
if (_id == kThemeBackground) {
|
||||
_tile = _themeTile;
|
||||
(nightMode() ? _tileNightValue : _tileDayValue) = _themeTile;
|
||||
setPreparedImage(QImage(_themeImage));
|
||||
} else if (_id == internal::kTestingThemeBackground
|
||||
|| _id == internal::kTestingDefaultBackground
|
||||
|
@ -418,10 +441,10 @@ void ChatBackground::setImage(int32 id, QImage &&image) {
|
|||
setPreparedImage(prepareBackgroundImage(std::move(image)));
|
||||
}
|
||||
Assert(!_pixmap.isNull() && !_pixmapForTiled.isNull());
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::New, _tile));
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::New, tile()));
|
||||
if (resetPalette) {
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, _tile), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::ApplyingTheme, _tile), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, tile()), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::ApplyingTheme, tile()), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,33 +452,30 @@ void ChatBackground::setPreparedImage(QImage &&image) {
|
|||
image = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
image.setDevicePixelRatio(cRetinaFactor());
|
||||
|
||||
auto adjustColors = [this] {
|
||||
auto someThemeApplied = [] {
|
||||
if (AreTestingTheme()) {
|
||||
return !instance->applying.path.isEmpty();
|
||||
}
|
||||
return IsNonDefaultUsed() || IsNightTheme();
|
||||
auto adjustColors = [&] {
|
||||
const auto usingThemeBackground = [&] {
|
||||
return (_id == kThemeBackground)
|
||||
|| (_id == internal::kTestingThemeBackground);
|
||||
};
|
||||
auto usingThemeBackground = [this] {
|
||||
return (_id == kThemeBackground || _id == internal::kTestingThemeBackground);
|
||||
const auto usingDefaultBackground = [&] {
|
||||
return (_id == kDefaultBackground)
|
||||
|| (_id == internal::kTestingDefaultBackground);
|
||||
};
|
||||
auto usingDefaultBackground = [this] {
|
||||
return (_id == kDefaultBackground || _id == internal::kTestingDefaultBackground);
|
||||
};
|
||||
auto testingPalette = [] {
|
||||
if (AreTestingTheme()) {
|
||||
return IsPaletteTestingPath(instance->applying.path);
|
||||
}
|
||||
return !Local::themePaletteAbsolutePath().isEmpty();
|
||||
const auto testingPalette = [&] {
|
||||
const auto path = AreTestingTheme()
|
||||
? instance->applying.pathAbsolute
|
||||
: _themeAbsolutePath;
|
||||
return IsPaletteTestingPath(path);
|
||||
};
|
||||
|
||||
if (someThemeApplied()) {
|
||||
return !usingThemeBackground() && !testingPalette();
|
||||
if (testingPalette()) {
|
||||
return false;
|
||||
} else if (IsNonDefaultThemeOrBackground() || nightMode()) {
|
||||
return !usingThemeBackground();
|
||||
}
|
||||
return !usingDefaultBackground();
|
||||
};
|
||||
|
||||
if (adjustColors()) {
|
||||
}();
|
||||
if (adjustColors) {
|
||||
adjustColorsUsingBackground(image);
|
||||
}
|
||||
|
||||
|
@ -494,15 +514,27 @@ int32 ChatBackground::id() const {
|
|||
}
|
||||
|
||||
bool ChatBackground::tile() const {
|
||||
return _tile;
|
||||
return nightMode() ? _tileNightValue : _tileDayValue;
|
||||
}
|
||||
|
||||
bool ChatBackground::tileForSave() const {
|
||||
bool ChatBackground::tileDay() const {
|
||||
if (_id == internal::kTestingThemeBackground ||
|
||||
_id == internal::kTestingDefaultBackground) {
|
||||
return _tileForRevert;
|
||||
if (!nightMode()) {
|
||||
return _tileForRevert;
|
||||
}
|
||||
}
|
||||
return tile();
|
||||
return _tileDayValue;
|
||||
}
|
||||
|
||||
bool ChatBackground::tileNight() const {
|
||||
if (_id == internal::kTestingThemeBackground ||
|
||||
_id == internal::kTestingDefaultBackground) {
|
||||
if (nightMode()) {
|
||||
return _tileForRevert;
|
||||
}
|
||||
}
|
||||
return _tileNightValue;
|
||||
}
|
||||
|
||||
void ChatBackground::ensureStarted() {
|
||||
|
@ -515,17 +547,42 @@ void ChatBackground::ensureStarted() {
|
|||
|
||||
void ChatBackground::setTile(bool tile) {
|
||||
ensureStarted();
|
||||
if (_tile != tile) {
|
||||
_tile = tile;
|
||||
if (_id != internal::kTestingThemeBackground && _id != internal::kTestingDefaultBackground) {
|
||||
const auto old = this->tile();
|
||||
if (nightMode()) {
|
||||
setTileNightValue(tile);
|
||||
} else {
|
||||
setTileDayValue(tile);
|
||||
}
|
||||
if (this->tile() != old) {
|
||||
if (_id != internal::kTestingThemeBackground
|
||||
&& _id != internal::kTestingDefaultBackground) {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::Changed, _tile));
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::Changed, tile));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatBackground::setTileDayValue(bool tile) {
|
||||
ensureStarted();
|
||||
_tileDayValue = tile;
|
||||
}
|
||||
|
||||
void ChatBackground::setTileNightValue(bool tile) {
|
||||
ensureStarted();
|
||||
_tileNightValue = tile;
|
||||
}
|
||||
|
||||
void ChatBackground::setThemeAbsolutePath(const QString &path) {
|
||||
_themeAbsolutePath = path;
|
||||
}
|
||||
|
||||
QString ChatBackground::themeAbsolutePath() const {
|
||||
return _themeAbsolutePath;
|
||||
}
|
||||
|
||||
void ChatBackground::reset() {
|
||||
if (_id == internal::kTestingThemeBackground || _id == internal::kTestingDefaultBackground) {
|
||||
if (_id == internal::kTestingThemeBackground
|
||||
|| _id == internal::kTestingDefaultBackground) {
|
||||
if (_themeImage.isNull()) {
|
||||
_idForRevert = kDefaultBackground;
|
||||
_imageForRevert = QImage();
|
||||
|
@ -542,10 +599,11 @@ void ChatBackground::reset() {
|
|||
|
||||
void ChatBackground::saveForRevert() {
|
||||
ensureStarted();
|
||||
if (_id != internal::kTestingThemeBackground && _id != internal::kTestingDefaultBackground) {
|
||||
if (_id != internal::kTestingThemeBackground
|
||||
&& _id != internal::kTestingDefaultBackground) {
|
||||
_idForRevert = _id;
|
||||
_imageForRevert = std::move(_pixmap).toImage();
|
||||
_tileForRevert = _tile;
|
||||
_tileForRevert = tile();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,8 +611,10 @@ void ChatBackground::setTestingTheme(Instance &&theme, ChangeMode mode) {
|
|||
style::main_palette::apply(theme.palette);
|
||||
auto switchToThemeBackground = (mode == ChangeMode::SwitchToThemeBackground && !theme.background.isNull())
|
||||
|| (_id == kThemeBackground)
|
||||
|| (_id == kDefaultBackground && !Local::hasTheme());
|
||||
if (AreTestingTheme() && IsPaletteTestingPath(instance->applying.path)) {
|
||||
|| (_id == kDefaultBackground
|
||||
&& !nightMode()
|
||||
&& _themeAbsolutePath.isEmpty());
|
||||
if (AreTestingTheme() && IsPaletteTestingPath(instance->applying.pathAbsolute)) {
|
||||
// Grab current background image if it is not already custom
|
||||
if (_id != kCustomBackground) {
|
||||
saveForRevert();
|
||||
|
@ -568,47 +628,61 @@ void ChatBackground::setTestingTheme(Instance &&theme, ChangeMode mode) {
|
|||
// Apply current background image so that service bg colors are recounted.
|
||||
setImage(_id, std::move(_pixmap).toImage());
|
||||
}
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, _tile), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, tile()), true);
|
||||
}
|
||||
|
||||
void ChatBackground::setTestingDefaultTheme() {
|
||||
style::main_palette::reset();
|
||||
if (_id == kThemeBackground) {
|
||||
saveForRevert();
|
||||
setImage(internal::kTestingDefaultBackground);
|
||||
setTile(false);
|
||||
} else {
|
||||
// Apply current background image so that service bg colors are recounted.
|
||||
setImage(_id, std::move(_pixmap).toImage());
|
||||
}
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, _tile), true);
|
||||
saveForRevert();
|
||||
setImage(internal::kTestingDefaultBackground);
|
||||
setTile(false);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::TestingTheme, tile()), true);
|
||||
}
|
||||
|
||||
void ChatBackground::keepApplied() {
|
||||
void ChatBackground::keepApplied(const QString &path, bool write) {
|
||||
setThemeAbsolutePath(path);
|
||||
if (_id == internal::kTestingEditorBackground) {
|
||||
_id = kCustomBackground;
|
||||
_themeImage = QImage();
|
||||
_themeTile = false;
|
||||
writeNewBackgroundSettings();
|
||||
if (write) {
|
||||
writeNewBackgroundSettings();
|
||||
}
|
||||
} else if (_id == internal::kTestingThemeBackground) {
|
||||
_id = kThemeBackground;
|
||||
_themeImage = _pixmap.toImage();
|
||||
_themeTile = _tile;
|
||||
writeNewBackgroundSettings();
|
||||
_themeTile = tile();
|
||||
if (write) {
|
||||
writeNewBackgroundSettings();
|
||||
}
|
||||
} else if (_id == internal::kTestingDefaultBackground) {
|
||||
_id = kDefaultBackground;
|
||||
_themeImage = QImage();
|
||||
_themeTile = false;
|
||||
writeNewBackgroundSettings();
|
||||
if (write) {
|
||||
writeNewBackgroundSettings();
|
||||
}
|
||||
}
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::ApplyingTheme, _tile), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::ApplyingTheme, tile()), true);
|
||||
}
|
||||
|
||||
bool ChatBackground::isNonDefaultThemeOrBackground() const {
|
||||
return nightMode()
|
||||
? (_themeAbsolutePath != NightThemePath()
|
||||
|| _id != kThemeBackground)
|
||||
: (!_themeAbsolutePath.isEmpty()
|
||||
|| _id != kDefaultBackground);
|
||||
}
|
||||
|
||||
void ChatBackground::writeNewBackgroundSettings() {
|
||||
if (_tile != _tileForRevert) {
|
||||
if (tile() != _tileForRevert) {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
Local::writeBackground(_id, (_id == kThemeBackground || _id == kDefaultBackground) ? QImage() : _pixmap.toImage());
|
||||
Local::writeBackground(
|
||||
_id,
|
||||
((_id == kThemeBackground || _id == kDefaultBackground)
|
||||
? QImage()
|
||||
: _pixmap.toImage()));
|
||||
}
|
||||
|
||||
void ChatBackground::revert() {
|
||||
|
@ -621,30 +695,100 @@ void ChatBackground::revert() {
|
|||
// Apply current background image so that service bg colors are recounted.
|
||||
setImage(_id, std::move(_pixmap).toImage());
|
||||
}
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::RevertingTheme, _tile), true);
|
||||
notify(BackgroundUpdate(BackgroundUpdate::Type::RevertingTheme, tile()), true);
|
||||
}
|
||||
|
||||
void ChatBackground::setNightModeValue(bool nightMode) {
|
||||
_nightMode = nightMode;
|
||||
}
|
||||
|
||||
bool ChatBackground::nightMode() const {
|
||||
return _nightMode;
|
||||
}
|
||||
|
||||
void ChatBackground::toggleNightMode() {
|
||||
const auto oldNightMode = _nightMode;
|
||||
const auto newNightMode = !_nightMode;
|
||||
_nightMode = newNightMode;
|
||||
auto read = Local::readThemeAfterSwitch();
|
||||
auto path = read.pathAbsolute;
|
||||
|
||||
_nightMode = oldNightMode;
|
||||
auto oldTileValue = (_nightMode ? _tileNightValue : _tileDayValue);
|
||||
const auto applied = [&] {
|
||||
if (read.content.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
auto preview = std::make_unique<Preview>();
|
||||
preview->pathAbsolute = std::move(read.pathAbsolute);
|
||||
preview->pathRelative = std::move(read.pathRelative);
|
||||
preview->content = std::move(read.content);
|
||||
preview->instance.cached = std::move(read.cache);
|
||||
const auto loaded = loadTheme(
|
||||
preview->content,
|
||||
preview->instance.cached,
|
||||
&preview->instance);
|
||||
if (!loaded) {
|
||||
return false;
|
||||
}
|
||||
Apply(std::move(preview));
|
||||
return true;
|
||||
}();
|
||||
if (!applied) {
|
||||
path = newNightMode ? NightThemePath() : QString();
|
||||
ApplyDefaultWithNightMode(newNightMode);
|
||||
}
|
||||
|
||||
// Theme editor could have already reverted the testing of this toggle.
|
||||
if (AreTestingTheme()) {
|
||||
_nightMode = newNightMode;
|
||||
if (oldNightMode) {
|
||||
_tileDayValue = _tileNightValue;
|
||||
_tileNightValue = oldTileValue;
|
||||
} else {
|
||||
_tileNightValue = _tileDayValue;
|
||||
_tileDayValue = oldTileValue;
|
||||
}
|
||||
|
||||
// We don't call full KeepApplied() here, because
|
||||
// we don't need to write theme or overwrite current background.
|
||||
instance->applying = Data::Applying();
|
||||
Local::writeSettings();
|
||||
keepApplied(path, false);
|
||||
if (tile() != _tileForRevert) {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
|
||||
if (!Local::readBackground()) {
|
||||
setImage(kThemeBackground);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChatBackground *Background() {
|
||||
instance.createIfNull();
|
||||
return &instance->background;
|
||||
}
|
||||
|
||||
bool Load(const QString &pathRelative, const QString &pathAbsolute, const QByteArray &content, Cached &cache) {
|
||||
if (content.size() < 4) {
|
||||
LOG(("Theme Error: Could not load theme from '%1' (%2)").arg(pathRelative).arg(pathAbsolute));
|
||||
bool Load(Saved &&saved) {
|
||||
if (saved.content.size() < 4) {
|
||||
LOG(("Theme Error: Could not load theme from '%1' (%2)"
|
||||
).arg(saved.pathRelative
|
||||
).arg(saved.pathAbsolute));
|
||||
return false;
|
||||
}
|
||||
|
||||
instance.createIfNull();
|
||||
if (loadThemeFromCache(content, cache)) {
|
||||
if (loadThemeFromCache(saved.content, saved.cache)) {
|
||||
Background()->setThemeAbsolutePath(saved.pathAbsolute);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!loadTheme(content, cache)) {
|
||||
if (!loadTheme(saved.content, saved.cache)) {
|
||||
return false;
|
||||
}
|
||||
Local::writeTheme(pathRelative, pathAbsolute, content, cache);
|
||||
Local::writeTheme(saved);
|
||||
Background()->setThemeAbsolutePath(saved.pathAbsolute);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -653,38 +797,16 @@ void Unload() {
|
|||
}
|
||||
|
||||
bool Apply(const QString &filepath) {
|
||||
auto preview = std::make_unique<Preview>();
|
||||
preview->path = filepath;
|
||||
if (!LoadFromFile(preview->path, &preview->instance, &preview->content)) {
|
||||
return false;
|
||||
if (auto preview = PreviewFromFile(filepath)) {
|
||||
return Apply(std::move(preview));
|
||||
}
|
||||
return Apply(std::move(preview));
|
||||
}
|
||||
|
||||
void SwitchNightTheme(bool enabled) {
|
||||
if (enabled) {
|
||||
auto preview = std::make_unique<Preview>();
|
||||
preview->path = str_const_toString(kNightThemeFile);
|
||||
if (!LoadFromFile(preview->path, &preview->instance, &preview->content)) {
|
||||
return;
|
||||
}
|
||||
instance.createIfNull();
|
||||
instance->applying.path = std::move(preview->path);
|
||||
instance->applying.content = std::move(preview->content);
|
||||
instance->applying.cached = std::move(preview->instance.cached);
|
||||
if (instance->applying.paletteForRevert.isEmpty()) {
|
||||
instance->applying.paletteForRevert = style::main_palette::save();
|
||||
}
|
||||
Background()->setTestingTheme(std::move(preview->instance), ChatBackground::ChangeMode::LeaveCurrentCustomBackground);
|
||||
} else {
|
||||
Window::Theme::ApplyDefault();
|
||||
}
|
||||
KeepApplied();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Apply(std::unique_ptr<Preview> preview) {
|
||||
instance.createIfNull();
|
||||
instance->applying.path = std::move(preview->path);
|
||||
instance->applying.pathRelative = std::move(preview->pathRelative);
|
||||
instance->applying.pathAbsolute = std::move(preview->pathAbsolute);
|
||||
instance->applying.content = std::move(preview->content);
|
||||
instance->applying.cached = std::move(preview->instance.cached);
|
||||
if (instance->applying.paletteForRevert.isEmpty()) {
|
||||
|
@ -695,14 +817,7 @@ bool Apply(std::unique_ptr<Preview> preview) {
|
|||
}
|
||||
|
||||
void ApplyDefault() {
|
||||
instance.createIfNull();
|
||||
instance->applying.path = QString();
|
||||
instance->applying.content = QByteArray();
|
||||
instance->applying.cached = Cached();
|
||||
if (instance->applying.paletteForRevert.isEmpty()) {
|
||||
instance->applying.paletteForRevert = style::main_palette::save();
|
||||
}
|
||||
Background()->setTestingDefaultTheme();
|
||||
ApplyDefaultWithNightMode(IsNightMode());
|
||||
}
|
||||
|
||||
bool ApplyEditedPalette(const QString &path, const QByteArray &content) {
|
||||
|
@ -715,7 +830,12 @@ bool ApplyEditedPalette(const QString &path, const QByteArray &content) {
|
|||
out.cached.contentChecksum = hashCrc32(content.constData(), content.size());
|
||||
|
||||
instance.createIfNull();
|
||||
instance->applying.path = path;
|
||||
instance->applying.pathRelative = path.isEmpty()
|
||||
? QString()
|
||||
: QDir().relativeFilePath(path);
|
||||
instance->applying.pathAbsolute = path.isEmpty()
|
||||
? QString()
|
||||
: QFileInfo(path).absoluteFilePath();
|
||||
instance->applying.content = content;
|
||||
instance->applying.cached = out.cached;
|
||||
if (instance->applying.paletteForRevert.isEmpty()) {
|
||||
|
@ -727,31 +847,52 @@ bool ApplyEditedPalette(const QString &path, const QByteArray &content) {
|
|||
}
|
||||
|
||||
void KeepApplied() {
|
||||
if (!instance) {
|
||||
if (!AreTestingTheme()) {
|
||||
return;
|
||||
}
|
||||
auto filepath = instance->applying.path;
|
||||
auto pathRelative = filepath.isEmpty() ? QString() : QDir().relativeFilePath(filepath);
|
||||
auto pathAbsolute = filepath.isEmpty() ? QString() : QFileInfo(filepath).absoluteFilePath();
|
||||
Local::writeTheme(pathRelative, pathAbsolute, instance->applying.content, instance->applying.cached);
|
||||
auto saved = Saved();
|
||||
saved.pathRelative = instance->applying.pathRelative;
|
||||
saved.pathAbsolute = instance->applying.pathAbsolute;
|
||||
saved.content = std::move(instance->applying.content);
|
||||
saved.cache = std::move(instance->applying.cached);
|
||||
Local::writeTheme(saved);
|
||||
instance->applying = Data::Applying();
|
||||
Background()->keepApplied();
|
||||
Background()->keepApplied(saved.pathAbsolute, true);
|
||||
}
|
||||
|
||||
void Revert() {
|
||||
if (!instance->applying.paletteForRevert.isEmpty()) {
|
||||
style::main_palette::load(instance->applying.paletteForRevert);
|
||||
if (!AreTestingTheme()) {
|
||||
return;
|
||||
}
|
||||
style::main_palette::load(instance->applying.paletteForRevert);
|
||||
instance->applying = Data::Applying();
|
||||
Background()->revert();
|
||||
}
|
||||
|
||||
bool IsNightTheme() {
|
||||
return (Local::themeAbsolutePath() == str_const_toString(kNightThemeFile));
|
||||
QString NightThemePath() {
|
||||
return str_const_toString(kNightThemeFile);
|
||||
}
|
||||
|
||||
bool IsNonDefaultUsed() {
|
||||
return Local::hasTheme() && !IsNightTheme();
|
||||
bool IsNonDefaultThemeOrBackground() {
|
||||
return Background()->isNonDefaultThemeOrBackground();
|
||||
}
|
||||
|
||||
bool IsNightMode() {
|
||||
return instance ? Background()->nightMode() : false;
|
||||
}
|
||||
|
||||
void SetNightModeValue(bool nightMode) {
|
||||
if (instance || nightMode) {
|
||||
Background()->setNightModeValue(nightMode);
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleNightMode() {
|
||||
Background()->toggleNightMode();
|
||||
}
|
||||
|
||||
bool SuggestThemeReset() {
|
||||
return IsNonDefaultThemeOrBackground();
|
||||
}
|
||||
|
||||
bool LoadFromFile(const QString &path, Instance *out, QByteArray *outContent) {
|
||||
|
|
|
@ -30,7 +30,13 @@ struct Cached {
|
|||
int32 paletteChecksum = 0;
|
||||
int32 contentChecksum = 0;
|
||||
};
|
||||
bool Load(const QString &pathRelative, const QString &pathAbsolute, const QByteArray &content, Cached &cache);
|
||||
struct Saved {
|
||||
QString pathRelative;
|
||||
QString pathAbsolute;
|
||||
QByteArray content;
|
||||
Cached cache;
|
||||
};
|
||||
bool Load(Saved &&saved);
|
||||
void Unload();
|
||||
|
||||
struct Instance {
|
||||
|
@ -41,7 +47,8 @@ struct Instance {
|
|||
};
|
||||
|
||||
struct Preview {
|
||||
QString path;
|
||||
QString pathRelative;
|
||||
QString pathAbsolute;
|
||||
Instance instance;
|
||||
QByteArray content;
|
||||
QImage preview;
|
||||
|
@ -52,9 +59,12 @@ bool Apply(std::unique_ptr<Preview> preview);
|
|||
void ApplyDefault();
|
||||
bool ApplyEditedPalette(const QString &path, const QByteArray &content);
|
||||
void KeepApplied();
|
||||
bool IsNonDefaultUsed();
|
||||
bool IsNightTheme();
|
||||
void SwitchNightTheme(bool enabled);
|
||||
QString NightThemePath();
|
||||
bool IsNightMode();
|
||||
void SetNightModeValue(bool nightMode);
|
||||
void ToggleNightMode();
|
||||
bool IsNonDefaultThemeOrBackground();
|
||||
bool SuggestThemeReset();
|
||||
void Revert();
|
||||
|
||||
bool LoadFromFile(const QString &file, Instance *out, QByteArray *outContent);
|
||||
|
@ -88,6 +98,10 @@ public:
|
|||
void start();
|
||||
void setImage(int32 id, QImage &&image = QImage());
|
||||
void setTile(bool tile);
|
||||
void setTileDayValue(bool tile);
|
||||
void setTileNightValue(bool tile);
|
||||
void setThemeAbsolutePath(const QString &path);
|
||||
QString themeAbsolutePath() const;
|
||||
void reset();
|
||||
|
||||
enum class ChangeMode {
|
||||
|
@ -96,7 +110,6 @@ public:
|
|||
};
|
||||
void setTestingTheme(Instance &&theme, ChangeMode mode = ChangeMode::SwitchToThemeBackground);
|
||||
void setTestingDefaultTheme();
|
||||
void keepApplied();
|
||||
void revert();
|
||||
|
||||
int32 id() const;
|
||||
|
@ -107,7 +120,8 @@ public:
|
|||
return _pixmapForTiled;
|
||||
}
|
||||
bool tile() const;
|
||||
bool tileForSave() const;
|
||||
bool tileDay() const;
|
||||
bool tileNight() const;
|
||||
|
||||
private:
|
||||
void ensureStarted();
|
||||
|
@ -115,11 +129,26 @@ private:
|
|||
void setPreparedImage(QImage &&image);
|
||||
void writeNewBackgroundSettings();
|
||||
|
||||
void setNightModeValue(bool nightMode);
|
||||
bool nightMode() const;
|
||||
void toggleNightMode();
|
||||
void keepApplied(const QString &path, bool write);
|
||||
bool isNonDefaultThemeOrBackground() const;
|
||||
|
||||
friend bool IsNightMode();
|
||||
friend void SetNightModeValue(bool nightMode);
|
||||
friend void ToggleNightMode();
|
||||
friend void KeepApplied();
|
||||
friend bool IsNonDefaultThemeOrBackground();
|
||||
|
||||
int32 _id = internal::kUninitializedBackground;
|
||||
QPixmap _pixmap;
|
||||
QPixmap _pixmapForTiled;
|
||||
bool _tile = false;
|
||||
bool _nightMode = false;
|
||||
bool _tileDayValue = false;
|
||||
bool _tileNightValue = true;
|
||||
|
||||
QString _themeAbsolutePath;
|
||||
QImage _themeImage;
|
||||
bool _themeTile = false;
|
||||
|
||||
|
|
|
@ -785,9 +785,9 @@ void Editor::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
void Editor::Start() {
|
||||
auto palettePath = Local::themePaletteAbsolutePath();
|
||||
if (palettePath.isEmpty()) {
|
||||
FileDialog::GetWritePath(App::wnd(), lang(lng_theme_editor_save_palette), "Palette (*.tdesktop-palette)", "colors.tdesktop-palette", [](const QString &path) {
|
||||
const auto path = Background()->themeAbsolutePath();
|
||||
if (path.isEmpty() || !Window::Theme::IsPaletteTestingPath(path)) {
|
||||
const auto start = [](const QString &path) {
|
||||
if (!Local::copyThemeColorsToPalette(path)) {
|
||||
writeDefaultPalette(path);
|
||||
}
|
||||
|
@ -799,9 +799,15 @@ void Editor::Start() {
|
|||
if (auto window = App::wnd()) {
|
||||
window->showRightColumn(Box<Editor>(path));
|
||||
}
|
||||
});
|
||||
};
|
||||
FileDialog::GetWritePath(
|
||||
App::wnd(),
|
||||
lang(lng_theme_editor_save_palette),
|
||||
"Palette (*.tdesktop-palette)",
|
||||
"colors.tdesktop-palette",
|
||||
start);
|
||||
} else if (auto window = App::wnd()) {
|
||||
window->showRightColumn(Box<Editor>(palettePath));
|
||||
window->showRightColumn(Box<Editor>(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -889,12 +889,25 @@ void Generator::restoreTextPalette() {
|
|||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Preview> PreviewFromFile(const QString &filepath) {
|
||||
auto result = std::make_unique<Preview>();
|
||||
result->pathRelative = filepath.isEmpty()
|
||||
? QString()
|
||||
: QDir().relativeFilePath(filepath);
|
||||
result->pathAbsolute = filepath.isEmpty()
|
||||
? QString()
|
||||
: QFileInfo(filepath).absoluteFilePath();
|
||||
if (!LoadFromFile(filepath, &result->instance, &result->content)) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Preview> GeneratePreview(
|
||||
const QString &filepath,
|
||||
CurrentData &&data) {
|
||||
auto result = std::make_unique<Preview>();
|
||||
result->path = filepath;
|
||||
if (!LoadFromFile(filepath, &result->instance, &result->content)) {
|
||||
auto result = PreviewFromFile(filepath);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
result->preview = Generator(
|
||||
|
|
|
@ -18,6 +18,7 @@ struct CurrentData {
|
|||
bool backgroundTiled = false;
|
||||
};
|
||||
|
||||
std::unique_ptr<Preview> PreviewFromFile(const QString &filepath);
|
||||
std::unique_ptr<Preview> GeneratePreview(
|
||||
const QString &filepath,
|
||||
CurrentData &&data);
|
||||
|
|
|
@ -44,9 +44,10 @@ MainMenu::MainMenu(
|
|||
checkSelf();
|
||||
|
||||
_nightThemeSwitch.setCallback([this] {
|
||||
if (auto action = *_nightThemeAction) {
|
||||
if (action->isChecked() != Window::Theme::IsNightTheme()) {
|
||||
Window::Theme::SwitchNightTheme(action->isChecked());
|
||||
if (const auto action = *_nightThemeAction) {
|
||||
const auto nightMode = Window::Theme::IsNightMode();
|
||||
if (action->isChecked() != nightMode) {
|
||||
Window::Theme::ToggleNightMode();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -104,19 +105,17 @@ void MainMenu::refreshMenu() {
|
|||
App::wnd()->showSettings();
|
||||
}, &st::mainMenuSettings, &st::mainMenuSettingsOver);
|
||||
|
||||
if (!Window::Theme::IsNonDefaultUsed()) {
|
||||
_nightThemeAction = std::make_shared<QPointer<QAction>>(nullptr);
|
||||
auto action = _menu->addAction(lang(lng_menu_night_mode), [this] {
|
||||
if (auto action = *_nightThemeAction) {
|
||||
action->setChecked(!action->isChecked());
|
||||
_nightThemeSwitch.callOnce(st::mainMenu.itemToggle.duration);
|
||||
}
|
||||
}, &st::mainMenuNightMode, &st::mainMenuNightModeOver);
|
||||
*_nightThemeAction = action;
|
||||
action->setCheckable(true);
|
||||
action->setChecked(Window::Theme::IsNightTheme());
|
||||
_menu->finishAnimating();
|
||||
}
|
||||
_nightThemeAction = std::make_shared<QPointer<QAction>>(nullptr);
|
||||
auto action = _menu->addAction(lang(lng_menu_night_mode), [this] {
|
||||
if (auto action = *_nightThemeAction) {
|
||||
action->setChecked(!action->isChecked());
|
||||
_nightThemeSwitch.callOnce(st::mainMenu.itemToggle.duration);
|
||||
}
|
||||
}, &st::mainMenuNightMode, &st::mainMenuNightModeOver);
|
||||
*_nightThemeAction = action;
|
||||
action->setCheckable(true);
|
||||
action->setChecked(Window::Theme::IsNightMode());
|
||||
_menu->finishAnimating();
|
||||
|
||||
updatePhone();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue