summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Preston <johnprestonmail@gmail.com>2022-12-28 14:07:38 +0400
committerJohn Preston <johnprestonmail@gmail.com>2022-12-28 14:07:38 +0400
commitb334a1f4fda6cd126d00ef20db4a5e98e20d60bf (patch)
tree8f9ae7b4b66ea9b4902ca05e98533c565ec7638f
parent17f40d6a1fcd8ece9e4773280cc0de2c2e154120 (diff)
Support spoilers in chats list media previews.
-rw-r--r--Telegram/SourceFiles/data/data_media_types.cpp71
-rw-r--r--Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp19
-rw-r--r--Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h2
-rw-r--r--Telegram/SourceFiles/history/view/history_view_item_preview.h4
4 files changed, 72 insertions, 24 deletions
diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp
index 1fe1b35d66..b6b881b22a 100644
--- a/Telegram/SourceFiles/data/data_media_types.cpp
+++ b/Telegram/SourceFiles/data/data_media_types.cpp
@@ -101,7 +101,8 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
[[nodiscard]] QImage PreparePreviewImage(
not_null<const Image*> image,
- ImageRoundRadius radius = ImageRoundRadius::Small) {
+ ImageRoundRadius radius,
+ bool spoiler) {
const auto original = image->original();
if (original.width() * 10 < original.height()
|| original.height() * 10 < original.width()) {
@@ -119,6 +120,11 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
size,
size
).convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ if (spoiler) {
+ square = Images::BlurLargeImage(
+ std::move(square),
+ style::ConvertScale(3) * factor);
+ }
if (radius == ImageRoundRadius::Small) {
struct Cache {
base::flat_map<int, std::array<QImage, 4>> all;
@@ -146,27 +152,33 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
return square;
}
+template <typename MediaType>
+[[nodiscard]] uint64 CountCacheKey(not_null<MediaType*> data, bool spoiler) {
+ return (reinterpret_cast<uint64>(data.get()) & ~1) | (spoiler ? 1 : 0);
+}
+
[[nodiscard]] ItemPreviewImage PreparePhotoPreview(
not_null<const HistoryItem*> item,
const std::shared_ptr<PhotoMedia> &media,
- ImageRoundRadius radius) {
+ ImageRoundRadius radius,
+ bool spoiler) {
const auto photo = media->owner();
- const auto readyCacheKey = reinterpret_cast<uint64>(photo.get());
+ const auto counted = CountCacheKey(photo, spoiler);
if (const auto small = media->image(PhotoSize::Small)) {
- return { PreparePreviewImage(small, radius), readyCacheKey };
+ return { PreparePreviewImage(small, radius, spoiler), counted };
} else if (const auto thumbnail = media->image(PhotoSize::Thumbnail)) {
- return { PreparePreviewImage(thumbnail, radius), readyCacheKey };
+ return { PreparePreviewImage(thumbnail, radius, spoiler), counted };
} else if (const auto large = media->image(PhotoSize::Large)) {
- return { PreparePreviewImage(large, radius), readyCacheKey };
+ return { PreparePreviewImage(large, radius, spoiler), counted };
}
const auto allowedToDownload = media->autoLoadThumbnailAllowed(
item->history()->peer);
- const auto cacheKey = allowedToDownload ? 0 : readyCacheKey;
+ const auto cacheKey = allowedToDownload ? 0 : counted;
if (allowedToDownload) {
media->owner()->load(PhotoSize::Small, item->fullId());
}
if (const auto blurred = media->thumbnailInline()) {
- return { PreparePreviewImage(blurred, radius), cacheKey };
+ return { PreparePreviewImage(blurred, radius, spoiler), cacheKey };
}
return { QImage(), allowedToDownload ? 0 : cacheKey };
}
@@ -174,17 +186,21 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
[[nodiscard]] ItemPreviewImage PrepareFilePreviewImage(
not_null<const HistoryItem*> item,
const std::shared_ptr<DocumentMedia> &media,
- ImageRoundRadius radius) {
+ ImageRoundRadius radius,
+ bool spoiler) {
Expects(media->owner()->hasThumbnail());
const auto document = media->owner();
- const auto readyCacheKey = reinterpret_cast<uint64>(document.get());
+ const auto readyCacheKey = CountCacheKey(document, spoiler);
if (const auto thumbnail = media->thumbnail()) {
- return { PreparePreviewImage(thumbnail, radius), readyCacheKey };
+ return {
+ PreparePreviewImage(thumbnail, radius, spoiler),
+ readyCacheKey,
+ };
}
document->loadThumbnail(item->fullId());
if (const auto blurred = media->thumbnailInline()) {
- return { PreparePreviewImage(blurred, radius), 0 };
+ return { PreparePreviewImage(blurred, radius, spoiler), 0 };
}
return { QImage(), 0 };
}
@@ -204,8 +220,9 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
[[nodiscard]] ItemPreviewImage PrepareFilePreview(
not_null<const HistoryItem*> item,
const std::shared_ptr<DocumentMedia> &media,
- ImageRoundRadius radius) {
- auto result = PrepareFilePreviewImage(item, media, radius);
+ ImageRoundRadius radius,
+ bool spoiler) {
+ auto result = PrepareFilePreviewImage(item, media, radius, spoiler);
const auto document = media->owner();
if (!result.data.isNull()
&& (document->isVideoFile() || document->isVideoMessage())) {
@@ -223,13 +240,14 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
template <typename MediaType>
[[nodiscard]] ItemPreviewImage FindCachedPreview(
const std::vector<ItemPreviewImage> *existing,
- not_null<MediaType*> data) {
+ not_null<MediaType*> data,
+ bool spoiler) {
if (!existing) {
return {};
}
const auto i = ranges::find(
*existing,
- reinterpret_cast<uint64>(data.get()),
+ CountCacheKey(data, spoiler),
&ItemPreviewImage::cacheKey);
return (i != end(*existing)) ? *i : ItemPreviewImage();
}
@@ -619,14 +637,18 @@ ItemPreview MediaPhoto::toPreview(ToPreviewOptions options) const {
}
auto images = std::vector<ItemPreviewImage>();
auto context = std::any();
- if (auto cached = FindCachedPreview(options.existing, _photo)) {
- images.push_back(std::move(cached));
+ if (auto found = FindCachedPreview(options.existing, _photo, _spoiler)) {
+ images.push_back(std::move(found));
} else {
const auto media = _photo->createMediaView();
const auto radius = _chat
? ImageRoundRadius::Ellipse
: ImageRoundRadius::Small;
- if (auto prepared = PreparePhotoPreview(parent(), media, radius)
+ if (auto prepared = PreparePhotoPreview(
+ parent(),
+ media,
+ radius,
+ _spoiler)
; prepared || !prepared.cacheKey) {
images.push_back(std::move(prepared));
if (!prepared.cacheKey) {
@@ -848,14 +870,19 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
}
auto images = std::vector<ItemPreviewImage>();
auto context = std::any();
- if (auto cached = FindCachedPreview(options.existing, _document)) {
- images.push_back(std::move(cached));
+ const auto existing = options.existing;
+ if (auto found = FindCachedPreview(existing, _document, _spoiler)) {
+ images.push_back(std::move(found));
} else if (TryFilePreview(_document)) {
const auto media = _document->createMediaView();
const auto radius = _document->isVideoMessage()
? ImageRoundRadius::Ellipse
: ImageRoundRadius::Small;
- if (auto prepared = PrepareFilePreview(parent(), media, radius)
+ if (auto prepared = PrepareFilePreview(
+ parent(),
+ media,
+ radius,
+ _spoiler)
; prepared || !prepared.cacheKey) {
images.push_back(std::move(prepared));
if (!prepared.cacheKey) {
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp
index 7159aa2d81..986ec35817 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.cpp
@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "dialogs/ui/dialogs_layout.h"
#include "dialogs/ui/dialogs_topics_view.h"
+#include "ui/effects/spoiler_mess.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/image/image.h"
@@ -185,6 +186,11 @@ void MessageView::prepare(
context);
_textCachedFor = item;
_imagesCache = std::move(preview.images);
+ if (!ranges::any_of(_imagesCache, &ItemPreviewImage::hasSpoiler)) {
+ _spoiler = nullptr;
+ } else if (!_spoiler) {
+ _spoiler = std::make_unique<SpoilerAnimation>(customEmojiRepaint);
+ }
if (preview.loadingContext.has_value()) {
if (!_loadingContext) {
_loadingContext = std::make_unique<LoadingContext>();
@@ -302,10 +308,19 @@ void MessageView::paint(
if (rect.width() < st::dialogsMiniPreview) {
break;
}
- p.drawImage(
+ const auto mini = QRect(
rect.x(),
rect.y() + st::dialogsMiniPreviewTop,
- image.data);
+ st::dialogsMiniPreview,
+ st::dialogsMiniPreview);
+ if (!image.data.isNull()) {
+ p.drawImage(mini, image.data);
+ if (image.hasSpoiler()) {
+ const auto frame = DefaultImageSpoiler().frame(
+ _spoiler->index(context.now, context.paused));
+ FillSpoilerRect(p, mini, frame);
+ }
+ }
rect.setLeft(rect.x()
+ st::dialogsMiniPreview
+ st::dialogsMiniPreviewSkip);
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h
index 7718f3c641..4ef089131c 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_message_view.h
@@ -18,6 +18,7 @@ struct DialogRow;
} // namespace style
namespace Ui {
+class SpoilerAnimation;
} // namespace Ui
namespace Data {
@@ -88,6 +89,7 @@ private:
mutable std::unique_ptr<TopicsView> _topics;
mutable Text::String _textCache;
mutable std::vector<ItemPreviewImage> _imagesCache;
+ mutable std::unique_ptr<SpoilerAnimation> _spoiler;
mutable std::unique_ptr<LoadingContext> _loadingContext;
};
diff --git a/Telegram/SourceFiles/history/view/history_view_item_preview.h b/Telegram/SourceFiles/history/view/history_view_item_preview.h
index 6bf76ecf97..a2229cddf4 100644
--- a/Telegram/SourceFiles/history/view/history_view_item_preview.h
+++ b/Telegram/SourceFiles/history/view/history_view_item_preview.h
@@ -13,6 +13,10 @@ struct ItemPreviewImage {
QImage data;
uint64 cacheKey = 0;
+ [[nodiscard]] bool hasSpoiler() const {
+ return (cacheKey & 1);
+ }
+
explicit operator bool() const {
return !data.isNull();
}