Nice price tag on sending media.

This commit is contained in:
John Preston 2024-06-20 12:41:27 +04:00
parent 6c1e7357c6
commit d47c5df73d
9 changed files with 132 additions and 21 deletions

View file

@ -398,6 +398,18 @@ void SendFilesBox::Block::applyChanges() {
}
}
QImage SendFilesBox::Block::generatePriceTagBackground() const {
const auto preview = _preview.get();
if (_isAlbum) {
const auto album = static_cast<Ui::AlbumPreview*>(preview);
return album->generatePriceTagBackground();
} else if (_isSingleMedia) {
const auto media = static_cast<Ui::SingleMediaPreview*>(preview);
return media->generatePriceTagBackground();
}
return QImage();
}
SendFilesBox::SendFilesBox(
QWidget*,
not_null<Window::SessionController*> controller,
@ -737,18 +749,17 @@ void SendFilesBox::refreshPriceTag() {
}
if (!hasPrice()) {
_priceTag = nullptr;
_priceTagBg = QImage();
} else if (!_priceTag) {
_priceTag = std::make_unique<Ui::RpWidget>(_inner.data());
const auto raw = _priceTag.get();
raw->show();
raw->paintRequest() | rpl::start_with_next([=] {
auto p = QPainter(raw);
auto hq = PainterHighQualityEnabler(p);
p.setBrush(st::toastBg);
p.setPen(Qt::NoPen);
const auto radius = std::min(raw->width(), raw->height()) / 2.;
p.drawRoundedRect(raw->rect(), radius, radius);
if (_priceTagBg.isNull()) {
_priceTagBg = preparePriceTagBg(raw->size());
}
QPainter(raw).drawImage(0, 0, _priceTagBg);
}, raw->lifetime());
const auto session = &_show->session();
@ -785,9 +796,44 @@ void SendFilesBox::refreshPriceTag() {
}, raw->lifetime());
} else {
_priceTag->raise();
_priceTag->update();
_priceTagBg = QImage();
}
}
QImage SendFilesBox::preparePriceTagBg(QSize size) const {
const auto ratio = style::DevicePixelRatio();
const auto outer = _blocks.empty()
? size
: _inner->widgetAt(0)->geometry().size();
auto bg = _blocks.empty()
? QImage()
: _blocks.front().generatePriceTagBackground();
if (bg.isNull()) {
bg = QImage(ratio, ratio, QImage::Format_ARGB32_Premultiplied);
bg.fill(Qt::black);
}
const auto bgSize = bg.size() / bg.devicePixelRatio();
auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(ratio);
result.fill(Qt::black);
auto p = QPainter(&result);
auto hq = PainterHighQualityEnabler(p);
p.drawImage(
QRect(
(size.width() - outer.width()) / 2,
(size.height() - outer.height()) / 2,
outer.width(),
outer.height()),
bg);
p.fillRect(QRect(QPoint(), size), st::msgDateImgBg);
p.end();
const auto radius = std::min(size.width(), size.height()) / 2;
return Images::Round(std::move(result), Images::CornersMask(radius));
}
void SendFilesBox::addMenuButton() {
const auto details = _sendMenuDetails();
if (!hasSendMenu(details)) {

View file

@ -166,6 +166,8 @@ private:
void toggleSpoilers(bool enabled);
void applyChanges();
[[nodiscard]] QImage generatePriceTagBackground() const;
private:
base::unique_qptr<Ui::RpWidget> _preview;
not_null<std::vector<Ui::PreparedFile>*> _items;
@ -196,6 +198,7 @@ private:
[[nodiscard]] bool canChangePrice() const;
[[nodiscard]] bool hasPrice() const;
void refreshPriceTag();
[[nodiscard]] QImage preparePriceTagBg(QSize size) const;
bool validateLength(const QString &text) const;
void refreshButtons();
@ -259,6 +262,7 @@ private:
Fn<void()> _cancelledCallback;
rpl::variable<uint64> _price = 0;
std::unique_ptr<Ui::RpWidget> _priceTag;
QImage _priceTagBg;
bool _confirmed = false;
bool _invertCaption = false;

View file

@ -383,7 +383,7 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
}
} else if (preview) {
drawPriceTag(p, rthumb, context, [&] {
return _spoiler ? _spoiler->background : QImage();
return priceTagBackground();
});
}
if (showEnlarge) {
@ -447,9 +447,10 @@ void Photo::drawPriceTag(
|| _priceTag->darken != darken
|| _priceTag->fg != fg
|| _priceTag->star != star) {
const auto ratio = style::DevicePixelRatio();
auto bg = generateBackground();
if (bg.isNull()) {
bg = QImage(2, 2, QImage::Format_ARGB32_Premultiplied);
bg = QImage(ratio, ratio, QImage::Format_ARGB32_Premultiplied);
bg.fill(Qt::black);
}
@ -474,7 +475,6 @@ void Photo::drawPriceTag(
const auto outer = inner.marginsAdded(st::paidTagPadding);
const auto size = outer.size();
const auto radius = std::min(size.width(), size.height()) / 2;
const auto ratio = style::DevicePixelRatio();
auto cache = QImage(
size * ratio,
QImage::Format_ARGB32_Premultiplied);

View file

@ -84,6 +84,10 @@ rpl::producer<bool> AbstractSingleMediaPreview::spoileredChanges() const {
return _spoileredChanges.events();
}
QImage AbstractSingleMediaPreview::generatePriceTagBackground() const {
return (_previewBlurred.isNull() ? _preview : _previewBlurred).toImage();
}
void AbstractSingleMediaPreview::preparePreview(QImage preview) {
auto maxW = 0;
auto maxH = 0;

View file

@ -44,6 +44,8 @@ public:
[[nodiscard]] bool canHaveSpoiler() const;
[[nodiscard]] rpl::producer<bool> spoileredChanges() const;
[[nodiscard]] QImage generatePriceTagBackground() const;
protected:
virtual bool supportsSpoilers() const = 0;
virtual bool drawBackground() const = 0;

View file

@ -20,6 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QApplication>
namespace Media::Streaming {
[[nodiscard]] QImage PrepareBlurredBackground(QSize outer, QImage frame);
} // namespace Media::Streaming
namespace Ui {
namespace {
@ -610,8 +616,47 @@ void AlbumPreview::switchToDrag() {
update();
}
rpl::producer<int> AlbumPreview::thumbModified() const {
return _thumbModified.events();
QImage AlbumPreview::generatePriceTagBackground() const {
auto wmax = 0;
auto hmax = 0;
for (auto &thumb : _thumbs) {
const auto geometry = thumb->geometry();
accumulate_max(wmax, geometry.x() + geometry.width());
accumulate_max(hmax, geometry.y() + geometry.height());
}
const auto size = QSize(wmax, hmax);
if (size.isEmpty()) {
return {};
}
const auto ratio = style::DevicePixelRatio();
const auto full = size * ratio;
const auto skip = st::historyGroupSkip;
auto result = QImage(full, QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(ratio);
result.fill(Qt::black);
auto p = QPainter(&result);
auto hq = PainterHighQualityEnabler(p);
for (auto &thumb : _thumbs) {
const auto geometry = thumb->geometry();
if (geometry.isEmpty()) {
continue;
}
const auto w = geometry.width();
const auto h = geometry.height();
const auto wscale = (w + skip) / float64(w);
const auto hscale = (h + skip) / float64(h);
p.save();
p.translate(geometry.center());
p.scale(wscale, hscale);
p.translate(-geometry.center());
thumb->paintInAlbum(p, 0, 0, 0., 0.);
p.restore();
}
p.end();
return ::Media::Streaming::PrepareBlurredBackground(
full,
std::move(result));
}
} // namespace Ui

View file

@ -47,7 +47,11 @@ public:
return _thumbChanged.events();
}
rpl::producer<int> thumbModified() const;
[[nodiscard]] rpl::producer<int> thumbModified() const {
return _thumbModified.events();
}
[[nodiscard]] QImage generatePriceTagBackground() const;
protected:
void paintEvent(QPaintEvent *e) override;

View file

@ -503,6 +503,10 @@ void AlbumThumbnail::paintFile(
_fileThumb.size() / style::DevicePixelRatio());
}
QRect AlbumThumbnail::geometry() const {
return _layout.geometry;
}
bool AlbumThumbnail::containsPoint(QPoint position) const {
return _layout.geometry.contains(position);
}

View file

@ -42,8 +42,8 @@ public:
void setSpoiler(bool spoiler);
[[nodiscard]] bool hasSpoiler() const;
int photoHeight() const;
int fileHeight() const;
[[nodiscard]] int photoHeight() const;
[[nodiscard]] int fileHeight() const;
void paintInAlbum(
QPainter &p,
@ -54,20 +54,22 @@ public:
void paintPhoto(Painter &p, int left, int top, int outerWidth);
void paintFile(Painter &p, int left, int top, int outerWidth);
bool containsPoint(QPoint position) const;
bool buttonsContainPoint(QPoint position) const;
AttachButtonType buttonTypeFromPoint(QPoint position) const;
int distanceTo(QPoint position) const;
bool isPointAfter(QPoint position) const;
[[nodiscard]] QRect geometry() const;
[[nodiscard]] bool containsPoint(QPoint position) const;
[[nodiscard]] bool buttonsContainPoint(QPoint position) const;
[[nodiscard]] AttachButtonType buttonTypeFromPoint(
QPoint position) const;
[[nodiscard]] int distanceTo(QPoint position) const;
[[nodiscard]] bool isPointAfter(QPoint position) const;
void moveInAlbum(QPoint to);
QPoint center() const;
[[nodiscard]] QPoint center() const;
void suggestMove(float64 delta, Fn<void()> callback);
void finishAnimations();
void setButtonVisible(bool value);
void moveButtons(int thumbTop);
bool isCompressedSticker() const;
[[nodiscard]] bool isCompressedSticker() const;
static constexpr auto kShrinkDuration = crl::time(150);