Check palette changes on editor cancel.

This commit is contained in:
John Preston 2019-09-08 16:40:15 +03:00
parent 95da2dbc34
commit cedb2d31af
6 changed files with 151 additions and 52 deletions

View File

@ -34,7 +34,6 @@ namespace Theme {
namespace { namespace {
constexpr auto kThemeFileSizeLimit = 5 * 1024 * 1024; constexpr auto kThemeFileSizeLimit = 5 * 1024 * 1024;
constexpr auto kThemeBackgroundSizeLimit = 4 * 1024 * 1024;
constexpr auto kBackgroundSizeLimit = 25 * 1024 * 1024; constexpr auto kBackgroundSizeLimit = 25 * 1024 * 1024;
constexpr auto kNightThemeFile = str_const(":/gui/night.tdesktop-theme"); constexpr auto kNightThemeFile = str_const(":/gui/night.tdesktop-theme");
constexpr auto kMinimumTiledSize = 512; constexpr auto kMinimumTiledSize = 512;

View File

@ -18,6 +18,7 @@ namespace Window {
namespace Theme { namespace Theme {
inline constexpr auto kThemeSchemeSizeLimit = 1024 * 1024; inline constexpr auto kThemeSchemeSizeLimit = 1024 * 1024;
inline constexpr auto kThemeBackgroundSizeLimit = 4 * 1024 * 1024;
[[nodiscard]] bool IsEmbeddedTheme(const QString &path); [[nodiscard]] bool IsEmbeddedTheme(const QString &path);

View File

@ -665,18 +665,7 @@ Editor::Editor(
_scroll->scrollToY(top, bottom); _scroll->scrollToY(top, bottom);
}); });
_close->setClickedCallback([=] { _close->setClickedCallback([=] {
const auto box = std::make_shared<QPointer<BoxContent>>(); closeWithConfirmation();
const auto close = crl::guard(this, [=] {
Background()->clearEditingTheme(ClearEditing::RevertChanges);
closeEditor();
if (*box) {
(*box)->closeBox();
}
});
*box = _window->show(Box<ConfirmBox>(
tr::lng_theme_editor_sure_close(tr::now),
tr::lng_close(tr::now),
close));
}); });
_close->show(anim::type::instant); _close->show(anim::type::instant);
@ -791,6 +780,26 @@ void Editor::paintEvent(QPaintEvent *e) {
// } // }
//} //}
void Editor::closeWithConfirmation() {
if (!PaletteChanged(_inner->paletteContent(), _cloud)) {
Background()->clearEditingTheme(ClearEditing::KeepChanges);
closeEditor();
return;
}
const auto box = std::make_shared<QPointer<BoxContent>>();
const auto close = crl::guard(this, [=] {
Background()->clearEditingTheme(ClearEditing::RevertChanges);
closeEditor();
if (*box) {
(*box)->closeBox();
}
});
*box = _window->show(Box<ConfirmBox>(
tr::lng_theme_editor_sure_close(tr::now),
tr::lng_close(tr::now),
close));
}
void Editor::closeEditor() { void Editor::closeEditor() {
if (const auto window = App::wnd()) { if (const auto window = App::wnd()) {
window->showRightColumn(nullptr); window->showRightColumn(nullptr);

View File

@ -49,6 +49,7 @@ protected:
private: private:
void save(); void save();
void closeEditor(); void closeEditor();
void closeWithConfirmation();
const not_null<Window::Controller*> _window; const not_null<Window::Controller*> _window;
const Data::CloudTheme _cloud; const Data::CloudTheme _cloud;

View File

@ -56,12 +56,29 @@ enum class SaveErrorType {
Link, Link,
}; };
struct ParsedTheme {
QByteArray palette;
QByteArray background;
bool isPng = false;
bool tiled = false;
};
struct PreparedBackground { struct PreparedBackground {
QByteArray content; QByteArray content;
bool tile = false; bool tile = false;
bool isPng = false; bool isPng = false;
bool changed = false;
}; };
template <size_t Size>
QByteArray qba(const char(&string)[Size]) {
return QByteArray::fromRawData(string, Size - 1);
}
QByteArray qba(QLatin1String string) {
return QByteArray::fromRawData(string.data(), string.size());
}
class BackgroundSelector : public Ui::RpWidget { class BackgroundSelector : public Ui::RpWidget {
public: public:
BackgroundSelector( BackgroundSelector(
@ -86,6 +103,7 @@ private:
QImage _background; QImage _background;
QByteArray _backgroundContent; QByteArray _backgroundContent;
bool _isPng = false; bool _isPng = false;
bool _changed = false;
QString _imageText; QString _imageText;
int _thumbnailSize = 0; int _thumbnailSize = 0;
QPixmap _thumbnail; QPixmap _thumbnail;
@ -185,6 +203,7 @@ void BackgroundSelector::chooseBackgroundFromFile() {
_background = image; _background = image;
_backgroundContent = content; _backgroundContent = content;
_isPng = (format == "png"); _isPng = (format == "png");
_changed = true;
const auto phrase = _isPng const auto phrase = _isPng
? tr::lng_theme_editor_read_from_png ? tr::lng_theme_editor_read_from_png
: tr::lng_theme_editor_read_from_jpg; : tr::lng_theme_editor_read_from_jpg;
@ -209,6 +228,7 @@ PreparedBackground BackgroundSelector::result() const {
_backgroundContent, _backgroundContent,
_tileBackground->checked(), _tileBackground->checked(),
_isPng, _isPng,
_changed,
}; };
} }
@ -239,27 +259,69 @@ void ImportFromFile(
return QString::fromUtf8(string.data(), string.size()); return QString::fromUtf8(string.data(), string.size());
} }
[[nodiscard]] bool CopyColorsToPalette( [[nodiscard]] ParsedTheme ParseTheme(
const QString &destination,
const QString &themePath,
const QByteArray &themeContent, const QByteArray &themeContent,
const Data::CloudTheme &cloud) { bool onlyPalette) {
auto paletteContent = themeContent; auto result = ParsedTheme();
result.palette = themeContent;
zlib::FileToRead file(themeContent); zlib::FileToRead file(themeContent);
unz_global_info globalInfo = { 0 }; unz_global_info globalInfo = { 0 };
file.getGlobalInfo(&globalInfo); file.getGlobalInfo(&globalInfo);
if (file.error() == UNZ_OK) { if (file.error() != UNZ_OK) {
paletteContent = file.readFileContent("colors.tdesktop-theme", zlib::kCaseInsensitive, kThemeSchemeSizeLimit); return result;
if (file.error() == UNZ_END_OF_LIST_OF_FILE) { }
result.palette = file.readFileContent("colors.tdesktop-theme", zlib::kCaseInsensitive, kThemeSchemeSizeLimit);
if (file.error() == UNZ_END_OF_LIST_OF_FILE) {
file.clearError();
result.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) {
result.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(); file.clearError();
paletteContent = file.readFileContent("colors.tdesktop-palette", zlib::kCaseInsensitive, kThemeSchemeSizeLimit); return true;
}
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;
} }
LOG(("Theme Error: could not read '%1' in the theme file.").arg(filename));
return false;
};
if (!fromFile("background.jpg") || !result.background.isEmpty()) {
return result.background.isEmpty() ? ParsedTheme() : result;
}
result.isPng = true;
if (!fromFile("background.png") || !result.background.isEmpty()) {
return result.background.isEmpty() ? ParsedTheme() : result;
}
result.tiled = true;
if (!fromFile("tiled.png") || !result.background.isEmpty()) {
return result.background.isEmpty() ? ParsedTheme() : result;
}
result.isPng = false;
if (!fromFile("background.jpg") || !result.background.isEmpty()) {
return result.background.isEmpty() ? ParsedTheme() : result;
}
return result;
}
[[nodiscard]] bool CopyColorsToPalette(
const QString &destination,
const QString &themePath,
const QByteArray &themeContent,
const Data::CloudTheme &cloud) {
auto parsed = ParseTheme(themeContent, true);
if (parsed.palette.isEmpty()) {
return false;
} }
QFile f(destination); QFile f(destination);
@ -269,18 +331,40 @@ void ImportFromFile(
} }
if (const auto colorizer = ColorizerForTheme(themePath)) { if (const auto colorizer = ColorizerForTheme(themePath)) {
paletteContent = Editor::ColorizeInContent( parsed.palette = Editor::ColorizeInContent(
std::move(paletteContent), std::move(parsed.palette),
colorizer); colorizer);
} }
paletteContent = WriteCloudToText(cloud) + paletteContent; const auto content = WriteCloudToText(cloud) + parsed.palette;
if (f.write(paletteContent) != paletteContent.size()) { if (f.write(content) != content.size()) {
LOG(("Theme Error: could not write palette to '%1'").arg(destination)); LOG(("Theme Error: could not write palette to '%1'").arg(destination));
return false; return false;
} }
return true; return true;
} }
QByteArray GenerateDefaultPalette() {
auto result = QByteArray();
const auto rows = style::main_palette::data();
for (const auto &row : std::as_const(rows)) {
result.append(qba(row.name)
).append(": "
).append(qba(row.value)
).append("; // "
).append(
qba(
row.description
).replace(
'\n',
' '
).replace(
'\r',
' ')
).append('\n');
}
return result;
}
bool WriteDefaultPalette( bool WriteDefaultPalette(
const QString &path, const QString &path,
const Data::CloudTheme &cloud) { const Data::CloudTheme &cloud) {
@ -290,27 +374,10 @@ bool WriteDefaultPalette(
return false; return false;
} }
QTextStream stream(&f); const auto content = WriteCloudToText(cloud) + GenerateDefaultPalette();
stream.setCodec("UTF-8"); if (f.write(content) != content.size()) {
LOG(("Theme Error: could not write palette to '%1'").arg(path));
stream << QString::fromLatin1(WriteCloudToText(cloud)); return false;
auto rows = style::main_palette::data();
for (const auto &row : std::as_const(rows)) {
stream
<< BytesToUTF8(row.name)
<< ": "
<< BytesToUTF8(row.value)
<< "; // "
<< BytesToUTF8(
row.description
).replace(
'\n',
' '
).replace(
'\r',
' ')
<< "\n";
} }
return true; return true;
} }
@ -623,7 +690,11 @@ void StartEditor(
auto object = Local::ReadThemeContent(); auto object = Local::ReadThemeContent();
const auto written = object.content.isEmpty() const auto written = object.content.isEmpty()
? WriteDefaultPalette(path, cloud) ? WriteDefaultPalette(path, cloud)
: CopyColorsToPalette(path, object.pathAbsolute, object.content, cloud); : CopyColorsToPalette(
path,
object.pathAbsolute,
object.content,
cloud);
if (!written) { 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;
@ -730,7 +801,11 @@ void SaveThemeBox(
const QByteArray &palette) { const QByteArray &palette) {
Expects(window->account().sessionExists()); Expects(window->account().sessionExists());
//Local::ReadThemeContent()
const auto background = Background()->createCurrentImage(); const auto background = Background()->createCurrentImage();
//if (Data::IsThemeWallPaper(Background()->paper())) {
//}
auto backgroundContent = QByteArray(); auto backgroundContent = QByteArray();
const auto tiled = Background()->tile(); const auto tiled = Background()->tile();
{ {
@ -854,5 +929,15 @@ void SaveThemeBox(
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
} }
bool PaletteChanged(
const QByteArray &editorPalette,
const Data::CloudTheme &cloud) {
auto object = Local::ReadThemeContent();
const auto real = object.content.isEmpty()
? GenerateDefaultPalette()
: ParseTheme(object.content, true).palette;
return (editorPalette != WriteCloudToText(cloud) + real);
}
} // namespace Theme } // namespace Theme
} // namespace Window } // namespace Window

View File

@ -40,5 +40,9 @@ void SaveThemeBox(
const Data::CloudTheme &cloud, const Data::CloudTheme &cloud,
const QByteArray &palette); const QByteArray &palette);
[[nodiscard]] bool PaletteChanged(
const QByteArray &editorPalette,
const Data::CloudTheme &cloud);
} // namespace Theme } // namespace Theme
} // namespace Window } // namespace Window