mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +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_section.h
|
||||||
history/view/history_view_pinned_tracker.cpp
|
history/view/history_view_pinned_tracker.cpp
|
||||||
history/view/history_view_pinned_tracker.h
|
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.cpp
|
||||||
history/view/history_view_replies_section.h
|
history/view/history_view_replies_section.h
|
||||||
history/view/history_view_requests_bar.cpp
|
history/view/history_view_requests_bar.cpp
|
||||||
|
|
|
@ -655,7 +655,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||||
&& chat->groupCall()->fullCount() > 0))
|
&& chat->groupCall()->fullCount() > 0))
|
||||||
? Flag::CallNotEmpty
|
? Flag::CallNotEmpty
|
||||||
: Flag())
|
: Flag())
|
||||||
| (data.is_noforwards() ? Flag::NoForwards : Flag());
|
| (data.is_noforwards() ? Flag() : Flag()); AssertIsDebug();
|
||||||
chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
|
chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
|
||||||
chat->count = data.vparticipants_count().v;
|
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_left() ? Flag::Left : Flag())
|
||||||
| (data.is_creator() ? Flag::Creator : Flag())
|
| (data.is_creator() ? Flag::Creator : Flag())
|
||||||
: Flag())
|
: Flag())
|
||||||
| (data.is_noforwards() ? Flag::NoForwards : Flag());
|
| (data.is_noforwards() ? Flag() : Flag()); AssertIsDebug();
|
||||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||||
|
|
||||||
channel->setName(
|
channel->setName(
|
||||||
|
|
|
@ -1699,12 +1699,15 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
this,
|
this,
|
||||||
st::reactionMenu);
|
st::reactionMenu);
|
||||||
auto &reactions = item->history()->owner().reactions();
|
auto &reactions = item->history()->owner().reactions();
|
||||||
for (const auto &entry : reactions.list(item->history()->peer)) {
|
const auto &list = reactions.list(item->history()->peer);
|
||||||
reactionMenu->addAction(entry.emoji, [=] {
|
if (!list.empty()) {
|
||||||
item->addReaction(entry.emoji);
|
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) {
|
if (canSendMessages) {
|
||||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
_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();
|
const auto item = message->message();
|
||||||
result.date = message->dateTime();
|
result.date = message->dateTime();
|
||||||
result.reactions = item->reactions();
|
if (message->embedReactionsInBottomInfo()) {
|
||||||
result.chosenReaction = item->chosenReaction();
|
result.reactions = item->reactions();
|
||||||
|
result.chosenReaction = item->chosenReaction();
|
||||||
|
}
|
||||||
if (message->hasOutLayout()) {
|
if (message->hasOutLayout()) {
|
||||||
result.flags |= Flag::OutLayout;
|
result.flags |= Flag::OutLayout;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history_message.h"
|
#include "history/history_message.h"
|
||||||
#include "history/view/media/history_view_media.h"
|
#include "history/view/media/history_view_media.h"
|
||||||
#include "history/view/media/history_view_web_page.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_group_call_bar.h" // UserpicInRow.
|
||||||
#include "history/view/history_view_view_button.h" // ViewButton.
|
#include "history/view/history_view_view_button.h" // ViewButton.
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -247,6 +248,7 @@ Message::Message(
|
||||||
BottomInfoContextFromMessage(this)) {
|
BottomInfoContextFromMessage(this)) {
|
||||||
initLogEntryOriginal();
|
initLogEntryOriginal();
|
||||||
initPsa();
|
initPsa();
|
||||||
|
refreshReactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::~Message() {
|
Message::~Message() {
|
||||||
|
@ -319,8 +321,13 @@ QSize Message::performCountOptimalSize() {
|
||||||
updateViewButtonExistence();
|
updateViewButtonExistence();
|
||||||
updateMediaInBubbleState();
|
updateMediaInBubbleState();
|
||||||
refreshRightBadge();
|
refreshRightBadge();
|
||||||
initTime();
|
refreshInfoSkipBlock();
|
||||||
|
|
||||||
|
const auto displayInfo = needInfoDisplay();
|
||||||
|
const auto reactionsInBubble = _reactions && displayInfo;
|
||||||
|
if (_reactions) {
|
||||||
|
_reactions->initDimensions();
|
||||||
|
}
|
||||||
if (drawBubble()) {
|
if (drawBubble()) {
|
||||||
const auto forwarded = item->Get<HistoryMessageForwarded>();
|
const auto forwarded = item->Get<HistoryMessageForwarded>();
|
||||||
const auto reply = displayedReply();
|
const auto reply = displayedReply();
|
||||||
|
@ -345,22 +352,19 @@ QSize Message::performCountOptimalSize() {
|
||||||
// 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()*/);
|
||||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
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();
|
maxWidth = plainMaxWidth();
|
||||||
if (context() == Context::Replies && item->isDiscussionPost()) {
|
if (context() == Context::Replies && item->isDiscussionPost()) {
|
||||||
maxWidth = std::max(maxWidth, st::msgMaxWidth);
|
maxWidth = std::max(maxWidth, st::msgMaxWidth);
|
||||||
}
|
}
|
||||||
minHeight = hasVisibleText() ? item->_text.minHeight() : 0;
|
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) {
|
if (!mediaOnBottom) {
|
||||||
minHeight += st::msgPadding.bottom();
|
minHeight += st::msgPadding.bottom();
|
||||||
if (mediaDisplayed) minHeight += st::mediaInBubbleSkip;
|
if (mediaDisplayed) minHeight += st::mediaInBubbleSkip;
|
||||||
|
@ -374,9 +378,17 @@ QSize Message::performCountOptimalSize() {
|
||||||
// Parts don't participate in maxWidth() in case of media message.
|
// Parts don't participate in maxWidth() in case of media message.
|
||||||
if (media->enforceBubbleWidth()) {
|
if (media->enforceBubbleWidth()) {
|
||||||
maxWidth = media->maxWidth();
|
maxWidth = media->maxWidth();
|
||||||
|
const auto innerWidth = maxWidth
|
||||||
|
- st::msgPadding.left()
|
||||||
|
- st::msgPadding.right();
|
||||||
if (hasVisibleText() && maxWidth < plainMaxWidth()) {
|
if (hasVisibleText() && maxWidth < plainMaxWidth()) {
|
||||||
minHeight -= item->_text.minHeight();
|
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 {
|
} else {
|
||||||
accumulate_max(maxWidth, media->maxWidth());
|
accumulate_max(maxWidth, media->maxWidth());
|
||||||
|
@ -441,6 +453,13 @@ 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>(
|
||||||
|
@ -518,6 +537,9 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||||
|
|
||||||
|
const auto displayInfo = needInfoDisplay();
|
||||||
|
const auto reactionsInBubble = _reactions && displayInfo;
|
||||||
|
|
||||||
auto mediaSelectionIntervals = (!context.selected() && mediaDisplayed)
|
auto mediaSelectionIntervals = (!context.selected() && mediaDisplayed)
|
||||||
? media->getBubbleSelectionIntervals(context.selection)
|
? media->getBubbleSelectionIntervals(context.selection)
|
||||||
: std::vector<Ui::BubbleSelectionInterval>();
|
: std::vector<Ui::BubbleSelectionInterval>();
|
||||||
|
@ -531,6 +553,9 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
if (_viewButton) {
|
if (_viewButton) {
|
||||||
localMediaBottom -= st::mediaInBubbleSkip + _viewButton->height();
|
localMediaBottom -= st::mediaInBubbleSkip + _viewButton->height();
|
||||||
}
|
}
|
||||||
|
if (reactionsInBubble) {
|
||||||
|
localMediaBottom -= st::mediaInBubbleSkip + _reactions->height();
|
||||||
|
}
|
||||||
if (!mediaOnBottom) {
|
if (!mediaOnBottom) {
|
||||||
localMediaBottom -= st::msgPadding.bottom();
|
localMediaBottom -= st::msgPadding.bottom();
|
||||||
}
|
}
|
||||||
|
@ -562,14 +587,23 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
|
|
||||||
auto keyboard = item->inlineReplyKeyboard();
|
auto keyboard = item->inlineReplyKeyboard();
|
||||||
if (keyboard) {
|
if (keyboard) {
|
||||||
auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
||||||
g.setHeight(g.height() - keyboardHeight);
|
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);
|
p.translate(keyboardPosition);
|
||||||
keyboard->paint(p, context.st, g.width(), context.clip.translated(-keyboardPosition));
|
keyboard->paint(p, context.st, g.width(), context.clip.translated(-keyboardPosition));
|
||||||
p.translate(-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 (bubble) {
|
||||||
if (displayFromName()
|
if (displayFromName()
|
||||||
&& item->displayFrom()
|
&& item->displayFrom()
|
||||||
|
@ -606,7 +640,6 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
auto inner = g;
|
auto inner = g;
|
||||||
paintCommentsButton(p, inner, context);
|
paintCommentsButton(p, inner, context);
|
||||||
|
|
||||||
const auto needDrawInfo = needInfoDisplay();
|
|
||||||
auto trect = inner.marginsRemoved(st::msgPadding);
|
auto trect = inner.marginsRemoved(st::msgPadding);
|
||||||
if (_viewButton) {
|
if (_viewButton) {
|
||||||
const auto belowInfo = _viewButton->belowMessageInfo();
|
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) {
|
if (mediaOnBottom) {
|
||||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||||
}
|
}
|
||||||
|
@ -641,7 +683,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
if (entry) {
|
if (entry) {
|
||||||
trect.setHeight(trect.height() - entry->height());
|
trect.setHeight(trect.height() - entry->height());
|
||||||
}
|
}
|
||||||
if (needDrawInfo) {
|
if (displayInfo) {
|
||||||
trect.setHeight(trect.height()
|
trect.setHeight(trect.height()
|
||||||
- (_bottomInfo.height() - st::msgDateFont->height));
|
- (_bottomInfo.height() - st::msgDateFont->height));
|
||||||
}
|
}
|
||||||
|
@ -671,7 +713,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||||
entry->draw(p, entryContext);
|
entry->draw(p, entryContext);
|
||||||
p.translate(-entryLeft, -entryTop);
|
p.translate(-entryLeft, -entryTop);
|
||||||
}
|
}
|
||||||
if (needDrawInfo) {
|
if (displayInfo) {
|
||||||
const auto bottomSelected = context.selected()
|
const auto bottomSelected = context.selected()
|
||||||
|| (!mediaSelectionIntervals.empty()
|
|| (!mediaSelectionIntervals.empty()
|
||||||
&& (mediaSelectionIntervals.back().top
|
&& (mediaSelectionIntervals.back().top
|
||||||
|
@ -1030,6 +1072,7 @@ PointState Message::pointState(QPoint point) const {
|
||||||
|
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
const auto item = message();
|
const auto item = message();
|
||||||
|
const auto reactionsInBubble = _reactions && needInfoDisplay();
|
||||||
if (drawBubble()) {
|
if (drawBubble()) {
|
||||||
if (!g.contains(point)) {
|
if (!g.contains(point)) {
|
||||||
return PointState::Outside;
|
return PointState::Outside;
|
||||||
|
@ -1052,6 +1095,11 @@ PointState Message::pointState(QPoint point) const {
|
||||||
trect.setHeight(trect.height() - st::mediaInBubbleSkip);
|
trect.setHeight(trect.height() - st::mediaInBubbleSkip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (reactionsInBubble) {
|
||||||
|
const auto reactionsHeight = st::mediaInBubbleSkip
|
||||||
|
+ _reactions->height();
|
||||||
|
trect.setHeight(trect.height() - reactionsHeight);
|
||||||
|
}
|
||||||
if (mediaOnBottom) {
|
if (mediaOnBottom) {
|
||||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||||
}
|
}
|
||||||
|
@ -1198,6 +1246,7 @@ TextState Message::textState(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto reactionsInBubble = _reactions && needInfoDisplay();
|
||||||
auto keyboard = item->inlineReplyKeyboard();
|
auto keyboard = item->inlineReplyKeyboard();
|
||||||
auto keyboardHeight = 0;
|
auto keyboardHeight = 0;
|
||||||
if (keyboard) {
|
if (keyboard) {
|
||||||
|
@ -1242,6 +1291,11 @@ TextState Message::textState(
|
||||||
trect.setHeight(trect.height() - st::mediaInBubbleSkip);
|
trect.setHeight(trect.height() - st::mediaInBubbleSkip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (reactionsInBubble) {
|
||||||
|
const auto reactionsHeight = _reactions->height()
|
||||||
|
+ st::mediaInBubbleSkip;
|
||||||
|
trect.setHeight(trect.height() - reactionsHeight);
|
||||||
|
}
|
||||||
if (mediaOnBottom) {
|
if (mediaOnBottom) {
|
||||||
trect.setHeight(trect.height()
|
trect.setHeight(trect.height()
|
||||||
+ st::msgPadding.bottom()
|
+ st::msgPadding.bottom()
|
||||||
|
@ -1828,14 +1882,38 @@ bool Message::isSignedAuthorElided() const {
|
||||||
return _bottomInfo.isSignedAuthorElided();
|
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() {
|
void Message::itemDataChanged() {
|
||||||
const auto wasInfo = _bottomInfo.currentSize();
|
const auto wasInfo = _bottomInfo.currentSize();
|
||||||
|
const auto wasReactions = _reactions
|
||||||
|
? _reactions->currentSize()
|
||||||
|
: QSize();
|
||||||
|
refreshReactions();
|
||||||
_bottomInfo.update(
|
_bottomInfo.update(
|
||||||
BottomInfoDataFromMessage(this),
|
BottomInfoDataFromMessage(this),
|
||||||
BottomInfoContextFromMessage(this),
|
BottomInfoContextFromMessage(this),
|
||||||
width());
|
width());
|
||||||
const auto nowInfo = _bottomInfo.currentSize();
|
const auto nowInfo = _bottomInfo.currentSize();
|
||||||
if (wasInfo != nowInfo) {
|
const auto nowReactions = _reactions
|
||||||
|
? _reactions->currentSize()
|
||||||
|
: QSize();
|
||||||
|
if (wasInfo != nowInfo || wasReactions != nowReactions) {
|
||||||
history()->owner().requestViewResize(this);
|
history()->owner().requestViewResize(this);
|
||||||
} else {
|
} else {
|
||||||
history()->owner().requestViewRepaint(this);
|
history()->owner().requestViewRepaint(this);
|
||||||
|
@ -2305,7 +2383,9 @@ void Message::updateMediaInBubbleState() {
|
||||||
const auto item = message();
|
const auto item = message();
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
|
|
||||||
auto mediaHasSomethingBelow = (_viewButton != nullptr);
|
const auto reactionsInBubble = (_reactions && needInfoDisplay());
|
||||||
|
auto mediaHasSomethingBelow = (_viewButton != nullptr)
|
||||||
|
|| reactionsInBubble;
|
||||||
auto mediaHasSomethingAbove = false;
|
auto mediaHasSomethingAbove = false;
|
||||||
auto getMediaHasSomethingAbove = [&] {
|
auto getMediaHasSomethingAbove = [&] {
|
||||||
return displayFromName()
|
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(
|
const auto bottomInfoHeight = _bottomInfo.resizeGetHeight(
|
||||||
std::min(
|
std::min(
|
||||||
_bottomInfo.optimalSize().width(),
|
_bottomInfo.optimalSize().width(),
|
||||||
contentWidth - st::msgPadding.left() - st::msgPadding.right() - 2 * st::msgDateDelta.x()));
|
textWidth - 2 * st::msgDateDelta.x()));
|
||||||
|
|
||||||
if (bubble) {
|
if (bubble) {
|
||||||
auto reply = displayedReply();
|
auto reply = displayedReply();
|
||||||
|
@ -2504,6 +2587,10 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||||
|
|
||||||
|
if (reactionsInBubble) {
|
||||||
|
_reactions->resizeGetHeight(textWidth);
|
||||||
|
}
|
||||||
|
|
||||||
if (contentWidth == maxWidth()) {
|
if (contentWidth == maxWidth()) {
|
||||||
if (mediaDisplayed) {
|
if (mediaDisplayed) {
|
||||||
if (entry) {
|
if (entry) {
|
||||||
|
@ -2515,7 +2602,6 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasVisibleText()) {
|
if (hasVisibleText()) {
|
||||||
auto textWidth = qMax(contentWidth - st::msgPadding.left() - st::msgPadding.right(), 1);
|
|
||||||
if (textWidth != item->_textWidth) {
|
if (textWidth != item->_textWidth) {
|
||||||
item->_textWidth = textWidth;
|
item->_textWidth = textWidth;
|
||||||
item->_textHeight = item->_text.countHeight(textWidth);
|
item->_textHeight = item->_text.countHeight(textWidth);
|
||||||
|
@ -2541,6 +2627,9 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
} else if (entry) {
|
} else if (entry) {
|
||||||
newHeight += entry->resizeGetHeight(contentWidth);
|
newHeight += entry->resizeGetHeight(contentWidth);
|
||||||
}
|
}
|
||||||
|
if (reactionsInBubble) {
|
||||||
|
newHeight += st::mediaInBubbleSkip + _reactions->height();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayFromName()) {
|
if (displayFromName()) {
|
||||||
|
@ -2564,7 +2653,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
reply->resize(contentWidth - st::msgPadding.left() - st::msgPadding.right());
|
reply->resize(contentWidth - st::msgPadding.left() - st::msgPadding.right());
|
||||||
newHeight += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
newHeight += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
||||||
}
|
}
|
||||||
if (needInfoDisplay()) {
|
if (displayInfo) {
|
||||||
newHeight += (bottomInfoHeight - st::msgDateFont->height);
|
newHeight += (bottomInfoHeight - st::msgDateFont->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2577,6 +2666,9 @@ int Message::resizeContentGetHeight(int newWidth) {
|
||||||
} else {
|
} else {
|
||||||
newHeight = 0;
|
newHeight = 0;
|
||||||
}
|
}
|
||||||
|
if (_reactions && !reactionsInBubble) {
|
||||||
|
newHeight += st::mediaInBubbleSkip + _reactions->resizeGetHeight(contentWidth);
|
||||||
|
}
|
||||||
if (const auto keyboard = item->inlineReplyKeyboard()) {
|
if (const auto keyboard = item->inlineReplyKeyboard()) {
|
||||||
const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
|
||||||
newHeight += keyboardHeight;
|
newHeight += keyboardHeight;
|
||||||
|
@ -2591,9 +2683,6 @@ bool Message::needInfoDisplay() const {
|
||||||
const auto media = this->media();
|
const auto media = this->media();
|
||||||
const auto mediaDisplayed = media ? media->isDisplayed() : false;
|
const auto mediaDisplayed = media ? media->isDisplayed() : false;
|
||||||
const auto entry = logEntryOriginal();
|
const auto entry = logEntryOriginal();
|
||||||
|
|
||||||
// Entry page is always a bubble bottom.
|
|
||||||
const auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
|
||||||
return entry
|
return entry
|
||||||
? !entry->customInfoLayout()
|
? !entry->customInfoLayout()
|
||||||
: (mediaDisplayed
|
: (mediaDisplayed
|
||||||
|
@ -2615,13 +2704,38 @@ QSize Message::performCountCurrentSize(int newWidth) {
|
||||||
return { newWidth, newHeight };
|
return { newWidth, newHeight };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Message::initTime() const {
|
void Message::refreshInfoSkipBlock() {
|
||||||
const auto item = message();
|
const auto item = message();
|
||||||
if (item->_text.hasSkipBlock()) {
|
const auto media = this->media();
|
||||||
if (item->_text.updateSkipBlock(skipBlockWidth(), skipBlockHeight())) {
|
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->_textWidth = -1;
|
||||||
item->_textHeight = 0;
|
item->_textHeight = 0;
|
||||||
}
|
}
|
||||||
|
} else if (item->_text.updateSkipBlock(skipWidth, skipHeight)) {
|
||||||
|
item->_textWidth = -1;
|
||||||
|
item->_textHeight = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct HistoryMessageForwarded;
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
class ViewButton;
|
class ViewButton;
|
||||||
|
class Reactions;
|
||||||
class WebPage;
|
class WebPage;
|
||||||
|
|
||||||
// Special type of Component for the channel actions log.
|
// Special type of Component for the channel actions log.
|
||||||
|
@ -56,6 +57,8 @@ public:
|
||||||
[[nodiscard]] const HistoryMessageEdited *displayedEditBadge() const;
|
[[nodiscard]] const HistoryMessageEdited *displayedEditBadge() const;
|
||||||
[[nodiscard]] HistoryMessageEdited *displayedEditBadge();
|
[[nodiscard]] HistoryMessageEdited *displayedEditBadge();
|
||||||
|
|
||||||
|
[[nodiscard]] bool embedReactionsInBottomInfo() const;
|
||||||
|
|
||||||
int marginTop() const override;
|
int marginTop() const override;
|
||||||
int marginBottom() const override;
|
int marginBottom() const override;
|
||||||
void draw(Painter &p, const PaintContext &context) const override;
|
void draw(Painter &p, const PaintContext &context) const override;
|
||||||
|
@ -211,7 +214,7 @@ private:
|
||||||
[[nodiscard]] ClickHandlerPtr fastReplyLink() const;
|
[[nodiscard]] ClickHandlerPtr fastReplyLink() const;
|
||||||
[[nodiscard]] bool displayPinIcon() const;
|
[[nodiscard]] bool displayPinIcon() const;
|
||||||
|
|
||||||
void initTime() const;
|
void refreshInfoSkipBlock();
|
||||||
[[nodiscard]] int plainMaxWidth() const;
|
[[nodiscard]] int plainMaxWidth() const;
|
||||||
[[nodiscard]] int monospaceMaxWidth() const;
|
[[nodiscard]] int monospaceMaxWidth() const;
|
||||||
|
|
||||||
|
@ -225,11 +228,13 @@ private:
|
||||||
void psaTooltipToggled(bool shown) const;
|
void psaTooltipToggled(bool shown) const;
|
||||||
|
|
||||||
void refreshRightBadge();
|
void refreshRightBadge();
|
||||||
|
void refreshReactions();
|
||||||
|
|
||||||
mutable ClickHandlerPtr _rightActionLink;
|
mutable ClickHandlerPtr _rightActionLink;
|
||||||
mutable ClickHandlerPtr _fastReplyLink;
|
mutable ClickHandlerPtr _fastReplyLink;
|
||||||
mutable std::unique_ptr<CommentsButton> _comments;
|
|
||||||
mutable std::unique_ptr<ViewButton> _viewButton;
|
mutable std::unique_ptr<ViewButton> _viewButton;
|
||||||
|
std::unique_ptr<Reactions> _reactions;
|
||||||
|
mutable std::unique_ptr<CommentsButton> _comments;
|
||||||
|
|
||||||
Ui::Text::String _rightBadge;
|
Ui::Text::String _rightBadge;
|
||||||
int _bubbleWidthLimit = 0;
|
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(
|
auto GroupedMedia::getBubbleSelectionIntervals(
|
||||||
TextSelection selection) const
|
TextSelection selection) const
|
||||||
-> std::vector<Ui::BubbleSelectionInterval> {
|
-> std::vector<Ui::BubbleSelectionInterval> {
|
||||||
|
if (_mode != Mode::Column) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
auto result = std::vector<Ui::BubbleSelectionInterval>();
|
auto result = std::vector<Ui::BubbleSelectionInterval>();
|
||||||
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
||||||
const auto &part = _parts[i];
|
const auto &part = _parts[i];
|
||||||
|
|
Loading…
Add table
Reference in a new issue