mirror of https://github.com/procxx/kepka.git
Add import theme to the editor.
This commit is contained in:
parent
d85f162bff
commit
dfd63e66ff
|
@ -1616,7 +1616,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_theme_editor_need_unlock" = "You need to unlock Telegram to save your theme.";
|
"lng_theme_editor_need_unlock" = "You need to unlock Telegram to save your theme.";
|
||||||
"lng_theme_editor_done" = "Theme exported successfully!";
|
"lng_theme_editor_done" = "Theme exported successfully!";
|
||||||
"lng_theme_editor_title" = "Edit color palette";
|
"lng_theme_editor_title" = "Edit color palette";
|
||||||
"lng_theme_editor_export_button" = "Export theme";
|
|
||||||
"lng_theme_editor_save_button" = "Save theme";
|
"lng_theme_editor_save_button" = "Save theme";
|
||||||
|
|
||||||
"lng_theme_editor_create_title" = "Create theme";
|
"lng_theme_editor_create_title" = "Create theme";
|
||||||
|
@ -1630,6 +1629,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_theme_editor_link_about" = "Your theme will be updated for all users each time you change it. Anyone can install it using this link.\n\nTheme links must be longer than 5 characters and use a-z, 0-9 and underscores.";
|
"lng_theme_editor_link_about" = "Your theme will be updated for all users each time you change it. Anyone can install it using this link.\n\nTheme links must be longer than 5 characters and use a-z, 0-9 and underscores.";
|
||||||
|
|
||||||
"lng_theme_editor_menu_export" = "Export theme";
|
"lng_theme_editor_menu_export" = "Export theme";
|
||||||
|
"lng_theme_editor_menu_import" = "Import theme";
|
||||||
"lng_theme_editor_menu_show" = "Show palette file";
|
"lng_theme_editor_menu_show" = "Show palette file";
|
||||||
|
|
||||||
"lng_payments_not_supported" = "Sorry, Telegram Desktop doesn't support payments yet. Please use one of our mobile apps to do this.";
|
"lng_payments_not_supported" = "Sorry, Telegram Desktop doesn't support payments yet. Please use one of our mobile apps to do this.";
|
||||||
|
|
|
@ -220,6 +220,9 @@ public:
|
||||||
void selectSkip(int direction);
|
void selectSkip(int direction);
|
||||||
void selectSkipPage(int delta, int direction);
|
void selectSkipPage(int delta, int direction);
|
||||||
|
|
||||||
|
void applyNewPalette(const QByteArray &newContent);
|
||||||
|
void recreateRows();
|
||||||
|
|
||||||
~Inner() {
|
~Inner() {
|
||||||
if (_context.box) _context.box->closeBox();
|
if (_context.box) _context.box->closeBox();
|
||||||
}
|
}
|
||||||
|
@ -418,7 +421,32 @@ Editor::Inner::Inner(QWidget *parent, const QString &path) : TWidget(parent)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Editor::Inner::recreateRows() {
|
||||||
|
_existingRows.create(this, EditorBlock::Type::Existing, &_context);
|
||||||
|
_existingRows->show();
|
||||||
|
_newRows.create(this, EditorBlock::Type::New, &_context);
|
||||||
|
_newRows->show();
|
||||||
|
if (!readData()) {
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Editor::Inner::prepare() {
|
void Editor::Inner::prepare() {
|
||||||
|
QFile f(_path);
|
||||||
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
|
LOG(("Theme Error: could not open color palette file '%1'").arg(_path));
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_paletteContent = f.readAll();
|
||||||
|
if (f.error() != QFileDevice::NoError) {
|
||||||
|
LOG(("Theme Error: could not read content from palette file '%1'").arg(_path));
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
|
||||||
if (!readData()) {
|
if (!readData()) {
|
||||||
error();
|
error();
|
||||||
}
|
}
|
||||||
|
@ -551,19 +579,6 @@ void Editor::Inner::sortByAccentDistance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Editor::Inner::readExistingRows() {
|
bool Editor::Inner::readExistingRows() {
|
||||||
QFile f(_path);
|
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
|
||||||
LOG(("Theme Error: could not open color palette file '%1'").arg(_path));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_paletteContent = f.readAll();
|
|
||||||
if (f.error() != QFileDevice::NoError) {
|
|
||||||
LOG(("Theme Error: could not read content from palette file '%1'").arg(_path));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
return ReadPaletteValues(_paletteContent, [this](QLatin1String name, QLatin1String value) {
|
return ReadPaletteValues(_paletteContent, [this](QLatin1String name, QLatin1String value) {
|
||||||
return feedExistingRow(name, value);
|
return feedExistingRow(name, value);
|
||||||
});
|
});
|
||||||
|
@ -598,6 +613,10 @@ void Editor::Inner::applyEditing(const QString &name, const QString ©Of, QCo
|
||||||
auto addedline = (_paletteContent.endsWith('\n') ? "" : newline);
|
auto addedline = (_paletteContent.endsWith('\n') ? "" : newline);
|
||||||
newContent = _paletteContent + addedline + plainName + ": " + plainValue + ";" + newline;
|
newContent = _paletteContent + addedline + plainName + ": " + plainValue + ";" + newline;
|
||||||
}
|
}
|
||||||
|
applyNewPalette(newContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::Inner::applyNewPalette(const QByteArray &newContent) {
|
||||||
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 a palette update.").arg(_path));
|
LOG(("Theme Error: could not open '%1' for writing a palette update.").arg(_path));
|
||||||
|
@ -704,6 +723,11 @@ void Editor::showMenu() {
|
||||||
exportTheme();
|
exportTheme();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
_menu->addAction(tr::lng_theme_editor_menu_import(tr::now), [=] {
|
||||||
|
App::CallDelayed(st::defaultRippleAnimation.hideDuration, this, [=] {
|
||||||
|
importTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
_menu->addAction(tr::lng_theme_editor_menu_show(tr::now), [=] {
|
_menu->addAction(tr::lng_theme_editor_menu_show(tr::now), [=] {
|
||||||
File::ShowInFolder(EditingPalettePath());
|
File::ShowInFolder(EditingPalettePath());
|
||||||
});
|
});
|
||||||
|
@ -732,6 +756,48 @@ void Editor::exportTheme() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Editor::importTheme() {
|
||||||
|
auto filters = QStringList(
|
||||||
|
qsl("Theme files (*.tdesktop-theme *.tdesktop-palette)"));
|
||||||
|
filters.push_back(FileDialog::AllFilesFilter());
|
||||||
|
const auto callback = crl::guard(this, [=](
|
||||||
|
const FileDialog::OpenResult &result) {
|
||||||
|
const auto path = result.paths.isEmpty()
|
||||||
|
? QString()
|
||||||
|
: result.paths.front();
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto f = QFile(path);
|
||||||
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto object = Object();
|
||||||
|
object.pathAbsolute = QFileInfo(path).absoluteFilePath();
|
||||||
|
object.pathRelative = QDir().relativeFilePath(path);
|
||||||
|
object.content = f.readAll();
|
||||||
|
if (object.content.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_select->clearQuery();
|
||||||
|
const auto parsed = ParseTheme(object, false, false);
|
||||||
|
_inner->applyNewPalette(parsed.palette);
|
||||||
|
_inner->recreateRows();
|
||||||
|
updateControlsGeometry();
|
||||||
|
auto image = App::readImage(parsed.background);
|
||||||
|
if (!image.isNull() && !image.size().isEmpty()) {
|
||||||
|
Background()->set(Data::CustomWallPaper(), std::move(image));
|
||||||
|
Background()->setTile(parsed.tiled);
|
||||||
|
Ui::ForceFullRepaint(_window->widget());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
FileDialog::GetOpenPath(
|
||||||
|
this,
|
||||||
|
tr::lng_theme_editor_menu_import(tr::now),
|
||||||
|
filters.join(qsl(";;")),
|
||||||
|
crl::guard(this, callback));
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray Editor::ColorizeInContent(
|
QByteArray Editor::ColorizeInContent(
|
||||||
QByteArray content,
|
QByteArray content,
|
||||||
const Colorizer &colorizer) {
|
const Colorizer &colorizer) {
|
||||||
|
@ -754,6 +820,10 @@ void Editor::save() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::resizeEvent(QResizeEvent *e) {
|
void Editor::resizeEvent(QResizeEvent *e) {
|
||||||
|
updateControlsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Editor::updateControlsGeometry() {
|
||||||
_save->resizeToWidth(width());
|
_save->resizeToWidth(width());
|
||||||
_close->moveToRight(0, 0);
|
_close->moveToRight(0, 0);
|
||||||
_menuToggle->moveToRight(_close->width(), 0);
|
_menuToggle->moveToRight(_close->width(), 0);
|
||||||
|
|
|
@ -65,8 +65,10 @@ private:
|
||||||
void save();
|
void save();
|
||||||
void showMenu();
|
void showMenu();
|
||||||
void exportTheme();
|
void exportTheme();
|
||||||
|
void importTheme();
|
||||||
void closeEditor();
|
void closeEditor();
|
||||||
void closeWithConfirmation();
|
void closeWithConfirmation();
|
||||||
|
void updateControlsGeometry();
|
||||||
|
|
||||||
const not_null<Window::Controller*> _window;
|
const not_null<Window::Controller*> _window;
|
||||||
const Data::CloudTheme _cloud;
|
const Data::CloudTheme _cloud;
|
||||||
|
|
|
@ -224,7 +224,6 @@ bool PaletteChanged(
|
||||||
void ImportFromFile(
|
void ImportFromFile(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
not_null<QWidget*> parent) {
|
not_null<QWidget*> parent) {
|
||||||
const auto &imgExtensions = cImgExtensions();
|
|
||||||
auto filters = QStringList(
|
auto filters = QStringList(
|
||||||
qsl("Theme files (*.tdesktop-theme *.tdesktop-palette)"));
|
qsl("Theme files (*.tdesktop-theme *.tdesktop-palette)"));
|
||||||
filters.push_back(FileDialog::AllFilesFilter());
|
filters.push_back(FileDialog::AllFilesFilter());
|
||||||
|
@ -239,7 +238,7 @@ void ImportFromFile(
|
||||||
});
|
});
|
||||||
FileDialog::GetOpenPath(
|
FileDialog::GetOpenPath(
|
||||||
parent.get(),
|
parent.get(),
|
||||||
tr::lng_choose_image(tr::now),
|
tr::lng_theme_editor_menu_import(tr::now),
|
||||||
filters.join(qsl(";;")),
|
filters.join(qsl(";;")),
|
||||||
crl::guard(parent, callback));
|
crl::guard(parent, callback));
|
||||||
}
|
}
|
||||||
|
@ -278,71 +277,6 @@ void ImportFromFile(
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only is valid for current theme, pass Local::ReadThemeContent() here.
|
|
||||||
[[nodiscard]] ParsedTheme ParseTheme(
|
|
||||||
const Object &theme,
|
|
||||||
bool onlyPalette = false) {
|
|
||||||
auto raw = ParsedTheme();
|
|
||||||
raw.palette = theme.content;
|
|
||||||
const auto result = [&] {
|
|
||||||
if (const auto colorizer = ColorizerForTheme(theme.pathAbsolute)) {
|
|
||||||
raw.palette = Editor::ColorizeInContent(
|
|
||||||
std::move(raw.palette),
|
|
||||||
colorizer);
|
|
||||||
}
|
|
||||||
raw.palette = ReplaceAdjustableColors(std::move(raw.palette));
|
|
||||||
return raw;
|
|
||||||
};
|
|
||||||
|
|
||||||
zlib::FileToRead file(theme.content);
|
|
||||||
|
|
||||||
unz_global_info globalInfo = { 0 };
|
|
||||||
file.getGlobalInfo(&globalInfo);
|
|
||||||
if (file.error() != UNZ_OK) {
|
|
||||||
return result();
|
|
||||||
}
|
|
||||||
raw.palette = file.readFileContent("colors.tdesktop-theme", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
|
|
||||||
if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
|
|
||||||
file.clearError();
|
|
||||||
raw.palette = 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."));
|
|
||||||
return ParsedTheme();
|
|
||||||
} else if (onlyPalette) {
|
|
||||||
return result();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto fromFile = [&](const char *filename) {
|
|
||||||
raw.background = file.readFileContent(filename, zlib::kCaseInsensitive, kThemeBackgroundSizeLimit);
|
|
||||||
if (file.error() == UNZ_OK) {
|
|
||||||
return true;
|
|
||||||
} else if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
|
|
||||||
file.clearError();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
LOG(("Theme Error: could not read '%1' in the theme file.").arg(filename));
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!fromFile("background.jpg") || !raw.background.isEmpty()) {
|
|
||||||
return raw.background.isEmpty() ? ParsedTheme() : result();
|
|
||||||
}
|
|
||||||
raw.isPng = true;
|
|
||||||
if (!fromFile("background.png") || !raw.background.isEmpty()) {
|
|
||||||
return raw.background.isEmpty() ? ParsedTheme() : result();
|
|
||||||
}
|
|
||||||
raw.tiled = true;
|
|
||||||
if (!fromFile("tiled.png") || !raw.background.isEmpty()) {
|
|
||||||
return raw.background.isEmpty() ? ParsedTheme() : result();
|
|
||||||
}
|
|
||||||
raw.isPng = false;
|
|
||||||
if (!fromFile("background.jpg") || !raw.background.isEmpty()) {
|
|
||||||
return raw.background.isEmpty() ? ParsedTheme() : result();
|
|
||||||
}
|
|
||||||
return result();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray GenerateDefaultPalette() {
|
QByteArray GenerateDefaultPalette() {
|
||||||
auto result = QByteArray();
|
auto result = QByteArray();
|
||||||
const auto rows = style::main_palette::data();
|
const auto rows = style::main_palette::data();
|
||||||
|
@ -994,5 +928,72 @@ void SaveThemeBox(
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParsedTheme ParseTheme(
|
||||||
|
const Object &theme,
|
||||||
|
bool onlyPalette,
|
||||||
|
bool parseCurrent) {
|
||||||
|
auto raw = ParsedTheme();
|
||||||
|
raw.palette = theme.content;
|
||||||
|
const auto result = [&] {
|
||||||
|
if (const auto colorizer = ColorizerForTheme(theme.pathAbsolute)) {
|
||||||
|
raw.palette = Editor::ColorizeInContent(
|
||||||
|
std::move(raw.palette),
|
||||||
|
colorizer);
|
||||||
|
}
|
||||||
|
if (parseCurrent) {
|
||||||
|
raw.palette = ReplaceAdjustableColors(std::move(raw.palette));
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
zlib::FileToRead file(theme.content);
|
||||||
|
|
||||||
|
unz_global_info globalInfo = { 0 };
|
||||||
|
file.getGlobalInfo(&globalInfo);
|
||||||
|
if (file.error() != UNZ_OK) {
|
||||||
|
return result();
|
||||||
|
}
|
||||||
|
raw.palette = file.readFileContent("colors.tdesktop-theme", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
|
||||||
|
if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
|
||||||
|
file.clearError();
|
||||||
|
raw.palette = 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."));
|
||||||
|
return ParsedTheme();
|
||||||
|
} else if (onlyPalette) {
|
||||||
|
return result();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fromFile = [&](const char *filename) {
|
||||||
|
raw.background = file.readFileContent(filename, zlib::kCaseInsensitive, kThemeBackgroundSizeLimit);
|
||||||
|
if (file.error() == UNZ_OK) {
|
||||||
|
return true;
|
||||||
|
} else if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
|
||||||
|
file.clearError();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG(("Theme Error: could not read '%1' in the theme file.").arg(filename));
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!fromFile("background.jpg") || !raw.background.isEmpty()) {
|
||||||
|
return raw.background.isEmpty() ? ParsedTheme() : result();
|
||||||
|
}
|
||||||
|
raw.isPng = true;
|
||||||
|
if (!fromFile("background.png") || !raw.background.isEmpty()) {
|
||||||
|
return raw.background.isEmpty() ? ParsedTheme() : result();
|
||||||
|
}
|
||||||
|
raw.tiled = true;
|
||||||
|
if (!fromFile("tiled.png") || !raw.background.isEmpty()) {
|
||||||
|
return raw.background.isEmpty() ? ParsedTheme() : result();
|
||||||
|
}
|
||||||
|
raw.isPng = false;
|
||||||
|
if (!fromFile("background.jpg") || !raw.background.isEmpty()) {
|
||||||
|
return raw.background.isEmpty() ? ParsedTheme() : result();
|
||||||
|
}
|
||||||
|
return result();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Theme
|
} // namespace Theme
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
|
@ -19,6 +19,9 @@ class Controller;
|
||||||
|
|
||||||
namespace Theme {
|
namespace Theme {
|
||||||
|
|
||||||
|
struct Object;
|
||||||
|
struct ParsedTheme;
|
||||||
|
|
||||||
void StartEditor(
|
void StartEditor(
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
const Data::CloudTheme &cloud);
|
const Data::CloudTheme &cloud);
|
||||||
|
@ -46,5 +49,10 @@ void SaveThemeBox(
|
||||||
|
|
||||||
[[nodiscard]] QByteArray CollectForExport(const QByteArray &palette);
|
[[nodiscard]] QByteArray CollectForExport(const QByteArray &palette);
|
||||||
|
|
||||||
|
[[nodiscard]] ParsedTheme ParseTheme(
|
||||||
|
const Object &theme,
|
||||||
|
bool onlyPalette = false,
|
||||||
|
bool parseCurrent = true);
|
||||||
|
|
||||||
} // namespace Theme
|
} // namespace Theme
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
Loading…
Reference in New Issue