Add import theme to the editor.

This commit is contained in:
John Preston 2019-09-09 23:58:41 +03:00
parent d85f162bff
commit dfd63e66ff
5 changed files with 162 additions and 81 deletions

View File

@ -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.";

View File

@ -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 &copyOf, 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);

View File

@ -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;

View File

@ -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

View File

@ -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