mirror of https://github.com/procxx/kepka.git
Show not supported themes placeholders.
This commit is contained in:
parent
639b4bdd27
commit
910f16312c
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -34,7 +34,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "window/themes/window_theme_editor.h"
|
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -4479,26 +4478,30 @@ std::vector<Lang::Language> readRecentLanguages() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copyThemeColorsToPalette(const QString &destination) {
|
Window::Theme::Object ReadThemeContent() {
|
||||||
using namespace Window::Theme;
|
using namespace Window::Theme;
|
||||||
|
|
||||||
auto &themeKey = IsNightMode() ? _themeKeyNight : _themeKeyDay;
|
auto &themeKey = IsNightMode() ? _themeKeyNight : _themeKeyDay;
|
||||||
if (!themeKey) {
|
if (!themeKey) {
|
||||||
return false;
|
return Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileReadDescriptor theme;
|
FileReadDescriptor theme;
|
||||||
if (!readEncryptedFile(theme, themeKey, FileOption::Safe, SettingsKey)) {
|
if (!readEncryptedFile(theme, themeKey, FileOption::Safe, SettingsKey)) {
|
||||||
return false;
|
return Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray themeContent;
|
QByteArray content;
|
||||||
QString pathRelative, pathAbsolute;
|
QString pathRelative, pathAbsolute;
|
||||||
theme.stream >> themeContent >> pathRelative >> pathAbsolute;
|
theme.stream >> content >> pathRelative >> pathAbsolute;
|
||||||
if (theme.stream.status() != QDataStream::Ok) {
|
if (theme.stream.status() != QDataStream::Ok) {
|
||||||
return false;
|
return Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
return CopyColorsToPalette(destination, pathAbsolute, themeContent);
|
auto result = Object();
|
||||||
|
result.pathAbsolute = pathAbsolute;
|
||||||
|
result.content = content;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeRecentHashtagsAndBots() {
|
void writeRecentHashtagsAndBots() {
|
||||||
|
|
|
@ -26,6 +26,7 @@ class EncryptionKey;
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
namespace Theme {
|
namespace Theme {
|
||||||
|
struct Object;
|
||||||
struct Saved;
|
struct Saved;
|
||||||
} // namespace Theme
|
} // namespace Theme
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
@ -152,8 +153,9 @@ bool readBackground();
|
||||||
|
|
||||||
void writeTheme(const Window::Theme::Saved &saved);
|
void writeTheme(const Window::Theme::Saved &saved);
|
||||||
void clearTheme();
|
void clearTheme();
|
||||||
bool copyThemeColorsToPalette(const QString &destination);
|
[[nodiscard]] Window::Theme::Saved readThemeAfterSwitch();
|
||||||
Window::Theme::Saved readThemeAfterSwitch();
|
|
||||||
|
[[nodiscard]] Window::Theme::Object ReadThemeContent();
|
||||||
|
|
||||||
void writeLangPack();
|
void writeLangPack();
|
||||||
void pushRecentLanguage(const Lang::Language &language);
|
void pushRecentLanguage(const Lang::Language &language);
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "window/themes/window_theme_preview.h"
|
#include "window/themes/window_theme_preview.h"
|
||||||
#include "window/themes/window_themes_embedded.h"
|
#include "window/themes/window_themes_embedded.h"
|
||||||
|
#include "window/themes/window_theme_editor.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
@ -49,14 +50,6 @@ Applying GlobalApplying;
|
||||||
|
|
||||||
inline bool AreTestingTheme() {
|
inline bool AreTestingTheme() {
|
||||||
return !GlobalApplying.paletteForRevert.isEmpty();
|
return !GlobalApplying.paletteForRevert.isEmpty();
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsEditingTheme(const QString &path) {
|
|
||||||
static const auto kEditingPath = QFileInfo(
|
|
||||||
EditingPalettePath()
|
|
||||||
).absoluteFilePath();
|
|
||||||
return !path.compare(kEditingPath, Qt::CaseInsensitive)
|
|
||||||
&& QFileInfo(path).exists();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalculateIsMonoColorImage(const QImage &image) {
|
bool CalculateIsMonoColorImage(const QImage &image) {
|
||||||
|
@ -408,7 +401,7 @@ bool InitializeFromSaved(Saved &&saved) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (editing) {
|
if (editing) {
|
||||||
Background()->setIsEditingTheme(true);
|
Background()->setEditingTheme(ReadCloudFromText(*editing));
|
||||||
} else {
|
} else {
|
||||||
Local::writeTheme(saved);
|
Local::writeTheme(saved);
|
||||||
}
|
}
|
||||||
|
@ -544,7 +537,7 @@ void ChatBackground::checkUploadWallPaper() {
|
||||||
}
|
}
|
||||||
if (!Data::IsCustomWallPaper(_paper)
|
if (!Data::IsCustomWallPaper(_paper)
|
||||||
|| _original.isNull()
|
|| _original.isNull()
|
||||||
|| isEditingTheme()) {
|
|| _editingTheme.has_value()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,7 +727,7 @@ bool ChatBackground::adjustPaletteRequired() {
|
||||||
|| Data::details::IsTestingDefaultWallPaper(_paper);
|
|| Data::details::IsTestingDefaultWallPaper(_paper);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isEditingTheme()) {
|
if (_editingTheme.has_value()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (isNonDefaultThemeOrBackground() || nightMode()) {
|
} else if (isNonDefaultThemeOrBackground() || nightMode()) {
|
||||||
return !usingThemeBackground();
|
return !usingThemeBackground();
|
||||||
|
@ -742,12 +735,13 @@ bool ChatBackground::adjustPaletteRequired() {
|
||||||
return !usingDefaultBackground();
|
return !usingDefaultBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatBackground::isEditingTheme() const {
|
std::optional<Data::CloudTheme> ChatBackground::editingTheme() const {
|
||||||
return _editingTheme;
|
return _editingTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBackground::setIsEditingTheme(bool editing) {
|
void ChatBackground::setEditingTheme(
|
||||||
if (_editingTheme == editing) {
|
std::optional<Data::CloudTheme> editing) {
|
||||||
|
if (!_editingTheme && !editing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_editingTheme = editing;
|
_editingTheme = editing;
|
||||||
|
@ -913,7 +907,7 @@ void ChatBackground::setTestingTheme(Instance &&theme) {
|
||||||
|| (Data::IsDefaultWallPaper(_paper)
|
|| (Data::IsDefaultWallPaper(_paper)
|
||||||
&& !nightMode()
|
&& !nightMode()
|
||||||
&& _themeObject.pathAbsolute.isEmpty());
|
&& _themeObject.pathAbsolute.isEmpty());
|
||||||
if (AreTestingTheme() && isEditingTheme()) {
|
if (AreTestingTheme() && _editingTheme.has_value()) {
|
||||||
// Grab current background image if it is not already custom
|
// Grab current background image if it is not already custom
|
||||||
// Use prepared pixmap, not original image, because we're
|
// Use prepared pixmap, not original image, because we're
|
||||||
// for sure switching to a non-pattern wall-paper (testing editor).
|
// for sure switching to a non-pattern wall-paper (testing editor).
|
||||||
|
|
|
@ -120,8 +120,8 @@ public:
|
||||||
void setTileNightValue(bool tile);
|
void setTileNightValue(bool tile);
|
||||||
void setThemeObject(const Object &object);
|
void setThemeObject(const Object &object);
|
||||||
[[nodiscard]] const Object &themeObject() const;
|
[[nodiscard]] const Object &themeObject() const;
|
||||||
[[nodiscard]] bool isEditingTheme() const;
|
[[nodiscard]] std::optional<Data::CloudTheme> editingTheme() const;
|
||||||
void setIsEditingTheme(bool editing);
|
void setEditingTheme(std::optional<Data::CloudTheme> editing);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void setTestingTheme(Instance &&theme);
|
void setTestingTheme(Instance &&theme);
|
||||||
|
@ -201,7 +201,7 @@ private:
|
||||||
Object _themeObject;
|
Object _themeObject;
|
||||||
QImage _themeImage;
|
QImage _themeImage;
|
||||||
bool _themeTile = false;
|
bool _themeTile = false;
|
||||||
bool _editingTheme = false;
|
std::optional<Data::CloudTheme> _editingTheme;
|
||||||
|
|
||||||
Data::WallPaper _paperForRevert
|
Data::WallPaper _paperForRevert
|
||||||
= Data::details::UninitializedWallPaper();
|
= Data::details::UninitializedWallPaper();
|
||||||
|
@ -221,11 +221,6 @@ ChatBackground *Background();
|
||||||
|
|
||||||
void ComputeBackgroundRects(QRect wholeFill, QSize imageSize, QRect &to, QRect &from);
|
void ComputeBackgroundRects(QRect wholeFill, QSize imageSize, QRect &to, QRect &from);
|
||||||
|
|
||||||
bool CopyColorsToPalette(
|
|
||||||
const QString &destination,
|
|
||||||
const QString &themePath,
|
|
||||||
const QByteArray &themeContent);
|
|
||||||
|
|
||||||
bool ReadPaletteValues(const QByteArray &content, Fn<bool(QLatin1String name, QLatin1String value)> callback);
|
bool ReadPaletteValues(const QByteArray &content, Fn<bool(QLatin1String name, QLatin1String value)> callback);
|
||||||
|
|
||||||
} // namespace Theme
|
} // namespace Theme
|
||||||
|
|
|
@ -35,6 +35,14 @@ namespace Window {
|
||||||
namespace Theme {
|
namespace Theme {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
template <size_t Size>
|
||||||
|
QByteArray qba(const char(&string)[Size]) {
|
||||||
|
return QByteArray::fromRawData(string, Size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto kCloudInTextStart = qba("// THEME EDITOR SERVICE INFO START\n");
|
||||||
|
const auto kCloudInTextEnd = qba("// THEME EDITOR SERVICE INFO END\n\n");
|
||||||
|
|
||||||
struct ReadColorResult {
|
struct ReadColorResult {
|
||||||
ReadColorResult(QColor color, bool error = false) : color(color), error(error) {
|
ReadColorResult(QColor color, bool error = false) : color(color), error(error) {
|
||||||
}
|
}
|
||||||
|
@ -186,7 +194,7 @@ QByteArray replaceValueInContent(const QByteArray &content, const QByteArray &na
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ColorizeInContent(
|
[[nodiscard]] QByteArray ColorizeInContent(
|
||||||
QByteArray content,
|
QByteArray content,
|
||||||
const Colorizer &colorizer) {
|
const Colorizer &colorizer) {
|
||||||
auto validNames = OrderedSet<QLatin1String>();
|
auto validNames = OrderedSet<QLatin1String>();
|
||||||
|
@ -294,44 +302,41 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CopyColorsToPalette(
|
[[nodiscard]] QByteArray WriteCloudToText(const Data::CloudTheme &cloud) {
|
||||||
const QString &destination,
|
auto result = QByteArray();
|
||||||
const QString &themePath,
|
const auto add = [&](const QByteArray &key, const QString &value) {
|
||||||
const QByteArray &themeContent) {
|
result.append("// " + key + ": " + value.toLatin1() + "\n");
|
||||||
auto paletteContent = themeContent;
|
};
|
||||||
|
result.append(kCloudInTextStart);
|
||||||
|
add("ID", QString::number(cloud.id));
|
||||||
|
add("ACCESS", QString::number(cloud.accessHash));
|
||||||
|
result.append(kCloudInTextEnd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
zlib::FileToRead file(themeContent);
|
[[nodiscard]] Data::CloudTheme ReadCloudFromText(const QByteArray &text) {
|
||||||
|
const auto index = text.indexOf(kCloudInTextEnd);
|
||||||
unz_global_info globalInfo = { 0 };
|
if (index <= 1) {
|
||||||
file.getGlobalInfo(&globalInfo);
|
return Data::CloudTheme();
|
||||||
if (file.error() == UNZ_OK) {
|
}
|
||||||
paletteContent = file.readFileContent("colors.tdesktop-theme", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
|
auto result = Data::CloudTheme();
|
||||||
if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
|
const auto list = text.mid(0, index - 1).split('\n');
|
||||||
file.clearError();
|
const auto take = [&](uint64 &value, int index) {
|
||||||
paletteContent = file.readFileContent("colors.tdesktop-palette", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
|
if (list.size() <= index) {
|
||||||
}
|
|
||||||
if (file.error() != UNZ_OK) {
|
|
||||||
LOG(("Theme Error: could not read 'colors.tdesktop-theme' or 'colors.tdesktop-palette' in the theme file, while copying to '%1'.").arg(destination));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const auto &entry = list[index];
|
||||||
|
const auto position = entry.indexOf(": ");
|
||||||
|
if (position < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = QString::fromLatin1(entry.mid(position + 2)).toULongLong();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (!take(result.id, 1) || !take(result.accessHash, 2)) {
|
||||||
|
return Data::CloudTheme();
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
QFile f(destination);
|
|
||||||
if (!f.open(QIODevice::WriteOnly)) {
|
|
||||||
LOG(("Theme Error: could not open file for write '%1'").arg(destination));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto colorizer = ColorizerForTheme(themePath)) {
|
|
||||||
paletteContent = ColorizeInContent(
|
|
||||||
std::move(paletteContent),
|
|
||||||
colorizer);
|
|
||||||
}
|
|
||||||
if (f.write(paletteContent) != paletteContent.size()) {
|
|
||||||
LOG(("Theme Error: could not write palette to '%1'").arg(destination));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor::Inner::Inner(QWidget *parent, const QString &path) : TWidget(parent)
|
Editor::Inner::Inner(QWidget *parent, const QString &path) : TWidget(parent)
|
||||||
|
@ -680,12 +685,22 @@ Editor::Editor(
|
||||||
resizeToWidth(st::windowMinWidth);
|
resizeToWidth(st::windowMinWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray Editor::ColorizeInContent(
|
||||||
|
QByteArray content,
|
||||||
|
const Colorizer &colorizer) {
|
||||||
|
return Window::Theme::ColorizeInContent(content, colorizer);
|
||||||
|
}
|
||||||
|
|
||||||
void Editor::save() {
|
void Editor::save() {
|
||||||
if (!_window->account().sessionExists()) {
|
if (!_window->account().sessionExists()) {
|
||||||
Ui::Toast::Show(tr::lng_theme_editor_need_auth(tr::now));
|
Ui::Toast::Show(tr::lng_theme_editor_need_auth(tr::now));
|
||||||
return;
|
return;
|
||||||
|
} else if (_saving) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Ui::show(Box(SaveThemeBox, _window, _cloud, _inner->paletteContent()));
|
_saving = true;
|
||||||
|
const auto unlock = crl::guard(this, [=] { _saving = false; });
|
||||||
|
SaveTheme(_window, _cloud, _inner->paletteContent(), unlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::resizeEvent(QResizeEvent *e) {
|
void Editor::resizeEvent(QResizeEvent *e) {
|
||||||
|
@ -776,7 +791,7 @@ void Editor::paintEvent(QPaintEvent *e) {
|
||||||
void Editor::closeEditor() {
|
void Editor::closeEditor() {
|
||||||
if (const auto window = App::wnd()) {
|
if (const auto window = App::wnd()) {
|
||||||
window->showRightColumn(nullptr);
|
window->showRightColumn(nullptr);
|
||||||
Background()->setIsEditingTheme(false);
|
Background()->setEditingTheme(std::nullopt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,10 @@ class Controller;
|
||||||
|
|
||||||
namespace Theme {
|
namespace Theme {
|
||||||
|
|
||||||
bool CopyColorsToPalette(
|
struct Colorizer;
|
||||||
const QString &destination,
|
|
||||||
const QString &themePath,
|
[[nodiscard]] QByteArray WriteCloudToText(const Data::CloudTheme &cloud);
|
||||||
const QByteArray &themeContent);
|
[[nodiscard]] Data::CloudTheme ReadCloudFromText(const QByteArray &text);
|
||||||
|
|
||||||
class Editor : public TWidget {
|
class Editor : public TWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -35,6 +35,10 @@ public:
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
const Data::CloudTheme &cloud);
|
const Data::CloudTheme &cloud);
|
||||||
|
|
||||||
|
[[nodiscard]] static QByteArray ColorizeInContent(
|
||||||
|
QByteArray content,
|
||||||
|
const Colorizer &colorizer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
@ -57,6 +61,7 @@ private:
|
||||||
object_ptr<Ui::PlainShadow> _leftShadow;
|
object_ptr<Ui::PlainShadow> _leftShadow;
|
||||||
object_ptr<Ui::PlainShadow> _topShadow;
|
object_ptr<Ui::PlainShadow> _topShadow;
|
||||||
object_ptr<Ui::FlatButton> _save;
|
object_ptr<Ui::FlatButton> _save;
|
||||||
|
bool _saving = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ private:
|
||||||
QByteArray _backgroundContent;
|
QByteArray _backgroundContent;
|
||||||
bool _isPng = false;
|
bool _isPng = false;
|
||||||
QString _imageText;
|
QString _imageText;
|
||||||
|
int _thumbnailSize = 0;
|
||||||
QPixmap _thumbnail;
|
QPixmap _thumbnail;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -112,12 +113,12 @@ BackgroundSelector::BackgroundSelector(
|
||||||
formatSizeText(_backgroundContent.size()));
|
formatSizeText(_backgroundContent.size()));
|
||||||
_chooseFromFile->setClickedCallback([=] { chooseBackgroundFromFile(); });
|
_chooseFromFile->setClickedCallback([=] { chooseBackgroundFromFile(); });
|
||||||
|
|
||||||
const auto height = st::boxTextFont->height
|
_thumbnailSize = st::boxTextFont->height
|
||||||
+ st::themesSmallSkip
|
+ st::themesSmallSkip
|
||||||
+ _chooseFromFile->heightNoMargins()
|
+ _chooseFromFile->heightNoMargins()
|
||||||
+ st::themesSmallSkip
|
+ st::themesSmallSkip
|
||||||
+ _tileBackground->heightNoMargins();
|
+ _tileBackground->heightNoMargins();
|
||||||
resize(width(), height);
|
resize(width(), _thumbnailSize + st::themesSmallSkip);
|
||||||
|
|
||||||
updateThumbnail();
|
updateThumbnail();
|
||||||
}
|
}
|
||||||
|
@ -125,7 +126,7 @@ BackgroundSelector::BackgroundSelector(
|
||||||
void BackgroundSelector::paintEvent(QPaintEvent *e) {
|
void BackgroundSelector::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
const auto left = height() + st::themesSmallSkip;
|
const auto left = _thumbnailSize + st::themesSmallSkip;
|
||||||
|
|
||||||
p.setPen(st::boxTextFg);
|
p.setPen(st::boxTextFg);
|
||||||
p.setFont(st::boxTextFont);
|
p.setFont(st::boxTextFont);
|
||||||
|
@ -135,14 +136,14 @@ void BackgroundSelector::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int BackgroundSelector::resizeGetHeight(int newWidth) {
|
int BackgroundSelector::resizeGetHeight(int newWidth) {
|
||||||
const auto left = height() + st::themesSmallSkip;
|
const auto left = _thumbnailSize + st::themesSmallSkip;
|
||||||
_chooseFromFile->moveToLeft(left, st::boxTextFont->height + st::themesSmallSkip);
|
_chooseFromFile->moveToLeft(left, st::boxTextFont->height + st::themesSmallSkip);
|
||||||
_tileBackground->moveToLeft(left, st::boxTextFont->height + st::themesSmallSkip + _chooseFromFile->height() + st::themesSmallSkip);
|
_tileBackground->moveToLeft(left, st::boxTextFont->height + st::themesSmallSkip + _chooseFromFile->height() + st::themesSmallSkip);
|
||||||
return height();
|
return height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundSelector::updateThumbnail() {
|
void BackgroundSelector::updateThumbnail() {
|
||||||
const auto size = height();
|
const auto size = _thumbnailSize;
|
||||||
auto back = QImage(
|
auto back = QImage(
|
||||||
QSize(size, size) * cIntRetinaFactor(),
|
QSize(size, size) * cIntRetinaFactor(),
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
@ -233,11 +234,55 @@ void ImportFromFile(
|
||||||
crl::guard(parent, callback));
|
crl::guard(parent, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BytesToUTF8(QLatin1String string) {
|
[[nodiscard]] QString BytesToUTF8(QLatin1String string) {
|
||||||
return QString::fromUtf8(string.data(), string.size());
|
return QString::fromUtf8(string.data(), string.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteDefaultPalette(const QString &path) {
|
[[nodiscard]] bool CopyColorsToPalette(
|
||||||
|
const QString &destination,
|
||||||
|
const QString &themePath,
|
||||||
|
const QByteArray &themeContent,
|
||||||
|
const Data::CloudTheme &cloud) {
|
||||||
|
auto paletteContent = themeContent;
|
||||||
|
|
||||||
|
zlib::FileToRead file(themeContent);
|
||||||
|
|
||||||
|
unz_global_info globalInfo = { 0 };
|
||||||
|
file.getGlobalInfo(&globalInfo);
|
||||||
|
if (file.error() == UNZ_OK) {
|
||||||
|
paletteContent = file.readFileContent("colors.tdesktop-theme", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
|
||||||
|
if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
|
||||||
|
file.clearError();
|
||||||
|
paletteContent = file.readFileContent("colors.tdesktop-palette", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
|
||||||
|
}
|
||||||
|
if (file.error() != UNZ_OK) {
|
||||||
|
LOG(("Theme Error: could not read 'colors.tdesktop-theme' or 'colors.tdesktop-palette' in the theme file, while copying to '%1'.").arg(destination));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile f(destination);
|
||||||
|
if (!f.open(QIODevice::WriteOnly)) {
|
||||||
|
LOG(("Theme Error: could not open file for write '%1'").arg(destination));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto colorizer = ColorizerForTheme(themePath)) {
|
||||||
|
paletteContent = Editor::ColorizeInContent(
|
||||||
|
std::move(paletteContent),
|
||||||
|
colorizer);
|
||||||
|
}
|
||||||
|
paletteContent = WriteCloudToText(cloud) + paletteContent;
|
||||||
|
if (f.write(paletteContent) != paletteContent.size()) {
|
||||||
|
LOG(("Theme Error: could not write palette to '%1'").arg(destination));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteDefaultPalette(
|
||||||
|
const QString &path,
|
||||||
|
const Data::CloudTheme &cloud) {
|
||||||
QFile f(path);
|
QFile f(path);
|
||||||
if (!f.open(QIODevice::WriteOnly)) {
|
if (!f.open(QIODevice::WriteOnly)) {
|
||||||
LOG(("Theme Error: could not open '%1' for writing.").arg(path));
|
LOG(("Theme Error: could not open '%1' for writing.").arg(path));
|
||||||
|
@ -247,6 +292,8 @@ bool WriteDefaultPalette(const QString &path) {
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
stream.setCodec("UTF-8");
|
stream.setCodec("UTF-8");
|
||||||
|
|
||||||
|
stream << QString::fromLatin1(WriteCloudToText(cloud));
|
||||||
|
|
||||||
auto rows = style::main_palette::data();
|
auto rows = style::main_palette::data();
|
||||||
for (const auto &row : std::as_const(rows)) {
|
for (const auto &row : std::as_const(rows)) {
|
||||||
stream
|
stream
|
||||||
|
@ -396,7 +443,7 @@ SendMediaReady PrepareThemeMedia(
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fn<void()> SaveTheme(
|
Fn<void()> SavePreparedTheme(
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
const QByteArray &palette,
|
const QByteArray &palette,
|
||||||
const PreparedBackground &background,
|
const PreparedBackground &background,
|
||||||
|
@ -494,12 +541,15 @@ void StartEditor(
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
const Data::CloudTheme &cloud) {
|
const Data::CloudTheme &cloud) {
|
||||||
const auto path = EditingPalettePath();
|
const auto path = EditingPalettePath();
|
||||||
if (!Local::copyThemeColorsToPalette(path)
|
auto object = Local::ReadThemeContent();
|
||||||
&& !WriteDefaultPalette(path)) {
|
const auto written = object.content.isEmpty()
|
||||||
|
? WriteDefaultPalette(path, cloud)
|
||||||
|
: CopyColorsToPalette(path, object.pathAbsolute, object.content, cloud);
|
||||||
|
if (!written) {
|
||||||
window->show(Box<InformBox>(tr::lng_theme_editor_error(tr::now)));
|
window->show(Box<InformBox>(tr::lng_theme_editor_error(tr::now)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Background()->setIsEditingTheme(true);
|
Background()->setEditingTheme(cloud);
|
||||||
window->showRightColumn(Box<Editor>(window, cloud));
|
window->showRightColumn(Box<Editor>(window, cloud));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,6 +611,40 @@ void CreateForExistingBox(
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SaveTheme(
|
||||||
|
not_null<Window::Controller*> window,
|
||||||
|
const Data::CloudTheme &cloud,
|
||||||
|
const QByteArray &palette,
|
||||||
|
Fn<void()> unlock) {
|
||||||
|
Expects(window->account().sessionExists());
|
||||||
|
|
||||||
|
using Data::CloudTheme;
|
||||||
|
|
||||||
|
const auto save = [=](const CloudTheme &fields) {
|
||||||
|
window->show(Box(SaveThemeBox, window, fields, palette));
|
||||||
|
};
|
||||||
|
if (cloud.id) {
|
||||||
|
window->account().session().api().request(MTPaccount_GetTheme(
|
||||||
|
MTP_string(Data::CloudThemes::Format()),
|
||||||
|
MTP_inputTheme(MTP_long(cloud.id), MTP_long(cloud.accessHash)),
|
||||||
|
MTP_long(0)
|
||||||
|
)).done([=](const MTPTheme &result) {
|
||||||
|
unlock();
|
||||||
|
result.match([&](const MTPDtheme &data) {
|
||||||
|
save(CloudTheme::Parse(&window->account().session(), data));
|
||||||
|
}, [&](const MTPDthemeDocumentNotModified &data) {
|
||||||
|
LOG(("API Error: Unexpected themeDocumentNotModified."));
|
||||||
|
save(CloudTheme());
|
||||||
|
});
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
unlock();
|
||||||
|
save(CloudTheme());
|
||||||
|
}).send();
|
||||||
|
} else {
|
||||||
|
save(CloudTheme());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SaveThemeBox(
|
void SaveThemeBox(
|
||||||
not_null<GenericBox*> box,
|
not_null<GenericBox*> box,
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
|
@ -594,7 +678,7 @@ void SaveThemeBox(
|
||||||
linkWrap,
|
linkWrap,
|
||||||
st::createThemeLink,
|
st::createThemeLink,
|
||||||
rpl::single(qsl("link")),
|
rpl::single(qsl("link")),
|
||||||
cloud.slug,
|
cloud.slug.isEmpty() ? GenerateSlug() : cloud.slug,
|
||||||
true);
|
true);
|
||||||
linkWrap->widthValue(
|
linkWrap->widthValue(
|
||||||
) | rpl::start_with_next([=](int width) {
|
) | rpl::start_with_next([=](int width) {
|
||||||
|
@ -657,6 +741,7 @@ void SaveThemeBox(
|
||||||
const auto fail = crl::guard(box, [=](
|
const auto fail = crl::guard(box, [=](
|
||||||
SaveErrorType type,
|
SaveErrorType type,
|
||||||
const QString &text) {
|
const QString &text) {
|
||||||
|
*saving = false;
|
||||||
if (!text.isEmpty()) {
|
if (!text.isEmpty()) {
|
||||||
Ui::Toast::Show(text);
|
Ui::Toast::Show(text);
|
||||||
}
|
}
|
||||||
|
@ -666,7 +751,7 @@ void SaveThemeBox(
|
||||||
link->showError();
|
link->showError();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*cancel = SaveTheme(
|
*cancel = SavePreparedTheme(
|
||||||
window,
|
window,
|
||||||
palette,
|
palette,
|
||||||
back->result(),
|
back->result(),
|
||||||
|
|
|
@ -29,6 +29,11 @@ void CreateForExistingBox(
|
||||||
not_null<GenericBox*> box,
|
not_null<GenericBox*> box,
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
const Data::CloudTheme &cloud);
|
const Data::CloudTheme &cloud);
|
||||||
|
void SaveTheme(
|
||||||
|
not_null<Window::Controller*> window,
|
||||||
|
const Data::CloudTheme &cloud,
|
||||||
|
const QByteArray &palette,
|
||||||
|
Fn<void()> unlock);
|
||||||
void SaveThemeBox(
|
void SaveThemeBox(
|
||||||
not_null<GenericBox*> box,
|
not_null<GenericBox*> box,
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
|
|
|
@ -46,9 +46,9 @@ void Controller::firstShow() {
|
||||||
|
|
||||||
void Controller::checkThemeEditor() {
|
void Controller::checkThemeEditor() {
|
||||||
using namespace Window::Theme;
|
using namespace Window::Theme;
|
||||||
if (Background()->isEditingTheme()) {
|
|
||||||
showRightColumn(
|
if (const auto editing = Background()->editingTheme()) {
|
||||||
Box<Editor>(this, Background()->themeObject().cloud));
|
showRightColumn(Box<Editor>(this, *editing));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue