mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Display reactions outside bottom info in groups.
This commit is contained in:
parent
3aacd15ef2
commit
535fd8d523
9 changed files with 328 additions and 40 deletions
|
@ -652,6 +652,8 @@ PRIVATE
|
|||
history/view/history_view_pinned_section.h
|
||||
history/view/history_view_pinned_tracker.cpp
|
||||
history/view/history_view_pinned_tracker.h
|
||||
history/view/history_view_reactions.cpp
|
||||
history/view/history_view_reactions.h
|
||||
history/view/history_view_replies_section.cpp
|
||||
history/view/history_view_replies_section.h
|
||||
history/view/history_view_requests_bar.cpp
|
||||
|
|
|
@ -655,7 +655,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
&& chat->groupCall()->fullCount() > 0))
|
||||
? Flag::CallNotEmpty
|
||||
: Flag())
|
||||
| (data.is_noforwards() ? Flag::NoForwards : Flag());
|
||||
| (data.is_noforwards() ? Flag() : Flag()); AssertIsDebug();
|
||||
chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
|
||||
chat->count = data.vparticipants_count().v;
|
||||
|
||||
|
@ -765,7 +765,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
|||
? (data.is_left() ? Flag::Left : Flag())
|
||||
| (data.is_creator() ? Flag::Creator : Flag())
|
||||
: Flag())
|
||||
| (data.is_noforwards() ? Flag::NoForwards : Flag());
|
||||
| (data.is_noforwards() ? Flag() : Flag()); AssertIsDebug();
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
|
||||
channel->setName(
|
||||
|
|
|
@ -1699,12 +1699,15 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
this,
|
||||
st::reactionMenu);
|
||||
auto &reactions = item->history()->owner().reactions();
|
||||
for (const auto &entry : reactions.list(item->history()->peer)) {
|
||||
reactionMenu->addAction(entry.emoji, [=] {
|
||||
item->addReaction(entry.emoji);
|
||||
});
|
||||
const auto &list = reactions.list(item->history()->peer);
|
||||
if (!list.empty()) {
|
||||
for (const auto &entry : list) {
|
||||
reactionMenu->addAction(entry.emoji, [=] {
|
||||
item->addReaction(entry.emoji);
|
||||
});
|
||||
}
|
||||
_menu->addAction("Reaction", std::move(reactionMenu));
|
||||
}
|
||||
_menu->addAction("Reaction", std::move(reactionMenu));
|
||||
}
|
||||
if (canSendMessages) {
|
||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
||||
|
|
|
@ -323,8 +323,10 @@ BottomInfo::Data BottomInfoDataFromMessage(not_null<Message*> message) {
|
|||
|
||||
const auto item = message->message();
|
||||
result.date = message->dateTime();
|
||||
result.reactions = item->reactions();
|
||||
result.chosenReaction = item->chosenReaction();
|
||||
if (message->embedReactionsInBottomInfo()) {
|
||||
result.reactions = item->reactions();
|
||||
result.chosenReaction = item->chosenReaction();
|
||||
}
|
||||
if (message->hasOutLayout()) {
|
||||
result.flags |= Flag::OutLayout;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_message.h"
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "history/view/media/history_view_web_page.h"
|
||||
#include "history/view/history_view_reactions.h"
|
||||
#include "history/view/history_view_group_call_bar.h" // UserpicInRow.
|
||||
#include "history/view/history_view_view_button.h" // ViewButton.
|
||||
#include "history/history.h"
|
||||
|
@ -247,6 +248,7 @@ Message::Message(
|
|||
BottomInfoContextFromMessage(this)) {
|
||||
initLogEntryOriginal();
|
||||
initPsa();
|
||||
refreshReactions();
|
||||
}
|
||||
|
||||
Message::~Message() {
|
||||
|
@ -319,8 +321,13 @@ QSize Message::performCountOptimalSize() {
|
|||
updateViewButtonExistence();
|
||||
updateMediaInBubbleState();
|
||||
refreshRightBadge();
|
||||
initTime();
|
||||
refreshInfoSkipBlock();
|
||||
|
||||
const auto displayInfo = needInfoDisplay();
|
||||
const auto reactionsInBubble = _reactions && displayInfo;
|
||||
if (_reactions) {
|
||||
_reactions->initDimensions();
|
||||
}
|
||||
if (drawBubble()) {
|
||||
const auto forwarded = item->Get<HistoryMessageForwarded>();
|
||||
const auto reply = displayedReply();
|
||||
|
@ -345,22 +352,19 @@ QSize Message::performCountOptimalSize() {
|
|||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
if (mediaOnBottom || (mediaDisplayed && _viewButton)) {
|
||||
if (item->_text.removeSkipBlock()) {
|
||||
item->_textWidth = -1;
|
||||
item->_textHeight = 0;
|
||||
}
|
||||
} else if (item->_text.updateSkipBlock(skipBlockWidth(), skipBlockHeight())) {
|
||||
item->_textWidth = -1;
|
||||
item->_textHeight = 0;
|
||||
}
|
||||
|
||||
maxWidth = plainMaxWidth();
|
||||
if (context() == Context::Replies && item->isDiscussionPost()) {
|
||||
maxWidth = std::max(maxWidth, st::msgMaxWidth);
|
||||
}
|
||||
minHeight = hasVisibleText() ? item->_text.minHeight() : 0;
|
||||
if (reactionsInBubble) {
|
||||
accumulate_max(maxWidth, std::min(
|
||||
st::msgMaxWidth,
|
||||
(st::msgPadding.left()
|
||||
+ _reactions->maxWidth()
|
||||
+ st::msgPadding.right())));
|
||||
minHeight += st::mediaInBubbleSkip + _reactions->minHeight();
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
if (mediaDisplayed) minHeight += st::mediaInBubbleSkip;
|
||||
|
@ -374,9 +378,17 @@ QSize Message::performCountOptimalSize() {
|
|||
// Parts don't participate in maxWidth() in case of media message.
|
||||
if (media->enforceBubbleWidth()) {
|
||||
maxWidth = media->maxWidth();
|
||||
const auto innerWidth = maxWidth
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
if (hasVisibleText() && maxWidth < plainMaxWidth()) {
|
||||
minHeight -= item->_text.minHeight();
|
||||
minHeight += item->_text.countHeight(maxWidth - st::msgPadding.left() - st::msgPadding.right());
|
||||
minHeight += item->_text.countHeight(innerWidth);
|
||||
}
|
||||
if (reactionsInBubble) {
|
||||
minHeight -= _reactions->minHeight();
|
||||
minHeight
|
||||
+= _reactions->countCurrentSize(innerWidth).height();
|
||||
}
|
||||
} else {
|
||||
accumulate_max(maxWidth, media->maxWidth());
|
||||
|
@ -441,6 +453,13 @@ QSize Message::performCountOptimalSize() {
|
|||
maxWidth = st::msgMinWidth;
|
||||
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 (!markup->inlineKeyboard) {
|
||||
markup->inlineKeyboard = std::make_unique<ReplyKeyboard>(
|
||||
|
@ -518,6 +537,9 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
const auto displayInfo = needInfoDisplay();
|
||||
const auto reactionsInBubble = _reactions && displayInfo;
|
||||
|
||||
auto mediaSelectionIntervals = (!context.selected() && mediaDisplayed)
|
||||
? media->getBubbleSelectionIntervals(context.selection)
|
||||
: std::vector<Ui::BubbleSelectionInterval>();
|
||||
|
@ -531,6 +553,9 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
if (_viewButton) {
|
||||
localMediaBottom -= st::mediaInBubbleSkip + _viewButton->height();
|
||||
}
|
||||
if (reactionsInBubble) {
|
||||
localMediaBottom -= st::mediaInBubbleSkip + _reactions->height();
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
localMediaBottom -= st::msgPadding.bottom();
|
||||
}
|
||||
|
@ -562,14 +587,23 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
|
||||
auto keyboard = item->inlineReplyKeyboard();
|
||||
if (keyboard) {
|
||||
auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
||||
const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
||||
g.setHeight(g.height() - keyboardHeight);
|
||||
auto keyboardPosition = QPoint(g.left(), g.top() + g.height() + st::msgBotKbButton.margin);
|
||||
const auto keyboardPosition = QPoint(g.left(), g.top() + g.height() + st::msgBotKbButton.margin);
|
||||
p.translate(keyboardPosition);
|
||||
keyboard->paint(p, context.st, g.width(), context.clip.translated(-keyboardPosition));
|
||||
p.translate(-keyboardPosition);
|
||||
}
|
||||
|
||||
if (_reactions && !reactionsInBubble) {
|
||||
const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height();
|
||||
g.setHeight(g.height() - reactionsHeight);
|
||||
const auto reactionsPosition = QPoint(g.left(), g.top() + g.height() + st::mediaInBubbleSkip);
|
||||
p.translate(reactionsPosition);
|
||||
_reactions->paint(p, context.st, g.width(), context.clip.translated(-reactionsPosition));
|
||||
p.translate(-reactionsPosition);
|
||||
}
|
||||
|
||||
if (bubble) {
|
||||
if (displayFromName()
|
||||
&& item->displayFrom()
|
||||
|
@ -606,7 +640,6 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
auto inner = g;
|
||||
paintCommentsButton(p, inner, context);
|
||||
|
||||
const auto needDrawInfo = needInfoDisplay();
|
||||
auto trect = inner.marginsRemoved(st::msgPadding);
|
||||
if (_viewButton) {
|
||||
const auto belowInfo = _viewButton->belowMessageInfo();
|
||||
|
@ -627,6 +660,15 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
}
|
||||
}
|
||||
|
||||
if (reactionsInBubble) {
|
||||
const auto reactionsHeight = st::mediaInBubbleSkip + _reactions->height();
|
||||
trect.setHeight(trect.height() - reactionsHeight);
|
||||
const auto reactionsPosition = QPoint(trect.left(), trect.top() + trect.height() + st::mediaInBubbleSkip);
|
||||
p.translate(reactionsPosition);
|
||||
_reactions->paint(p, context.st, g.width(), context.clip.translated(-reactionsPosition));
|
||||
p.translate(-reactionsPosition);
|
||||
}
|
||||
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
}
|
||||
|
@ -641,7 +683,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
if (entry) {
|
||||
trect.setHeight(trect.height() - entry->height());
|
||||
}
|
||||
if (needDrawInfo) {
|
||||
if (displayInfo) {
|
||||
trect.setHeight(trect.height()
|
||||
- (_bottomInfo.height() - st::msgDateFont->height));
|
||||
}
|
||||
|
@ -671,7 +713,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
|||
entry->draw(p, entryContext);
|
||||
p.translate(-entryLeft, -entryTop);
|
||||
}
|
||||
if (needDrawInfo) {
|
||||
if (displayInfo) {
|
||||
const auto bottomSelected = context.selected()
|
||||
|| (!mediaSelectionIntervals.empty()
|
||||
&& (mediaSelectionIntervals.back().top
|
||||
|
@ -1030,6 +1072,7 @@ PointState Message::pointState(QPoint point) const {
|
|||
|
||||
const auto media = this->media();
|
||||
const auto item = message();
|
||||
const auto reactionsInBubble = _reactions && needInfoDisplay();
|
||||
if (drawBubble()) {
|
||||
if (!g.contains(point)) {
|
||||
return PointState::Outside;
|
||||
|
@ -1052,6 +1095,11 @@ PointState Message::pointState(QPoint point) const {
|
|||
trect.setHeight(trect.height() - st::mediaInBubbleSkip);
|
||||
}
|
||||
}
|
||||
if (reactionsInBubble) {
|
||||
const auto reactionsHeight = st::mediaInBubbleSkip
|
||||
+ _reactions->height();
|
||||
trect.setHeight(trect.height() - reactionsHeight);
|
||||
}
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
}
|
||||
|
@ -1198,6 +1246,7 @@ TextState Message::textState(
|
|||
return result;
|
||||
}
|
||||
|
||||
const auto reactionsInBubble = _reactions && needInfoDisplay();
|
||||
auto keyboard = item->inlineReplyKeyboard();
|
||||
auto keyboardHeight = 0;
|
||||
if (keyboard) {
|
||||
|
@ -1242,6 +1291,11 @@ TextState Message::textState(
|
|||
trect.setHeight(trect.height() - st::mediaInBubbleSkip);
|
||||
}
|
||||
}
|
||||
if (reactionsInBubble) {
|
||||
const auto reactionsHeight = _reactions->height()
|
||||
+ st::mediaInBubbleSkip;
|
||||
trect.setHeight(trect.height() - reactionsHeight);
|
||||
}
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height()
|
||||
+ st::msgPadding.bottom()
|
||||
|
@ -1828,14 +1882,38 @@ bool Message::isSignedAuthorElided() const {
|
|||
return _bottomInfo.isSignedAuthorElided();
|
||||
}
|
||||
|
||||
bool Message::embedReactionsInBottomInfo() const {
|
||||
return data()->history()->peer->isUser();
|
||||
}
|
||||
|
||||
void Message::refreshReactions() {
|
||||
const auto item = data();
|
||||
const auto &list = item->reactions();
|
||||
if (list.empty() || embedReactionsInBottomInfo()) {
|
||||
_reactions = nullptr;
|
||||
} else if (!_reactions) {
|
||||
_reactions = std::make_unique<Reactions>(
|
||||
ReactionsDataFromMessage(this));
|
||||
} else {
|
||||
_reactions->update(ReactionsDataFromMessage(this), width());
|
||||
}
|
||||
}
|
||||
|
||||
void Message::itemDataChanged() {
|
||||
const auto wasInfo = _bottomInfo.currentSize();
|
||||
const auto wasReactions = _reactions
|
||||
? _reactions->currentSize()
|
||||
: QSize();
|
||||
refreshReactions();
|
||||
_bottomInfo.update(
|
||||
BottomInfoDataFromMessage(this),
|
||||
BottomInfoContextFromMessage(this),
|
||||
width());
|
||||
const auto nowInfo = _bottomInfo.currentSize();
|
||||
if (wasInfo != nowInfo) {
|
||||
const auto nowReactions = _reactions
|
||||
? _reactions->currentSize()
|
||||
: QSize();
|
||||
if (wasInfo != nowInfo || wasReactions != nowReactions) {
|
||||
history()->owner().requestViewResize(this);
|
||||
} else {
|
||||
history()->owner().requestViewRepaint(this);
|
||||
|
@ -2305,7 +2383,9 @@ void Message::updateMediaInBubbleState() {
|
|||
const auto item = message();
|
||||
const auto media = this->media();
|
||||
|
||||
auto mediaHasSomethingBelow = (_viewButton != nullptr);
|
||||
const auto reactionsInBubble = (_reactions && needInfoDisplay());
|
||||
auto mediaHasSomethingBelow = (_viewButton != nullptr)
|
||||
|| reactionsInBubble;
|
||||
auto mediaHasSomethingAbove = false;
|
||||
auto getMediaHasSomethingAbove = [&] {
|
||||
return displayFromName()
|
||||
|
@ -2490,10 +2570,13 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
}
|
||||
}
|
||||
}
|
||||
const auto textWidth = qMax(contentWidth - st::msgPadding.left() - st::msgPadding.right(), 1);
|
||||
const auto displayInfo = needInfoDisplay();
|
||||
const auto reactionsInBubble = _reactions && displayInfo;
|
||||
const auto bottomInfoHeight = _bottomInfo.resizeGetHeight(
|
||||
std::min(
|
||||
_bottomInfo.optimalSize().width(),
|
||||
contentWidth - st::msgPadding.left() - st::msgPadding.right() - 2 * st::msgDateDelta.x()));
|
||||
textWidth - 2 * st::msgDateDelta.x()));
|
||||
|
||||
if (bubble) {
|
||||
auto reply = displayedReply();
|
||||
|
@ -2504,6 +2587,10 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
if (reactionsInBubble) {
|
||||
_reactions->resizeGetHeight(textWidth);
|
||||
}
|
||||
|
||||
if (contentWidth == maxWidth()) {
|
||||
if (mediaDisplayed) {
|
||||
if (entry) {
|
||||
|
@ -2515,7 +2602,6 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
}
|
||||
} else {
|
||||
if (hasVisibleText()) {
|
||||
auto textWidth = qMax(contentWidth - st::msgPadding.left() - st::msgPadding.right(), 1);
|
||||
if (textWidth != item->_textWidth) {
|
||||
item->_textWidth = textWidth;
|
||||
item->_textHeight = item->_text.countHeight(textWidth);
|
||||
|
@ -2541,6 +2627,9 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
} else if (entry) {
|
||||
newHeight += entry->resizeGetHeight(contentWidth);
|
||||
}
|
||||
if (reactionsInBubble) {
|
||||
newHeight += st::mediaInBubbleSkip + _reactions->height();
|
||||
}
|
||||
}
|
||||
|
||||
if (displayFromName()) {
|
||||
|
@ -2564,7 +2653,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
reply->resize(contentWidth - st::msgPadding.left() - st::msgPadding.right());
|
||||
newHeight += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
||||
}
|
||||
if (needInfoDisplay()) {
|
||||
if (displayInfo) {
|
||||
newHeight += (bottomInfoHeight - st::msgDateFont->height);
|
||||
}
|
||||
|
||||
|
@ -2577,6 +2666,9 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
} else {
|
||||
newHeight = 0;
|
||||
}
|
||||
if (_reactions && !reactionsInBubble) {
|
||||
newHeight += st::mediaInBubbleSkip + _reactions->resizeGetHeight(contentWidth);
|
||||
}
|
||||
if (const auto keyboard = item->inlineReplyKeyboard()) {
|
||||
const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
||||
newHeight += keyboardHeight;
|
||||
|
@ -2591,9 +2683,6 @@ bool Message::needInfoDisplay() const {
|
|||
const auto media = this->media();
|
||||
const auto mediaDisplayed = media ? media->isDisplayed() : false;
|
||||
const auto entry = logEntryOriginal();
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
const auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
return entry
|
||||
? !entry->customInfoLayout()
|
||||
: (mediaDisplayed
|
||||
|
@ -2615,13 +2704,38 @@ QSize Message::performCountCurrentSize(int newWidth) {
|
|||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
void Message::initTime() const {
|
||||
void Message::refreshInfoSkipBlock() {
|
||||
const auto item = message();
|
||||
if (item->_text.hasSkipBlock()) {
|
||||
if (item->_text.updateSkipBlock(skipBlockWidth(), skipBlockHeight())) {
|
||||
const auto media = this->media();
|
||||
const auto hasTextSkipBlock = [&] {
|
||||
if (item->_text.isEmpty()) {
|
||||
return false;
|
||||
} else if (item->Has<HistoryMessageLogEntryOriginal>()) {
|
||||
return false;
|
||||
} else if (media && media->isDisplayed()) {
|
||||
return false;
|
||||
} else if (_reactions) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
const auto skipWidth = skipBlockWidth();
|
||||
const auto skipHeight = skipBlockHeight();
|
||||
if (_reactions) {
|
||||
if (needInfoDisplay()) {
|
||||
_reactions->updateSkipBlock(skipWidth, skipHeight);
|
||||
} else {
|
||||
_reactions->removeSkipBlock();
|
||||
}
|
||||
}
|
||||
if (!hasTextSkipBlock) {
|
||||
if (item->_text.removeSkipBlock()) {
|
||||
item->_textWidth = -1;
|
||||
item->_textHeight = 0;
|
||||
}
|
||||
} else if (item->_text.updateSkipBlock(skipWidth, skipHeight)) {
|
||||
item->_textWidth = -1;
|
||||
item->_textHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ struct HistoryMessageForwarded;
|
|||
namespace HistoryView {
|
||||
|
||||
class ViewButton;
|
||||
class Reactions;
|
||||
class WebPage;
|
||||
|
||||
// Special type of Component for the channel actions log.
|
||||
|
@ -56,6 +57,8 @@ public:
|
|||
[[nodiscard]] const HistoryMessageEdited *displayedEditBadge() const;
|
||||
[[nodiscard]] HistoryMessageEdited *displayedEditBadge();
|
||||
|
||||
[[nodiscard]] bool embedReactionsInBottomInfo() const;
|
||||
|
||||
int marginTop() const override;
|
||||
int marginBottom() const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
|
@ -211,7 +214,7 @@ private:
|
|||
[[nodiscard]] ClickHandlerPtr fastReplyLink() const;
|
||||
[[nodiscard]] bool displayPinIcon() const;
|
||||
|
||||
void initTime() const;
|
||||
void refreshInfoSkipBlock();
|
||||
[[nodiscard]] int plainMaxWidth() const;
|
||||
[[nodiscard]] int monospaceMaxWidth() const;
|
||||
|
||||
|
@ -225,11 +228,13 @@ private:
|
|||
void psaTooltipToggled(bool shown) const;
|
||||
|
||||
void refreshRightBadge();
|
||||
void refreshReactions();
|
||||
|
||||
mutable ClickHandlerPtr _rightActionLink;
|
||||
mutable ClickHandlerPtr _fastReplyLink;
|
||||
mutable std::unique_ptr<CommentsButton> _comments;
|
||||
mutable std::unique_ptr<ViewButton> _viewButton;
|
||||
std::unique_ptr<Reactions> _reactions;
|
||||
mutable std::unique_ptr<CommentsButton> _comments;
|
||||
|
||||
Ui::Text::String _rightBadge;
|
||||
int _bubbleWidthLimit = 0;
|
||||
|
|
104
Telegram/SourceFiles/history/view/history_view_reactions.cpp
Normal file
104
Telegram/SourceFiles/history/view/history_view_reactions.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "history/view/history_view_reactions.h"
|
||||
|
||||
#include "history/view/history_view_message.h"
|
||||
#include "history/history_message.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
Reactions::Reactions(Data &&data)
|
||||
: _data(std::move(data))
|
||||
, _reactions(st::msgMinWidth / 2) {
|
||||
layout();
|
||||
}
|
||||
|
||||
void Reactions::update(Data &&data, int availableWidth) {
|
||||
_data = std::move(data);
|
||||
layout();
|
||||
if (width() > 0) {
|
||||
resizeGetHeight(std::min(maxWidth(), availableWidth));
|
||||
}
|
||||
}
|
||||
|
||||
void Reactions::updateSkipBlock(int width, int height) {
|
||||
_reactions.updateSkipBlock(width, height);
|
||||
}
|
||||
|
||||
void Reactions::removeSkipBlock() {
|
||||
_reactions.removeSkipBlock();
|
||||
}
|
||||
|
||||
void Reactions::layout() {
|
||||
layoutReactionsText();
|
||||
initDimensions();
|
||||
}
|
||||
|
||||
void Reactions::layoutReactionsText() {
|
||||
if (_data.reactions.empty()) {
|
||||
_reactions.clear();
|
||||
return;
|
||||
}
|
||||
auto sorted = ranges::view::all(
|
||||
_data.reactions
|
||||
) | ranges::view::transform([](const auto &pair) {
|
||||
return std::make_pair(pair.first, pair.second);
|
||||
}) | ranges::to_vector;
|
||||
ranges::sort(sorted, std::greater<>(), &std::pair<QString, int>::second);
|
||||
|
||||
auto text = TextWithEntities();
|
||||
for (const auto &[string, count] : sorted) {
|
||||
if (!text.text.isEmpty()) {
|
||||
text.append(" - ");
|
||||
}
|
||||
const auto chosen = (_data.chosenReaction == string);
|
||||
text.append(string);
|
||||
if (_data.chosenReaction == string) {
|
||||
text.append(Ui::Text::Bold(QString::number(count)));
|
||||
} else {
|
||||
text.append(QString::number(count));
|
||||
}
|
||||
}
|
||||
|
||||
_reactions.setMarkedText(
|
||||
st::msgDateTextStyle,
|
||||
text,
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
QSize Reactions::countOptimalSize() {
|
||||
return QSize(_reactions.maxWidth(), _reactions.minHeight());
|
||||
}
|
||||
|
||||
QSize Reactions::countCurrentSize(int newWidth) {
|
||||
if (newWidth >= maxWidth()) {
|
||||
return optimalSize();
|
||||
}
|
||||
return { newWidth, _reactions.countHeight(newWidth) };
|
||||
}
|
||||
|
||||
void Reactions::paint(
|
||||
Painter &p,
|
||||
const Ui::ChatStyle *st,
|
||||
int outerWidth,
|
||||
const QRect &clip) const {
|
||||
_reactions.draw(p, 0, 0, outerWidth);
|
||||
}
|
||||
|
||||
Reactions::Data ReactionsDataFromMessage(not_null<Message*> message) {
|
||||
auto result = Reactions::Data();
|
||||
|
||||
const auto item = message->message();
|
||||
result.reactions = item->reactions();
|
||||
result.chosenReaction = item->chosenReaction();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
55
Telegram/SourceFiles/history/view/history_view_reactions.h
Normal file
55
Telegram/SourceFiles/history/view/history_view_reactions.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "history/view/history_view_object.h"
|
||||
|
||||
namespace Ui {
|
||||
class ChatStyle;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class Message;
|
||||
|
||||
class Reactions final : public Object {
|
||||
public:
|
||||
struct Data {
|
||||
base::flat_map<QString, int> reactions;
|
||||
QString chosenReaction;
|
||||
};
|
||||
|
||||
explicit Reactions(Data &&data);
|
||||
|
||||
void update(Data &&data, int availableWidth);
|
||||
QSize countCurrentSize(int newWidth) override;
|
||||
|
||||
void updateSkipBlock(int width, int height);
|
||||
void removeSkipBlock();
|
||||
|
||||
void paint(
|
||||
Painter &p,
|
||||
const Ui::ChatStyle *st,
|
||||
int outerWidth,
|
||||
const QRect &clip) const;
|
||||
|
||||
private:
|
||||
void layout();
|
||||
void layoutReactionsText();
|
||||
|
||||
QSize countOptimalSize() override;
|
||||
|
||||
Data _data;
|
||||
Ui::Text::String _reactions;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] Reactions::Data ReactionsDataFromMessage(
|
||||
not_null<Message*> message);
|
||||
|
||||
} // namespace HistoryView
|
|
@ -531,6 +531,9 @@ TextForMimeData GroupedMedia::selectedText(
|
|||
auto GroupedMedia::getBubbleSelectionIntervals(
|
||||
TextSelection selection) const
|
||||
-> std::vector<Ui::BubbleSelectionInterval> {
|
||||
if (_mode != Mode::Column) {
|
||||
return {};
|
||||
}
|
||||
auto result = std::vector<Ui::BubbleSelectionInterval>();
|
||||
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
||||
const auto &part = _parts[i];
|
||||
|
|
Loading…
Add table
Reference in a new issue