diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp index 24b73c01f4..7f68f803d2 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_bar.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_poll.h" #include "data/data_web_page.h" #include "history/view/history_view_pinned_tracker.h" +#include "history/view/history_view_reply.h" #include "history/history_item.h" #include "history/history_item_components.h" #include "history/history.h" @@ -22,6 +23,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/ui_integration.h" #include "base/weak_ptr.h" #include "apiwrap.h" +#include "ui/dynamic_image.h" +#include "ui/effects/spoiler_mess.h" +#include "ui/power_saving.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" #include "ui/basic_click_handlers.h" @@ -42,31 +46,79 @@ namespace { }; } +class PreviewImage final : public Ui::DynamicImage { +public: + PreviewImage(QImage source, bool spoiler); + + std::shared_ptr clone() override; + QImage image(int size) override; + void subscribeToUpdates(Fn callback) override; + +private: + QImage _source; + QPixmap _pixmap; + QImage _frame; + QImage _spoilerCache; + std::unique_ptr _spoiler; + bool _spoilered = false; + +}; + +PreviewImage::PreviewImage(QImage source, bool spoiler) +: _source(std::move(source)) +, _pixmap(QPixmap::fromImage(_source, Qt::ColorOnly)) +, _spoilered(spoiler) { +} + +std::shared_ptr PreviewImage::clone() { + return std::make_shared(_source, _spoilered); +} + +void PreviewImage::subscribeToUpdates(Fn callback) { + if (!callback || !_spoilered) { + _spoiler = nullptr; + } else { + _spoiler = std::make_unique( + std::move(callback)); + } +} + +QImage PreviewImage::image(int size) { + const auto ratio = style::DevicePixelRatio(); + const auto full = QSize(size, size) * ratio; + const auto to = QRect(0, 0, size, size); + if (_frame.size() != full) { + _frame = QImage(full, QImage::Format_ARGB32_Premultiplied); + _frame.setDevicePixelRatio(ratio); + } + _frame.fill(Qt::transparent); + auto p = QPainter(&_frame); + p.drawPixmap(to, _pixmap); + if (_spoiler) { + FillPreviewSpoiler( + p, + to, + _pixmap, + Ui::DefaultImageSpoiler().frame(_spoiler->index( + crl::now(), + On(PowerSaving::kChatSpoiler))), + _spoilerCache); + } + p.end(); + return _frame; +} + [[nodiscard]] Ui::MessageBarContent ContentWithPreview( not_null item, Image *preview, bool spoiler, Fn repaint) { auto result = ContentWithoutPreview(item, repaint); - if (!preview) { - static const auto kEmpty = [&] { - const auto size = st::historyReplyHeight - * style::DevicePixelRatio(); - auto result = QImage( - QSize(size, size), - QImage::Format_ARGB32_Premultiplied); - result.fill(Qt::transparent); - result.setDevicePixelRatio(style::DevicePixelRatio()); - return result; - }(); - result.preview = kEmpty; - result.spoilerRepaint = nullptr; - } else { - result.preview = Images::Round( - preview->original(), - ImageRoundRadius::Small); - result.spoilerRepaint = spoiler ? repaint : nullptr; - } + result.preview = std::make_shared( + (preview + ? Images::Round(preview->original(), ImageRoundRadius::Small) + : QImage()), + preview && spoiler); return result; } diff --git a/Telegram/SourceFiles/ui/chat/message_bar.cpp b/Telegram/SourceFiles/ui/chat/message_bar.cpp index 0efe8eaa97..75456c2925 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bar.cpp @@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "ui/chat/message_bar.h" -#include "ui/effects/spoiler_mess.h" +#include "ui/dynamic_image.h" #include "ui/image/image_prepare.h" #include "ui/painter.h" #include "ui/power_saving.h" @@ -123,13 +123,13 @@ void MessageBar::tweenTo(MessageBarContent &&content) { updateFromContent(std::move(content)); return; } - const auto hasImageChanged = (_content.preview.isNull() - != content.preview.isNull()); + const auto hasImageChanged = ((_content.preview != nullptr) + != (content.preview != nullptr)); const auto bodyChanged = (_content.index != content.index || _content.count != content.count || _content.title != content.title || _content.text != content.text - || _content.preview.constBits() != content.preview.constBits()); + || _content.preview != content.preview); const auto barCountChanged = (_content.count != content.count); const auto barFrom = _content.index; const auto barTo = content.index; @@ -144,7 +144,6 @@ void MessageBar::tweenTo(MessageBarContent &&content) { ? RectPart::Bottom : RectPart::None; animation.imageFrom = grabImagePart(); - animation.spoilerFrom = std::move(_spoiler); animation.bodyOrTextFrom = grabBodyOrTextPart(animation.bodyAnimation); const auto sameLength = SameFirstPartLength( _content.title, @@ -205,6 +204,9 @@ void MessageBar::tweenTo(MessageBarContent &&content) { } void MessageBar::updateFromContent(MessageBarContent &&content) { + if (_content.preview && _content.preview != content.preview) { + _content.preview->subscribeToUpdates(nullptr); + } _content = std::move(content); _title.setText(_st.title, _content.title); _text.setMarkedText( @@ -212,13 +214,21 @@ void MessageBar::updateFromContent(MessageBarContent &&content) { _content.text, Ui::DialogTextOptions(), _content.context); - _image = prepareImage(_content.preview); - if (!_content.spoilerRepaint) { - _spoiler = nullptr; - } else if (!_spoiler) { - _spoiler = std::make_unique( - _content.spoilerRepaint); + if (_content.preview) { + _content.preview->subscribeToUpdates(crl::guard(&_widget, [=] { + refreshImage(); + _widget.update(); + })); } + refreshImage(); +} + +void MessageBar::refreshImage() { + _image = _content.preview + ? QPixmap::fromImage( + _content.preview->image(st::historyReplyPreview), + Qt::ColorOnly) + : QPixmap(); } QRect MessageBar::imageRect() const { @@ -266,21 +276,10 @@ auto MessageBar::makeGrabGuard() { auto imageShown = _animation ? std::move(_animation->imageShown) : Ui::Animations::Simple(); - auto spoiler = std::move(_spoiler); - auto fromSpoiler = _animation - ? std::move(_animation->spoilerFrom) - : nullptr; - return gsl::finally([ - &, - shown = std::move(imageShown), - spoiler = std::move(spoiler), - fromSpoiler = std::move(fromSpoiler) - ]() mutable { + return gsl::finally([&, shown = std::move(imageShown)]() mutable { if (_animation) { _animation->imageShown = std::move(shown); - _animation->spoilerFrom = std::move(fromSpoiler); } - _spoiler = std::move(spoiler); }); } @@ -336,10 +335,6 @@ void MessageBar::finishAnimating() { } } -QPixmap MessageBar::prepareImage(const QImage &preview) { - return QPixmap::fromImage(preview, Qt::ColorOnly); -} - void MessageBar::paint(Painter &p) { const auto progress = _animation ? _animation->bodyMoved.value(1.) : 1.; const auto imageFinal = _image.isNull() ? 0. : 1.; @@ -385,13 +380,7 @@ void MessageBar::paint(Painter &p) { if (!_animation) { if (!_image.isNull()) { - paintImageWithSpoiler( - p, - image, - _image, - _spoiler.get(), - now, - pausedSpoiler); + p.drawPixmap(image, _image); } } else if (!_animation->imageTo.isNull() || (!_animation->imageFrom.isNull() @@ -409,30 +398,12 @@ void MessageBar::paint(Painter &p) { }(); if (_animation->bodyMoved.animating()) { p.setOpacity(1. - progress); - paintImageWithSpoiler( - p, - rect.translated(0, shiftFrom), - _animation->imageFrom, - _animation->spoilerFrom.get(), - now, - pausedSpoiler); + p.drawPixmap(rect.translated(0, shiftFrom), _animation->imageFrom); p.setOpacity(progress); - paintImageWithSpoiler( - p, - rect.translated(0, shiftTo), - _animation->imageTo, - _spoiler.get(), - now, - pausedSpoiler); + p.drawPixmap(rect.translated(0, shiftTo), _animation->imageTo); p.setOpacity(1.); } else { - paintImageWithSpoiler( - p, - rect, - _image, - _spoiler.get(), - now, - pausedSpoiler); + p.drawPixmap(rect, _image); } } if (!_animation || _animation->bodyAnimation == BodyAnimation::None) { @@ -558,21 +529,6 @@ void MessageBar::ensureGradientsCreated(int size) { _topBarGradient = Images::PixmapFast(std::move(top)); } -void MessageBar::paintImageWithSpoiler( - QPainter &p, - QRect rect, - const QPixmap &image, - SpoilerAnimation *spoiler, - crl::time now, - bool paused) const { - p.drawPixmap(rect, image); - if (spoiler) { - const auto frame = DefaultImageSpoiler().frame( - spoiler->index(now, paused)); - FillSpoilerRect(p, rect, frame); - } -} - void MessageBar::paintLeftBar(Painter &p) { const auto state = countBarState(); const auto gradientSize = int(std::ceil(state.size * 2.5)); diff --git a/Telegram/SourceFiles/ui/chat/message_bar.h b/Telegram/SourceFiles/ui/chat/message_bar.h index 6132ae446b..a04ae2364e 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.h +++ b/Telegram/SourceFiles/ui/chat/message_bar.h @@ -19,7 +19,7 @@ struct MessageBar; namespace Ui { -class SpoilerAnimation; +class DynamicImage; struct MessageBarContent { int index = 0; @@ -27,8 +27,7 @@ struct MessageBarContent { QString title; TextWithEntities text; Text::MarkedContext context; - QImage preview; - Fn spoilerRepaint; + std::shared_ptr preview; style::margins margins; }; @@ -67,7 +66,6 @@ private: QPixmap titleTo; QPixmap imageFrom; QPixmap imageTo; - std::unique_ptr spoilerFrom; BodyAnimation bodyAnimation = BodyAnimation::None; RectPart movingTo = RectPart::None; }; @@ -78,11 +76,11 @@ private: float64 offset = 0.; }; void setup(); + void refreshImage(); void paint(Painter &p); void paintLeftBar(Painter &p); void tweenTo(MessageBarContent &&content); void updateFromContent(MessageBarContent &&content); - [[nodiscard]] QPixmap prepareImage(const QImage &preview); [[nodiscard]] QRect imageRect() const; [[nodiscard]] QRect titleRangeRect(int from, int till) const; @@ -103,14 +101,6 @@ private: [[nodiscard]] BarState countBarState() const; void ensureGradientsCreated(int size); - void paintImageWithSpoiler( - QPainter &p, - QRect rect, - const QPixmap &image, - SpoilerAnimation *spoiler, - crl::time now, - bool paused) const; - [[nodiscard]] static BodyAnimation DetectBodyAnimationType( Animation *currentAnimation, const MessageBarContent ¤tContent, @@ -124,7 +114,6 @@ private: Text::String _title, _text; QPixmap _image, _topBarGradient, _bottomBarGradient; std::unique_ptr _animation; - std::unique_ptr _spoiler; bool _customEmojiRepaintScheduled = false; };