Save themes, apply and close editor on save.

This commit is contained in:
John Preston 2019-09-06 14:33:51 +03:00
parent 910f16312c
commit 9c86f0e0a5
9 changed files with 122 additions and 53 deletions

View File

@ -78,4 +78,12 @@ const std::vector<CloudTheme> &CloudThemes::list() const {
return _list; return _list;
} }
void CloudThemes::apply(const CloudTheme &theme) {
const auto i = ranges::find(_list, theme.id, &CloudTheme::id);
if (i != end(_list)) {
*i = theme;
_updates.fire({});
}
}
} // namespace Data } // namespace Data

View File

@ -35,6 +35,7 @@ public:
void refresh(); void refresh();
[[nodiscard]] rpl::producer<> updated() const; [[nodiscard]] rpl::producer<> updated() const;
[[nodiscard]] const std::vector<CloudTheme> &list() const; [[nodiscard]] const std::vector<CloudTheme> &list() const;
void apply(const CloudTheme &data);
private: private:
void parseThemes(const QVector<MTPTheme> &list); void parseThemes(const QVector<MTPTheme> &list);

View File

@ -568,6 +568,17 @@ void DocumentData::validateLottieSticker() {
} }
} }
void DocumentData::setDataAndCache(const QByteArray &data) {
setData(data);
if (saveToCache() && data.size() <= Storage::kMaxFileInMemory) {
session().data().cache().put(
cacheKey(),
Storage::Cache::Database::TaggedValue(
base::duplicate(data),
cacheTag()));
}
}
bool DocumentData::checkWallPaperProperties() { bool DocumentData::checkWallPaperProperties() {
if (type == WallPaperDocument) { if (type == WallPaperDocument) {
return true; return true;

View File

@ -166,6 +166,7 @@ public:
void setData(const QByteArray &data) { void setData(const QByteArray &data) {
_data = data; _data = data;
} }
void setDataAndCache(const QByteArray &data);
bool checkWallPaperProperties(); bool checkWallPaperProperties();
[[nodiscard]] bool isWallPaper() const; [[nodiscard]] bool isWallPaper() const;
[[nodiscard]] bool isPatternWallPaper() const; [[nodiscard]] bool isPatternWallPaper() const;

View File

@ -154,10 +154,6 @@ QPixmap PrepareStaticImage(const QString &path) {
return App::pixmapFromImageInPlace(std::move(image)); return App::pixmapFromImageInPlace(std::move(image));
} }
[[nodiscard]] QString CachedThemePath(uint64 documentId) {
return QString::fromLatin1("special://cached-%1").arg(documentId);
}
} // namespace } // namespace
struct OverlayWidget::SharedMedia { struct OverlayWidget::SharedMedia {
@ -2226,15 +2222,19 @@ void OverlayWidget::initThemePreview() {
&Data::CloudTheme::documentId); &Data::CloudTheme::documentId);
const auto cloud = (i != end(cloudList)) ? *i : Data::CloudTheme(); const auto cloud = (i != end(cloudList)) ? *i : Data::CloudTheme();
const auto isTrusted = (cloud.documentId != 0); const auto isTrusted = (cloud.documentId != 0);
const auto fields = [&] {
auto result = cloud;
if (!result.documentId) {
result.documentId = _doc->id;
}
return result;
}();
const auto realPath = _doc->location().name(); const auto path = _doc->location().name();
const auto path = realPath.isEmpty()
? CachedThemePath(_doc->id)
: realPath;
const auto id = _themePreviewId = rand_value<uint64>(); const auto id = _themePreviewId = rand_value<uint64>();
const auto weak = make_weak(this); const auto weak = make_weak(this);
crl::async([=, data = std::move(current)]() mutable { crl::async([=, data = std::move(current)]() mutable {
auto preview = GeneratePreview(bytes, path, cloud, std::move(data)); auto preview = GeneratePreview(bytes, path, fields, std::move(data));
crl::on_main(weak, [=, result = std::move(preview)]() mutable { crl::on_main(weak, [=, result = std::move(preview)]() mutable {
if (id != _themePreviewId) { if (id != _themePreviewId) {
return; return;

View File

@ -162,18 +162,10 @@ void Uploader::uploadMedia(
media.document, media.document,
base::duplicate(media.photoThumbs.front().second)); base::duplicate(media.photoThumbs.front().second));
if (!media.data.isEmpty()) { if (!media.data.isEmpty()) {
document->setData(media.data); document->setDataAndCache(media.data);
if (media.type == SendMediaType::ThemeFile) { if (media.type == SendMediaType::ThemeFile) {
document->checkWallPaperProperties(); document->checkWallPaperProperties();
} }
if (document->saveToCache()
&& media.data.size() <= Storage::kMaxFileInMemory) {
Auth().data().cache().put(
document->cacheKey(),
Storage::Cache::Database::TaggedValue(
base::duplicate(media.data),
document->cacheTag()));
}
} }
if (!media.file.isEmpty()) { if (!media.file.isEmpty()) {
document->setLocation(FileLocation(media.file)); document->setLocation(FileLocation(media.file));
@ -206,18 +198,10 @@ void Uploader::upload(
std::move(file->goodThumbnail), std::move(file->goodThumbnail),
std::move(file->goodThumbnailBytes)); std::move(file->goodThumbnailBytes));
if (!file->content.isEmpty()) { if (!file->content.isEmpty()) {
document->setData(file->content); document->setDataAndCache(file->content);
if (file->type == SendMediaType::ThemeFile) { if (file->type == SendMediaType::ThemeFile) {
document->checkWallPaperProperties(); document->checkWallPaperProperties();
} }
if (document->saveToCache()
&& file->content.size() <= Storage::kMaxFileInMemory) {
Auth().data().cache().put(
document->cacheKey(),
Storage::Cache::Database::TaggedValue(
base::duplicate(file->content),
document->cacheTag()));
}
} }
if (!file->filepath.isEmpty()) { if (!file->filepath.isEmpty()) {
document->setLocation(FileLocation(file->filepath)); document->setLocation(FileLocation(file->filepath));

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "window/themes/window_theme_editor.h" #include "window/themes/window_theme_editor.h"
#include "window/themes/window_theme_preview.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
@ -409,7 +410,7 @@ SendMediaReady PrepareThemeMedia(
//push("s", scaled(320)); //push("s", scaled(320));
const auto filename = File::NameFromUserString(name) const auto filename = File::NameFromUserString(name)
+ qsl(".tdesktop-theme"); // #TODO themes + qsl(".tdesktop-theme");
auto attributes = QVector<MTPDocumentAttribute>( auto attributes = QVector<MTPDocumentAttribute>(
1, 1,
MTP_documentAttributeFilename(MTP_string(filename))); MTP_documentAttributeFilename(MTP_string(filename)));
@ -447,22 +448,25 @@ 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,
const QString &name, const Data::CloudTheme &fields,
const QString &link,
Fn<void()> done, Fn<void()> done,
Fn<void(SaveErrorType,QString)> fail) { Fn<void(SaveErrorType,QString)> fail) {
Expects(window->account().sessionExists());
using Storage::UploadedDocument; using Storage::UploadedDocument;
struct State { struct State {
FullMsgId id; FullMsgId id;
bool generating = false; bool generating = false;
mtpRequestId requestId = 0; mtpRequestId requestId = 0;
QByteArray themeContent;
QString filename;
rpl::lifetime lifetime; rpl::lifetime lifetime;
}; };
if (name.isEmpty()) { if (fields.title.isEmpty()) {
fail(SaveErrorType::Name, {}); fail(SaveErrorType::Name, {});
return nullptr; return nullptr;
} else if (!IsGoodSlug(link)) { } else if (!IsGoodSlug(fields.slug)) {
fail(SaveErrorType::Link, {}); fail(SaveErrorType::Link, {});
return nullptr; return nullptr;
} }
@ -473,14 +477,62 @@ Fn<void()> SavePreparedTheme(
0, 0,
session->data().nextLocalMessageId()); session->data().nextLocalMessageId());
const auto creating = !fields.id
|| (fields.createdBy != session->userId());
const auto finish = [=](const MTPTheme &result) {
done();
const auto cloud = result.match([&](const MTPDtheme &data) {
const auto result = Data::CloudTheme::Parse(session, data);
session->data().cloudThemes().apply(result);
return result;
}, [&](const MTPDthemeDocumentNotModified &data) {
LOG(("API Error: Unexpected themeDocumentNotModified."));
return fields;
});
if (cloud.documentId) {
const auto document = session->data().document(cloud.documentId);
document->setDataAndCache(state->themeContent);
}
auto preview = PreviewFromFile(
state->themeContent,
QString(),
cloud);
if (preview) {
Apply(std::move(preview));
KeepApplied();
}
Background()->setEditingTheme(std::nullopt);
};
const auto createTheme = [=](const MTPDocument &data) { const auto createTheme = [=](const MTPDocument &data) {
const auto document = session->data().processDocument(data); const auto document = session->data().processDocument(data);
state->requestId = api->request(MTPaccount_CreateTheme( state->requestId = api->request(MTPaccount_CreateTheme(
MTP_string(link), MTP_string(fields.slug),
MTP_string(name), MTP_string(fields.title),
document->mtpInput() document->mtpInput()
)).done([=](const MTPTheme &result) { )).done([=](const MTPTheme &result) {
done(); finish(result);
}).fail([=](const RPCError &error) {
fail(SaveErrorType::Other, error.type());
}).send();
};
const auto updateTheme = [=](const MTPDocument &data) {
const auto document = session->data().processDocument(data);
const auto flags = MTPaccount_UpdateTheme::Flag::f_title
| MTPaccount_UpdateTheme::Flag::f_slug
| MTPaccount_UpdateTheme::Flag::f_document;
state->requestId = api->request(MTPaccount_UpdateTheme(
MTP_flags(flags),
MTP_string(Data::CloudThemes::Format()),
MTP_inputTheme(MTP_long(fields.id), MTP_long(fields.accessHash)),
MTP_string(fields.slug),
MTP_string(fields.title),
document->mtpInput()
)).done([=](const MTPTheme &result) {
finish(result);
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
fail(SaveErrorType::Other, error.type()); fail(SaveErrorType::Other, error.type());
}).send(); }).send();
@ -491,16 +543,24 @@ Fn<void()> SavePreparedTheme(
MTP_flags(0), MTP_flags(0),
data.file, data.file,
MTPInputFile(), // thumb MTPInputFile(), // thumb
MTP_string(name + ".tdesktop-theme"), // #TODO themes MTP_string(state->filename),
MTP_string("application/x-tgtheme-tdesktop") MTP_string("application/x-tgtheme-tdesktop")
)).done([=](const MTPDocument &result) { )).done([=](const MTPDocument &result) {
createTheme(result); if (creating) {
createTheme(result);
} else {
updateTheme(result);
}
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
fail(SaveErrorType::Other, error.type()); fail(SaveErrorType::Other, error.type());
}).send(); }).send();
}; };
const auto uploadFile = [=](const QByteArray &theme) { const auto uploadFile = [=](const QByteArray &theme) {
const auto media = PrepareThemeMedia(fields.title, theme);
state->filename = media.filename;
state->themeContent = theme;
session->uploader().documentReady( session->uploader().documentReady(
) | rpl::filter([=](const UploadedDocument &data) { ) | rpl::filter([=](const UploadedDocument &data) {
return data.fullId == state->id; return data.fullId == state->id;
@ -508,9 +568,7 @@ Fn<void()> SavePreparedTheme(
uploadTheme(data); uploadTheme(data);
}, state->lifetime); }, state->lifetime);
session->uploader().uploadMedia( session->uploader().uploadMedia(state->id, media);
state->id,
PrepareThemeMedia(name, theme));
}; };
state->generating = true; state->generating = true;
@ -621,6 +679,7 @@ void SaveTheme(
using Data::CloudTheme; using Data::CloudTheme;
const auto save = [=](const CloudTheme &fields) { const auto save = [=](const CloudTheme &fields) {
unlock();
window->show(Box(SaveThemeBox, window, fields, palette)); window->show(Box(SaveThemeBox, window, fields, palette));
}; };
if (cloud.id) { if (cloud.id) {
@ -629,7 +688,6 @@ void SaveTheme(
MTP_inputTheme(MTP_long(cloud.id), MTP_long(cloud.accessHash)), MTP_inputTheme(MTP_long(cloud.id), MTP_long(cloud.accessHash)),
MTP_long(0) MTP_long(0)
)).done([=](const MTPTheme &result) { )).done([=](const MTPTheme &result) {
unlock();
result.match([&](const MTPDtheme &data) { result.match([&](const MTPDtheme &data) {
save(CloudTheme::Parse(&window->account().session(), data)); save(CloudTheme::Parse(&window->account().session(), data));
}, [&](const MTPDthemeDocumentNotModified &data) { }, [&](const MTPDthemeDocumentNotModified &data) {
@ -637,7 +695,6 @@ void SaveTheme(
save(CloudTheme()); save(CloudTheme());
}); });
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
unlock();
save(CloudTheme()); save(CloudTheme());
}).send(); }).send();
} else { } else {
@ -751,12 +808,14 @@ void SaveThemeBox(
link->showError(); link->showError();
} }
}); });
auto fields = cloud;
fields.title = name->getLastText().trimmed();
fields.slug = link->getLastText().trimmed();
*cancel = SavePreparedTheme( *cancel = SavePreparedTheme(
window, window,
palette, palette,
back->result(), back->result(),
name->getLastText().trimmed(), fields,
link->getLastText().trimmed(),
done, done,
fail); fail);
}); });

View File

@ -906,23 +906,25 @@ void Generator::restoreTextPalette() {
_p->restoreTextPalette(); _p->restoreTextPalette();
} }
[[nodiscard]] QString CachedThemePath(uint64 documentId) {
return QString::fromLatin1("special://cached-%1").arg(documentId);
}
} // namespace } // namespace
std::unique_ptr<Preview> PreviewFromFile( std::unique_ptr<Preview> PreviewFromFile(
const QByteArray &bytes, const QByteArray &bytes,
const QString &filepath, const QString &filepath,
const Data::CloudTheme &cloud) { const Data::CloudTheme &cloud) {
Expects(!filepath.isEmpty()); // Use
auto result = std::make_unique<Preview>(); auto result = std::make_unique<Preview>();
auto &object = result->object; auto &object = result->object;
object.cloud = cloud; object.cloud = cloud;
object.pathRelative = filepath.isEmpty()
? QString()
: QDir().relativeFilePath(filepath);
object.pathAbsolute = filepath.isEmpty() object.pathAbsolute = filepath.isEmpty()
? QString() ? CachedThemePath(cloud.documentId)
: QFileInfo(filepath).absoluteFilePath(); : QFileInfo(filepath).absoluteFilePath();
object.pathRelative = filepath.isEmpty()
? object.pathAbsolute
: QDir().relativeFilePath(filepath);
if (bytes.isEmpty()) { if (bytes.isEmpty()) {
if (!LoadFromFile(filepath, &result->instance, &object.content)) { if (!LoadFromFile(filepath, &result->instance, &object.content)) {
return nullptr; return nullptr;

View File

@ -447,9 +447,12 @@ bool CloudList::insertTillLimit(
}) | ranges::view::take(insertCount); }) | ranges::view::take(insertCount);
for (const auto &theme : insertElements) { for (const auto &theme : insertElements) {
auto &index = isGood(theme) ? positionForGood : positionForBad; const auto good = isGood(theme);
insert(index, theme); insert(good ? positionForGood : positionForBad, theme);
++index; if (good) {
++positionForGood;
}
++positionForBad;
} }
return true; return true;
} }