Improve reactions position and colors.

This commit is contained in:
John Preston 2021-12-28 16:46:43 +03:00
parent 38c296b69f
commit 4228557722
17 changed files with 195 additions and 55 deletions

View file

@ -746,7 +746,7 @@ bool HistoryItem::suggestDeleteAllReport() const {
} }
bool HistoryItem::canReact() const { bool HistoryItem::canReact() const {
return isRegular(); return isRegular() && !isService();
} }
void HistoryItem::addReaction(const QString &reaction) { void HistoryItem::addReaction(const QString &reaction) {

View file

@ -359,15 +359,23 @@ QSize Message::performCountOptimalSize() {
} }
minHeight = hasVisibleText() ? item->_text.minHeight() : 0; minHeight = hasVisibleText() ? item->_text.minHeight() : 0;
if (reactionsInBubble) { if (reactionsInBubble) {
accumulate_max(maxWidth, std::min( const auto reactionsMaxWidth = st::msgPadding.left()
st::msgMaxWidth, + _reactions->maxWidth()
(st::msgPadding.left() + st::msgPadding.right();
+ _reactions->maxWidth() accumulate_max(
+ st::msgPadding.right()))); maxWidth,
std::min(st::msgMaxWidth, reactionsMaxWidth));
if (!mediaDisplayed) { if (!mediaDisplayed) {
minHeight += st::mediaInBubbleSkip; minHeight += st::mediaInBubbleSkip;
} }
minHeight += _reactions->minHeight(); if (maxWidth >= reactionsMaxWidth) {
minHeight += _reactions->minHeight();
} else {
const auto widthForReactions = maxWidth
- st::msgPadding.left()
- st::msgPadding.right();
minHeight += _reactions->resizeGetHeight(widthForReactions);
}
} }
if (!mediaOnBottom) { if (!mediaOnBottom) {
minHeight += st::msgPadding.bottom(); minHeight += st::msgPadding.bottom();
@ -457,13 +465,6 @@ QSize Message::performCountOptimalSize() {
maxWidth = st::msgMinWidth; maxWidth = st::msgMinWidth;
minHeight = 0; minHeight = 0;
} }
if (_reactions && !reactionsInBubble) {
// if we have a text bubble we can resize it to fit the keyboard
// but if we have only media we don't do that
if (hasVisibleText()) {
accumulate_max(maxWidth, _reactions->maxWidth());
}
}
if (const auto markup = item->inlineReplyMarkup()) { if (const auto markup = item->inlineReplyMarkup()) {
if (!markup->inlineKeyboard) { if (!markup->inlineKeyboard) {
markup->inlineKeyboard = std::make_unique<ReplyKeyboard>( markup->inlineKeyboard = std::make_unique<ReplyKeyboard>(
@ -601,8 +602,11 @@ void Message::draw(Painter &p, const PaintContext &context) const {
if (_reactions && !reactionsInBubble) { if (_reactions && !reactionsInBubble) {
const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height(); const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height();
const auto reactionsLeft = (!bubble && mediaDisplayed)
? media->contentRectForReactionButton().x()
: 0;
g.setHeight(g.height() - reactionsHeight); g.setHeight(g.height() - reactionsHeight);
const auto reactionsPosition = QPoint(g.left(), g.top() + g.height() + st::mediaInBubbleSkip); const auto reactionsPosition = QPoint(reactionsLeft + g.left(), g.top() + g.height() + st::mediaInBubbleSkip);
p.translate(reactionsPosition); p.translate(reactionsPosition);
_reactions->paint(p, context, g.width(), context.clip.translated(-reactionsPosition)); _reactions->paint(p, context, g.width(), context.clip.translated(-reactionsPosition));
p.translate(-reactionsPosition); p.translate(-reactionsPosition);
@ -1250,7 +1254,9 @@ TextState Message::textState(
return result; return result;
} }
const auto bubble = drawBubble();
const auto reactionsInBubble = _reactions && embedReactionsInBubble(); const auto reactionsInBubble = _reactions && embedReactionsInBubble();
const auto mediaDisplayed = media && media->isDisplayed();
auto keyboard = item->inlineReplyKeyboard(); auto keyboard = item->inlineReplyKeyboard();
auto keyboardHeight = 0; auto keyboardHeight = 0;
if (keyboard) { if (keyboard) {
@ -1260,17 +1266,19 @@ TextState Message::textState(
if (_reactions && !reactionsInBubble) { if (_reactions && !reactionsInBubble) {
const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height(); const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height();
const auto reactionsLeft = (!bubble && mediaDisplayed)
? media->contentRectForReactionButton().x()
: 0;
g.setHeight(g.height() - reactionsHeight); g.setHeight(g.height() - reactionsHeight);
const auto reactionsPosition = QPoint(g.left(), g.top() + g.height() + st::mediaInBubbleSkip); const auto reactionsPosition = QPoint(reactionsLeft + g.left(), g.top() + g.height() + st::mediaInBubbleSkip);
if (_reactions->getState(point - reactionsPosition, &result)) { if (_reactions->getState(point - reactionsPosition, &result)) {
return result; return result;
} }
} }
if (drawBubble()) { if (bubble) {
const auto inBubble = g.contains(point); const auto inBubble = g.contains(point);
auto entry = logEntryOriginal(); auto entry = logEntryOriginal();
auto mediaDisplayed = media && media->isDisplayed();
// Entry page is always a bubble bottom. // Entry page is always a bubble bottom.
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/); auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
@ -1807,17 +1815,39 @@ TextSelection Message::adjustSelection(
Reactions::ButtonParameters Message::reactionButtonParameters( Reactions::ButtonParameters Message::reactionButtonParameters(
QPoint position, QPoint position,
const TextState &reactionState) const { const TextState &reactionState) const {
auto result = Reactions::ButtonParameters{ .context = data()->fullId() }; using namespace Reactions;
const auto outbg = result.outbg = hasOutLayout(); auto result = ButtonParameters{ .context = data()->fullId() };
const auto outbg = hasOutLayout();
result.style = (!_comments && !embedReactionsInBubble())
? ButtonStyle::Service
: outbg
? ButtonStyle::Outgoing
: ButtonStyle::Incoming;
const auto geometry = countGeometry(); const auto geometry = countGeometry();
result.pointer = position; result.pointer = position;
const auto onTheLeft = (outbg && !delegate()->elementIsChatWide()); const auto onTheLeft = (outbg && !delegate()->elementIsChatWide());
const auto leftAdd = onTheLeft ? 0 : geometry.width(); const auto leftAdd = onTheLeft ? 0 : geometry.width();
result.center = geometry.topLeft() + (onTheLeft
? (QPoint(0, geometry.height()) + QPoint( const auto keyboard = data()->inlineReplyKeyboard();
const auto keyboardHeight = keyboard
? (st::msgBotKbButton.margin + keyboard->naturalHeight())
: 0;
const auto reactionsHeight = (_reactions && !embedReactionsInBubble())
? (st::mediaInBubbleSkip + _reactions->height())
: 0;
const auto innerHeight = geometry.height()
- keyboardHeight
- reactionsHeight;
const auto contentRect = (result.style == ButtonStyle::Service
&& !drawBubble())
? media()->contentRectForReactionButton().translated(
geometry.topLeft())
: geometry;
result.center = contentRect.topLeft() + (onTheLeft
? (QPoint(0, innerHeight) + QPoint(
-st::reactionCornerCenter.x(), -st::reactionCornerCenter.x(),
st::reactionCornerCenter.y())) st::reactionCornerCenter.y()))
: (QPoint(geometry.width(), geometry.height()) : (QPoint(contentRect.width(), innerHeight)
+ st::reactionCornerCenter)); + st::reactionCornerCenter));
if (reactionState.itemId != result.context) { if (reactionState.itemId != result.context) {
const auto top = marginTop(); const auto top = marginTop();
@ -2739,7 +2769,11 @@ int Message::resizeContentGetHeight(int newWidth) {
newHeight = 0; newHeight = 0;
} }
if (_reactions && !reactionsInBubble) { if (_reactions && !reactionsInBubble) {
newHeight += st::mediaInBubbleSkip + _reactions->resizeGetHeight(contentWidth); const auto reactionsWidth = (!bubble && mediaDisplayed)
? media->contentRectForReactionButton().width()
: contentWidth;
newHeight += st::mediaInBubbleSkip
+ _reactions->resizeGetHeight(reactionsWidth);
} }
if (const auto keyboard = item->inlineReplyKeyboard()) { if (const auto keyboard = item->inlineReplyKeyboard()) {

View file

@ -25,6 +25,7 @@ constexpr auto kActivateDuration = crl::time(150);
constexpr auto kExpandDuration = crl::time(150); constexpr auto kExpandDuration = crl::time(150);
constexpr auto kInCacheIndex = 0; constexpr auto kInCacheIndex = 0;
constexpr auto kOutCacheIndex = 1; constexpr auto kOutCacheIndex = 1;
constexpr auto kServiceCacheIndex = 2;
constexpr auto kShadowCacheIndex = 0; constexpr auto kShadowCacheIndex = 0;
constexpr auto kEmojiCacheIndex = 1; constexpr auto kEmojiCacheIndex = 1;
constexpr auto kMaskCacheIndex = 2; constexpr auto kMaskCacheIndex = 2;
@ -86,8 +87,8 @@ Button::Button(
Button::~Button() = default; Button::~Button() = default;
bool Button::outbg() const { ButtonStyle Button::style() const {
return _outbg; return _style;
} }
bool Button::isHidden() const { bool Button::isHidden() const {
@ -150,8 +151,8 @@ void Button::applyParameters(
? State::Active ? State::Active
: State::Shown; : State::Shown;
applyState(state, update); applyState(state, update);
if (_outbg != parameters.outbg) { if (_style != parameters.style) {
_outbg = parameters.outbg; _style = parameters.style;
if (update) { if (update) {
update(_geometry); update(_geometry);
} }
@ -264,12 +265,12 @@ Manager::Manager(
QRect({}, _outer).center() - _innerActive.center()); QRect({}, _outer).center() - _innerActive.center());
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
_cacheInOut = QImage( _cacheInOutService = QImage(
_outer.width() * 2 * ratio, _outer.width() * 3 * ratio,
_outer.height() * kFramesCount * ratio, _outer.height() * kFramesCount * ratio,
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
_cacheInOut.setDevicePixelRatio(ratio); _cacheInOutService.setDevicePixelRatio(ratio);
_cacheInOut.fill(Qt::transparent); _cacheInOutService.fill(Qt::transparent);
_cacheParts = QImage( _cacheParts = QImage(
_outer.width() * kCacheColumsCount * ratio, _outer.width() * kCacheColumsCount * ratio,
_outer.height() * kFramesCount * ratio, _outer.height() * kFramesCount * ratio,
@ -529,8 +530,8 @@ void Manager::paintButton(
const auto geometry = button->geometry(); const auto geometry = button->geometry();
const auto position = geometry.topLeft(); const auto position = geometry.topLeft();
const auto size = geometry.size(); const auto size = geometry.size();
const auto outbg = button->outbg(); const auto style = button->style();
const auto patterned = outbg const auto patterned = (style == ButtonStyle::Outgoing)
&& context.bubblesPattern && context.bubblesPattern
&& !context.viewport.isEmpty() && !context.viewport.isEmpty()
&& !context.bubblesPattern->pixmap.size().isEmpty(); && !context.bubblesPattern->pixmap.size().isEmpty();
@ -547,15 +548,19 @@ void Manager::paintButton(
_cacheForPattern, _cacheForPattern,
QRect(QPoint(), geometry.size() * style::DevicePixelRatio())); QRect(QPoint(), geometry.size() * style::DevicePixelRatio()));
} else { } else {
const auto &stm = context.st->messageStyle(outbg, false); const auto background = (style == ButtonStyle::Service)
const auto background = stm.msgBg->c; ? context.st->msgServiceFg()->c
: context.st->messageStyle(
(style == ButtonStyle::Outgoing),
false
).msgBg->c;
const auto source = validateFrame( const auto source = validateFrame(
outbg, style,
frameIndex, frameIndex,
scale, scale,
stm.msgBg->c, background,
shadow); shadow);
paintLongImage(p, geometry, _cacheInOut, source); paintLongImage(p, geometry, _cacheInOutService, source);
} }
const auto mainEmojiPosition = position + (button->expandUp() const auto mainEmojiPosition = position + (button->expandUp()
@ -746,20 +751,32 @@ QRect Manager::validateEmoji(int frameIndex, float64 scale) {
} }
QRect Manager::validateFrame( QRect Manager::validateFrame(
bool outbg, ButtonStyle style,
int frameIndex, int frameIndex,
float64 scale, float64 scale,
const QColor &background, const QColor &background,
const QColor &shadow) { const QColor &shadow) {
applyPatternedShadow(shadow); applyPatternedShadow(shadow);
auto &valid = outbg ? _validOut : _validIn; auto &valid = (style == ButtonStyle::Service)
auto &color = outbg ? _backgroundOut : _backgroundIn; ? _validService
: (style == ButtonStyle::Outgoing)
? _validOut
: _validIn;
auto &color = (style == ButtonStyle::Service)
? _backgroundService
: (style == ButtonStyle::Outgoing)
? _backgroundOut
: _backgroundIn;
if (color != background) { if (color != background) {
color = background; color = background;
ranges::fill(valid, false); ranges::fill(valid, false);
} }
const auto columnIndex = outbg ? kOutCacheIndex : kInCacheIndex; const auto columnIndex = (style == ButtonStyle::Service)
? kServiceCacheIndex
: (style == ButtonStyle::Outgoing)
? kOutCacheIndex
: kInCacheIndex;
const auto result = cacheRect(frameIndex, columnIndex); const auto result = cacheRect(frameIndex, columnIndex);
if (valid[frameIndex]) { if (valid[frameIndex]) {
return result; return result;
@ -767,7 +784,7 @@ QRect Manager::validateFrame(
const auto shadowSource = validateShadow(frameIndex, scale, shadow); const auto shadowSource = validateShadow(frameIndex, scale, shadow);
const auto position = result.topLeft() / style::DevicePixelRatio(); const auto position = result.topLeft() / style::DevicePixelRatio();
auto p = QPainter(&_cacheInOut); auto p = QPainter(&_cacheInOutService);
p.setCompositionMode(QPainter::CompositionMode_Source); p.setCompositionMode(QPainter::CompositionMode_Source);
p.drawImage(position, _cacheParts, shadowSource); p.drawImage(position, _cacheParts, shadowSource);
p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setCompositionMode(QPainter::CompositionMode_SourceOver);

View file

@ -27,7 +27,9 @@ struct TextState;
namespace HistoryView::Reactions { namespace HistoryView::Reactions {
enum class ButtonStyle { enum class ButtonStyle {
Bubble, Incoming,
Outgoing,
Service,
}; };
enum class ExpandDirection { enum class ExpandDirection {
@ -46,11 +48,10 @@ struct ButtonParameters {
FullMsgId context; FullMsgId context;
QPoint center; QPoint center;
QPoint pointer; QPoint pointer;
ButtonStyle style = ButtonStyle::Bubble; ButtonStyle style = ButtonStyle::Incoming;
int reactionsCount = 1; int reactionsCount = 1;
int visibleTop = 0; int visibleTop = 0;
int visibleBottom = 0; int visibleBottom = 0;
bool outbg = false;
}; };
enum class ButtonState { enum class ButtonState {
@ -70,7 +71,7 @@ public:
using State = ButtonState; using State = ButtonState;
void applyState(State state); void applyState(State state);
[[nodiscard]] bool outbg() const; [[nodiscard]] ButtonStyle style() const;
[[nodiscard]] bool expandUp() const; [[nodiscard]] bool expandUp() const;
[[nodiscard]] bool isHidden() const; [[nodiscard]] bool isHidden() const;
[[nodiscard]] QRect geometry() const; [[nodiscard]] QRect geometry() const;
@ -101,7 +102,7 @@ private:
int _finalHeight = 0; int _finalHeight = 0;
int _scroll = 0; int _scroll = 0;
ExpandDirection _expandDirection = ExpandDirection::Up; ExpandDirection _expandDirection = ExpandDirection::Up;
bool _outbg = false; ButtonStyle _style = ButtonStyle::Incoming;
}; };
@ -171,7 +172,7 @@ private:
const QColor &shadow); const QColor &shadow);
QRect validateEmoji(int frameIndex, float64 scale); QRect validateEmoji(int frameIndex, float64 scale);
QRect validateFrame( QRect validateFrame(
bool outbg, ButtonStyle style,
int frameIndex, int frameIndex,
float64 scale, float64 scale,
const QColor &background, const QColor &background,
@ -198,17 +199,19 @@ private:
QSize _outer; QSize _outer;
QRectF _inner; QRectF _inner;
QRect _innerActive; QRect _innerActive;
QImage _cacheInOut; QImage _cacheInOutService;
QImage _cacheParts; QImage _cacheParts;
QImage _cacheForPattern; QImage _cacheForPattern;
QImage _shadowBuffer; QImage _shadowBuffer;
std::array<bool, kFramesCount> _validIn = { { false } }; std::array<bool, kFramesCount> _validIn = { { false } };
std::array<bool, kFramesCount> _validOut = { { false } }; std::array<bool, kFramesCount> _validOut = { { false } };
std::array<bool, kFramesCount> _validService = { { false } };
std::array<bool, kFramesCount> _validShadow = { { false } }; std::array<bool, kFramesCount> _validShadow = { { false } };
std::array<bool, kFramesCount> _validEmoji = { { false } }; std::array<bool, kFramesCount> _validEmoji = { { false } };
std::array<bool, kFramesCount> _validMask = { { false } }; std::array<bool, kFramesCount> _validMask = { { false } };
QColor _backgroundIn; QColor _backgroundIn;
QColor _backgroundOut; QColor _backgroundOut;
QColor _backgroundService;
QColor _shadow; QColor _shadow;
std::shared_ptr<Data::DocumentMedia> _mainReactionMedia; std::shared_ptr<Data::DocumentMedia> _mainReactionMedia;

View file

@ -22,6 +22,11 @@ namespace {
constexpr auto kInNonChosenOpacity = 0.12; constexpr auto kInNonChosenOpacity = 0.12;
constexpr auto kOutNonChosenOpacity = 0.18; constexpr auto kOutNonChosenOpacity = 0.18;
[[nodiscard]] QColor AdaptChosenServiceFg(QColor serviceBg) {
serviceBg.setAlpha(std::max(serviceBg.alpha(), 192));
return serviceBg;
}
} // namespace } // namespace
InlineList::InlineList( InlineList::InlineList(
@ -146,6 +151,14 @@ QSize InlineList::countCurrentSize(int newWidth) {
return { newWidth, height + add }; return { newWidth, height + add };
} }
int InlineList::placeAndResizeGetHeight(QRect available) {
const auto result = resizeGetHeight(available.width());
for (auto &button : _buttons) {
button.geometry.translate(available.x(), 0);
}
return result;
}
void InlineList::paint( void InlineList::paint(
Painter &p, Painter &p,
const PaintContext &context, const PaintContext &context,
@ -173,9 +186,7 @@ void InlineList::paint(
} }
p.setBrush(stm->msgFileBg); p.setBrush(stm->msgFileBg);
} else { } else {
p.setBrush(chosen p.setBrush(chosen ? st->msgServiceFg() : st->msgServiceBg());
? st->msgServiceBgSelected()
: st->msgServiceBg());
} }
const auto radius = geometry.height() / 2.; const auto radius = geometry.height() / 2.;
p.drawRoundedRect(geometry, radius, radius); p.drawRoundedRect(geometry, radius, radius);
@ -192,7 +203,9 @@ void InlineList::paint(
p.drawImage(inner.topLeft(), button.image); p.drawImage(inner.topLeft(), button.image);
} }
p.setPen(!inbubble p.setPen(!inbubble
? st->msgServiceFg() ? (chosen
? QPen(AdaptChosenServiceFg(st->msgServiceBg()->c))
: st->msgServiceFg())
: !chosen : !chosen
? stm->msgServiceFg ? stm->msgServiceFg
: context.outbg : context.outbg

View file

@ -48,6 +48,7 @@ public:
void update(Data &&data, int availableWidth); void update(Data &&data, int availableWidth);
QSize countCurrentSize(int newWidth) override; QSize countCurrentSize(int newWidth) override;
[[nodiscard]] int placeAndResizeGetHeight(QRect available);
void updateSkipBlock(int width, int height); void updateSkipBlock(int width, int height);
void removeSkipBlock(); void removeSkipBlock();

View file

@ -1170,6 +1170,27 @@ bool Gif::needsBubble() const {
return false; return false;
} }
QRect Gif::contentRectForReactionButton() const {
if (isSeparateRoundVideo()) {
return QRect(0, 0, width(), height());
}
auto paintx = 0, painty = 0, paintw = width(), painth = height();
auto usex = 0, usew = paintw;
const auto outbg = _parent->hasOutLayout();
const auto item = _parent->data();
const auto via = item->Get<HistoryMessageVia>();
const auto reply = _parent->displayedReply();
const auto forwarded = item->Get<HistoryMessageForwarded>();
if (via || reply || forwarded) {
usew = maxWidth() - additionalWidth(via, reply, forwarded);
if (outbg) {
usex = width() - usew;
}
}
if (rtl()) usex = width() - usex - usew;
return style::rtlrect(usex + paintx, painty, usew, painth, width());
}
int Gif::additionalWidth() const { int Gif::additionalWidth() const {
const auto item = _parent->data(); const auto item = _parent->data();
return additionalWidth( return additionalWidth(

View file

@ -96,6 +96,7 @@ public:
bool customInfoLayout() const override { bool customInfoLayout() const override {
return _caption.isEmpty(); return _caption.isEmpty();
} }
QRect contentRectForReactionButton() const override;
QString additionalInfoString() const override; QString additionalInfoString() const override;
bool skipBubbleTail() const override { bool skipBubbleTail() const override {

View file

@ -345,6 +345,10 @@ bool Location::needsBubble() const {
|| _parent->displayFromName(); || _parent->displayFromName();
} }
QRect Location::contentRectForReactionButton() const {
return QRect(0, 0, width(), height());
}
int Location::fullWidth() const { int Location::fullWidth() const {
return st::locationSize.width(); return st::locationSize.width();
} }

View file

@ -53,6 +53,7 @@ public:
bool customInfoLayout() const override { bool customInfoLayout() const override {
return true; return true;
} }
QRect contentRectForReactionButton() const override;
bool skipBubbleTail() const override { bool skipBubbleTail() const override {
return isRoundedInBubbleBottom(); return isRoundedInBubbleBottom();

View file

@ -205,6 +205,9 @@ public:
} }
[[nodiscard]] virtual bool needsBubble() const = 0; [[nodiscard]] virtual bool needsBubble() const = 0;
[[nodiscard]] virtual bool customInfoLayout() const = 0; [[nodiscard]] virtual bool customInfoLayout() const = 0;
[[nodiscard]] virtual QRect contentRectForReactionButton() const {
Unexpected("Media::contentRectForReactionButton");
}
[[nodiscard]] virtual QMargins bubbleMargins() const { [[nodiscard]] virtual QMargins bubbleMargins() const {
return QMargins(); return QMargins();
} }

View file

@ -730,6 +730,10 @@ bool GroupedMedia::needsBubble() const {
return _needBubble; return _needBubble;
} }
QRect GroupedMedia::contentRectForReactionButton() const {
return QRect(0, 0, width(), height());
}
bool GroupedMedia::computeNeedBubble() const { bool GroupedMedia::computeNeedBubble() const {
if (!_caption.isEmpty() || _mode == Mode::Column) { if (!_caption.isEmpty() || _mode == Mode::Column) {
return true; return true;

View file

@ -84,6 +84,7 @@ public:
bool customInfoLayout() const override { bool customInfoLayout() const override {
return _caption.isEmpty() && (_mode != Mode::Column); return _caption.isEmpty() && (_mode != Mode::Column);
} }
QRect contentRectForReactionButton() const override;
bool allowsFastShare() const override { bool allowsFastShare() const override {
return true; return true;
} }

View file

@ -401,6 +401,37 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
return result; return result;
} }
QRect UnwrappedMedia::contentRectForReactionButton() const {
const auto inWebPage = (_parent->media() != this);
if (inWebPage) {
return QRect(0, 0, width(), height());
}
const auto rightAligned = _parent->hasOutLayout()
&& !_parent->delegate()->elementIsChatWide();
const auto item = _parent->data();
const auto via = item->Get<HistoryMessageVia>();
const auto reply = _parent->displayedReply();
const auto forwarded = getDisplayedForwardedInfo();
auto usex = 0;
auto usew = maxWidth();
if (!inWebPage) {
usew -= additionalWidth(via, reply, forwarded);
if (rightAligned) {
usex = width() - usew;
}
}
if (rtl()) {
usex = width() - usex - usew;
}
const auto usey = rightAligned ? 0 : (height() - _contentSize.height());
const auto useh = rightAligned
? std::max(
_contentSize.height(),
height() - st::msgDateImgPadding.y() * 2 - st::msgDateFont->height)
: _contentSize.height();
return QRect(usex, usey, usew, useh);
}
std::unique_ptr<Lottie::SinglePlayer> UnwrappedMedia::stickerTakeLottie( std::unique_ptr<Lottie::SinglePlayer> UnwrappedMedia::stickerTakeLottie(
not_null<DocumentData*> data, not_null<DocumentData*> data,
const Lottie::ColorReplacements *replacements) { const Lottie::ColorReplacements *replacements) {

View file

@ -81,6 +81,7 @@ public:
bool customInfoLayout() const override { bool customInfoLayout() const override {
return true; return true;
} }
QRect contentRectForReactionButton() const override;
void stickerClearLoopPlayed() override { void stickerClearLoopPlayed() override {
_content->stickerClearLoopPlayed(); _content->stickerClearLoopPlayed();
} }

View file

@ -831,6 +831,10 @@ bool Photo::needsBubble() const {
|| _parent->displayFromName()); || _parent->displayFromName());
} }
QRect Photo::contentRectForReactionButton() const {
return QRect(0, 0, width(), height());
}
bool Photo::isReadyForOpen() const { bool Photo::isReadyForOpen() const {
ensureDataMediaCreated(); ensureDataMediaCreated();
return _dataMedia->loaded(); return _dataMedia->loaded();

View file

@ -82,6 +82,7 @@ public:
bool customInfoLayout() const override { bool customInfoLayout() const override {
return _caption.isEmpty(); return _caption.isEmpty();
} }
QRect contentRectForReactionButton() const override;
bool skipBubbleTail() const override { bool skipBubbleTail() const override {
return isRoundedInBubbleBottom() && _caption.isEmpty(); return isRoundedInBubbleBottom() && _caption.isEmpty();
} }