diff --git a/Telegram/SourceFiles/data/data_cloud_themes.cpp b/Telegram/SourceFiles/data/data_cloud_themes.cpp index 6d2bf3fc90..4be5d9aa76 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.cpp +++ b/Telegram/SourceFiles/data/data_cloud_themes.cpp @@ -78,4 +78,12 @@ const std::vector &CloudThemes::list() const { 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 diff --git a/Telegram/SourceFiles/data/data_cloud_themes.h b/Telegram/SourceFiles/data/data_cloud_themes.h index e3860d6a02..072561ddbc 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.h +++ b/Telegram/SourceFiles/data/data_cloud_themes.h @@ -35,6 +35,7 @@ public: void refresh(); [[nodiscard]] rpl::producer<> updated() const; [[nodiscard]] const std::vector &list() const; + void apply(const CloudTheme &data); private: void parseThemes(const QVector &list); diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index f42ca8e258..a599c717f2 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -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() { if (type == WallPaperDocument) { return true; diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 79375a9f1b..016d66d606 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -166,6 +166,7 @@ public: void setData(const QByteArray &data) { _data = data; } + void setDataAndCache(const QByteArray &data); bool checkWallPaperProperties(); [[nodiscard]] bool isWallPaper() const; [[nodiscard]] bool isPatternWallPaper() const; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 6af6a2753a..e0422f6463 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -154,10 +154,6 @@ QPixmap PrepareStaticImage(const QString &path) { return App::pixmapFromImageInPlace(std::move(image)); } -[[nodiscard]] QString CachedThemePath(uint64 documentId) { - return QString::fromLatin1("special://cached-%1").arg(documentId); -} - } // namespace struct OverlayWidget::SharedMedia { @@ -2226,15 +2222,19 @@ void OverlayWidget::initThemePreview() { &Data::CloudTheme::documentId); const auto cloud = (i != end(cloudList)) ? *i : Data::CloudTheme(); 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 = realPath.isEmpty() - ? CachedThemePath(_doc->id) - : realPath; + const auto path = _doc->location().name(); const auto id = _themePreviewId = rand_value(); const auto weak = make_weak(this); 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 { if (id != _themePreviewId) { return; diff --git a/Telegram/SourceFiles/storage/file_upload.cpp b/Telegram/SourceFiles/storage/file_upload.cpp index 81aa637770..6d852cdb96 100644 --- a/Telegram/SourceFiles/storage/file_upload.cpp +++ b/Telegram/SourceFiles/storage/file_upload.cpp @@ -162,18 +162,10 @@ void Uploader::uploadMedia( media.document, base::duplicate(media.photoThumbs.front().second)); if (!media.data.isEmpty()) { - document->setData(media.data); + document->setDataAndCache(media.data); if (media.type == SendMediaType::ThemeFile) { 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()) { document->setLocation(FileLocation(media.file)); @@ -206,18 +198,10 @@ void Uploader::upload( std::move(file->goodThumbnail), std::move(file->goodThumbnailBytes)); if (!file->content.isEmpty()) { - document->setData(file->content); + document->setDataAndCache(file->content); if (file->type == SendMediaType::ThemeFile) { 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()) { document->setLocation(FileLocation(file->filepath)); diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp index bf0566bac0..f42ca06245 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/themes/window_theme.h" #include "window/themes/window_theme_editor.h" +#include "window/themes/window_theme_preview.h" #include "window/window_controller.h" #include "boxes/confirm_box.h" #include "ui/text/text_utilities.h" @@ -409,7 +410,7 @@ SendMediaReady PrepareThemeMedia( //push("s", scaled(320)); const auto filename = File::NameFromUserString(name) - + qsl(".tdesktop-theme"); // #TODO themes + + qsl(".tdesktop-theme"); auto attributes = QVector( 1, MTP_documentAttributeFilename(MTP_string(filename))); @@ -447,22 +448,25 @@ Fn SavePreparedTheme( not_null window, const QByteArray &palette, const PreparedBackground &background, - const QString &name, - const QString &link, + const Data::CloudTheme &fields, Fn done, Fn fail) { + Expects(window->account().sessionExists()); + using Storage::UploadedDocument; struct State { FullMsgId id; bool generating = false; mtpRequestId requestId = 0; + QByteArray themeContent; + QString filename; rpl::lifetime lifetime; }; - if (name.isEmpty()) { + if (fields.title.isEmpty()) { fail(SaveErrorType::Name, {}); return nullptr; - } else if (!IsGoodSlug(link)) { + } else if (!IsGoodSlug(fields.slug)) { fail(SaveErrorType::Link, {}); return nullptr; } @@ -473,14 +477,62 @@ Fn SavePreparedTheme( 0, 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 document = session->data().processDocument(data); state->requestId = api->request(MTPaccount_CreateTheme( - MTP_string(link), - MTP_string(name), + MTP_string(fields.slug), + MTP_string(fields.title), document->mtpInput() )).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(SaveErrorType::Other, error.type()); }).send(); @@ -491,16 +543,24 @@ Fn SavePreparedTheme( MTP_flags(0), data.file, MTPInputFile(), // thumb - MTP_string(name + ".tdesktop-theme"), // #TODO themes + MTP_string(state->filename), MTP_string("application/x-tgtheme-tdesktop") )).done([=](const MTPDocument &result) { - createTheme(result); + if (creating) { + createTheme(result); + } else { + updateTheme(result); + } }).fail([=](const RPCError &error) { fail(SaveErrorType::Other, error.type()); }).send(); }; const auto uploadFile = [=](const QByteArray &theme) { + const auto media = PrepareThemeMedia(fields.title, theme); + state->filename = media.filename; + state->themeContent = theme; + session->uploader().documentReady( ) | rpl::filter([=](const UploadedDocument &data) { return data.fullId == state->id; @@ -508,9 +568,7 @@ Fn SavePreparedTheme( uploadTheme(data); }, state->lifetime); - session->uploader().uploadMedia( - state->id, - PrepareThemeMedia(name, theme)); + session->uploader().uploadMedia(state->id, media); }; state->generating = true; @@ -621,6 +679,7 @@ void SaveTheme( using Data::CloudTheme; const auto save = [=](const CloudTheme &fields) { + unlock(); window->show(Box(SaveThemeBox, window, fields, palette)); }; if (cloud.id) { @@ -629,7 +688,6 @@ void SaveTheme( 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) { @@ -637,7 +695,6 @@ void SaveTheme( save(CloudTheme()); }); }).fail([=](const RPCError &error) { - unlock(); save(CloudTheme()); }).send(); } else { @@ -751,12 +808,14 @@ void SaveThemeBox( link->showError(); } }); + auto fields = cloud; + fields.title = name->getLastText().trimmed(); + fields.slug = link->getLastText().trimmed(); *cancel = SavePreparedTheme( window, palette, back->result(), - name->getLastText().trimmed(), - link->getLastText().trimmed(), + fields, done, fail); }); diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp index c010312228..ae3a48eee0 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp @@ -906,23 +906,25 @@ void Generator::restoreTextPalette() { _p->restoreTextPalette(); } +[[nodiscard]] QString CachedThemePath(uint64 documentId) { + return QString::fromLatin1("special://cached-%1").arg(documentId); +} + } // namespace std::unique_ptr PreviewFromFile( const QByteArray &bytes, const QString &filepath, const Data::CloudTheme &cloud) { - Expects(!filepath.isEmpty()); // Use - auto result = std::make_unique(); auto &object = result->object; object.cloud = cloud; - object.pathRelative = filepath.isEmpty() - ? QString() - : QDir().relativeFilePath(filepath); object.pathAbsolute = filepath.isEmpty() - ? QString() + ? CachedThemePath(cloud.documentId) : QFileInfo(filepath).absoluteFilePath(); + object.pathRelative = filepath.isEmpty() + ? object.pathAbsolute + : QDir().relativeFilePath(filepath); if (bytes.isEmpty()) { if (!LoadFromFile(filepath, &result->instance, &object.content)) { return nullptr; diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp index 9ea9acd23a..ec2a7c8a55 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp @@ -447,9 +447,12 @@ bool CloudList::insertTillLimit( }) | ranges::view::take(insertCount); for (const auto &theme : insertElements) { - auto &index = isGood(theme) ? positionForGood : positionForBad; - insert(index, theme); - ++index; + const auto good = isGood(theme); + insert(good ? positionForGood : positionForBad, theme); + if (good) { + ++positionForGood; + } + ++positionForBad; } return true; }