diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index cd4222eb7..8fd8a81e1 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1149,6 +1149,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_media_size_limit" = "Limit by size"; "lng_media_size_up_to" = "up to {size}"; "lng_media_chat_background" = "Chat background"; +"lng_media_color_theme" = "Color theme"; "lng_emoji_category1" = "People"; "lng_emoji_category2" = "Nature"; diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index a599c717f..89c7b0894 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -650,6 +650,7 @@ void DocumentData::validateGoodThumbnail() { if (!isVideoFile() && !isAnimation() && !isWallPaper() + && !isTheme() && (!sticker() || !sticker()->animated)) { _goodThumbnail = nullptr; } else if (!_goodThumbnail && hasRemoteLocation()) { @@ -1470,7 +1471,8 @@ bool DocumentData::isGifv() const { bool DocumentData::isTheme() const { return - _filename.endsWith( + _mimeString == qstr("application/x-tgtheme-tdesktop") + || _filename.endsWith( qstr(".tdesktop-theme"), Qt::CaseInsensitive) || _filename.endsWith( diff --git a/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp b/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp index 39349a567..d2ac8ecab 100644 --- a/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp +++ b/Telegram/SourceFiles/data/data_document_good_thumbnail.cpp @@ -10,8 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_document.h" #include "data/data_file_origin.h" +#include "data/data_cloud_themes.h" #include "media/clip/media_clip_reader.h" #include "lottie/lottie_animation.h" +#include "window/themes/window_theme_preview.h" #include "main/main_session.h" #include @@ -27,6 +29,7 @@ enum class FileType { Video, AnimatedSticker, WallPaper, + Theme, }; QImage Prepare( @@ -37,6 +40,8 @@ QImage Prepare( return ::Media::Clip::PrepareForSending(path, data).thumbnail; } else if (type == FileType::AnimatedSticker) { return Lottie::ReadThumbnail(Lottie::ReadContent(data, path)); + } else if (type == FileType::Theme) { + return Window::Theme::GeneratePreview(data, path); } const auto validateSize = [](QSize size) { return (size.width() + size.height()) < 10'000; @@ -78,6 +83,8 @@ void GoodThumbSource::generate(base::binary_guard &&guard) { const auto data = _document->data(); const auto type = _document->isWallPaper() ? FileType::WallPaper + : _document->isTheme() + ? FileType::Theme : _document->sticker() ? FileType::AnimatedSticker : FileType::Video; @@ -143,13 +150,13 @@ void GoodThumbSource::ready( _document->goodThumbnailCacheKey(), Storage::Cache::Database::TaggedValue{ std::move(bytes), - Data::kImageCacheTag }); + kImageCacheTag }); } Auth().downloaderTaskFinished().notify(); }); } -void GoodThumbSource::load(Data::FileOrigin origin) { +void GoodThumbSource::load(FileOrigin origin) { if (loading() || _empty) { return; } @@ -178,7 +185,7 @@ void GoodThumbSource::load(Data::FileOrigin origin) { std::move(callback)); } -void GoodThumbSource::loadEvenCancelled(Data::FileOrigin origin) { +void GoodThumbSource::loadEvenCancelled(FileOrigin origin) { _empty = false; load(origin); } @@ -193,7 +200,7 @@ void GoodThumbSource::unload() { } void GoodThumbSource::automaticLoad( - Data::FileOrigin origin, + FileOrigin origin, const HistoryItem *item) { } @@ -235,7 +242,7 @@ void GoodThumbSource::setDelayedStorageLocation( const StorageImageLocation &location) { } -void GoodThumbSource::performDelayedLoad(Data::FileOrigin origin) { +void GoodThumbSource::performDelayedLoad(FileOrigin origin) { } bool GoodThumbSource::isDelayedStorageImage() const { diff --git a/Telegram/SourceFiles/data/data_document_good_thumbnail.h b/Telegram/SourceFiles/data/data_document_good_thumbnail.h index 861102d21..58b53e384 100644 --- a/Telegram/SourceFiles/data/data_document_good_thumbnail.h +++ b/Telegram/SourceFiles/data/data_document_good_thumbnail.h @@ -17,13 +17,13 @@ class GoodThumbSource : public Images::Source { public: explicit GoodThumbSource(not_null document); - void load(Data::FileOrigin origin) override; - void loadEvenCancelled(Data::FileOrigin origin) override; + void load(FileOrigin origin) override; + void loadEvenCancelled(FileOrigin origin) override; QImage takeLoaded() override; void unload() override; void automaticLoad( - Data::FileOrigin origin, + FileOrigin origin, const HistoryItem *item) override; void automaticLoadSettingsChanged() override; @@ -38,7 +38,7 @@ public: std::optional cacheKey() override; void setDelayedStorageLocation( const StorageImageLocation &location) override; - void performDelayedLoad(Data::FileOrigin origin) override; + void performDelayedLoad(FileOrigin origin) override; bool isDelayedStorageImage() const override; void setImageBytes(const QByteArray &bytes) override; diff --git a/Telegram/SourceFiles/data/data_file_origin.cpp b/Telegram/SourceFiles/data/data_file_origin.cpp index 9ff88180c..b2932a5b9 100644 --- a/Telegram/SourceFiles/data/data_file_origin.cpp +++ b/Telegram/SourceFiles/data/data_file_origin.cpp @@ -51,6 +51,9 @@ struct FileReferenceAccumulator { if (const auto document = data.vdocument()) { push(*document); } + if (const auto documents = data.vdocuments()) { + push(*documents); + } if (const auto photo = data.vphoto()) { push(*photo); } diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 7e49fdf9d..7c1c9636c 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_call.h" #include "history/view/media/history_view_web_page.h" #include "history/view/media/history_view_poll.h" +#include "history/view/media/history_view_theme_document.h" #include "ui/image/image.h" #include "ui/image/image_source.h" #include "ui/text_options.h" @@ -779,6 +780,10 @@ std::unique_ptr MediaFile::createView( message, realParent, _document); + } else if (_document->isTheme() && _document->hasThumbnail()) { + return std::make_unique( + message, + _document); } return std::make_unique(message, _document); } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 30a4ad1ce..897ef57a6 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2762,6 +2762,17 @@ void Session::webpageApplyFields( const auto pendingTill = TimeId(0); const auto photo = data.vphoto(); const auto document = data.vdocument(); + const auto lookupThemeDocument = [&]() -> DocumentData* { + if (const auto documents = data.vdocuments()) { + for (const auto &document : documents->v) { + const auto processed = processDocument(document); + if (processed->isTheme()) { + return processed; + } + } + } + return nullptr; + }; webpageApplyFields( page, ParseWebPageType(data), @@ -2771,7 +2782,7 @@ void Session::webpageApplyFields( qs(data.vtitle().value_or_empty()), description, photo ? processPhoto(*photo).get() : nullptr, - document ? processDocument(*document).get() : nullptr, + document ? processDocument(*document).get() : lookupThemeDocument(), WebPageCollage(data), data.vduration().value_or_empty(), qs(data.vauthor().value_or_empty()), diff --git a/Telegram/SourceFiles/data/data_web_page.cpp b/Telegram/SourceFiles/data/data_web_page.cpp index afc40f445..d4818683b 100644 --- a/Telegram/SourceFiles/data/data_web_page.cpp +++ b/Telegram/SourceFiles/data/data_web_page.cpp @@ -139,6 +139,8 @@ WebPageType ParseWebPageType(const MTPDwebPage &page) { return WebPageType::Profile; } else if (type == qstr("telegram_background")) { return WebPageType::WallPaper; + } else if (type == qstr("telegram_theme")) { + return WebPageType::Theme; } else if (page.vcached_page()) { return WebPageType::ArticleWithIV; } else { diff --git a/Telegram/SourceFiles/data/data_web_page.h b/Telegram/SourceFiles/data/data_web_page.h index 30fb70348..f3e6dfbae 100644 --- a/Telegram/SourceFiles/data/data_web_page.h +++ b/Telegram/SourceFiles/data/data_web_page.h @@ -15,6 +15,7 @@ enum class WebPageType { Video, Profile, WallPaper, + Theme, Article, ArticleWithIV, }; diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style index 9bc5a7d7b..a5c3fc442 100644 --- a/Telegram/SourceFiles/history/history.style +++ b/Telegram/SourceFiles/history/history.style @@ -18,6 +18,7 @@ maxVideoMessageSize: 240px; maxSignatureSize: 144px; maxWallPaperWidth: 160px; maxWallPaperHeight: 240px; +historyThemeSize: size(309px, 200px); historyMinimalWidth: 380px; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp index cbf367390..8d16dcee4 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp @@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_document.h" #include "history/view/media/history_view_sticker.h" #include "history/view/media/history_view_video.h" -#include "history/view/media/history_view_wall_paper.h" +#include "history/view/media/history_view_theme_document.h" #include "styles/style_history.h" namespace HistoryView { @@ -80,8 +80,8 @@ std::unique_ptr CreateAttach( parent, parent->data(), document); - } else if (document->isWallPaper()) { - return std::make_unique( + } else if (document->isWallPaper() || document->isTheme()) { + return std::make_unique( parent, document, webpageUrl); diff --git a/Telegram/SourceFiles/history/view/media/history_view_wall_paper.cpp b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp similarity index 84% rename from Telegram/SourceFiles/history/view/media/history_view_wall_paper.cpp rename to Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp index 0701101ac..c0265dfac 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_wall_paper.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp @@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ -#include "history/view/media/history_view_wall_paper.h" +#include "history/view/media/history_view_theme_document.h" #include "layout.h" #include "history/history_item.h" @@ -19,22 +19,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { -WallPaper::WallPaper( +ThemeDocument::ThemeDocument( not_null parent, not_null document, const QString &url) : File(parent, parent->data()) , _data(document) { - Expects(_data->hasThumbnail()); + Expects(_data->hasThumbnail() || _data->isTheme()); - fillPatternFieldsFrom(url); + if (_data->isWallPaper()) { + fillPatternFieldsFrom(url); + } - _data->thumbnail()->load(parent->data()->fullId()); + _data->loadThumbnail(_parent->data()->fullId()); setDocumentLinks(_data, parent->data()); setStatusSize(FileStatusSizeReady, _data->size, -1, 0); } -void WallPaper::fillPatternFieldsFrom(const QString &url) { +void ThemeDocument::fillPatternFieldsFrom(const QString &url) { const auto paramsPosition = url.indexOf('?'); if (paramsPosition < 0) { return; @@ -49,7 +51,10 @@ void WallPaper::fillPatternFieldsFrom(const QString &url) { _background = paper.backgroundColor().value_or(kDefaultBackground); } -QSize WallPaper::countOptimalSize() { +QSize ThemeDocument::countOptimalSize() { + if (_data->isTheme()) { + return st::historyThemeSize; + } auto tw = ConvertScale(_data->thumbnail()->width()); auto th = ConvertScale(_data->thumbnail()->height()); if (!tw || !th) { @@ -66,7 +71,12 @@ QSize WallPaper::countOptimalSize() { return { maxWidth, minHeight }; } -QSize WallPaper::countCurrentSize(int newWidth) { +QSize ThemeDocument::countCurrentSize(int newWidth) { + if (_data->isTheme()) { + _pixw = st::historyThemeSize.width(); + _pixh = st::historyThemeSize.height(); + return st::historyThemeSize; + } auto tw = ConvertScale(_data->thumbnail()->width()); auto th = ConvertScale(_data->thumbnail()->height()); if (!tw || !th) { @@ -86,7 +96,7 @@ QSize WallPaper::countCurrentSize(int newWidth) { return { newWidth, newHeight }; } -void WallPaper::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const { +void ThemeDocument::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_realParent->fullId(), _parent->data()); @@ -166,7 +176,7 @@ void WallPaper::draw(Painter &p, const QRect &r, TextSelection selection, crl::t } } -void WallPaper::validateThumbnail() const { +void ThemeDocument::validateThumbnail() const { if (_thumbnailGood > 0) { return; } @@ -179,7 +189,7 @@ void WallPaper::validateThumbnail() const { good->load({}); } } - if (_thumbnailGood >= 0) { + if (_thumbnailGood >= 0 || !_data->thumbnail()) { return; } if (_data->thumbnail()->loaded()) { @@ -191,11 +201,12 @@ void WallPaper::validateThumbnail() const { } } -void WallPaper::prepareThumbnailFrom( +void ThemeDocument::prepareThumbnailFrom( not_null image, int good) const { Expects(_thumbnailGood <= good); + const auto isTheme = _data->isTheme(); const auto isPattern = _data->isPatternWallPaper(); auto options = Images::Option::Smooth | (good >= 0 ? Images::Option(0) : Images::Option::Blurred) @@ -203,8 +214,8 @@ void WallPaper::prepareThumbnailFrom( ? Images::Option::TransparentBackground : Images::Option(0)); auto original = image->original(); - auto tw = ConvertScale(_data->thumbnail()->width()); - auto th = ConvertScale(_data->thumbnail()->height()); + auto tw = isTheme ? _pixw : ConvertScale(_data->thumbnail()->width()); + auto th = isTheme ? _pixh : ConvertScale(_data->thumbnail()->height()); if (!tw || !th) { tw = th = 1; } @@ -226,7 +237,7 @@ void WallPaper::prepareThumbnailFrom( _thumbnailGood = good; } -TextState WallPaper::textState(QPoint point, StateRequest request) const { +TextState ThemeDocument::textState(QPoint point, StateRequest request) const { auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { @@ -248,24 +259,24 @@ TextState WallPaper::textState(QPoint point, StateRequest request) const { return result; } -float64 WallPaper::dataProgress() const { +float64 ThemeDocument::dataProgress() const { return _data->progress(); } -bool WallPaper::dataFinished() const { +bool ThemeDocument::dataFinished() const { return !_data->loading() && (!_data->uploading() || _data->waitingForAlbum()); } -bool WallPaper::dataLoaded() const { +bool ThemeDocument::dataLoaded() const { return _data->loaded(); } -bool WallPaper::isReadyForOpen() const { +bool ThemeDocument::isReadyForOpen() const { return _data->loaded(); } -QString WallPaper::additionalInfoString() const { +QString ThemeDocument::additionalInfoString() const { // This will force message info (time) to be displayed below // this attachment in WebPage media. static auto result = QString(" "); diff --git a/Telegram/SourceFiles/history/view/media/history_view_wall_paper.h b/Telegram/SourceFiles/history/view/media/history_view_theme_document.h similarity index 94% rename from Telegram/SourceFiles/history/view/media/history_view_wall_paper.h rename to Telegram/SourceFiles/history/view/media/history_view_theme_document.h index e61cea573..421280994 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_wall_paper.h +++ b/Telegram/SourceFiles/history/view/media/history_view_theme_document.h @@ -11,9 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { -class WallPaper : public File { +class ThemeDocument : public File { public: - WallPaper( + ThemeDocument( not_null parent, not_null document, const QString &url = QString()); @@ -59,6 +59,8 @@ private: int _pixh = 1; mutable QPixmap _thumbnail; mutable int _thumbnailGood = -1; // -1 inline, 0 thumbnail, 1 good + + // For wallpaper documents. QColor _background; int _intensity = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index 2bdbd2d6c..adb6d7ab2 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -129,7 +129,9 @@ QSize WebPage::countOptimalSize() { _openl = previewOfHiddenUrl ? std::make_shared(_data->url) : std::make_shared(_data->url, true); - if (_data->document && _data->document->isWallPaper()) { + if (_data->document + && (_data->document->isWallPaper() + || _data->document->isTheme())) { _openl = std::make_shared( std::move(_openl), _data->document, @@ -652,7 +654,7 @@ ClickHandlerPtr WebPage::replaceAttachLink( return link; } if (_data->document) { - if (_data->document->isWallPaper()) { + if (_data->document->isWallPaper() || _data->document->isTheme()) { return _openl; } } else if (_data->photo) { @@ -674,7 +676,7 @@ TextSelection WebPage::adjustSelection(TextSelection selection, TextSelectType t if ((!_titleLines && !_descriptionLines) || selection.to <= _siteName.length()) { return _siteName.adjustSelection(selection, type); } - + auto titleSelection = _title.adjustSelection(toTitleSelection(selection), type); if ((!_siteNameLines && !_descriptionLines) || (selection.from >= _siteName.length() && selection.to <= _description.length())) { return fromTitleSelection(titleSelection); @@ -708,7 +710,7 @@ void WebPage::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) bool WebPage::enforceBubbleWidth() const { return (_attach != nullptr) && (_data->document != nullptr) - && _data->document->isWallPaper(); + && (_data->document->isWallPaper() || _data->document->isTheme()); } void WebPage::playAnimation(bool autoplay) { @@ -779,6 +781,8 @@ int WebPage::bottomInfoPadding() const { QString WebPage::displayedSiteName() const { return (_data->document && _data->document->isWallPaper()) ? tr::lng_media_chat_background(tr::now) + : (_data->document && _data->document->isWallPaper()) + ? tr::lng_media_color_theme(tr::now) : _data->siteName; } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 06f3f7c2c..50d7ccf50 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2251,7 +2251,12 @@ void OverlayWidget::initThemePreview() { const auto id = _themePreviewId = rand_value(); const auto weak = make_weak(this); crl::async([=, data = std::move(current)]() mutable { - auto preview = GeneratePreview(bytes, path, fields, std::move(data)); + auto preview = GeneratePreview( + bytes, + path, + fields, + std::move(data), + Window::Theme::PreviewType::Extended); crl::on_main(weak, [=, result = std::move(preview)]() mutable { if (id != _themePreviewId) { return; diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp index 0a94bdbd9..28da2fc8a 100644 --- a/Telegram/SourceFiles/storage/localimageloader.cpp +++ b/Telegram/SourceFiles/storage/localimageloader.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "storage/file_download.h" #include "storage/storage_media_prepare.h" +#include "window/themes/window_theme_preview.h" #include "mainwidget.h" #include "mainwindow.h" #include "main/main_session.h" @@ -78,13 +79,6 @@ PreparedFileThumbnail PrepareFileThumbnail(QImage &&original) { return result; } -PreparedFileThumbnail PrepareAnimatedStickerThumbnail( - const QString &file, - const QByteArray &bytes) { - return PrepareFileThumbnail( - Lottie::ReadThumbnail(Lottie::ReadContent(bytes, file))); -} - bool FileThumbnailUploadRequired(const QString &filemime, int32 filesize) { constexpr auto kThumbnailUploadBySize = 5 * 1024 * 1024; const auto kThumbnailKnownMimes = { @@ -818,6 +812,15 @@ void FileLoadTask::process() { } thumbnail = PrepareFileThumbnail(std::move(video->thumbnail)); + } else if (filemime == qstr("application/x-tdesktop-theme") + || filemime == qstr("application/x-tgtheme-tdesktop")) { + goodThumbnail = Window::Theme::GeneratePreview(_content, _filepath); + if (!goodThumbnail.isNull()) { + QBuffer buffer(&goodThumbnailBytes); + goodThumbnail.save(&buffer, "JPG", kThumbnailQuality); + + thumbnail = PrepareFileThumbnail(base::duplicate(goodThumbnail)); + } } } diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp index ed14ff72d..c9c952322 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp @@ -465,15 +465,26 @@ SendMediaReady PrepareThemeMedia( PreparedPhotoThumbs thumbnails; QVector sizes; - //const auto push = [&](const char *type, QImage &&image) { - // sizes.push_back(MTP_photoSize( - // MTP_string(type), - // MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), - // MTP_int(image.width()), - // MTP_int(image.height()), MTP_int(0))); - // thumbnails.emplace(type[0], std::move(image)); - //}; - //push("s", scaled(320)); + auto thumbnail = GeneratePreview(content, QString()).scaled( + 320, + 320, + Qt::KeepAspectRatio, + Qt::SmoothTransformation); + auto thumbnailBytes = QByteArray(); + { + QBuffer buffer(&thumbnailBytes); + thumbnail.save(&buffer, "JPG", 87); + } + + const auto push = [&](const char *type, QImage &&image) { + sizes.push_back(MTP_photoSize( + MTP_string(type), + MTP_fileLocationToBeDeprecated(MTP_long(0), MTP_int(0)), + MTP_int(image.width()), + MTP_int(image.height()), MTP_int(0))); + thumbnails.emplace(type[0], std::move(image)); + }; + push("s", std::move(thumbnail)); const auto filename = File::NameFromUserString(name) + qsl(".tdesktop-theme"); @@ -506,7 +517,7 @@ SendMediaReady PrepareThemeMedia( MTP_photoEmpty(MTP_long(0)), thumbnails, document, - QByteArray(), + thumbnailBytes, 0); } @@ -520,7 +531,7 @@ Fn SavePreparedTheme( Fn fail) { Expects(window->account().sessionExists()); - using Storage::UploadedDocument; + using Storage::UploadedThumbDocument; struct State { FullMsgId id; bool generating = false; @@ -539,6 +550,7 @@ Fn SavePreparedTheme( const auto creating = !fields.id || (fields.createdBy != session->userId()); + const auto oldDocumentId = creating ? 0 : fields.documentId; const auto changed = (parsed.background != originalParsed.background) || (parsed.tiled != originalParsed.tiled) || PaletteChanged(parsed.palette, originalParsed.palette, fields); @@ -602,11 +614,11 @@ Fn SavePreparedTheme( }).send(); }; - const auto uploadTheme = [=](const UploadedDocument &data) { + const auto uploadTheme = [=](const UploadedThumbDocument &data) { state->requestId = api->request(MTPaccount_UploadTheme( - MTP_flags(0), + MTP_flags(MTPaccount_UploadTheme::Flag::f_thumb), data.file, - MTPInputFile(), // thumb + data.thumb, MTP_string(state->filename), MTP_string("application/x-tgtheme-tdesktop") )).done([=](const MTPDocument &result) { @@ -625,10 +637,10 @@ Fn SavePreparedTheme( state->filename = media.filename; state->themeContent = theme; - session->uploader().documentReady( - ) | rpl::filter([=](const UploadedDocument &data) { + session->uploader().thumbDocumentReady( + ) | rpl::filter([=](const UploadedThumbDocument &data) { return data.fullId == state->id; - }) | rpl::start_with_next([=](const UploadedDocument &data) { + }) | rpl::start_with_next([=](const UploadedThumbDocument &data) { uploadTheme(data); }, state->lifetime); diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp index 56eb4979d..c72fa7049 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp @@ -83,9 +83,12 @@ QString fillLetters(const QString &name) { class Generator { public: - Generator(const Instance &theme, CurrentData &¤t); + Generator( + const Instance &theme, + CurrentData &¤t, + PreviewType type); - QImage generate(); + [[nodiscard]] QImage generate(); private: enum class Status { @@ -131,6 +134,7 @@ private: Ui::Text::String replyText = { st::msgMinWidth }; }; + [[nodiscard]] bool extended() const; void prepare(); void addRow(QString name, int peerIndex, QString date, QString text); @@ -162,7 +166,8 @@ private: const Instance &_theme; const style::palette &_palette; - CurrentData _current; + const CurrentData _current; + const PreviewType _type; Painter *_p = nullptr; QRect _rect; @@ -188,10 +193,19 @@ private: }; +bool Generator::extended() const { + return (_type == PreviewType::Extended); +} + void Generator::prepare() { - _rect = QRect(0, 0, st::themePreviewMargin.left() + st::themePreviewSize.width() + st::themePreviewMargin.right(), st::themePreviewMargin.top() + st::themePreviewSize.height() + st::themePreviewMargin.bottom()); - _inner = _rect.marginsRemoved(st::themePreviewMargin); - _body = _inner.marginsRemoved(QMargins(0, Platform::PreviewTitleHeight(), 0, 0)); + const auto size = extended() + ? QRect( + QPoint(), + st::themePreviewSize).marginsAdded(st::themePreviewMargin).size() + : st::themePreviewSize; + _rect = QRect(QPoint(), size); + _inner = extended() ? _rect.marginsRemoved(st::themePreviewMargin) : _rect; + _body = extended() ? _inner.marginsRemoved(QMargins(0, Platform::PreviewTitleHeight(), 0, 0)) : _inner; _dialogs = QRect(_body.x(), _body.y(), st::themePreviewDialogsWidth, _body.height()); _dialogsList = _dialogs.marginsRemoved(QMargins(0, st::dialogsFilterPadding.y() + st::dialogsMenuToggle.height + st::dialogsFilterPadding.y(), 0, st::dialogsPadding.y())); _topBar = QRect(_dialogs.x() + _dialogs.width(), _dialogs.y(), _body.width() - _dialogs.width(), st::topBarHeight); @@ -339,10 +353,14 @@ void Generator::generateData() { _bubbles.back().replyText.setText(st::messageTextStyle, "Mark Twain said that " + QString() + QChar(9757) + QChar(55356) + QChar(57339), Ui::DialogTextOptions()); } -Generator::Generator(const Instance &theme, CurrentData &¤t) +Generator::Generator( + const Instance &theme, + CurrentData &¤t, + PreviewType type) : _theme(theme) , _palette(_theme.palette) -, _current(std::move(current)) { +, _current(std::move(current)) +, _type(type) { } QImage Generator::generate() { @@ -368,7 +386,9 @@ QImage Generator::generate() { paintDialogs(); paintHistoryShadows(); } - Platform::PreviewWindowFramePaint(result, _palette, _body, _rect.width()); + if (extended()) { + Platform::PreviewWindowFramePaint(result, _palette, _body, _rect.width()); + } return result; } @@ -944,18 +964,32 @@ std::unique_ptr GeneratePreview( const QByteArray &bytes, const QString &filepath, const Data::CloudTheme &cloud, - CurrentData &&data) { + CurrentData &&data, + PreviewType type) { auto result = PreviewFromFile(bytes, filepath, cloud); if (!result) { return nullptr; } result->preview = Generator( result->instance, - std::move(data) + std::move(data), + type ).generate(); return result; } +QImage GeneratePreview( + const QByteArray &bytes, + const QString &filepath) { + const auto preview = GeneratePreview( + bytes, + filepath, + Data::CloudTheme(), + CurrentData{ Data::ThemeWallPaper().id() }, + PreviewType::Normal); + return preview ? preview->preview : QImage(); +} + int DefaultPreviewTitleHeight() { return st::titleHeight; } diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.h b/Telegram/SourceFiles/window/themes/window_theme_preview.h index 0ab28e503..008763286 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_preview.h +++ b/Telegram/SourceFiles/window/themes/window_theme_preview.h @@ -17,11 +17,16 @@ namespace Window { namespace Theme { struct CurrentData { - int32 backgroundId = 0; + WallPaperId backgroundId = 0; QImage backgroundImage; bool backgroundTiled = false; }; +enum class PreviewType { + Normal, + Extended, +}; + [[nodiscard]] QString CachedThemePath(uint64 documentId); std::unique_ptr PreviewFromFile( @@ -32,7 +37,11 @@ std::unique_ptr GeneratePreview( const QByteArray &bytes, const QString &filepath, const Data::CloudTheme &cloud, - CurrentData &&data); + CurrentData &&data, + PreviewType type); +QImage GeneratePreview( + const QByteArray &bytes, + const QString &filepath); int DefaultPreviewTitleHeight(); void DefaultPreviewWindowFramePaint( diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 047385623..4be242198 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -316,10 +316,10 @@ <(src_loc)/history/view/media/history_view_poll.cpp <(src_loc)/history/view/media/history_view_sticker.h <(src_loc)/history/view/media/history_view_sticker.cpp +<(src_loc)/history/view/media/history_view_theme_document.h +<(src_loc)/history/view/media/history_view_theme_document.cpp <(src_loc)/history/view/media/history_view_video.h <(src_loc)/history/view/media/history_view_video.cpp -<(src_loc)/history/view/media/history_view_wall_paper.h -<(src_loc)/history/view/media/history_view_wall_paper.cpp <(src_loc)/history/view/media/history_view_web_page.h <(src_loc)/history/view/media/history_view_web_page.cpp <(src_loc)/history/view/history_view_compose_controls.cpp