mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Track and render reactions as tags in Saved Messages.
This commit is contained in:
parent
0faf801de7
commit
9b43d204e2
9 changed files with 216 additions and 39 deletions
|
@ -20,6 +20,8 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kPerPage = 50;
|
constexpr auto kPerPage = 50;
|
||||||
constexpr auto kFirstPerPage = 10;
|
constexpr auto kFirstPerPage = 10;
|
||||||
|
constexpr auto kListPerPage = 100;
|
||||||
|
constexpr auto kListFirstPerPage = 20;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -82,7 +84,7 @@ void SavedMessages::sendLoadMore() {
|
||||||
MTP_int(_offsetDate),
|
MTP_int(_offsetDate),
|
||||||
MTP_int(_offsetId),
|
MTP_int(_offsetId),
|
||||||
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
_offsetPeer ? _offsetPeer->input : MTP_inputPeerEmpty(),
|
||||||
MTP_int(kPerPage),
|
MTP_int(_offsetId ? kListPerPage : kListFirstPerPage),
|
||||||
MTP_long(0)) // hash
|
MTP_long(0)) // hash
|
||||||
).done([=](const MTPmessages_SavedDialogs &result) {
|
).done([=](const MTPmessages_SavedDialogs &result) {
|
||||||
apply(result, false);
|
apply(result, false);
|
||||||
|
|
|
@ -313,6 +313,8 @@ enum class MessageFlag : uint64 {
|
||||||
ShowSimilarChannels = (1ULL << 41),
|
ShowSimilarChannels = (1ULL << 41),
|
||||||
|
|
||||||
Sponsored = (1ULL << 42),
|
Sponsored = (1ULL << 42),
|
||||||
|
|
||||||
|
ReactionsAreTags = (1ULL << 43),
|
||||||
};
|
};
|
||||||
inline constexpr bool is_flag_type(MessageFlag) { return true; }
|
inline constexpr bool is_flag_type(MessageFlag) { return true; }
|
||||||
using MessageFlags = base::flags<MessageFlag>;
|
using MessageFlags = base::flags<MessageFlag>;
|
||||||
|
|
|
@ -2429,6 +2429,10 @@ const std::vector<Data::MessageReaction> &HistoryItem::reactions() const {
|
||||||
return _reactions ? _reactions->list() : kEmpty;
|
return _reactions ? _reactions->list() : kEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::reactionsAreTags() const {
|
||||||
|
return _flags & MessageFlag::ReactionsAreTags;
|
||||||
|
}
|
||||||
|
|
||||||
auto HistoryItem::recentReactions() const
|
auto HistoryItem::recentReactions() const
|
||||||
-> const base::flat_map<
|
-> const base::flat_map<
|
||||||
Data::ReactionId,
|
Data::ReactionId,
|
||||||
|
@ -3556,31 +3560,40 @@ bool HistoryItem::changeReactions(const MTPMessageReactions *reactions) {
|
||||||
}
|
}
|
||||||
if (!reactions) {
|
if (!reactions) {
|
||||||
_flags &= ~MessageFlag::CanViewReactions;
|
_flags &= ~MessageFlag::CanViewReactions;
|
||||||
|
if (_history->peer->isSelf()) {
|
||||||
|
_flags |= MessageFlag::ReactionsAreTags;
|
||||||
|
}
|
||||||
return (base::take(_reactions) != nullptr);
|
return (base::take(_reactions) != nullptr);
|
||||||
}
|
}
|
||||||
return reactions->match([&](const MTPDmessageReactions &data) {
|
const auto &data = reactions->data();
|
||||||
if (data.is_can_see_list()) {
|
const auto empty = data.vresults().v.isEmpty();
|
||||||
_flags |= MessageFlag::CanViewReactions;
|
if (data.is_reactions_as_tags()
|
||||||
} else {
|
|| (empty && _history->peer->isSelf())) {
|
||||||
_flags &= ~MessageFlag::CanViewReactions;
|
_flags |= MessageFlag::ReactionsAreTags;
|
||||||
|
} else {
|
||||||
|
_flags &= ~MessageFlag::ReactionsAreTags;
|
||||||
|
}
|
||||||
|
if (data.is_can_see_list()) {
|
||||||
|
_flags |= MessageFlag::CanViewReactions;
|
||||||
|
} else {
|
||||||
|
_flags &= ~MessageFlag::CanViewReactions;
|
||||||
|
}
|
||||||
|
if (empty) {
|
||||||
|
return (base::take(_reactions) != nullptr);
|
||||||
|
} else if (!_reactions) {
|
||||||
|
_reactions = std::make_unique<Data::MessageReactions>(this);
|
||||||
|
}
|
||||||
|
const auto min = data.is_min();
|
||||||
|
const auto &list = data.vresults().v;
|
||||||
|
const auto &recent = data.vrecent_reactions().value_or_empty();
|
||||||
|
if (min && hasUnreadReaction()) {
|
||||||
|
// We can't update reactions from min if we have unread.
|
||||||
|
if (_reactions->checkIfChanged(list, recent, min)) {
|
||||||
|
updateReactionsUnknown();
|
||||||
}
|
}
|
||||||
if (data.vresults().v.isEmpty()) {
|
return false;
|
||||||
return (base::take(_reactions) != nullptr);
|
}
|
||||||
} else if (!_reactions) {
|
return _reactions->change(list, recent, min);
|
||||||
_reactions = std::make_unique<Data::MessageReactions>(this);
|
|
||||||
}
|
|
||||||
const auto min = data.is_min();
|
|
||||||
const auto &list = data.vresults().v;
|
|
||||||
const auto &recent = data.vrecent_reactions().value_or_empty();
|
|
||||||
if (min && hasUnreadReaction()) {
|
|
||||||
// We can't update reactions from min if we have unread.
|
|
||||||
if (_reactions->checkIfChanged(list, recent, min)) {
|
|
||||||
updateReactionsUnknown();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _reactions->change(list, recent, min);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryItem::applyTTL(const MTPDmessage &data) {
|
void HistoryItem::applyTTL(const MTPDmessage &data) {
|
||||||
|
|
|
@ -454,6 +454,7 @@ public:
|
||||||
not_null<UserData*> from) const;
|
not_null<UserData*> from) const;
|
||||||
[[nodiscard]] crl::time lastReactionsRefreshTime() const;
|
[[nodiscard]] crl::time lastReactionsRefreshTime() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool reactionsAreTags() const;
|
||||||
[[nodiscard]] bool hasDirectLink() const;
|
[[nodiscard]] bool hasDirectLink() const;
|
||||||
[[nodiscard]] bool changesWallPaper() const;
|
[[nodiscard]] bool changesWallPaper() const;
|
||||||
|
|
||||||
|
|
|
@ -2917,8 +2917,12 @@ bool Message::isSignedAuthorElided() const {
|
||||||
bool Message::embedReactionsInBottomInfo() const {
|
bool Message::embedReactionsInBottomInfo() const {
|
||||||
const auto item = data();
|
const auto item = data();
|
||||||
const auto user = item->history()->peer->asUser();
|
const auto user = item->history()->peer->asUser();
|
||||||
if (!user || user->isPremium() || user->session().premium()) {
|
if (!user
|
||||||
|
|| user->isPremium()
|
||||||
|
|| user->isSelf()
|
||||||
|
|| user->session().premium()) {
|
||||||
// Only in messages of a non premium user with a non premium user.
|
// Only in messages of a non premium user with a non premium user.
|
||||||
|
// In saved messages we use reactions for tags, we don't embed them.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto seenMy = false;
|
auto seenMy = false;
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct InlineList::Button {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int countTextWidth = 0;
|
int countTextWidth = 0;
|
||||||
bool chosen = false;
|
bool chosen = false;
|
||||||
|
bool tag = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
InlineList::InlineList(
|
InlineList::InlineList(
|
||||||
|
@ -118,6 +119,7 @@ void InlineList::layoutButtons() {
|
||||||
) | ranges::views::transform([](const MessageReaction &reaction) {
|
) | ranges::views::transform([](const MessageReaction &reaction) {
|
||||||
return not_null{ &reaction };
|
return not_null{ &reaction };
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
|
const auto tags = _data.flags & Data::Flag::Tags;
|
||||||
const auto &list = _owner->list(::Data::Reactions::Type::All);
|
const auto &list = _owner->list(::Data::Reactions::Type::All);
|
||||||
ranges::sort(sorted, [&](
|
ranges::sort(sorted, [&](
|
||||||
not_null<const MessageReaction*> a,
|
not_null<const MessageReaction*> a,
|
||||||
|
@ -142,8 +144,10 @@ void InlineList::layoutButtons() {
|
||||||
buttons.push_back((i != end(_buttons))
|
buttons.push_back((i != end(_buttons))
|
||||||
? std::move(*i)
|
? std::move(*i)
|
||||||
: prepareButtonWithId(id));
|
: prepareButtonWithId(id));
|
||||||
const auto j = _data.recent.find(id);
|
if (tags) {
|
||||||
if (j != end(_data.recent) && !j->second.empty()) {
|
setButtonTag(buttons.back());
|
||||||
|
} else if (const auto j = _data.recent.find(id)
|
||||||
|
; j != end(_data.recent) && !j->second.empty()) {
|
||||||
setButtonUserpics(buttons.back(), j->second);
|
setButtonUserpics(buttons.back(), j->second);
|
||||||
} else {
|
} else {
|
||||||
setButtonCount(buttons.back(), reaction->count);
|
setButtonCount(buttons.back(), reaction->count);
|
||||||
|
@ -168,12 +172,22 @@ InlineList::Button InlineList::prepareButtonWithId(const ReactionId &id) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InlineList::setButtonTag(Button &button) {
|
||||||
|
if (button.tag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
button.userpics = nullptr;
|
||||||
|
button.count = 0;
|
||||||
|
button.tag = true;
|
||||||
|
}
|
||||||
|
|
||||||
void InlineList::setButtonCount(Button &button, int count) {
|
void InlineList::setButtonCount(Button &button, int count) {
|
||||||
if (button.count == count && !button.userpics) {
|
if (!button.tag && button.count == count && !button.userpics) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
button.userpics = nullptr;
|
button.userpics = nullptr;
|
||||||
button.count = count;
|
button.count = count;
|
||||||
|
button.tag = false;
|
||||||
button.countText = Lang::FormatCountToShort(count).string;
|
button.countText = Lang::FormatCountToShort(count).string;
|
||||||
button.countTextWidth = st::semiboldFont->width(button.countText);
|
button.countTextWidth = st::semiboldFont->width(button.countText);
|
||||||
}
|
}
|
||||||
|
@ -181,6 +195,7 @@ void InlineList::setButtonCount(Button &button, int count) {
|
||||||
void InlineList::setButtonUserpics(
|
void InlineList::setButtonUserpics(
|
||||||
Button &button,
|
Button &button,
|
||||||
const std::vector<not_null<PeerData*>> &peers) {
|
const std::vector<not_null<PeerData*>> &peers) {
|
||||||
|
button.tag = false;
|
||||||
if (!button.userpics) {
|
if (!button.userpics) {
|
||||||
button.userpics = std::make_unique<Userpics>();
|
button.userpics = std::make_unique<Userpics>();
|
||||||
}
|
}
|
||||||
|
@ -228,6 +243,10 @@ QSize InlineList::countOptimalSize() {
|
||||||
const auto between = st::reactionInlineBetween;
|
const auto between = st::reactionInlineBetween;
|
||||||
const auto padding = st::reactionInlinePadding;
|
const auto padding = st::reactionInlinePadding;
|
||||||
const auto size = st::reactionInlineSize;
|
const auto size = st::reactionInlineSize;
|
||||||
|
const auto widthBaseTag = padding.left()
|
||||||
|
+ size
|
||||||
|
+ st::reactionInlineTagSkip
|
||||||
|
+ padding.right();
|
||||||
const auto widthBaseCount = padding.left()
|
const auto widthBaseCount = padding.left()
|
||||||
+ size
|
+ size
|
||||||
+ st::reactionInlineSkip
|
+ st::reactionInlineSkip
|
||||||
|
@ -245,7 +264,9 @@ QSize InlineList::countOptimalSize() {
|
||||||
};
|
};
|
||||||
const auto height = padding.top() + size + padding.bottom();
|
const auto height = padding.top() + size + padding.bottom();
|
||||||
for (auto &button : _buttons) {
|
for (auto &button : _buttons) {
|
||||||
const auto width = button.userpics
|
const auto width = button.tag
|
||||||
|
? widthBaseTag
|
||||||
|
: button.userpics
|
||||||
? (widthBaseUserpics + userpicsWidth(button))
|
? (widthBaseUserpics + userpicsWidth(button))
|
||||||
: (widthBaseCount + button.countTextWidth);
|
: (widthBaseCount + button.countTextWidth);
|
||||||
button.geometry.setSize({ width, height });
|
button.geometry.setSize({ width, height });
|
||||||
|
@ -336,7 +357,8 @@ void InlineList::paint(
|
||||||
const auto padding = st::reactionInlinePadding;
|
const auto padding = st::reactionInlinePadding;
|
||||||
const auto size = st::reactionInlineSize;
|
const auto size = st::reactionInlineSize;
|
||||||
const auto skip = (size - st::reactionInlineImage) / 2;
|
const auto skip = (size - st::reactionInlineImage) / 2;
|
||||||
const auto inbubble = (_data.flags & InlineListData::Flag::InBubble);
|
const auto tags = (_data.flags & Data::Flag::Tags);
|
||||||
|
const auto inbubble = (_data.flags & Data::Flag::InBubble);
|
||||||
const auto flipped = (_data.flags & Data::Flag::Flipped);
|
const auto flipped = (_data.flags & Data::Flag::Flipped);
|
||||||
p.setFont(st::semiboldFont);
|
p.setFont(st::semiboldFont);
|
||||||
for (const auto &button : _buttons) {
|
for (const auto &button : _buttons) {
|
||||||
|
@ -366,21 +388,26 @@ void InlineList::paint(
|
||||||
if (bubbleProgress > 0.) {
|
if (bubbleProgress > 0.) {
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
|
auto opacity = 1.;
|
||||||
|
auto color = QColor();
|
||||||
if (inbubble) {
|
if (inbubble) {
|
||||||
if (!chosen) {
|
if (!chosen) {
|
||||||
p.setOpacity(bubbleProgress * (context.outbg
|
opacity = bubbleProgress * (context.outbg
|
||||||
? kOutNonChosenOpacity
|
? kOutNonChosenOpacity
|
||||||
: kInNonChosenOpacity));
|
: kInNonChosenOpacity);
|
||||||
} else if (!bubbleReady) {
|
} else if (!bubbleReady) {
|
||||||
p.setOpacity(bubbleProgress);
|
opacity = bubbleProgress;
|
||||||
}
|
}
|
||||||
p.setBrush(stm->msgFileBg);
|
color = stm->msgFileBg->c;
|
||||||
} else {
|
} else {
|
||||||
if (!bubbleReady) {
|
if (!bubbleReady) {
|
||||||
p.setOpacity(bubbleProgress);
|
opacity = bubbleProgress;
|
||||||
}
|
}
|
||||||
p.setBrush(chosen ? st->msgServiceFg() : st->msgServiceBg());
|
color = (chosen
|
||||||
|
? st->msgServiceFg()
|
||||||
|
: st->msgServiceBg())->c;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto radius = geometry.height() / 2.;
|
const auto radius = geometry.height() / 2.;
|
||||||
const auto fill = geometry.marginsAdded({
|
const auto fill = geometry.marginsAdded({
|
||||||
flipped ? bubbleSkip : 0,
|
flipped ? bubbleSkip : 0,
|
||||||
|
@ -388,7 +415,7 @@ void InlineList::paint(
|
||||||
flipped ? 0 : bubbleSkip,
|
flipped ? 0 : bubbleSkip,
|
||||||
0,
|
0,
|
||||||
});
|
});
|
||||||
p.drawRoundedRect(fill, radius, radius);
|
paintSingleBg(p, fill, color, opacity);
|
||||||
if (inbubble && !chosen) {
|
if (inbubble && !chosen) {
|
||||||
p.setOpacity(bubbleProgress);
|
p.setOpacity(bubbleProgress);
|
||||||
}
|
}
|
||||||
|
@ -434,7 +461,8 @@ void InlineList::paint(
|
||||||
.target = image,
|
.target = image,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (bubbleProgress == 0.) {
|
if (tags || bubbleProgress == 0.) {
|
||||||
|
p.setOpacity(1.);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
resolveUserpicsImage(button);
|
resolveUserpicsImage(button);
|
||||||
|
@ -479,6 +507,115 @@ void InlineList::paint(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InlineList::validateTagBg(const QColor &color) const {
|
||||||
|
if (!_tagBg.isNull() && _tagBgColor == color) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_tagBgColor = color;
|
||||||
|
|
||||||
|
const auto padding = st::reactionInlinePadding;
|
||||||
|
const auto size = st::reactionInlineSize;
|
||||||
|
const auto width = padding.left()
|
||||||
|
+ size
|
||||||
|
+ st::reactionInlineTagSkip
|
||||||
|
+ padding.right();
|
||||||
|
const auto height = padding.top() + size + padding.bottom();
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
|
||||||
|
auto mask = QImage(
|
||||||
|
QSize(width, height) * ratio,
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
mask.setDevicePixelRatio(ratio);
|
||||||
|
|
||||||
|
mask.fill(Qt::transparent);
|
||||||
|
auto p = QPainter(&mask);
|
||||||
|
|
||||||
|
auto path = QPainterPath();
|
||||||
|
const auto arrow = st::reactionInlineTagArrow;
|
||||||
|
const auto rradius = st::reactionInlineTagRightRadius * 1.;
|
||||||
|
const auto radius = st::reactionInlineTagLeftRadius - rradius;
|
||||||
|
const auto fg = QColor(255, 255, 255);
|
||||||
|
auto pen = QPen(fg);
|
||||||
|
pen.setWidthF(rradius * 2.);
|
||||||
|
pen.setJoinStyle(Qt::RoundJoin);
|
||||||
|
const auto rect = QRectF(0, 0, width, height).marginsRemoved(
|
||||||
|
{ rradius, rradius, rradius, rradius });
|
||||||
|
|
||||||
|
const auto right = rect.x() + rect.width();
|
||||||
|
const auto bottom = rect.y() + rect.height();
|
||||||
|
path.moveTo(rect.x() + radius, rect.y());
|
||||||
|
path.lineTo(right - arrow, rect.y());
|
||||||
|
path.lineTo(right, rect.y() + rect.height() / 2);
|
||||||
|
path.lineTo(right - arrow, bottom);
|
||||||
|
path.lineTo(rect.x() + radius, bottom);
|
||||||
|
path.arcTo(QRectF(rect.x(), bottom - radius * 2, radius * 2, radius * 2), 270, -90);
|
||||||
|
path.lineTo(rect.x(), rect.y() + radius);
|
||||||
|
path.arcTo(QRectF(rect.x(), rect.y(), radius * 2, radius * 2), 180, -90);
|
||||||
|
path.closeSubpath();
|
||||||
|
|
||||||
|
const auto dsize = st::reactionInlineTagDot;
|
||||||
|
const auto dot = QRectF(
|
||||||
|
right - st::reactionInlineTagDotSkip - dsize,
|
||||||
|
rect.y() + (rect.height() - dsize) / 2.,
|
||||||
|
dsize,
|
||||||
|
dsize);
|
||||||
|
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
p.setPen(pen);
|
||||||
|
p.setBrush(fg);
|
||||||
|
p.drawPath(path);
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(QColor(255, 255, 255, 255 * 0.6));
|
||||||
|
p.drawEllipse(dot);
|
||||||
|
|
||||||
|
p.end();
|
||||||
|
|
||||||
|
_tagBg = style::colorizeImage(mask, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InlineList::paintSingleBg(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &fill,
|
||||||
|
const QColor &color,
|
||||||
|
float64 opacity) const {
|
||||||
|
p.setOpacity(opacity);
|
||||||
|
if (!(_data.flags & Data::Flag::Tags)) {
|
||||||
|
const auto radius = fill.height() / 2.;
|
||||||
|
p.setBrush(color);
|
||||||
|
p.drawRoundedRect(fill, radius, radius);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
validateTagBg(color);
|
||||||
|
const auto ratio = style::DevicePixelRatio();
|
||||||
|
const auto left = st::reactionInlineTagLeftRadius;
|
||||||
|
const auto right = (_tagBg.width() / ratio) - left;
|
||||||
|
Assert(right > 0);
|
||||||
|
const auto useLeft = std::min(fill.width(), left);
|
||||||
|
p.drawImage(
|
||||||
|
QRect(fill.x(), fill.y(), useLeft, fill.height()),
|
||||||
|
_tagBg,
|
||||||
|
QRect(0, 0, useLeft * ratio, _tagBg.height()));
|
||||||
|
const auto middle = fill.width() - left - right;
|
||||||
|
if (middle > 0) {
|
||||||
|
p.fillRect(fill.x() + left, fill.y(), middle, fill.height(), color);
|
||||||
|
}
|
||||||
|
if (const auto useRight = fill.width() - left; useRight > 0) {
|
||||||
|
p.drawImage(
|
||||||
|
QRect(
|
||||||
|
fill.x() + fill.width() - useRight,
|
||||||
|
fill.y(),
|
||||||
|
useRight,
|
||||||
|
fill.height()),
|
||||||
|
_tagBg,
|
||||||
|
QRect(_tagBg.width() - useRight * ratio,
|
||||||
|
0,
|
||||||
|
useRight * ratio,
|
||||||
|
_tagBg.height()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool InlineList::getState(
|
bool InlineList::getState(
|
||||||
QPoint point,
|
QPoint point,
|
||||||
not_null<TextState*> outResult) const {
|
not_null<TextState*> outResult) const {
|
||||||
|
@ -654,7 +791,8 @@ InlineListData InlineListDataFromMessage(not_null<Message*> message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.flags = (message->hasOutLayout() ? Flag::OutLayout : Flag())
|
result.flags = (message->hasOutLayout() ? Flag::OutLayout : Flag())
|
||||||
| (message->embedReactionsInBubble() ? Flag::InBubble : Flag());
|
| (message->embedReactionsInBubble() ? Flag::InBubble : Flag())
|
||||||
|
| (item->reactionsAreTags() ? Flag::Tags : Flag());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct InlineListData {
|
||||||
InBubble = 0x01,
|
InBubble = 0x01,
|
||||||
OutLayout = 0x02,
|
OutLayout = 0x02,
|
||||||
Flipped = 0x04,
|
Flipped = 0x04,
|
||||||
|
Tags = 0x08,
|
||||||
};
|
};
|
||||||
friend inline constexpr bool is_flag_type(Flag) { return true; };
|
friend inline constexpr bool is_flag_type(Flag) { return true; };
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
|
@ -103,6 +104,7 @@ private:
|
||||||
void layout();
|
void layout();
|
||||||
void layoutButtons();
|
void layoutButtons();
|
||||||
|
|
||||||
|
void setButtonTag(Button &button);
|
||||||
void setButtonCount(Button &button, int count);
|
void setButtonCount(Button &button, int count);
|
||||||
void setButtonUserpics(
|
void setButtonUserpics(
|
||||||
Button &button,
|
Button &button,
|
||||||
|
@ -115,6 +117,13 @@ private:
|
||||||
QPoint innerTopLeft,
|
QPoint innerTopLeft,
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
const QColor &textColor) const;
|
const QColor &textColor) const;
|
||||||
|
void paintSingleBg(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &fill,
|
||||||
|
const QColor &color,
|
||||||
|
float64 opacity) const;
|
||||||
|
|
||||||
|
void validateTagBg(const QColor &color) const;
|
||||||
|
|
||||||
QSize countOptimalSize() override;
|
QSize countOptimalSize() override;
|
||||||
|
|
||||||
|
@ -124,6 +133,8 @@ private:
|
||||||
Data _data;
|
Data _data;
|
||||||
std::vector<Button> _buttons;
|
std::vector<Button> _buttons;
|
||||||
QSize _skipBlock;
|
QSize _skipBlock;
|
||||||
|
mutable QImage _tagBg;
|
||||||
|
mutable QColor _tagBgColor;
|
||||||
mutable QImage _customCache;
|
mutable QImage _customCache;
|
||||||
mutable int _customSkip = 0;
|
mutable int _customSkip = 0;
|
||||||
bool _hasCustomEmoji = false;
|
bool _hasCustomEmoji = false;
|
||||||
|
|
|
@ -851,6 +851,12 @@ reactionInlinePadding: margins(5px, 2px, 7px, 2px);
|
||||||
reactionInlineSize: 18px;
|
reactionInlineSize: 18px;
|
||||||
reactionInlineImage: 32px;
|
reactionInlineImage: 32px;
|
||||||
reactionInlineSkip: 3px;
|
reactionInlineSkip: 3px;
|
||||||
|
reactionInlineTagSkip: 6px;
|
||||||
|
reactionInlineTagLeftRadius: 6px;
|
||||||
|
reactionInlineTagRightRadius: 3px;
|
||||||
|
reactionInlineTagArrow: 5px;
|
||||||
|
reactionInlineTagDot: 5px;
|
||||||
|
reactionInlineTagDotSkip: 2px;
|
||||||
reactionInlineBetween: 4px;
|
reactionInlineBetween: 4px;
|
||||||
reactionInlineInBubbleLeft: -3px;
|
reactionInlineInBubbleLeft: -3px;
|
||||||
reactionInlineUserpicsPadding: margins(1px, 1px, 1px, 1px);
|
reactionInlineUserpicsPadding: margins(1px, 1px, 1px, 1px);
|
||||||
|
|
|
@ -440,7 +440,7 @@ void EmptyUserpic::PaintHiddenAuthor(
|
||||||
{ 0., st::premiumButtonBg2->c },
|
{ 0., st::premiumButtonBg2->c },
|
||||||
{ 1., st::premiumButtonBg3->c },
|
{ 1., st::premiumButtonBg3->c },
|
||||||
});
|
});
|
||||||
const auto &fg = st::historyPeerUserpicFg;
|
const auto &fg = st::premiumButtonFg;
|
||||||
PaintHiddenAuthor(p, x, y, outerWidth, size, QBrush(bg), fg);
|
PaintHiddenAuthor(p, x, y, outerWidth, size, QBrush(bg), fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue