mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-22 09:07:05 +02:00
Extract BottomInfo from HistoryView::Message.
This commit is contained in:
parent
3a43217301
commit
1af2cfe143
25 changed files with 561 additions and 365 deletions
|
@ -621,6 +621,8 @@ PRIVATE
|
|||
history/view/media/history_view_theme_document.cpp
|
||||
history/view/media/history_view_web_page.h
|
||||
history/view/media/history_view_web_page.cpp
|
||||
history/view/history_view_bottom_info.cpp
|
||||
history/view/history_view_bottom_info.h
|
||||
history/view/history_view_contact_status.cpp
|
||||
history/view/history_view_contact_status.h
|
||||
history/view/history_view_context_menu.cpp
|
||||
|
|
|
@ -1163,7 +1163,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
|||
auto needToAdd = true;
|
||||
if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
|
||||
const auto &data = d.vmessage().c_message();
|
||||
if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
|
||||
if (_session->data().updateExistingMessage(data)) { // already in blocks
|
||||
LOG(("Skipping message, because it is already in blocks!"));
|
||||
needToAdd = false;
|
||||
}
|
||||
|
@ -1257,7 +1257,7 @@ void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
|
|||
auto needToAdd = true;
|
||||
if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
|
||||
const auto &data = d.vmessage().c_message();
|
||||
if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
|
||||
if (_session->data().updateExistingMessage(data)) { // already in blocks
|
||||
LOG(("Skipping message, because it is already in blocks!"));
|
||||
needToAdd = false;
|
||||
}
|
||||
|
@ -2163,7 +2163,9 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
const auto &d = update.c_updateChannelMessageViews();
|
||||
const auto peerId = peerFromChannel(d.vchannel_id());
|
||||
if (const auto item = session().data().message(peerId, d.vid().v)) {
|
||||
item->setViewsCount(d.vviews().v);
|
||||
if (item->changeViewsCount(d.vviews().v)) {
|
||||
session().data().notifyItemDataChange(item);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
|
@ -99,7 +99,9 @@ void ViewsManager::done(
|
|||
if (const auto item = owner.message(peer->id, ids[j].v)) {
|
||||
v[j].match([&](const MTPDmessageViews &data) {
|
||||
if (const auto views = data.vviews()) {
|
||||
item->setViewsCount(views->v);
|
||||
if (item->changeViewsCount(views->v)) {
|
||||
_session->data().notifyItemDataChange(item);
|
||||
}
|
||||
}
|
||||
if (const auto forwards = data.vforwards()) {
|
||||
item->setForwardsCount(forwards->v);
|
||||
|
|
|
@ -1448,6 +1448,14 @@ rpl::producer<not_null<HistoryItem*>> Session::itemViewRefreshRequest() const {
|
|||
return _itemViewRefreshRequest.events();
|
||||
}
|
||||
|
||||
void Session::notifyItemDataChange(not_null<HistoryItem*> item) {
|
||||
_itemDataChanges.fire_copy(item);
|
||||
}
|
||||
|
||||
rpl::producer<not_null<HistoryItem*>> Session::itemDataChanges() const {
|
||||
return _itemDataChanges.events();
|
||||
}
|
||||
|
||||
void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
|
||||
if (const auto i = _views.find(item); i != _views.end()) {
|
||||
for (const auto view : i->second) {
|
||||
|
@ -1806,7 +1814,7 @@ void Session::reorderTwoPinnedChats(
|
|||
notifyPinnedDialogsOrderUpdated();
|
||||
}
|
||||
|
||||
bool Session::checkEntitiesAndViewsUpdate(const MTPDmessage &data) {
|
||||
bool Session::updateExistingMessage(const MTPDmessage &data) {
|
||||
const auto peer = peerFromMTP(data.vpeer_id());
|
||||
const auto existing = message(peer, data.vid().v);
|
||||
if (!existing) {
|
||||
|
@ -1834,7 +1842,7 @@ void Session::updateEditedMessage(const MTPMessage &data) {
|
|||
return;
|
||||
}
|
||||
if (existing->isLocalUpdateMedia() && data.type() == mtpc_message) {
|
||||
checkEntitiesAndViewsUpdate(data.c_message());
|
||||
updateExistingMessage(data.c_message());
|
||||
}
|
||||
data.match([](const MTPDmessageEmpty &) {
|
||||
}, [&](const MTPDmessageService &data) {
|
||||
|
@ -1854,7 +1862,7 @@ void Session::processMessages(
|
|||
const auto &data = message.c_message();
|
||||
// new message, index my forwarded messages to links overview
|
||||
if ((type == NewMessageType::Unread)
|
||||
&& checkEntitiesAndViewsUpdate(data)) {
|
||||
&& updateExistingMessage(data)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,6 +251,8 @@ public:
|
|||
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> animationPlayInlineRequest() const;
|
||||
void notifyHistoryUnloaded(not_null<const History*> history);
|
||||
[[nodiscard]] rpl::producer<not_null<const History*>> historyUnloaded() const;
|
||||
void notifyItemDataChange(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> itemDataChanges() const;
|
||||
|
||||
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRemoved() const;
|
||||
[[nodiscard]] rpl::producer<not_null<const HistoryItem*>> itemRemoved(
|
||||
|
@ -337,7 +339,7 @@ public:
|
|||
void unregisterMessageTTL(TimeId when, not_null<HistoryItem*> item);
|
||||
|
||||
// Returns true if item found and it is not detached.
|
||||
bool checkEntitiesAndViewsUpdate(const MTPDmessage &data);
|
||||
bool updateExistingMessage(const MTPDmessage &data);
|
||||
void updateEditedMessage(const MTPMessage &data);
|
||||
void processMessages(
|
||||
const QVector<MTPMessage> &data,
|
||||
|
@ -832,6 +834,7 @@ private:
|
|||
rpl::event_stream<not_null<ViewElement*>> _viewResizeRequest;
|
||||
rpl::event_stream<not_null<HistoryItem*>> _itemViewRefreshRequest;
|
||||
rpl::event_stream<not_null<HistoryItem*>> _itemTextRefreshRequest;
|
||||
rpl::event_stream<not_null<HistoryItem*>> _itemDataChanges;
|
||||
rpl::event_stream<not_null<HistoryItem*>> _animationPlayInlineRequest;
|
||||
rpl::event_stream<not_null<const HistoryItem*>> _itemRemoved;
|
||||
rpl::event_stream<not_null<const ViewElement*>> _viewRemoved;
|
||||
|
|
|
@ -285,6 +285,12 @@ InnerWidget::InnerWidget(
|
|||
}
|
||||
}
|
||||
}, lifetime());
|
||||
session().data().itemDataChanges(
|
||||
) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
|
||||
if (const auto view = viewForItem(item)) {
|
||||
view->itemDataChanged();
|
||||
}
|
||||
}, lifetime());
|
||||
session().data().animationPlayInlineRequest(
|
||||
) | rpl::start_with_next([=](auto item) {
|
||||
if (const auto view = viewForItem(item)) {
|
||||
|
|
|
@ -245,6 +245,14 @@ HistoryInner::HistoryInner(
|
|||
}) | rpl::start_with_next([this](not_null<const Element*> view) {
|
||||
mouseActionUpdate();
|
||||
}, lifetime());
|
||||
|
||||
session().data().itemDataChanges(
|
||||
) | rpl::filter([=](not_null<HistoryItem*> item) {
|
||||
return item->mainView() != nullptr;
|
||||
}) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
|
||||
item->mainView()->itemDataChanged();
|
||||
}, lifetime());
|
||||
|
||||
session().changes().historyUpdates(
|
||||
_history,
|
||||
Data::HistoryUpdate::Flag::OutboxRead
|
||||
|
|
|
@ -524,7 +524,7 @@ void HistoryItem::applySentMessage(const MTPDmessage &data) {
|
|||
}, data.vmedia());
|
||||
updateReplyMarkup(HistoryMessageMarkupData(data.vreply_markup()));
|
||||
updateForwardedInfo(data.vfwd_from());
|
||||
setViewsCount(data.vviews().value_or(-1));
|
||||
changeViewsCount(data.vviews().value_or(-1));
|
||||
if (const auto replies = data.vreplies()) {
|
||||
setReplies(HistoryMessageRepliesData(replies));
|
||||
} else {
|
||||
|
@ -541,6 +541,7 @@ void HistoryItem::applySentMessage(const MTPDmessage &data) {
|
|||
setPostAuthor(data.vpost_author().value_or_empty());
|
||||
contributeToSlowmode(data.vdate().v);
|
||||
indexAsNewItem();
|
||||
history()->owner().notifyItemDataChange(this);
|
||||
history()->owner().requestItemTextRefresh(this);
|
||||
history()->owner().updateDependentMessages(this);
|
||||
}
|
||||
|
@ -596,6 +597,7 @@ void HistoryItem::setRealId(MsgId newId) {
|
|||
}
|
||||
}
|
||||
|
||||
_history->owner().notifyItemDataChange(this);
|
||||
_history->owner().requestItemRepaint(this);
|
||||
}
|
||||
|
||||
|
@ -914,6 +916,7 @@ void HistoryItem::sendFailed() {
|
|||
Expects(!(_flags & MessageFlag::SendingFailed));
|
||||
|
||||
_flags = (_flags | MessageFlag::SendingFailed) & ~MessageFlag::BeingSent;
|
||||
_history->owner().notifyItemDataChange(this);
|
||||
history()->session().changes().historyUpdated(
|
||||
history(),
|
||||
Data::HistoryUpdate::Flag::ClientSideMessages);
|
||||
|
|
|
@ -352,7 +352,8 @@ public:
|
|||
return TextForMimeData();
|
||||
}
|
||||
|
||||
virtual void setViewsCount(int count) {
|
||||
virtual bool changeViewsCount(int count) {
|
||||
return false;
|
||||
}
|
||||
virtual void setForwardsCount(int count) {
|
||||
}
|
||||
|
|
|
@ -84,38 +84,6 @@ void HistoryMessageVia::resize(int32 availw) const {
|
|||
}
|
||||
}
|
||||
|
||||
void HistoryMessageSigned::refresh(const QString &date) {
|
||||
Expects(!isAnonymousRank);
|
||||
|
||||
auto name = author;
|
||||
const auto time = qsl(", ") + date;
|
||||
const auto timew = st::msgDateFont->width(time);
|
||||
const auto namew = st::msgDateFont->width(name);
|
||||
isElided = (timew + namew > st::maxSignatureSize);
|
||||
if (isElided) {
|
||||
name = st::msgDateFont->elided(author, st::maxSignatureSize - timew);
|
||||
}
|
||||
signature.setText(
|
||||
st::msgDateTextStyle,
|
||||
name + time,
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
int HistoryMessageSigned::maxWidth() const {
|
||||
return signature.maxWidth();
|
||||
}
|
||||
|
||||
void HistoryMessageEdited::refresh(const QString &date, bool displayed) {
|
||||
const auto prefix = displayed
|
||||
? (tr::lng_edited(tr::now) + ' ')
|
||||
: QString();
|
||||
text.setText(st::msgDateTextStyle, prefix + date, Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
int HistoryMessageEdited::maxWidth() const {
|
||||
return text.maxWidth();
|
||||
}
|
||||
|
||||
HistoryMessageSponsored::HistoryMessageSponsored() {
|
||||
text.setText(
|
||||
st::msgDateTextStyle,
|
||||
|
|
|
@ -60,21 +60,12 @@ struct HistoryMessageViews : public RuntimeComponent<HistoryMessageViews, Histor
|
|||
};
|
||||
|
||||
struct HistoryMessageSigned : public RuntimeComponent<HistoryMessageSigned, HistoryItem> {
|
||||
void refresh(const QString &date);
|
||||
int maxWidth() const;
|
||||
|
||||
QString author;
|
||||
Ui::Text::String signature;
|
||||
bool isElided = false;
|
||||
bool isAnonymousRank = false;
|
||||
};
|
||||
|
||||
struct HistoryMessageEdited : public RuntimeComponent<HistoryMessageEdited, HistoryItem> {
|
||||
void refresh(const QString &date, bool displayed);
|
||||
int maxWidth() const;
|
||||
|
||||
TimeId date = 0;
|
||||
Ui::Text::String text;
|
||||
};
|
||||
|
||||
struct HistoryMessageSponsored : public RuntimeComponent<
|
||||
|
|
|
@ -1124,7 +1124,7 @@ void HistoryMessage::createComponents(CreateConfig &&config) {
|
|||
via->create(&history()->owner(), config.viaBotId);
|
||||
}
|
||||
if (const auto views = Get<HistoryMessageViews>()) {
|
||||
setViewsCount(config.viewsCount);
|
||||
changeViewsCount(config.viewsCount);
|
||||
if (config.replies.isNull
|
||||
&& isSending()
|
||||
&& config.markup.isNull()) {
|
||||
|
@ -1423,7 +1423,7 @@ void HistoryMessage::applyEdition(HistoryMessageEdition &&edition) {
|
|||
if (!isLocalUpdateMedia()) {
|
||||
refreshMedia(edition.mtpMedia);
|
||||
}
|
||||
setViewsCount(edition.views);
|
||||
changeViewsCount(edition.views);
|
||||
setForwardsCount(edition.forwards);
|
||||
setText(_media
|
||||
? edition.textWithEntities
|
||||
|
@ -1449,7 +1449,7 @@ void HistoryMessage::applyEdition(const MTPDmessageService &message) {
|
|||
setReplyMarkup({});
|
||||
refreshMedia(nullptr);
|
||||
setEmptyText();
|
||||
setViewsCount(-1);
|
||||
changeViewsCount(-1);
|
||||
setForwardsCount(-1);
|
||||
if (wasGrouped) {
|
||||
history()->owner().groups().unregisterMessage(this);
|
||||
|
@ -1744,27 +1744,16 @@ bool HistoryMessage::textHasLinks() const {
|
|||
return emptyText() ? false : _text.hasLinks();
|
||||
}
|
||||
|
||||
void HistoryMessage::setViewsCount(int count) {
|
||||
bool HistoryMessage::changeViewsCount(int count) {
|
||||
const auto views = Get<HistoryMessageViews>();
|
||||
if (!views
|
||||
|| views->views.count == count
|
||||
|| (count >= 0 && views->views.count > count)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
views->views.count = count;
|
||||
views->views.text = Lang::FormatCountToShort(
|
||||
std::max(views->views.count, 1)
|
||||
).string;
|
||||
const auto was = views->views.textWidth;
|
||||
views->views.textWidth = views->views.text.isEmpty()
|
||||
? 0
|
||||
: st::msgDateFont->width(views->views.text);
|
||||
if (was == views->views.textWidth) {
|
||||
history()->owner().requestItemRepaint(this);
|
||||
} else {
|
||||
history()->owner().requestItemResize(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HistoryMessage::setForwardsCount(int count) {
|
||||
|
@ -1852,7 +1841,6 @@ void HistoryMessage::clearReplies() {
|
|||
void HistoryMessage::refreshRepliesText(
|
||||
not_null<HistoryMessageViews*> views,
|
||||
bool forceResize) {
|
||||
const auto was = views->replies.textWidth;
|
||||
if (views->commentsMegagroupId) {
|
||||
views->replies.text = (views->replies.count > 0)
|
||||
? tr::lng_comments_open_count(
|
||||
|
@ -1867,15 +1855,8 @@ void HistoryMessage::refreshRepliesText(
|
|||
: QString();
|
||||
views->repliesSmall.textWidth = st::semiboldFont->width(
|
||||
views->repliesSmall.text);
|
||||
} else {
|
||||
views->replies.text = (views->replies.count > 0)
|
||||
? Lang::FormatCountToShort(views->replies.count).string
|
||||
: QString();
|
||||
views->replies.textWidth = views->replies.text.isEmpty()
|
||||
? 0
|
||||
: st::msgDateFont->width(views->replies.text);
|
||||
}
|
||||
if (forceResize || views->replies.textWidth != was) {
|
||||
if (forceResize) {
|
||||
history()->owner().requestItemResize(this);
|
||||
} else {
|
||||
history()->owner().requestItemRepaint(this);
|
||||
|
|
|
@ -129,7 +129,7 @@ public:
|
|||
[[nodiscard]] bool allowsSendNow() const override;
|
||||
[[nodiscard]] bool allowsEdit(TimeId now) const override;
|
||||
|
||||
void setViewsCount(int count) override;
|
||||
bool changeViewsCount(int count) override;
|
||||
void setForwardsCount(int count) override;
|
||||
void setReplies(HistoryMessageRepliesData &&data) override;
|
||||
void clearReplies() override;
|
||||
|
@ -263,10 +263,7 @@ private:
|
|||
[[nodiscard]] bool checkRepliesPts(
|
||||
const HistoryMessageRepliesData &data) const;
|
||||
|
||||
QString _timeText;
|
||||
int _timeWidth = 0;
|
||||
|
||||
mutable int32 _fromNameVersion = 0;
|
||||
mutable int _fromNameVersion = 0;
|
||||
|
||||
friend class HistoryView::Element;
|
||||
friend class HistoryView::Message;
|
||||
|
|
|
@ -507,6 +507,13 @@ HistoryWidget::HistoryWidget(
|
|||
}
|
||||
}, lifetime());
|
||||
|
||||
session().data().itemDataChanges(
|
||||
) | rpl::filter([=](not_null<HistoryItem*> item) {
|
||||
return !_list && (item->mainView() != nullptr);
|
||||
}) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
|
||||
item->mainView()->itemDataChanged();
|
||||
}, lifetime());
|
||||
|
||||
Core::App().settings().largeEmojiChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
crl::on_main(this, [=] {
|
||||
|
|
303
Telegram/SourceFiles/history/view/history_view_bottom_info.cpp
Normal file
303
Telegram/SourceFiles/history/view/history_view_bottom_info.cpp
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
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_bottom_info.h"
|
||||
|
||||
#include "ui/chat/message_bubble.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_message.h"
|
||||
#include "history/view/history_view_message.h"
|
||||
#include "styles/style_chat.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
BottomInfo::BottomInfo(Data &&data) : _data(std::move(data)) {
|
||||
layout();
|
||||
}
|
||||
|
||||
void BottomInfo::update(Data &&data) {
|
||||
_data = std::move(data);
|
||||
layout();
|
||||
if (!_size.isEmpty()) {
|
||||
resizeToWidth(_size.width());
|
||||
}
|
||||
}
|
||||
|
||||
QSize BottomInfo::optimalSize() const {
|
||||
return _optimalSize;
|
||||
}
|
||||
|
||||
QSize BottomInfo::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
bool BottomInfo::pointInTime(QPoint position) const {
|
||||
return QRect(
|
||||
_size.width() - _dateWidth,
|
||||
0,
|
||||
_dateWidth,
|
||||
st::msgDateFont->height
|
||||
).contains(position);
|
||||
}
|
||||
|
||||
bool BottomInfo::isSignedAuthorElided() const {
|
||||
return _authorElided;
|
||||
}
|
||||
|
||||
void BottomInfo::paint(
|
||||
Painter &p,
|
||||
QPoint position,
|
||||
int outerWidth,
|
||||
bool unread,
|
||||
bool inverted,
|
||||
const PaintContext &context) const {
|
||||
const auto st = context.st;
|
||||
const auto sti = context.imageStyle();
|
||||
const auto stm = context.messageStyle();
|
||||
|
||||
auto right = position.x() + _size.width();
|
||||
const auto firstLineBottom = position.y() + st::msgDateFont->height;
|
||||
if (_data.flags & Data::Flag::OutLayout) {
|
||||
const auto &icon = (_data.flags & Data::Flag::Sending)
|
||||
? (inverted
|
||||
? st->historySendingInvertedIcon()
|
||||
: st->historySendingIcon())
|
||||
: unread
|
||||
? (inverted
|
||||
? st->historySentInvertedIcon()
|
||||
: stm->historySentIcon)
|
||||
: (inverted
|
||||
? st->historyReceivedInvertedIcon()
|
||||
: stm->historyReceivedIcon);
|
||||
icon.paint(
|
||||
p,
|
||||
QPoint(right, firstLineBottom) + st::historySendStatePosition,
|
||||
outerWidth);
|
||||
right -= st::historySendStateSpace;
|
||||
}
|
||||
|
||||
const auto authorEditedWidth = _authorEditedDate.maxWidth();
|
||||
right -= authorEditedWidth;
|
||||
_authorEditedDate.drawLeft(
|
||||
p,
|
||||
right,
|
||||
position.y(),
|
||||
authorEditedWidth,
|
||||
outerWidth);
|
||||
|
||||
if (!_views.isEmpty()) {
|
||||
const auto viewsWidth = _views.maxWidth();
|
||||
right -= st::historyViewsSpace + viewsWidth;
|
||||
_views.drawLeft(p, right, position.y(), viewsWidth, outerWidth);
|
||||
|
||||
const auto &icon = inverted
|
||||
? st->historyViewsInvertedIcon()
|
||||
: stm->historyViewsIcon;
|
||||
icon.paint(
|
||||
p,
|
||||
right - st::historyViewsWidth,
|
||||
firstLineBottom + st::historyViewsTop,
|
||||
outerWidth);
|
||||
}
|
||||
if (!_replies.isEmpty()) {
|
||||
const auto repliesWidth = _replies.maxWidth();
|
||||
right -= st::historyViewsSpace + repliesWidth;
|
||||
_replies.drawLeft(p, right, position.y(), repliesWidth, outerWidth);
|
||||
|
||||
const auto &icon = inverted
|
||||
? st->historyRepliesInvertedIcon()
|
||||
: stm->historyRepliesIcon;
|
||||
icon.paint(
|
||||
p,
|
||||
right - st::historyViewsWidth,
|
||||
firstLineBottom + st::historyViewsTop,
|
||||
outerWidth);
|
||||
}
|
||||
if ((_data.flags & Data::Flag::Sending)
|
||||
&& !(_data.flags & Data::Flag::OutLayout)) {
|
||||
right -= st::historySendStateSpace;
|
||||
const auto &icon = inverted
|
||||
? st->historyViewsSendingInvertedIcon()
|
||||
: st->historyViewsSendingIcon();
|
||||
icon.paint(
|
||||
p,
|
||||
right,
|
||||
firstLineBottom + st::historyViewsTop,
|
||||
outerWidth);
|
||||
}
|
||||
if (!_reactions.isEmpty()) {
|
||||
if (_size.height() == _optimalSize.height()) {
|
||||
_reactions.drawLeft(
|
||||
p,
|
||||
position.x(),
|
||||
position.y(),
|
||||
_reactions.maxWidth(),
|
||||
outerWidth);
|
||||
} else {
|
||||
const auto available = _size.width();
|
||||
const auto use = std::min(available, _reactions.maxWidth());
|
||||
_reactions.drawLeftElided(
|
||||
p,
|
||||
position.x() + _size.width() - use,
|
||||
position.y() + st::msgDateFont->height,
|
||||
use,
|
||||
outerWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BottomInfo::resizeToWidth(int newWidth) {
|
||||
if (newWidth >= _optimalSize.width()) {
|
||||
_size = _optimalSize;
|
||||
return _size.height();
|
||||
}
|
||||
return 2 * st::msgDateFont->height;
|
||||
}
|
||||
|
||||
void BottomInfo::layout() {
|
||||
layoutDateText();
|
||||
layoutViewsText();
|
||||
layoutReactionsText();
|
||||
countOptimalSize();
|
||||
}
|
||||
|
||||
void BottomInfo::layoutDateText() {
|
||||
const auto edited = (_data.flags & Data::Flag::Edited)
|
||||
? (tr::lng_edited(tr::now) + ' ')
|
||||
: QString();
|
||||
const auto author = _data.author;
|
||||
const auto prefix = author.isEmpty() ? qsl(", ") : QString();
|
||||
const auto date = _data.date.toString(cTimeFormat());
|
||||
_dateWidth = st::msgDateFont->width(date);
|
||||
const auto afterAuthor = prefix + edited + date;
|
||||
const auto afterAuthorWidth = st::msgDateFont->width(afterAuthor);
|
||||
const auto authorWidth = st::msgDateFont->width(author);
|
||||
const auto maxWidth = st::maxSignatureSize;
|
||||
_authorElided = !author.isEmpty()
|
||||
&& (authorWidth + afterAuthorWidth > maxWidth);
|
||||
const auto name = _authorElided
|
||||
? st::msgDateFont->elided(author, maxWidth - afterAuthorWidth)
|
||||
: author;
|
||||
const auto full = name + date;
|
||||
_authorEditedDate.setText(
|
||||
st::msgDateTextStyle,
|
||||
full,
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
void BottomInfo::layoutViewsText() {
|
||||
if (!_data.views || (_data.flags & Data::Flag::Sending)) {
|
||||
_views.clear();
|
||||
return;
|
||||
}
|
||||
_views.setText(
|
||||
st::msgDateTextStyle,
|
||||
Lang::FormatCountToShort(std::max(*_data.views, 1)).string,
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
void BottomInfo::layoutRepliesText() {
|
||||
if (!_data.replies
|
||||
|| !*_data.replies
|
||||
|| (_data.flags & Data::Flag::RepliesContext)
|
||||
|| (_data.flags & Data::Flag::Sending)) {
|
||||
_replies.clear();
|
||||
return;
|
||||
}
|
||||
_replies.setText(
|
||||
st::msgDateTextStyle,
|
||||
Lang::FormatCountToShort(*_data.replies).string,
|
||||
Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
void BottomInfo::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 fullCount = 0;
|
||||
auto text = QString();
|
||||
for (const auto &[string, count] : sorted) {
|
||||
text.append(string);
|
||||
fullCount += count;
|
||||
}
|
||||
text += QString::number(fullCount);
|
||||
|
||||
_reactions.setText(st::msgDateTextStyle, text, Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
void BottomInfo::countOptimalSize() {
|
||||
auto width = 0;
|
||||
if (_data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) {
|
||||
width += st::historySendStateSpace;
|
||||
}
|
||||
width += _authorEditedDate.maxWidth();
|
||||
if (!_views.isEmpty()) {
|
||||
width += st::historyViewsSpace
|
||||
+ _views.maxWidth()
|
||||
+ st::historyViewsWidth;
|
||||
}
|
||||
if (!_reactions.isEmpty()) {
|
||||
width += st::historyReactionsSkip + _reactions.maxWidth();
|
||||
}
|
||||
_optimalSize = QSize(width, st::msgDateFont->height);
|
||||
}
|
||||
|
||||
BottomInfo::Data BottomInfoDataFromMessage(not_null<Message*> message) {
|
||||
using Flag = BottomInfo::Data::Flag;
|
||||
|
||||
auto result = BottomInfo::Data();
|
||||
|
||||
const auto item = message->message();
|
||||
result.date = message->dateTime();
|
||||
result.reactions = item->reactions();
|
||||
if (message->hasOutLayout()) {
|
||||
result.flags |= Flag::OutLayout;
|
||||
}
|
||||
if (message->context() == Context::Replies) {
|
||||
result.flags |= Flag::RepliesContext;
|
||||
}
|
||||
if (const auto msgsigned = item->Get<HistoryMessageSigned>()) {
|
||||
if (!msgsigned->isAnonymousRank) {
|
||||
result.author = msgsigned->author;
|
||||
}
|
||||
}
|
||||
if (!item->hideEditedBadge()) {
|
||||
if (const auto edited = message->displayedEditBadge()) {
|
||||
result.flags |= Flag::Edited;
|
||||
}
|
||||
}
|
||||
if (const auto views = item->Get<HistoryMessageViews>()) {
|
||||
if (views->views.count >= 0) {
|
||||
result.views = views->views.count;
|
||||
}
|
||||
if (views->replies.count >= 0 && !views->commentsMegagroupId) {
|
||||
result.replies = views->replies.count;
|
||||
}
|
||||
}
|
||||
if (item->isSending() || item->hasFailed()) {
|
||||
result.flags |= Flag::Sending;
|
||||
}
|
||||
// We don't want to pass and update it in Date for now.
|
||||
//if (item->unread()) {
|
||||
// result.flags |= Flag::Unread;
|
||||
//}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
85
Telegram/SourceFiles/history/view/history_view_bottom_info.h
Normal file
85
Telegram/SourceFiles/history/view/history_view_bottom_info.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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 "ui/text/text.h"
|
||||
#include "base/flags.h"
|
||||
|
||||
namespace Ui {
|
||||
struct ChatPaintContext;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
using PaintContext = Ui::ChatPaintContext;
|
||||
|
||||
class Message;
|
||||
|
||||
class BottomInfo {
|
||||
public:
|
||||
struct Data {
|
||||
enum class Flag {
|
||||
Edited = 0x01,
|
||||
OutLayout = 0x02,
|
||||
Sending = 0x04,
|
||||
RepliesContext = 0x08,
|
||||
//Unread, // We don't want to pass and update it in Date for now.
|
||||
};
|
||||
friend inline constexpr bool is_flag_type(Flag) { return true; };
|
||||
using Flags = base::flags<Flag>;
|
||||
|
||||
QDateTime date;
|
||||
QString author;
|
||||
base::flat_map<QString, int> reactions;
|
||||
std::optional<int> views;
|
||||
std::optional<int> replies;
|
||||
Flags flags;
|
||||
};
|
||||
explicit BottomInfo(Data &&data);
|
||||
|
||||
void update(Data &&data);
|
||||
|
||||
[[nodiscard]] QSize optimalSize() const;
|
||||
[[nodiscard]] QSize size() const;
|
||||
[[nodiscard]] bool pointInTime(QPoint position) const;
|
||||
[[nodiscard]] bool isSignedAuthorElided() const;
|
||||
|
||||
void paint(
|
||||
Painter &p,
|
||||
QPoint position,
|
||||
int outerWidth,
|
||||
bool unread,
|
||||
bool inverted,
|
||||
const PaintContext &context) const;
|
||||
|
||||
int resizeToWidth(int newWidth);
|
||||
|
||||
private:
|
||||
void layout();
|
||||
void layoutDateText();
|
||||
void layoutViewsText();
|
||||
void layoutRepliesText();
|
||||
void layoutReactionsText();
|
||||
void countOptimalSize();
|
||||
|
||||
Data _data;
|
||||
QSize _optimalSize;
|
||||
QSize _size;
|
||||
Ui::Text::String _authorEditedDate;
|
||||
Ui::Text::String _views;
|
||||
Ui::Text::String _replies;
|
||||
Ui::Text::String _reactions;
|
||||
int _dateWidth = 0;
|
||||
bool _authorElided = false;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] BottomInfo::Data BottomInfoDataFromMessage(
|
||||
not_null<Message*> message);
|
||||
|
||||
} // namespace HistoryView
|
|
@ -231,8 +231,8 @@ QString DateTooltipText(not_null<Element*> view) {
|
|||
+ "\n\n" + dateText;
|
||||
}
|
||||
}
|
||||
if (view->isSignedAuthorElided()) {
|
||||
if (const auto msgsigned = view->data()->Get<HistoryMessageSigned>()) {
|
||||
if (msgsigned->isElided && !msgsigned->isAnonymousRank) {
|
||||
dateText += '\n'
|
||||
+ tr::lng_signed_author(tr::now, lt_user, msgsigned->author);
|
||||
}
|
||||
|
@ -841,6 +841,13 @@ void Element::checkHeavyPart() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Element::isSignedAuthorElided() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Element::itemDataChanged() {
|
||||
}
|
||||
|
||||
void Element::unloadHeavyPart() {
|
||||
history()->owner().unregisterHeavyViewPart(this);
|
||||
if (_media) {
|
||||
|
|
|
@ -318,31 +318,31 @@ public:
|
|||
|
||||
// hasFromPhoto() returns true even if we don't display the photo
|
||||
// but we need to skip a place at the left side for this photo
|
||||
virtual bool hasFromPhoto() const;
|
||||
virtual bool displayFromPhoto() const;
|
||||
virtual bool hasFromName() const;
|
||||
virtual bool displayFromName() const;
|
||||
virtual bool displayForwardedFrom() const;
|
||||
virtual bool hasOutLayout() const;
|
||||
virtual bool drawBubble() const;
|
||||
virtual bool hasBubble() const;
|
||||
virtual int minWidthForMedia() const {
|
||||
[[nodiscard]] virtual bool hasFromPhoto() const;
|
||||
[[nodiscard]] virtual bool displayFromPhoto() const;
|
||||
[[nodiscard]] virtual bool hasFromName() const;
|
||||
[[nodiscard]] virtual bool displayFromName() const;
|
||||
[[nodiscard]] virtual bool displayForwardedFrom() const;
|
||||
[[nodiscard]] virtual bool hasOutLayout() const;
|
||||
[[nodiscard]] virtual bool drawBubble() const;
|
||||
[[nodiscard]] virtual bool hasBubble() const;
|
||||
[[nodiscard]] virtual int minWidthForMedia() const {
|
||||
return 0;
|
||||
}
|
||||
virtual bool hasFastReply() const;
|
||||
virtual bool displayFastReply() const;
|
||||
virtual std::optional<QSize> rightActionSize() const;
|
||||
[[nodiscard]] virtual bool hasFastReply() const;
|
||||
[[nodiscard]] virtual bool displayFastReply() const;
|
||||
[[nodiscard]] virtual std::optional<QSize> rightActionSize() const;
|
||||
virtual void drawRightAction(
|
||||
Painter &p,
|
||||
const PaintContext &context,
|
||||
int left,
|
||||
int top,
|
||||
int outerWidth) const;
|
||||
virtual ClickHandlerPtr rightActionLink() const;
|
||||
virtual bool displayEditedBadge() const;
|
||||
virtual TimeId displayedEditDate() const;
|
||||
virtual bool hasVisibleText() const;
|
||||
virtual HistoryMessageReply *displayedReply() const;
|
||||
[[nodiscard]] virtual ClickHandlerPtr rightActionLink() const;
|
||||
[[nodiscard]] virtual bool displayEditedBadge() const;
|
||||
[[nodiscard]] virtual TimeId displayedEditDate() const;
|
||||
[[nodiscard]] virtual bool hasVisibleText() const;
|
||||
[[nodiscard]] virtual HistoryMessageReply *displayedReply() const;
|
||||
virtual void applyGroupAdminChanges(
|
||||
const base::flat_set<UserId> &changes) {
|
||||
}
|
||||
|
@ -355,6 +355,10 @@ public:
|
|||
};
|
||||
[[nodiscard]] virtual VerticalRepaintRange verticalRepaintRange() const;
|
||||
|
||||
[[nodiscard]] virtual bool isSignedAuthorElided() const;
|
||||
|
||||
virtual void itemDataChanged();
|
||||
|
||||
virtual bool hasHeavyPart() const;
|
||||
virtual void unloadHeavyPart();
|
||||
void checkHeavyPart();
|
||||
|
|
|
@ -294,6 +294,12 @@ ListWidget::ListWidget(
|
|||
}
|
||||
}
|
||||
}, lifetime());
|
||||
session().data().itemDataChanges(
|
||||
) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
|
||||
if (const auto view = viewForItem(item)) {
|
||||
view->itemDataChanged();
|
||||
}
|
||||
}, lifetime());
|
||||
session().data().animationPlayInlineRequest(
|
||||
) | rpl::start_with_next([this](auto item) {
|
||||
if (const auto view = viewForItem(item)) {
|
||||
|
|
|
@ -237,30 +237,12 @@ LogEntryOriginal &LogEntryOriginal::operator=(LogEntryOriginal &&other) {
|
|||
|
||||
LogEntryOriginal::~LogEntryOriginal() = default;
|
||||
|
||||
void Reactions::update(const base::flat_map<QString, int> &list) {
|
||||
auto sorted = ranges::view::all(
|
||||
list
|
||||
) | 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 fullCount = 0;
|
||||
auto composed = QString();
|
||||
for (const auto &[string, count] : sorted) {
|
||||
composed.append(string);
|
||||
fullCount += count;
|
||||
}
|
||||
composed += QString::number(fullCount);
|
||||
|
||||
text.setText(st::msgDateTextStyle, composed, Ui::NameTextOptions());
|
||||
}
|
||||
|
||||
Message::Message(
|
||||
not_null<ElementDelegate*> delegate,
|
||||
not_null<HistoryMessage*> data,
|
||||
Element *replacing)
|
||||
: Element(delegate, data, replacing) {
|
||||
: Element(delegate, data, replacing)
|
||||
, _bottomInfo(BottomInfoDataFromMessage(this)) {
|
||||
initLogEntryOriginal();
|
||||
initPsa();
|
||||
}
|
||||
|
@ -334,16 +316,8 @@ QSize Message::performCountOptimalSize() {
|
|||
|
||||
updateViewButtonExistence();
|
||||
updateMediaInBubbleState();
|
||||
refreshEditedBadge();
|
||||
refreshRightBadge();
|
||||
|
||||
if (const auto list = item->reactions(); !list.empty()) {
|
||||
AddComponents(Reactions::Bit());
|
||||
const auto reactions = Get<Reactions>();
|
||||
reactions->update(list);
|
||||
} else {
|
||||
RemoveComponents(Reactions::Bit());
|
||||
}
|
||||
initTime();
|
||||
|
||||
if (drawBubble()) {
|
||||
const auto forwarded = item->Get<HistoryMessageForwarded>();
|
||||
|
@ -1776,111 +1750,25 @@ void Message::drawInfo(
|
|||
break;
|
||||
}
|
||||
|
||||
const auto item = message();
|
||||
auto infoW = infoWidth();
|
||||
if (rtl()) infoRight = width - infoRight + infoW;
|
||||
|
||||
auto dateX = infoRight - infoW;
|
||||
auto dateY = infoBottom - st::msgDateFont->height;
|
||||
const auto size = _bottomInfo.size();
|
||||
const auto dateX = infoRight - size.width();
|
||||
const auto dateY = infoBottom - size.height();
|
||||
if (type == InfoDisplayType::Image) {
|
||||
auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y();
|
||||
const auto dateW = size.width() + 2 * st::msgDateImgPadding.x();
|
||||
const auto dateH = size.height() + 2 * st::msgDateImgPadding.y();
|
||||
Ui::FillRoundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, sti->msgDateImgBg, sti->msgDateImgBgCorners);
|
||||
} else if (type == InfoDisplayType::Background) {
|
||||
auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y();
|
||||
const auto dateW = size.width() + 2 * st::msgDateImgPadding.x();
|
||||
const auto dateH = size.height() + 2 * st::msgDateImgPadding.y();
|
||||
Ui::FillRoundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, sti->msgServiceBg, sti->msgServiceBgCorners);
|
||||
}
|
||||
dateX += timeLeft();
|
||||
|
||||
if (const auto msgsigned = item->Get<HistoryMessageSigned>()
|
||||
; msgsigned && !msgsigned->isAnonymousRank) {
|
||||
msgsigned->signature.drawElided(p, dateX, dateY, item->_timeWidth);
|
||||
} else if (const auto sponsored = displayedSponsorBadge()) {
|
||||
const auto skipY = viewButtonHeight();
|
||||
sponsored->text.drawElided(p, dateX, dateY - skipY, item->_timeWidth);
|
||||
} else if (const auto edited = displayedEditBadge()) {
|
||||
edited->text.drawElided(p, dateX, dateY, item->_timeWidth);
|
||||
} else {
|
||||
p.drawText(dateX, dateY + st::msgDateFont->ascent, item->_timeText);
|
||||
}
|
||||
|
||||
const auto viewIconTop = infoBottom + st::historyViewsTop;
|
||||
const auto pinIconTop = infoBottom + st::historyPinTop;
|
||||
auto left = infoRight - infoW;
|
||||
if (const auto reactions = Get<Reactions>()) {
|
||||
reactions->text.draw(p, left, dateY, reactions->text.maxWidth());
|
||||
left += reactions->text.maxWidth() + st::historyReactionsSkip;
|
||||
}
|
||||
if (const auto views = item->Get<HistoryMessageViews>()) {
|
||||
const auto textTop = infoBottom - st::msgDateFont->descent;
|
||||
if (views->replies.count > 0
|
||||
&& !views->commentsMegagroupId
|
||||
&& this->context() != Context::Replies) {
|
||||
const auto &icon = (!item->isSending() && !item->hasFailed())
|
||||
? (invertedsprites
|
||||
? st->historyRepliesInvertedIcon()
|
||||
: stm->historyRepliesIcon)
|
||||
: (invertedsprites
|
||||
? st->historyViewsSendingInvertedIcon()
|
||||
: st->historyViewsSendingIcon());
|
||||
if (!item->isSending() && !item->hasFailed()) {
|
||||
icon.paint(p, left, viewIconTop, width);
|
||||
p.drawText(left + st::historyViewsWidth, textTop, views->replies.text);
|
||||
} else if (!context.outbg && views->views.count < 0) { // sending outbg icon will be painted below
|
||||
auto iconSkip = st::historyViewsSpace + views->replies.textWidth;
|
||||
icon.paint(p, left + iconSkip, viewIconTop, width);
|
||||
}
|
||||
left += st::historyViewsSpace
|
||||
+ views->replies.textWidth
|
||||
+ st::historyViewsWidth;
|
||||
}
|
||||
if (views->views.count >= 0) {
|
||||
const auto &icon = (!item->isSending() && !item->hasFailed())
|
||||
? (invertedsprites
|
||||
? st->historyViewsInvertedIcon()
|
||||
: stm->historyViewsIcon)
|
||||
: (invertedsprites
|
||||
? st->historyViewsSendingInvertedIcon()
|
||||
: st->historyViewsSendingIcon());
|
||||
if (!item->isSending() && !item->hasFailed()) {
|
||||
icon.paint(p, left, viewIconTop, width);
|
||||
p.drawText(left + st::historyViewsWidth, textTop, views->views.text);
|
||||
} else if (!context.outbg) { // sending outbg icon will be painted below
|
||||
auto iconSkip = st::historyViewsSpace + views->views.textWidth;
|
||||
icon.paint(p, left + iconSkip, viewIconTop, width);
|
||||
}
|
||||
left += st::historyViewsSpace
|
||||
+ views->views.textWidth
|
||||
+ st::historyViewsWidth;
|
||||
}
|
||||
} else if ((item->isSending() || item->hasFailed())
|
||||
&& item->history()->peer->isSelf()
|
||||
&& !context.outbg) {
|
||||
const auto &icon = invertedsprites
|
||||
? st->historyViewsSendingInvertedIcon()
|
||||
: st->historyViewsSendingIcon();
|
||||
icon.paint(p, left, viewIconTop, width);
|
||||
}
|
||||
if (displayPinIcon()) {
|
||||
const auto &icon = invertedsprites
|
||||
? st->historyPinInvertedIcon()
|
||||
: stm->historyPinIcon;
|
||||
icon.paint(p, left, pinIconTop, width);
|
||||
left += st::historyPinWidth;
|
||||
}
|
||||
if (context.outbg) {
|
||||
const auto &icon = (item->isSending() || item->hasFailed())
|
||||
? (invertedsprites
|
||||
? st->historySendingInvertedIcon()
|
||||
: st->historySendingIcon())
|
||||
: delegate()->elementShownUnread(this)
|
||||
? (invertedsprites
|
||||
? st->historySentInvertedIcon()
|
||||
: stm->historySentIcon)
|
||||
: (invertedsprites
|
||||
? st->historyReceivedInvertedIcon()
|
||||
: stm->historyReceivedIcon);
|
||||
icon.paint(p, QPoint(infoRight, infoBottom) + st::historySendStatePosition, width);
|
||||
}
|
||||
_bottomInfo.paint(
|
||||
p,
|
||||
{ dateX, dateY },
|
||||
width,
|
||||
delegate()->elementShownUnread(this),
|
||||
invertedsprites,
|
||||
context);
|
||||
}
|
||||
|
||||
bool Message::pointInTime(
|
||||
|
@ -1904,53 +1792,28 @@ bool Message::pointInTime(
|
|||
infoBottom -= st::msgDateImgPadding.y();
|
||||
break;
|
||||
}
|
||||
const auto item = message();
|
||||
auto dateX = infoRight - infoWidth() + timeLeft();
|
||||
auto dateY = infoBottom - st::msgDateFont->height;
|
||||
return QRect(
|
||||
dateX,
|
||||
dateY,
|
||||
item->_timeWidth,
|
||||
st::msgDateFont->height).contains(point);
|
||||
const auto size = _bottomInfo.size();
|
||||
const auto infoLeft = infoRight - size.width();
|
||||
const auto infoTop = infoBottom - size.height();
|
||||
return _bottomInfo.pointInTime({ infoLeft, infoTop });
|
||||
}
|
||||
|
||||
int Message::infoWidth() const {
|
||||
const auto item = message();
|
||||
auto result = item->_timeWidth;
|
||||
if (const auto views = item->Get<HistoryMessageViews>()) {
|
||||
if (views->views.count >= 0) {
|
||||
result += st::historyViewsSpace
|
||||
+ views->views.textWidth
|
||||
+ st::historyViewsWidth;
|
||||
}
|
||||
if (views->replies.count > 0
|
||||
&& !views->commentsMegagroupId
|
||||
&& context() != Context::Replies) {
|
||||
result += st::historyViewsSpace
|
||||
+ views->replies.textWidth
|
||||
+ st::historyViewsWidth;
|
||||
}
|
||||
} else if ((item->isSending() || item->hasFailed())
|
||||
&& item->history()->peer->isSelf()) {
|
||||
if (!hasOutLayout()) {
|
||||
result += st::historySendStateSpace;
|
||||
}
|
||||
}
|
||||
if (displayPinIcon()) {
|
||||
result += st::historyPinWidth;
|
||||
return _bottomInfo.optimalSize().width();
|
||||
}
|
||||
|
||||
// When message is scheduled until online, time is not displayed,
|
||||
// so message should have less space.
|
||||
if (!item->_timeWidth) {
|
||||
result += st::historyScheduledUntilOnlineStateSpace;
|
||||
} else if (hasOutLayout()) {
|
||||
result += st::historySendStateSpace;
|
||||
bool Message::isSignedAuthorElided() const {
|
||||
return _bottomInfo.isSignedAuthorElided();
|
||||
}
|
||||
if (const auto reactions = Get<Reactions>()) {
|
||||
result += st::historyReactionsSkip + reactions->text.maxWidth();
|
||||
|
||||
void Message::itemDataChanged() {
|
||||
const auto was = _bottomInfo.size();
|
||||
_bottomInfo.update(BottomInfoDataFromMessage(this));
|
||||
if (was != _bottomInfo.size()) {
|
||||
history()->owner().requestViewResize(this);
|
||||
} else {
|
||||
history()->owner().requestViewRepaint(this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Message::verticalRepaintRange() const -> VerticalRepaintRange {
|
||||
|
@ -1974,34 +1837,6 @@ void Message::refreshDataIdHook() {
|
|||
}
|
||||
}
|
||||
|
||||
int Message::timeLeft() const {
|
||||
const auto item = message();
|
||||
auto result = 0;
|
||||
if (auto views = item->Get<HistoryMessageViews>()) {
|
||||
if (views->views.count >= 0) {
|
||||
result += st::historyViewsSpace + views->views.textWidth + st::historyViewsWidth;
|
||||
}
|
||||
if (views->replies.count > 0
|
||||
&& !views->commentsMegagroupId
|
||||
&& context() != Context::Replies) {
|
||||
result += st::historyViewsSpace + views->replies.textWidth + st::historyViewsWidth;
|
||||
}
|
||||
} else if ((item->isSending() || item->hasFailed())
|
||||
&& item->history()->peer->isSelf()) {
|
||||
if (!hasOutLayout()) {
|
||||
result += st::historySendStateSpace;
|
||||
}
|
||||
}
|
||||
if (displayPinIcon()) {
|
||||
result += st::historyPinWidth;
|
||||
}
|
||||
|
||||
if (const auto reactions = Get<Reactions>()) {
|
||||
result += st::historyReactionsSkip + reactions->text.maxWidth();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Message::plainMaxWidth() const {
|
||||
return st::msgPadding.left()
|
||||
+ (hasVisibleText() ? message()->_text.maxWidth() : 0)
|
||||
|
@ -2629,6 +2464,8 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
}
|
||||
}
|
||||
}
|
||||
_bottomInfo.resizeToWidth(
|
||||
std::min(_bottomInfo.optimalSize().width(), contentWidth));
|
||||
|
||||
if (bubble) {
|
||||
auto reply = displayedReply();
|
||||
|
@ -2733,46 +2570,8 @@ QSize Message::performCountCurrentSize(int newWidth) {
|
|||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
void Message::refreshEditedBadge() {
|
||||
const auto item = message();
|
||||
const auto edited = displayedEditBadge();
|
||||
const auto editDate = displayedEditDate();
|
||||
const auto dateText = dateTime().toString(cTimeFormat());
|
||||
if (edited) {
|
||||
edited->refresh(dateText, editDate != 0);
|
||||
}
|
||||
if (const auto msgsigned = item->Get<HistoryMessageSigned>()) {
|
||||
if (!msgsigned->isAnonymousRank) {
|
||||
const auto text = (!edited || !editDate)
|
||||
? dateText
|
||||
: edited->text.toString();
|
||||
msgsigned->refresh(text);
|
||||
}
|
||||
}
|
||||
initTime();
|
||||
}
|
||||
|
||||
void Message::initTime() const {
|
||||
const auto item = message();
|
||||
if (const auto msgsigned = item->Get<HistoryMessageSigned>()
|
||||
; msgsigned && !msgsigned->isAnonymousRank) {
|
||||
item->_timeWidth = msgsigned->maxWidth();
|
||||
} else if (const auto sponsored = displayedSponsorBadge()) {
|
||||
item->_timeWidth = sponsored->maxWidth();
|
||||
} else if (const auto edited = displayedEditBadge()) {
|
||||
item->_timeWidth = edited->maxWidth();
|
||||
} else {
|
||||
const auto forwarded = item->Get<HistoryMessageForwarded>();
|
||||
if (forwarded && forwarded->imported) {
|
||||
const auto date = base::unixtime::parse(forwarded->originalDate);
|
||||
item->_timeText = date.toString(
|
||||
cDateFormat() + u", "_q + cTimeFormat() + ' '
|
||||
) + tr::lng_imported(tr::now);
|
||||
} else {
|
||||
item->_timeText = dateTime().toString(cTimeFormat());
|
||||
}
|
||||
item->_timeWidth = st::msgDateFont->width(item->_timeText);
|
||||
}
|
||||
if (item->_text.hasSkipBlock()) {
|
||||
if (item->_text.updateSkipBlock(skipBlockWidth(), skipBlockHeight())) {
|
||||
item->_textWidth = -1;
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_bottom_info.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "base/weak_ptr.h"
|
||||
|
||||
|
@ -39,12 +40,6 @@ struct PsaTooltipState : public RuntimeComponent<PsaTooltipState, Element> {
|
|||
mutable bool buttonVisible = true;
|
||||
};
|
||||
|
||||
struct Reactions : public RuntimeComponent<Reactions, Element> {
|
||||
void update(const base::flat_map<QString, int> &list);
|
||||
|
||||
Ui::Text::String text;
|
||||
};
|
||||
|
||||
class Message : public Element, public base::has_weak_ptr {
|
||||
public:
|
||||
Message(
|
||||
|
@ -57,6 +52,11 @@ public:
|
|||
const ClickHandlerPtr &handler,
|
||||
bool pressed) override;
|
||||
|
||||
not_null<HistoryMessage*> message() const;
|
||||
|
||||
const HistoryMessageEdited *displayedEditBadge() const;
|
||||
HistoryMessageEdited *displayedEditBadge();
|
||||
|
||||
int marginTop() const override;
|
||||
int marginBottom() const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
|
@ -113,6 +113,9 @@ public:
|
|||
bool toggleSelectionByHandlerClick(
|
||||
const ClickHandlerPtr &handler) const override;
|
||||
int infoWidth() const override;
|
||||
bool isSignedAuthorElided() const override;
|
||||
|
||||
void itemDataChanged() override;
|
||||
|
||||
VerticalRepaintRange verticalRepaintRange() const override;
|
||||
|
||||
|
@ -125,11 +128,8 @@ protected:
|
|||
private:
|
||||
struct CommentsButton;
|
||||
|
||||
not_null<HistoryMessage*> message() const;
|
||||
|
||||
void initLogEntryOriginal();
|
||||
void initPsa();
|
||||
void refreshEditedBadge();
|
||||
void fromNameUpdated(int width) const;
|
||||
|
||||
[[nodiscard]] bool showForwardsFromSender(
|
||||
|
@ -208,14 +208,11 @@ private:
|
|||
[[nodiscard]] bool displayFastShare() const;
|
||||
[[nodiscard]] bool displayGoToOriginal() const;
|
||||
[[nodiscard]] ClickHandlerPtr fastReplyLink() const;
|
||||
[[nodiscard]] const HistoryMessageEdited *displayedEditBadge() const;
|
||||
[[nodiscard]] HistoryMessageEdited *displayedEditBadge();
|
||||
[[nodiscard]] auto displayedSponsorBadge() const
|
||||
-> const HistoryMessageSponsored*;
|
||||
[[nodiscard]] bool displayPinIcon() const;
|
||||
|
||||
void initTime() const;
|
||||
[[nodiscard]] int timeLeft() const;
|
||||
[[nodiscard]] int plainMaxWidth() const;
|
||||
[[nodiscard]] int monospaceMaxWidth() const;
|
||||
|
||||
|
@ -238,6 +235,8 @@ private:
|
|||
Ui::Text::String _rightBadge;
|
||||
int _bubbleWidthLimit = 0;
|
||||
|
||||
BottomInfo _bottomInfo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -154,7 +154,10 @@ QSize Gif::countOptimalSize() {
|
|||
}
|
||||
_thumbw = tw;
|
||||
_thumbh = th;
|
||||
auto maxWidth = qMax(tw, st::minPhotoSize);
|
||||
auto maxWidth = std::clamp(
|
||||
std::max(tw, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())),
|
||||
st::minPhotoSize,
|
||||
maxSize);
|
||||
auto minHeight = qMax(th, st::minPhotoSize);
|
||||
if (!activeCurrentStreamed()) {
|
||||
accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()));
|
||||
|
@ -211,7 +214,10 @@ QSize Gif::countCurrentSize(int newWidth) {
|
|||
_thumbw = tw;
|
||||
_thumbh = th;
|
||||
|
||||
newWidth = qMax(tw, st::minPhotoSize);
|
||||
newWidth = std::clamp(
|
||||
std::max(tw, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())),
|
||||
st::minPhotoSize,
|
||||
maxSize);
|
||||
auto newHeight = qMax(th, st::minPhotoSize);
|
||||
if (!activeCurrentStreamed()) {
|
||||
accumulate_max(newWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()));
|
||||
|
|
|
@ -82,7 +82,10 @@ QSize Location::countOptimalSize() {
|
|||
th = (st::maxMediaSize * th) / tw;
|
||||
tw = st::maxMediaSize;
|
||||
}
|
||||
auto minWidth = qMax(st::minPhotoSize, _parent->minWidthForMedia());
|
||||
auto minWidth = std::clamp(
|
||||
_parent->minWidthForMedia(),
|
||||
st::minPhotoSize,
|
||||
st::maxMediaSize);
|
||||
auto maxWidth = qMax(tw, minWidth);
|
||||
auto minHeight = qMax(th, st::minPhotoSize);
|
||||
|
||||
|
@ -118,7 +121,10 @@ QSize Location::countCurrentSize(int newWidth) {
|
|||
} else {
|
||||
newWidth = tw;
|
||||
}
|
||||
auto minWidth = qMax(st::minPhotoSize, _parent->minWidthForMedia());
|
||||
auto minWidth = std::clamp(
|
||||
_parent->minWidthForMedia(),
|
||||
st::minPhotoSize,
|
||||
st::maxMediaSize);
|
||||
accumulate_max(newWidth, minWidth);
|
||||
accumulate_max(newHeight, st::minPhotoSize);
|
||||
if (_parent->hasBubble()) {
|
||||
|
|
|
@ -408,19 +408,19 @@ int UnwrappedMedia::calculateFullRight(const QRect &inner) const {
|
|||
+ st::msgDateImgPadding.x() * 2
|
||||
+ st::msgReplyPadding.left();
|
||||
const auto rightActionSize = _parent->rightActionSize();
|
||||
const auto rightActionWidth = rightActionSize
|
||||
? (st::historyFastShareLeft * 2
|
||||
+ rightActionSize->width()
|
||||
+ st::msgPadding.left()
|
||||
const auto rightSkip = st::msgPadding.left()
|
||||
+ (_parent->hasFromPhoto()
|
||||
? st::msgMargin.right()
|
||||
: st::msgPadding.right()))
|
||||
: st::msgPadding.right());
|
||||
const auto rightActionWidth = rightActionSize
|
||||
? (st::historyFastShareLeft * 2
|
||||
+ rightActionSize->width())
|
||||
: 0;
|
||||
auto fullRight = inner.x()
|
||||
+ inner.width()
|
||||
+ (rightAligned ? 0 : infoWidth);
|
||||
if (fullRight + rightActionWidth > _parent->width()) {
|
||||
fullRight = _parent->width() - rightActionWidth;
|
||||
if (fullRight + rightActionWidth + rightSkip > _parent->width()) {
|
||||
fullRight = _parent->width() - rightActionWidth - rightSkip;
|
||||
}
|
||||
return fullRight;
|
||||
}
|
||||
|
|
|
@ -164,9 +164,10 @@ QSize Photo::countOptimalSize() {
|
|||
if (_serviceWidth > 0) {
|
||||
return { _serviceWidth, _serviceWidth };
|
||||
}
|
||||
const auto minWidth = qMax(
|
||||
const auto minWidth = std::clamp(
|
||||
_parent->minWidthForMedia(),
|
||||
(_parent->hasBubble() ? st::historyPhotoBubbleMinWidth : st::minPhotoSize),
|
||||
_parent->minWidthForMedia());
|
||||
st::maxMediaSize);
|
||||
const auto maxActualWidth = qMax(tw, minWidth);
|
||||
maxWidth = qMax(maxActualWidth, th);
|
||||
minHeight = qMax(th, st::minPhotoSize);
|
||||
|
@ -206,9 +207,10 @@ QSize Photo::countCurrentSize(int newWidth) {
|
|||
if (_pixw < 1) _pixw = 1;
|
||||
if (_pixh < 1) _pixh = 1;
|
||||
|
||||
auto minWidth = qMax(
|
||||
const auto minWidth = std::clamp(
|
||||
_parent->minWidthForMedia(),
|
||||
(_parent->hasBubble() ? st::historyPhotoBubbleMinWidth : st::minPhotoSize),
|
||||
_parent->minWidthForMedia());
|
||||
st::maxMediaSize);
|
||||
newWidth = qMax(_pixw, minWidth);
|
||||
auto newHeight = qMax(_pixh, st::minPhotoSize);
|
||||
if (_parent->hasBubble() && !_caption.isEmpty()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue