mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 06:35:14 +00:00
Better channel log entry layout inside messages.
Also move HistoryService class to a separate module.
This commit is contained in:
@@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "history/history_location_manager.h"
|
||||
#include "history/history_service_layout.h"
|
||||
#include "history/history_media_types.h"
|
||||
#include "history/history_service.h"
|
||||
#include "auth_session.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_widgets.h"
|
||||
@@ -37,26 +38,11 @@ namespace {
|
||||
|
||||
constexpr auto kPinnedMessageTextLimit = 16;
|
||||
|
||||
TextParseOptions _historySrvOptions = {
|
||||
TextParseLinks | TextParseMentions | TextParseHashtags/* | TextParseMultiline*/ | TextParseRichText, // flags
|
||||
0, // maxw
|
||||
0, // maxh
|
||||
Qt::LayoutDirectionAuto, // lang-dependent
|
||||
};
|
||||
|
||||
inline void initTextOptions() {
|
||||
_historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir();
|
||||
_textDlgOptions.maxw = st::dialogsWidthMax * 2;
|
||||
}
|
||||
|
||||
ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) {
|
||||
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
|
||||
if (auto item = App::histItemById(dependent)) {
|
||||
item->updateDependencyItem();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
style::color fromNameFg(int index) {
|
||||
Expects(index >= 0 && index < 8);
|
||||
style::color colors[] = {
|
||||
@@ -87,8 +73,8 @@ style::color fromNameFgSelected(int index) {
|
||||
return colors[index];
|
||||
}
|
||||
|
||||
MTPDmessage::Flags newForwardedFlags(PeerData *peer, int32 from, HistoryMessage *fwd) {
|
||||
auto result = newMessageFlags(peer) | MTPDmessage::Flag::f_fwd_from;
|
||||
MTPDmessage::Flags NewForwardedFlags(gsl::not_null<PeerData*> peer, int32 from, gsl::not_null<HistoryMessage*> fwd) {
|
||||
auto result = NewMessageFlags(peer) | MTPDmessage::Flag::f_fwd_from;
|
||||
if (from) {
|
||||
result |= MTPDmessage::Flag::f_from_id;
|
||||
}
|
||||
@@ -121,7 +107,26 @@ MTPDmessage::Flags newForwardedFlags(PeerData *peer, int32 from, HistoryMessage
|
||||
|
||||
} // namespace
|
||||
|
||||
void historyInitMessages() {
|
||||
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId) {
|
||||
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
|
||||
if (auto item = App::histItemById(dependent)) {
|
||||
item->updateDependencyItem();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
MTPDmessage::Flags NewMessageFlags(gsl::not_null<PeerData*> peer) {
|
||||
MTPDmessage::Flags result = 0;
|
||||
if (!peer->isSelf()) {
|
||||
result |= MTPDmessage::Flag::f_out;
|
||||
//if (p->isChat() || (p->isUser() && !p->asUser()->botInfo)) {
|
||||
// result |= MTPDmessage::Flag::f_unread;
|
||||
//}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HistoryInitMessages() {
|
||||
initTextOptions();
|
||||
}
|
||||
|
||||
@@ -451,8 +456,8 @@ HistoryMessage::HistoryMessage(gsl::not_null<History*> history, const MTPDmessag
|
||||
setText(TextWithEntities {});
|
||||
}
|
||||
|
||||
HistoryMessage::HistoryMessage(gsl::not_null<History*> history, MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *fwd)
|
||||
: HistoryItem(history, id, newForwardedFlags(history->peer, from, fwd) | flags, date, from) {
|
||||
HistoryMessage::HistoryMessage(gsl::not_null<History*> history, MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, gsl::not_null<HistoryMessage*> fwd)
|
||||
: HistoryItem(history, id, NewForwardedFlags(history->peer, from, fwd) | flags, date, from) {
|
||||
CreateConfig config;
|
||||
|
||||
if (fwd->Has<HistoryMessageForwarded>() || !fwd->history()->peer->isSelf()) {
|
||||
@@ -596,6 +601,10 @@ bool HistoryMessage::displayEditedBadge(bool hasViaBotOrInlineMarkup) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HistoryMessage::uploading() const {
|
||||
return _media && _media->uploading();
|
||||
}
|
||||
|
||||
void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||
uint64 mask = 0;
|
||||
if (config.replyTo) {
|
||||
@@ -638,7 +647,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||
if (auto reply = Get<HistoryMessageReply>()) {
|
||||
reply->replyToMsgId = config.replyTo;
|
||||
if (!reply->updateData(this) && App::api()) {
|
||||
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId()));
|
||||
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, HistoryDependentItemCallback(fullId()));
|
||||
}
|
||||
}
|
||||
if (auto via = Get<HistoryMessageVia>()) {
|
||||
@@ -793,71 +802,84 @@ int32 HistoryMessage::plainMaxWidth() const {
|
||||
}
|
||||
|
||||
void HistoryMessage::initDimensions() {
|
||||
auto reply = Get<HistoryMessageReply>();
|
||||
if (reply) {
|
||||
reply->updateName();
|
||||
}
|
||||
|
||||
updateMediaInBubbleState();
|
||||
if (drawBubble()) {
|
||||
auto forwarded = Get<HistoryMessageForwarded>();
|
||||
auto reply = Get<HistoryMessageReply>();
|
||||
auto via = Get<HistoryMessageVia>();
|
||||
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
||||
if (forwarded) {
|
||||
forwarded->create(via);
|
||||
}
|
||||
if (reply) {
|
||||
reply->updateName();
|
||||
}
|
||||
|
||||
auto mediaDisplayed = false;
|
||||
if (_media) {
|
||||
mediaDisplayed = _media->isDisplayed();
|
||||
_media->initDimensions();
|
||||
if (mediaDisplayed && _media->isBubbleBottom()) {
|
||||
if (_text.hasSkipBlock()) {
|
||||
_text.removeSkipBlock();
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
}
|
||||
} else if (!_text.hasSkipBlock()) {
|
||||
_text.setSkipBlock(skipBlockWidth(), skipBlockHeight());
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
}
|
||||
}
|
||||
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
||||
if (entry) {
|
||||
entry->_page->initDimensions();
|
||||
}
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && _media->isBubbleBottom()) || (entry/* && entry->_page->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && _media->isBubbleTop()) || (entry && entry->_page->isBubbleTop());
|
||||
|
||||
if (mediaDisplayed && mediaOnBottom) {
|
||||
if (_text.hasSkipBlock()) {
|
||||
_text.removeSkipBlock();
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
}
|
||||
} else if (!_text.hasSkipBlock()) {
|
||||
_text.setSkipBlock(skipBlockWidth(), skipBlockHeight());
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
}
|
||||
|
||||
_maxw = plainMaxWidth();
|
||||
_minh = emptyText() ? 0 : _text.minHeight();
|
||||
if (!mediaOnBottom) {
|
||||
_minh += st::msgPadding.bottom();
|
||||
if (mediaDisplayed) _minh += st::mediaInBubbleSkip;
|
||||
}
|
||||
if (!mediaOnTop) {
|
||||
_minh += st::msgPadding.top();
|
||||
if (mediaDisplayed) _minh += st::mediaInBubbleSkip;
|
||||
if (entry) _minh += st::mediaInBubbleSkip;
|
||||
}
|
||||
if (mediaDisplayed) {
|
||||
if (!_media->isBubbleTop()) {
|
||||
_minh += st::msgPadding.top() + st::mediaInBubbleSkip;
|
||||
}
|
||||
if (!_media->isBubbleBottom()) {
|
||||
_minh += st::msgPadding.bottom() + st::mediaInBubbleSkip;
|
||||
}
|
||||
auto maxw = _media->maxWidth();
|
||||
if (maxw > _maxw) _maxw = maxw;
|
||||
// Parts don't participate in maxWidth() in case of media message.
|
||||
accumulate_max(_maxw, _media->maxWidth());
|
||||
_minh += _media->minHeight();
|
||||
} else {
|
||||
_minh += st::msgPadding.top() + st::msgPadding.bottom();
|
||||
// Count parts in maxWidth(), don't count them in minHeight().
|
||||
// They will be added in resizeGetHeight() anyway.
|
||||
if (displayFromName()) {
|
||||
auto namew = st::msgPadding.left() + author()->nameText.maxWidth() + st::msgPadding.right();
|
||||
if (via && !forwarded) {
|
||||
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||
}
|
||||
if (namew > _maxw) _maxw = namew;
|
||||
accumulate_max(_maxw, namew);
|
||||
} else if (via && !forwarded) {
|
||||
if (st::msgPadding.left() + via->_maxWidth + st::msgPadding.right() > _maxw) {
|
||||
_maxw = st::msgPadding.left() + via->_maxWidth + st::msgPadding.right();
|
||||
}
|
||||
accumulate_max(_maxw, st::msgPadding.left() + via->_maxWidth + st::msgPadding.right());
|
||||
}
|
||||
if (forwarded) {
|
||||
auto _namew = st::msgPadding.left() + forwarded->_text.maxWidth() + st::msgPadding.right();
|
||||
auto namew = st::msgPadding.left() + forwarded->_text.maxWidth() + st::msgPadding.right();
|
||||
if (via) {
|
||||
_namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||
}
|
||||
if (_namew > _maxw) _maxw = _namew;
|
||||
accumulate_max(_maxw, namew);
|
||||
}
|
||||
if (reply) {
|
||||
auto replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
|
||||
if (reply->_replyToVia) {
|
||||
replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth;
|
||||
}
|
||||
accumulate_max(_maxw, replyw);
|
||||
}
|
||||
if (entry) {
|
||||
accumulate_max(_maxw, entry->_page->maxWidth());
|
||||
@@ -874,22 +896,15 @@ void HistoryMessage::initDimensions() {
|
||||
_maxw = st::msgMinWidth;
|
||||
_minh = 0;
|
||||
}
|
||||
if (reply && !emptyText()) {
|
||||
int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
|
||||
if (reply->_replyToVia) {
|
||||
replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth;
|
||||
}
|
||||
if (replyw > _maxw) _maxw = replyw;
|
||||
}
|
||||
if (auto markup = inlineReplyMarkup()) {
|
||||
if (!markup->inlineKeyboard) {
|
||||
markup->inlineKeyboard.reset(new ReplyKeyboard(this, std::make_unique<KeyboardStyle>(st::msgBotKbButton)));
|
||||
markup->inlineKeyboard = std::make_unique<ReplyKeyboard>(this, std::make_unique<KeyboardStyle>(st::msgBotKbButton));
|
||||
}
|
||||
|
||||
// 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 (!emptyText()) {
|
||||
_maxw = qMax(_maxw, markup->inlineKeyboard->naturalWidth());
|
||||
accumulate_max(_maxw, markup->inlineKeyboard->naturalWidth());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -986,6 +1001,17 @@ void HistoryMessage::applyEditionToEmpty() {
|
||||
finishEditionToEmpty();
|
||||
}
|
||||
|
||||
bool HistoryMessage::displayForwardedFrom() const {
|
||||
if (auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
return Has<HistoryMessageVia>()
|
||||
|| !_media
|
||||
|| !_media->isDisplayed()
|
||||
|| !_media->hideForwardedFrom()
|
||||
|| forwarded->_authorOriginal->isChannel();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HistoryMessage::updateMedia(const MTPMessageMedia *media) {
|
||||
auto setMediaAllowed = [](HistoryMediaType type) {
|
||||
return (type == MediaTypeWebPage || type == MediaTypeGame || type == MediaTypeLocation);
|
||||
@@ -1387,8 +1413,15 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||
auto displayTail = skipTail ? RectPart::None : (outbg && !Adaptive::ChatWide()) ? RectPart::Right : RectPart::Left;
|
||||
HistoryLayout::paintBubble(p, g, width(), selected, outbg, displayTail);
|
||||
|
||||
auto trect = g.marginsAdded(-st::msgPadding);
|
||||
if (mediaDisplayed && _media->isBubbleTop()) {
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && _media->isBubbleBottom()) || (entry/* && entry->_page->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && _media->isBubbleTop()) || (entry && entry->_page->isBubbleTop());
|
||||
|
||||
auto trect = g.marginsRemoved(st::msgPadding);
|
||||
if (mediaOnBottom) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
}
|
||||
if (mediaOnTop) {
|
||||
trect.setY(trect.y() - st::msgPadding.top());
|
||||
} else {
|
||||
paintFromName(p, trect, selected);
|
||||
@@ -1396,13 +1429,10 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||
paintReplyInfo(p, trect, selected);
|
||||
paintViaBotIdInfo(p, trect, selected);
|
||||
}
|
||||
if (mediaDisplayed && _media->isBubbleBottom()) {
|
||||
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||
}
|
||||
if (entry) {
|
||||
trect.setHeight(trect.height() - entry->_page->height());
|
||||
}
|
||||
auto needDrawInfo = true;
|
||||
auto needDrawInfo = mediaOnBottom ? !(entry ? entry->_page->customInfoLayout() : _media->customInfoLayout()) : true;
|
||||
if (mediaDisplayed) {
|
||||
auto mediaAboveText = _media->isAboveMessage();
|
||||
auto mediaHeight = _media->height();
|
||||
@@ -1418,9 +1448,9 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||
if (mediaAboveText) {
|
||||
trect.setY(trect.y() + mediaHeight);
|
||||
paintText(p, trect, selection);
|
||||
} else {
|
||||
needDrawInfo = !_media->customInfoLayout();
|
||||
}
|
||||
|
||||
needDrawInfo = !_media->customInfoLayout();
|
||||
} else {
|
||||
paintText(p, trect, selection);
|
||||
}
|
||||
@@ -1563,11 +1593,14 @@ int HistoryMessage::performResizeGetHeight() {
|
||||
auto entry = Get<HistoryMessageLogEntryOriginal>();
|
||||
|
||||
auto mediaDisplayed = false;
|
||||
auto mediaInBubbleState = MediaInBubbleState::None;
|
||||
if (_media) {
|
||||
mediaDisplayed = _media->isDisplayed();
|
||||
mediaInBubbleState = _media->inBubbleState();
|
||||
}
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && _media->isBubbleBottom()) || (entry/* && entry->_page->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && _media->isBubbleTop()) || (entry && entry->_page->isBubbleTop());
|
||||
|
||||
if (contentWidth >= _maxw) {
|
||||
_height = _minh;
|
||||
if (mediaDisplayed) {
|
||||
@@ -1587,16 +1620,17 @@ int HistoryMessage::performResizeGetHeight() {
|
||||
}
|
||||
_height = _textHeight;
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
_height += st::msgPadding.bottom();
|
||||
if (mediaDisplayed) _height += st::mediaInBubbleSkip;
|
||||
}
|
||||
if (!mediaOnTop) {
|
||||
_height += st::msgPadding.top();
|
||||
if (mediaDisplayed) _height += st::mediaInBubbleSkip;
|
||||
if (entry) _height += st::mediaInBubbleSkip;
|
||||
}
|
||||
if (mediaDisplayed) {
|
||||
if (!_media->isBubbleTop()) {
|
||||
_height += st::msgPadding.top() + st::mediaInBubbleSkip;
|
||||
}
|
||||
if (!_media->isBubbleBottom()) {
|
||||
_height += st::msgPadding.bottom() + st::mediaInBubbleSkip;
|
||||
}
|
||||
_height += _media->resizeGetHeight(contentWidth);
|
||||
} else {
|
||||
_height += st::msgPadding.top() + st::msgPadding.bottom();
|
||||
}
|
||||
if (entry) {
|
||||
_height += entry->_page->resizeGetHeight(contentWidth);
|
||||
@@ -1887,6 +1921,16 @@ TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelec
|
||||
return { textSelection.from, fromMediaSelection(mediaSelection).to };
|
||||
}
|
||||
|
||||
void HistoryMessage::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||
if (_media) _media->clickHandlerActiveChanged(p, active);
|
||||
HistoryItem::clickHandlerActiveChanged(p, active);
|
||||
}
|
||||
|
||||
void HistoryMessage::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
|
||||
if (_media) _media->clickHandlerPressedChanged(p, pressed);
|
||||
HistoryItem::clickHandlerPressedChanged(p, pressed);
|
||||
}
|
||||
|
||||
QString HistoryMessage::notificationHeader() const {
|
||||
return (!_history->peer->isUser() && !isPost()) ? from()->name : QString();
|
||||
}
|
||||
@@ -1905,644 +1949,3 @@ HistoryMessage::~HistoryMessage() {
|
||||
reply->clearData(this);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
auto prepareChatAddUserText = [this](const MTPDmessageActionChatAddUser &action) {
|
||||
auto result = PreparedText {};
|
||||
auto &users = action.vusers.v;
|
||||
if (users.size() == 1) {
|
||||
auto u = App::user(peerFromUser(users[0]));
|
||||
if (u == _from) {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_user_joined(lt_from, fromLinkText());
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
result.links.push_back(peerOpenClickHandler(u));
|
||||
result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, u->name));
|
||||
}
|
||||
} else if (users.isEmpty()) {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_add_user(lt_from, fromLinkText(), lt_user, "somebody");
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
for (auto i = 0, l = users.size(); i != l; ++i) {
|
||||
auto user = App::user(peerFromUser(users[i]));
|
||||
result.links.push_back(peerOpenClickHandler(user));
|
||||
|
||||
auto linkText = textcmdLink(i + 2, user->name);
|
||||
if (i == 0) {
|
||||
result.text = linkText;
|
||||
} else if (i + 1 == l) {
|
||||
result.text = lng_action_add_users_and_last(lt_accumulated, result.text, lt_user, linkText);
|
||||
} else {
|
||||
result.text = lng_action_add_users_and_one(lt_accumulated, result.text, lt_user, linkText);
|
||||
}
|
||||
}
|
||||
result.text = lng_action_add_users_many(lt_from, fromLinkText(), lt_users, result.text);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) {
|
||||
auto result = PreparedText {};
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_user_joined_by_link(lt_from, fromLinkText());
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) {
|
||||
auto result = PreparedText {};
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChannelCreate = [this](const MTPDmessageActionChannelCreate &action) {
|
||||
auto result = PreparedText {};
|
||||
if (isPost()) {
|
||||
result.text = lang(lng_action_created_channel);
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatDeletePhoto = [this] {
|
||||
auto result = PreparedText {};
|
||||
if (isPost()) {
|
||||
result.text = lang(lng_action_removed_photo_channel);
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_removed_photo(lt_from, fromLinkText());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatDeleteUser = [this](const MTPDmessageActionChatDeleteUser &action) {
|
||||
auto result = PreparedText {};
|
||||
if (peerFromUser(action.vuser_id) == _from->id) {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_user_left(lt_from, fromLinkText());
|
||||
} else {
|
||||
auto user = App::user(peerFromUser(action.vuser_id));
|
||||
result.links.push_back(fromLink());
|
||||
result.links.push_back(peerOpenClickHandler(user));
|
||||
result.text = lng_action_kick_user(lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatEditPhoto = [this](const MTPDmessageActionChatEditPhoto &action) {
|
||||
auto result = PreparedText {};
|
||||
if (isPost()) {
|
||||
result.text = lang(lng_action_changed_photo_channel);
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_changed_photo(lt_from, fromLinkText());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) {
|
||||
auto result = PreparedText {};
|
||||
if (isPost()) {
|
||||
result.text = lng_action_changed_title_channel(lt_title, textClean(qs(action.vtitle)));
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_changed_title(lt_from, fromLinkText(), lt_title, textClean(qs(action.vtitle)));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto messageText = PreparedText {};
|
||||
|
||||
switch (action.type()) {
|
||||
case mtpc_messageActionChatAddUser: messageText = prepareChatAddUserText(action.c_messageActionChatAddUser()); break;
|
||||
case mtpc_messageActionChatJoinedByLink: messageText = prepareChatJoinedByLink(action.c_messageActionChatJoinedByLink()); break;
|
||||
case mtpc_messageActionChatCreate: messageText = prepareChatCreate(action.c_messageActionChatCreate()); break;
|
||||
case mtpc_messageActionChannelCreate: messageText = prepareChannelCreate(action.c_messageActionChannelCreate()); break;
|
||||
case mtpc_messageActionHistoryClear: break; // Leave empty text.
|
||||
case mtpc_messageActionChatDeletePhoto: messageText = prepareChatDeletePhoto(); break;
|
||||
case mtpc_messageActionChatDeleteUser: messageText = prepareChatDeleteUser(action.c_messageActionChatDeleteUser()); break;
|
||||
case mtpc_messageActionChatEditPhoto: messageText = prepareChatEditPhoto(action.c_messageActionChatEditPhoto()); break;
|
||||
case mtpc_messageActionChatEditTitle: messageText = prepareChatEditTitle(action.c_messageActionChatEditTitle()); break;
|
||||
case mtpc_messageActionChatMigrateTo: messageText.text = lang(lng_action_group_migrate); break;
|
||||
case mtpc_messageActionChannelMigrateFrom: messageText.text = lang(lng_action_group_migrate); break;
|
||||
case mtpc_messageActionPinMessage: messageText = preparePinnedText(); break;
|
||||
case mtpc_messageActionGameScore: messageText = prepareGameScoreText(); break;
|
||||
case mtpc_messageActionPhoneCall: Unexpected("PhoneCall type in HistoryService.");
|
||||
case mtpc_messageActionPaymentSent: messageText = preparePaymentSentText(); break;
|
||||
default: messageText.text = lang(lng_message_empty); break;
|
||||
}
|
||||
|
||||
setServiceText(messageText);
|
||||
|
||||
// Additional information.
|
||||
switch (action.type()) {
|
||||
case mtpc_messageActionChatAddUser: {
|
||||
if (auto channel = history()->peer->asMegagroup()) {
|
||||
auto &users = action.c_messageActionChatAddUser().vusers;
|
||||
for_const (auto &item, users.v) {
|
||||
if (item.v == AuthSession::CurrentUserId()) {
|
||||
channel->mgInfo->joinedMessageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatJoinedByLink: {
|
||||
if (_from->isSelf() && history()->peer->isMegagroup()) {
|
||||
history()->peer->asChannel()->mgInfo->joinedMessageFound = true;
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatEditPhoto: {
|
||||
auto &photo = action.c_messageActionChatEditPhoto().vphoto;
|
||||
if (photo.type() == mtpc_photo) {
|
||||
_media = std::make_unique<HistoryPhoto>(this, history()->peer, photo.c_photo(), st::msgServicePhotoWidth);
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatMigrateTo:
|
||||
case mtpc_messageActionChannelMigrateFrom: {
|
||||
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryService::updateDependent(bool force) {
|
||||
auto dependent = GetDependentData();
|
||||
t_assert(dependent != nullptr);
|
||||
|
||||
if (!force) {
|
||||
if (!dependent->msgId || dependent->msg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dependent->lnk) {
|
||||
dependent->lnk = goToMessageClickHandler(history()->peer, dependent->msgId);
|
||||
}
|
||||
bool gotDependencyItem = false;
|
||||
if (!dependent->msg) {
|
||||
dependent->msg = App::histItemById(channelId(), dependent->msgId);
|
||||
if (dependent->msg) {
|
||||
App::historyRegDependency(this, dependent->msg);
|
||||
gotDependencyItem = true;
|
||||
}
|
||||
}
|
||||
if (dependent->msg) {
|
||||
updateDependentText();
|
||||
} else if (force) {
|
||||
if (dependent->msgId > 0) {
|
||||
dependent->msgId = 0;
|
||||
gotDependencyItem = true;
|
||||
}
|
||||
updateDependentText();
|
||||
}
|
||||
if (force && gotDependencyItem) {
|
||||
AuthSession::Current().notifications().checkDelayed();
|
||||
}
|
||||
return (dependent->msg || !dependent->msgId);
|
||||
}
|
||||
|
||||
HistoryService::PreparedText HistoryService::preparePinnedText() {
|
||||
auto result = PreparedText {};
|
||||
auto pinned = Get<HistoryServicePinned>();
|
||||
if (pinned && pinned->msg) {
|
||||
auto mediaText = ([pinned]() -> QString {
|
||||
auto media = pinned->msg->getMedia();
|
||||
switch (media ? media->type() : MediaTypeCount) {
|
||||
case MediaTypePhoto: return lang(lng_action_pinned_media_photo);
|
||||
case MediaTypeVideo: return lang(lng_action_pinned_media_video);
|
||||
case MediaTypeContact: return lang(lng_action_pinned_media_contact);
|
||||
case MediaTypeFile: return lang(lng_action_pinned_media_file);
|
||||
case MediaTypeGif: {
|
||||
if (auto document = media->getDocument()) {
|
||||
if (document->isRoundVideo()) {
|
||||
return lang(lng_action_pinned_media_video_message);
|
||||
}
|
||||
}
|
||||
return lang(lng_action_pinned_media_gif);
|
||||
} break;
|
||||
case MediaTypeSticker: {
|
||||
auto emoji = static_cast<HistorySticker*>(media)->emoji();
|
||||
if (emoji.isEmpty()) {
|
||||
return lang(lng_action_pinned_media_sticker);
|
||||
}
|
||||
return lng_action_pinned_media_emoji_sticker(lt_emoji, emoji);
|
||||
} break;
|
||||
case MediaTypeLocation: return lang(lng_action_pinned_media_location);
|
||||
case MediaTypeMusicFile: return lang(lng_action_pinned_media_audio);
|
||||
case MediaTypeVoiceFile: return lang(lng_action_pinned_media_voice);
|
||||
case MediaTypeGame: {
|
||||
auto title = static_cast<HistoryGame*>(media)->game()->title;
|
||||
return lng_action_pinned_media_game(lt_game, title);
|
||||
} break;
|
||||
}
|
||||
return QString();
|
||||
})();
|
||||
|
||||
result.links.push_back(fromLink());
|
||||
result.links.push_back(pinned->lnk);
|
||||
if (mediaText.isEmpty()) {
|
||||
auto original = pinned->msg->originalText().text;
|
||||
auto cutAt = 0;
|
||||
auto limit = kPinnedMessageTextLimit;
|
||||
auto size = original.size();
|
||||
for (; limit != 0;) {
|
||||
--limit;
|
||||
if (cutAt >= size) break;
|
||||
if (original.at(cutAt).isLowSurrogate() && cutAt + 1 < size && original.at(cutAt + 1).isHighSurrogate()) {
|
||||
cutAt += 2;
|
||||
} else {
|
||||
++cutAt;
|
||||
}
|
||||
}
|
||||
if (!limit && cutAt + 5 < size) {
|
||||
original = original.mid(0, cutAt) + qstr("...");
|
||||
}
|
||||
result.text = lng_action_pinned_message(lt_from, fromLinkText(), lt_text, textcmdLink(2, original));
|
||||
} else {
|
||||
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, textcmdLink(2, mediaText));
|
||||
}
|
||||
} else if (pinned && pinned->msgId) {
|
||||
result.links.push_back(fromLink());
|
||||
result.links.push_back(pinned->lnk);
|
||||
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, textcmdLink(2, lang(lng_contacts_loading)));
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_pinned_media(lt_from, fromLinkText(), lt_media, lang(lng_deleted_message));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HistoryService::PreparedText HistoryService::prepareGameScoreText() {
|
||||
auto result = PreparedText {};
|
||||
auto gamescore = Get<HistoryServiceGameScore>();
|
||||
|
||||
auto computeGameTitle = [gamescore, &result]() -> QString {
|
||||
if (gamescore && gamescore->msg) {
|
||||
if (auto media = gamescore->msg->getMedia()) {
|
||||
if (media->type() == MediaTypeGame) {
|
||||
result.links.push_back(MakeShared<ReplyMarkupClickHandler>(gamescore->msg, 0, 0));
|
||||
auto titleText = static_cast<HistoryGame*>(media)->game()->title;
|
||||
return textcmdLink(result.links.size(), titleText);
|
||||
}
|
||||
}
|
||||
return lang(lng_deleted_message);
|
||||
} else if (gamescore && gamescore->msgId) {
|
||||
return lang(lng_contacts_loading);
|
||||
}
|
||||
return QString();
|
||||
};
|
||||
|
||||
auto scoreNumber = gamescore ? gamescore->score : 0;
|
||||
if (_from->isSelf()) {
|
||||
auto gameTitle = computeGameTitle();
|
||||
if (gameTitle.isEmpty()) {
|
||||
result.text = lng_action_game_you_scored_no_game(lt_count, scoreNumber);
|
||||
} else {
|
||||
result.text = lng_action_game_you_scored(lt_count, scoreNumber, lt_game, gameTitle);
|
||||
}
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
auto gameTitle = computeGameTitle();
|
||||
if (gameTitle.isEmpty()) {
|
||||
result.text = lng_action_game_score_no_game(lt_count, scoreNumber, lt_from, fromLinkText());
|
||||
} else {
|
||||
result.text = lng_action_game_score(lt_count, scoreNumber, lt_from, fromLinkText(), lt_game, gameTitle);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HistoryService::PreparedText HistoryService::preparePaymentSentText() {
|
||||
auto result = PreparedText {};
|
||||
auto payment = Get<HistoryServicePayment>();
|
||||
|
||||
auto invoiceTitle = ([payment]() -> QString {
|
||||
if (payment && payment->msg) {
|
||||
if (auto media = payment->msg->getMedia()) {
|
||||
if (media->type() == MediaTypeInvoice) {
|
||||
return static_cast<HistoryInvoice*>(media)->getTitle();
|
||||
}
|
||||
}
|
||||
return lang(lng_deleted_message);
|
||||
} else if (payment && payment->msgId) {
|
||||
return lang(lng_contacts_loading);
|
||||
}
|
||||
return QString();
|
||||
})();
|
||||
|
||||
if (invoiceTitle.isEmpty()) {
|
||||
result.text = lng_action_payment_done(lt_amount, payment->amount, lt_user, history()->peer->name);
|
||||
} else {
|
||||
result.text = lng_action_payment_done_for(lt_amount, payment->amount, lt_user, history()->peer->name, lt_invoice, invoiceTitle);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HistoryService::HistoryService(gsl::not_null<History*> history, const MTPDmessageService &message) :
|
||||
HistoryItem(history, message.vid.v, mtpCastFlags(message.vflags.v), ::date(message.vdate), message.has_from_id() ? message.vfrom_id.v : 0) {
|
||||
createFromMtp(message);
|
||||
setMessageByAction(message.vaction);
|
||||
}
|
||||
|
||||
HistoryService::HistoryService(gsl::not_null<History*> history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags, int32 from, PhotoData *photo) :
|
||||
HistoryItem(history, msgId, flags, date, from) {
|
||||
setServiceText(message);
|
||||
if (photo) {
|
||||
_media = std::make_unique<HistoryPhoto>(this, history->peer, photo, st::msgServicePhotoWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryService::initDimensions() {
|
||||
_maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right();
|
||||
_minh = _text.minHeight();
|
||||
if (_media) _media->initDimensions();
|
||||
}
|
||||
|
||||
bool HistoryService::updateDependencyItem() {
|
||||
if (GetDependentData()) {
|
||||
return updateDependent(true);
|
||||
}
|
||||
return HistoryItem::updateDependencyItem();
|
||||
}
|
||||
|
||||
QRect HistoryService::countGeometry() const {
|
||||
auto result = QRect(0, 0, width(), _height);
|
||||
if (Adaptive::ChatWide()) {
|
||||
result.setWidth(qMin(result.width(), st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
return result.marginsRemoved(st::msgServiceMargin);
|
||||
}
|
||||
|
||||
TextWithEntities HistoryService::selectedText(TextSelection selection) const {
|
||||
return _text.originalTextWithEntities((selection == FullSelection) ? AllTextSelection : selection);
|
||||
}
|
||||
|
||||
QString HistoryService::inDialogsText() const {
|
||||
return textcmdLink(1, textClean(notificationText()));
|
||||
}
|
||||
|
||||
QString HistoryService::inReplyText() const {
|
||||
QString result = HistoryService::notificationText();
|
||||
return result.trimmed().startsWith(author()->name) ? result.trimmed().mid(author()->name.size()).trimmed() : result;
|
||||
}
|
||||
|
||||
void HistoryService::setServiceText(const PreparedText &prepared) {
|
||||
_text.setText(st::serviceTextStyle, prepared.text, _historySrvOptions);
|
||||
auto linkIndex = 0;
|
||||
for_const (auto &link, prepared.links) {
|
||||
// Link indices start with 1.
|
||||
_text.setLink(++linkIndex, link);
|
||||
}
|
||||
|
||||
setPendingInitDimensions();
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
}
|
||||
|
||||
void HistoryService::draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const {
|
||||
auto height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom();
|
||||
auto dateh = 0;
|
||||
auto unreadbarh = 0;
|
||||
if (auto date = Get<HistoryMessageDate>()) {
|
||||
dateh = date->height();
|
||||
p.translate(0, dateh);
|
||||
clip.translate(0, -dateh);
|
||||
height -= dateh;
|
||||
}
|
||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||
unreadbarh = unreadbar->height();
|
||||
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
|
||||
unreadbar->paint(p, 0, width());
|
||||
}
|
||||
p.translate(0, unreadbarh);
|
||||
clip.translate(0, -unreadbarh);
|
||||
height -= unreadbarh;
|
||||
}
|
||||
|
||||
HistoryLayout::PaintContext context(ms, clip, selection);
|
||||
HistoryLayout::ServiceMessagePainter::paint(p, this, context, height);
|
||||
|
||||
if (auto skiph = dateh + unreadbarh) {
|
||||
p.translate(0, -skiph);
|
||||
}
|
||||
}
|
||||
|
||||
int HistoryService::resizeContentGetHeight() {
|
||||
_height = displayedDateHeight();
|
||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||
_height += unreadbar->height();
|
||||
}
|
||||
|
||||
if (_text.isEmpty()) {
|
||||
_textHeight = 0;
|
||||
} else {
|
||||
auto contentWidth = width();
|
||||
if (Adaptive::ChatWide()) {
|
||||
accumulate_min(contentWidth, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left());
|
||||
}
|
||||
contentWidth -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins
|
||||
if (contentWidth < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) {
|
||||
contentWidth = st::msgServicePadding.left() + st::msgServicePadding.right() + 1;
|
||||
}
|
||||
|
||||
auto nwidth = qMax(contentWidth - st::msgServicePadding.left() - st::msgServicePadding.right(), 0);
|
||||
if (nwidth != _textWidth) {
|
||||
_textWidth = nwidth;
|
||||
_textHeight = _text.countHeight(nwidth);
|
||||
}
|
||||
if (contentWidth >= _maxw) {
|
||||
_height += _minh;
|
||||
} else {
|
||||
_height += _textHeight;
|
||||
}
|
||||
_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
|
||||
if (_media) {
|
||||
_height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth());
|
||||
}
|
||||
}
|
||||
|
||||
return _height;
|
||||
}
|
||||
|
||||
bool HistoryService::hasPoint(QPoint point) const {
|
||||
auto g = countGeometry();
|
||||
if (g.width() < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto dateh = displayedDateHeight()) {
|
||||
g.setTop(g.top() + dateh);
|
||||
}
|
||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||
g.setTop(g.top() + unreadbar->height());
|
||||
}
|
||||
if (_media) {
|
||||
g.setHeight(g.height() - (st::msgServiceMargin.top() + _media->height()));
|
||||
}
|
||||
return g.contains(point);
|
||||
}
|
||||
|
||||
HistoryTextState HistoryService::getState(QPoint point, HistoryStateRequest request) const {
|
||||
HistoryTextState result;
|
||||
|
||||
auto g = countGeometry();
|
||||
if (g.width() < 1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (auto dateh = displayedDateHeight()) {
|
||||
point.setY(point.y() - dateh);
|
||||
g.setHeight(g.height() - dateh);
|
||||
}
|
||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||
auto unreadbarh = unreadbar->height();
|
||||
point.setY(point.y() - unreadbarh);
|
||||
g.setHeight(g.height() - unreadbarh);
|
||||
}
|
||||
|
||||
if (_media) {
|
||||
g.setHeight(g.height() - (st::msgServiceMargin.top() + _media->height()));
|
||||
}
|
||||
auto trect = g.marginsAdded(-st::msgServicePadding);
|
||||
if (trect.contains(point)) {
|
||||
auto textRequest = request.forText();
|
||||
textRequest.align = style::al_center;
|
||||
result = _text.getState(point - trect.topLeft(), trect.width(), textRequest);
|
||||
if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) {
|
||||
result.link = gamescore->lnk;
|
||||
}
|
||||
} else if (auto payment = Get<HistoryServicePayment>()) {
|
||||
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) {
|
||||
result.link = payment->lnk;
|
||||
}
|
||||
}
|
||||
} else if (_media) {
|
||||
result = _media->getState(point - QPoint(st::msgServiceMargin.left() + (g.width() - _media->maxWidth()) / 2, st::msgServiceMargin.top() + g.height() + st::msgServiceMargin.top()), request);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||
if (message.vaction.type() == mtpc_messageActionGameScore) {
|
||||
UpdateComponents(HistoryServiceGameScore::Bit());
|
||||
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
|
||||
} else if (message.vaction.type() == mtpc_messageActionPaymentSent) {
|
||||
UpdateComponents(HistoryServicePayment::Bit());
|
||||
auto amount = message.vaction.c_messageActionPaymentSent().vtotal_amount.v;
|
||||
auto currency = qs(message.vaction.c_messageActionPaymentSent().vcurrency);
|
||||
Get<HistoryServicePayment>()->amount = HistoryInvoice::fillAmountAndCurrency(amount, currency);
|
||||
}
|
||||
if (message.has_reply_to_msg_id()) {
|
||||
if (message.vaction.type() == mtpc_messageActionPinMessage) {
|
||||
UpdateComponents(HistoryServicePinned::Bit());
|
||||
}
|
||||
if (auto dependent = GetDependentData()) {
|
||||
dependent->msgId = message.vreply_to_msg_id.v;
|
||||
if (!updateDependent() && App::api()) {
|
||||
App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
setMessageByAction(message.vaction);
|
||||
}
|
||||
|
||||
void HistoryService::applyEdition(const MTPDmessageService &message) {
|
||||
clearDependency();
|
||||
UpdateComponents(0);
|
||||
|
||||
createFromMtp(message);
|
||||
|
||||
if (message.vaction.type() == mtpc_messageActionHistoryClear) {
|
||||
removeMedia();
|
||||
finishEditionToEmpty();
|
||||
} else {
|
||||
finishEdition(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryService::removeMedia() {
|
||||
if (!_media) return;
|
||||
|
||||
bool mediaWasDisplayed = _media->isDisplayed();
|
||||
_media.reset();
|
||||
if (mediaWasDisplayed) {
|
||||
_textWidth = -1;
|
||||
_textHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32 HistoryService::addToOverview(AddToOverviewMethod method) {
|
||||
if (!indexInOverview()) return 0;
|
||||
|
||||
int32 result = 0;
|
||||
if (auto media = getMedia()) {
|
||||
result |= media->addToOverview(method);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HistoryService::eraseFromOverview() {
|
||||
if (auto media = getMedia()) {
|
||||
media->eraseFromOverview();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryService::updateDependentText() {
|
||||
auto text = PreparedText {};
|
||||
if (Has<HistoryServicePinned>()) {
|
||||
text = preparePinnedText();
|
||||
} else if (Has<HistoryServiceGameScore>()) {
|
||||
text = prepareGameScoreText();
|
||||
} else if (Has<HistoryServicePayment>()) {
|
||||
text = preparePaymentSentText();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
setServiceText(text);
|
||||
if (history()->textCachedFor == this) {
|
||||
history()->textCachedFor = nullptr;
|
||||
}
|
||||
if (App::main()) {
|
||||
App::main()->dlgUpdated(history()->peer, id);
|
||||
}
|
||||
App::historyUpdateDependent(this);
|
||||
}
|
||||
|
||||
void HistoryService::clearDependency() {
|
||||
if (auto dependent = GetDependentData()) {
|
||||
if (dependent->msg) {
|
||||
App::historyUnregDependency(this, dependent->msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HistoryService::~HistoryService() {
|
||||
clearDependency();
|
||||
_media.reset();
|
||||
}
|
||||
|
||||
HistoryJoined::HistoryJoined(gsl::not_null<History*> history, const QDateTime &inviteDate, gsl::not_null<UserData*> inviter, MTPDmessage::Flags flags)
|
||||
: HistoryService(history, clientMsgId(), inviteDate, GenerateText(history, inviter), flags) {
|
||||
}
|
||||
|
||||
HistoryJoined::PreparedText HistoryJoined::GenerateText(gsl::not_null<History*> history, gsl::not_null<UserData*> inviter) {
|
||||
if (inviter->id == AuthSession::CurrentUserPeerId()) {
|
||||
return { lang(history->isMegagroup() ? lng_action_you_joined_group : lng_action_you_joined) };
|
||||
}
|
||||
auto result = PreparedText {};
|
||||
result.links.push_back(peerOpenClickHandler(inviter));
|
||||
if (history->isMegagroup()) {
|
||||
result.text = lng_action_add_you_group(lt_from, textcmdLink(1, inviter->name));
|
||||
}
|
||||
result.text = lng_action_add_you(lt_from, textcmdLink(1, inviter->name));
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user