Replaced preview image of message bar with dynamic image.

This commit is contained in:
23rd
2026-08-31 19:52:32 +03:00
parent d52a4a3de9
commit c12ae683b2
3 changed files with 100 additions and 103 deletions

View File

@@ -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<Ui::DynamicImage> clone() override;
QImage image(int size) override;
void subscribeToUpdates(Fn<void()> callback) override;
private:
QImage _source;
QPixmap _pixmap;
QImage _frame;
QImage _spoilerCache;
std::unique_ptr<Ui::SpoilerAnimation> _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<Ui::DynamicImage> PreviewImage::clone() {
return std::make_shared<PreviewImage>(_source, _spoilered);
}
void PreviewImage::subscribeToUpdates(Fn<void()> callback) {
if (!callback || !_spoilered) {
_spoiler = nullptr;
} else {
_spoiler = std::make_unique<Ui::SpoilerAnimation>(
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<HistoryItem*> item,
Image *preview,
bool spoiler,
Fn<void()> 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<PreviewImage>(
(preview
? Images::Round(preview->original(), ImageRoundRadius::Small)
: QImage()),
preview && spoiler);
return result;
}

View File

@@ -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<SpoilerAnimation>(
_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));

View File

@@ -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<void()> spoilerRepaint;
std::shared_ptr<DynamicImage> preview;
style::margins margins;
};
@@ -67,7 +66,6 @@ private:
QPixmap titleTo;
QPixmap imageFrom;
QPixmap imageTo;
std::unique_ptr<SpoilerAnimation> 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 &currentContent,
@@ -124,7 +114,6 @@ private:
Text::String _title, _text;
QPixmap _image, _topBarGradient, _bottomBarGradient;
std::unique_ptr<Animation> _animation;
std::unique_ptr<SpoilerAnimation> _spoiler;
bool _customEmojiRepaintScheduled = false;
};