From a34e998c42d7b3640d42f6db1428e3c255de17ce Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 15 Mar 2019 19:15:56 +0400 Subject: [PATCH] Handle fwd_from without a link to the account. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/apiwrap.cpp | 20 +-- Telegram/SourceFiles/app.cpp | 3 + .../SourceFiles/boxes/edit_caption_box.cpp | 2 +- .../boxes/peer_list_controllers.cpp | 2 +- Telegram/SourceFiles/data/data_peer.cpp | 6 + Telegram/SourceFiles/data/data_peer.h | 1 + Telegram/SourceFiles/data/data_session.cpp | 4 +- .../SourceFiles/dialogs/dialogs_layout.cpp | 25 +++- .../export/data/export_data_types.cpp | 8 ++ .../export/data/export_data_types.h | 2 + .../export/output/export_output_abstract.cpp | 3 + .../export/output/export_output_html.cpp | 50 ++++++-- .../export/output/export_output_json.cpp | 4 + .../export/output/export_output_text.cpp | 2 + .../history/history_inner_widget.cpp | 42 ++++-- .../history/history_inner_widget.h | 2 + Telegram/SourceFiles/history/history_item.cpp | 15 ++- Telegram/SourceFiles/history/history_item.h | 7 +- .../history/history_item_components.cpp | 35 ++++- .../history/history_item_components.h | 20 +++ .../SourceFiles/history/history_message.cpp | 121 ++++++++++++------ .../SourceFiles/history/history_message.h | 8 +- .../SourceFiles/history/history_widget.cpp | 65 ++++++---- .../history/media/history_media_contact.cpp | 7 +- .../history/view/history_view_element.cpp | 22 +++- .../history/view/history_view_list_widget.cpp | 38 ++++-- .../history/view/history_view_list_widget.h | 2 + .../history/view/history_view_message.cpp | 81 +++++++++--- .../inline_bots/inline_bot_result.cpp | 2 +- .../inline_bots/inline_bot_send_data.cpp | 2 +- Telegram/SourceFiles/mainwidget.cpp | 31 ++--- .../media/view/media_view_overlay_widget.cpp | 43 ++++--- .../media/view/media_view_overlay_widget.h | 4 +- Telegram/SourceFiles/mtproto/type_utils.cpp | 13 -- Telegram/SourceFiles/mtproto/type_utils.h | 2 - 36 files changed, 503 insertions(+), 192 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 40f05d2d6..e123220c5 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1010,6 +1010,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_forwarded_via" = "Forwarded from {user} via {inline_bot}"; "lng_forwarded_channel_via" = "Forwarded from {channel} via {inline_bot}"; "lng_forwarded_signed" = "{channel} ({user})"; +"lng_forwarded_hidden" = "The account was hidden by the user."; "lng_signed_author" = "Author: {user}"; "lng_in_reply_to" = "In reply to"; "lng_edited" = "edited"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 371b10042..34b28c9ce 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3407,7 +3407,7 @@ void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) { d.vdate, d.vmessage, MTP_messageMediaEmpty(), - MTPnullMarkup, + MTPReplyMarkup(), d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint(), @@ -3431,7 +3431,7 @@ void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) { d.vdate, d.vmessage, MTP_messageMediaEmpty(), - MTPnullMarkup, + MTPReplyMarkup(), d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint(), @@ -4366,7 +4366,7 @@ void ApiWrap::sendSharedContact( MTP_int(newId.msg), MTP_int(messageFromId), peerToMTP(peer->id), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTPint(), MTP_int(options.replyTo), MTP_int(unixtime()), @@ -4377,7 +4377,7 @@ void ApiWrap::sendSharedContact( MTP_string(lastName), MTP_string(vcard), MTP_int(userId)), - MTPnullMarkup, + MTPReplyMarkup(), MTPnullEntities, MTP_int(views), MTPint(), @@ -4636,13 +4636,13 @@ void ApiWrap::sendMessage(MessageToSend &&message) { MTP_int(newId.msg), MTP_int(messageFromId), peerToMTP(peer->id), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTPint(), MTP_int(message.replyTo), MTP_int(unixtime()), msgText, media, - MTPnullMarkup, + MTPReplyMarkup(), localEntities, MTP_int(1), MTPint(), @@ -4655,7 +4655,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) { MTP_int(message.replyTo), msgText, MTP_long(randomId), - MTPnullMarkup, + MTPReplyMarkup(), sentEntities )).done([=](const MTPUpdates &result) { applyUpdates(result, randomId); @@ -4847,7 +4847,7 @@ void ApiWrap::sendExistingDocument( messagePostAuthor, document, caption, - MTPnullMarkup); + MTPReplyMarkup()); auto failHandler = std::make_shared>(); auto performRequest = [=] { @@ -4861,7 +4861,7 @@ void ApiWrap::sendExistingDocument( MTPint()), MTP_string(captionText), MTP_long(randomId), - MTPnullMarkup, + MTPReplyMarkup(), sentEntities )).done([=](const MTPUpdates &result) { applyUpdates(result, randomId); @@ -5011,7 +5011,7 @@ void ApiWrap::sendMediaWithRandomId( media, MTP_string(caption.text), MTP_long(randomId), - MTPnullMarkup, + MTPReplyMarkup(), sentEntities )).done([=](const MTPUpdates &result) { applyUpdates(result); }).fail([=](const RPCError &error) { sendMessageFail(error); diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 6a6aedabc..ae378db2f 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -145,6 +145,9 @@ namespace App { existing->updateReplyMarkup(m.has_reply_markup() ? (&m.vreply_markup) : nullptr); + existing->updateForwardedInfo(m.has_fwd_from() + ? &m.vfwd_from + : nullptr); existing->setViewsCount(m.has_views() ? m.vviews.v : -1); existing->indexAsNewItem(); Auth().data().requestItemTextRefresh(existing); diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index f83d242f1..5c4e147af 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -529,7 +529,7 @@ void EditCaptionBox::save() { MTP_int(item->id), MTP_string(sending.text), MTPInputMedia(), - MTPnullMarkup, + MTPReplyMarkup(), sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 63b981f63..92c6fed07 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -39,7 +39,7 @@ void ShareBotGame(not_null bot, not_null chat) { MTP_string(bot->botInfo->shareGameShortName))), MTP_string(""), MTP_long(randomId), - MTPnullMarkup, + MTPReplyMarkup(), MTPnullEntities), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 73497e779..b8b161a8f 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -63,6 +63,12 @@ style::color PeerUserpicColor(PeerId peerId) { return colors[PeerColorIndex(peerId)]; } +PeerId FakePeerIdForJustName(const QString &name) { + return peerFromUser(name.isEmpty() + ? 777 + : hashCrc32(name.constData(), name.size() * sizeof(QChar))); +} + } // namespace Data PeerClickHandler::PeerClickHandler(not_null peer) diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index aa9ef401e..700b9eb0a 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -31,6 +31,7 @@ class Session; int PeerColorIndex(PeerId peerId); int PeerColorIndex(int32 bareId); style::color PeerUserpicColor(PeerId peerId); +PeerId FakePeerIdForJustName(const QString &name); } // namespace Data diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 14547d58b..adc15335e 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -3019,13 +3019,13 @@ void Session::insertCheckedServiceNotification( MTP_int(clientMsgId()), MTP_int(peerToUser(PeerData::kServiceNotificationsId)), MTP_peerUser(MTP_int(_session->userId())), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTPint(), MTPint(), MTP_int(date), MTP_string(sending.text), media, - MTPnullMarkup, + MTPReplyMarkup(), TextUtilities::EntitiesToMTP(sending.entities), MTPint(), MTPint(), diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 465124954..875268046 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text_options.h" #include "lang/lang_keys.h" #include "support/support_helper.h" +#include "history/history_item_components.h" #include "history/history_item.h" #include "history/history.h" #include "data/data_channel.h" @@ -175,6 +176,7 @@ void paintRow( not_null entry, Dialogs::Key chat, PeerData *from, + const HiddenSenderInfo *hiddenSenderInfo, HistoryItem *item, const Data::Draft *draft, QDateTime date, @@ -220,6 +222,13 @@ void paintRow( st::dialogsPadding.y(), fullWidth, st::dialogsPhotoSize); + } else if (hiddenSenderInfo) { + hiddenSenderInfo->userpic.paint( + p, + st::dialogsPadding.x(), + st::dialogsPadding.y(), + fullWidth, + st::dialogsPhotoSize); } else { entry->paintUserpicLeft( p, @@ -382,6 +391,8 @@ void paintRow( icon->paint(p, rectForName.topLeft() + QPoint(qMin(from->dialogName().maxWidth(), rectForName.width()), 0), fullWidth); } from->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } else if (hiddenSenderInfo) { + hiddenSenderInfo->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } else { p.setFont(st::msgNameFont); auto text = entry->chatListName(); // TODO feed name with emoji @@ -658,6 +669,7 @@ void RowPainter::paint( entry, row->key(), from, + nullptr, item, cloudDraft, displayDate, @@ -684,7 +696,7 @@ void RowPainter::paint( if (const auto searchChat = row->searchInChat()) { if (const auto peer = searchChat.peer()) { if (peer->isSelf()) { - return item->senderOriginal().get(); + return item->senderOriginal(); } else if (!peer->isChannel() || peer->isMegagroup()) { return item->from().get(); } @@ -694,6 +706,16 @@ void RowPainter::paint( ? history->peer->migrateTo() : history->peer.get(); }(); + const auto hiddenSenderInfo = [&]() -> const HiddenSenderInfo* { + if (const auto searchChat = row->searchInChat()) { + if (const auto peer = searchChat.peer()) { + if (peer->isSelf()) { + return item->hiddenForwardedInfo(); + } + } + } + return nullptr; + }(); const auto drawInDialogWay = [&] { if (const auto searchChat = row->searchInChat()) { if (const auto peer = searchChat.peer()) { @@ -775,6 +797,7 @@ void RowPainter::paint( history, history, from, + hiddenSenderInfo, item, cloudDraft, ItemDateTime(item), diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 3dc7b4e87..abc6fd57b 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -1156,6 +1156,12 @@ Message ParseMessage( } return PeerId(0); }); + result.forwardedFromName = data.vfwd_from.match( + [](const MTPDmessageFwdHeader &data) { + return data.has_from_name() + ? data.vfrom_name.v + : QByteArray(); + }); result.forwardedDate = data.vfwd_from.match( [](const MTPDmessageFwdHeader &data) { return data.vdate.v; @@ -1167,6 +1173,8 @@ Message ParseMessage( } return PeerId(0); }); + result.forwarded = result.forwardedFromId + || !result.forwardedFromName.isEmpty(); } if (data.has_post_author()) { result.signature = ParseString(data.vpost_author); diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 8c91246be..08c9f6145 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -501,7 +501,9 @@ struct Message { int32 fromId = 0; PeerId toId = 0; PeerId forwardedFromId = 0; + Utf8String forwardedFromName; TimeId forwardedDate = 0; + bool forwarded = false; PeerId savedFromChatId = 0; Utf8String signature; int32 viaBotId = 0; diff --git a/Telegram/SourceFiles/export/output/export_output_abstract.cpp b/Telegram/SourceFiles/export/output/export_output_abstract.cpp index 8c885401f..e39468b12 100644 --- a/Telegram/SourceFiles/export/output/export_output_abstract.cpp +++ b/Telegram/SourceFiles/export/output/export_output_abstract.cpp @@ -203,6 +203,9 @@ Stats AbstractWriter::produceTestExample( if (++count % 3 == 0) { message.forwardedFromId = Data::UserPeerId(user.info.userId); message.forwardedDate = date(); + } else if (count % 3 == 2) { + message.forwardedFromName = "Test hidden forward"; + message.forwardedDate = date(); } message.fromId = user.info.userId; message.replyToMsgId = counter(); diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index f669cb273..4a38c3095 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -513,6 +513,8 @@ struct HtmlWriter::MessageInfo { int32 fromId = 0; TimeId date = 0; Data::PeerId forwardedFromId = 0; + QString forwardedFromName; + bool forwarded = false; TimeId forwardedDate = 0; }; @@ -648,6 +650,20 @@ void FillUserpicNames(UserpicData &data, const Data::Peer &peer) { } } +void FillUserpicNames(UserpicData &data, const QByteArray &full) { + const auto names = full.split(' '); + data.firstName = names[0]; + for (auto i = 1; i != names.size(); ++i) { + if (names[i].isEmpty()) { + continue; + } + if (!data.lastName.isEmpty()) { + data.lastName.append(' '); + } + data.lastName.append(names[i]); + } +} + QByteArray ComposeName(const UserpicData &data, const QByteArray &empty) { return ((data.firstName.isEmpty() && data.lastName.isEmpty()) ? empty @@ -948,7 +964,9 @@ auto HtmlWriter::Wrap::pushMessage( info.fromId = message.fromId; info.date = message.date; info.forwardedFromId = message.forwardedFromId; + info.forwardedFromName = message.forwardedFromName; info.forwardedDate = message.forwardedDate; + info.forwarded = message.forwarded; if (message.media.content.is()) { return { info, pushServiceMessage( message.id, @@ -1122,19 +1140,24 @@ auto HtmlWriter::Wrap::pushMessage( block.append(pushDiv("from_name")); block.append(SerializeString( ComposeName(userpic, "Deleted Account"))); - if (!via.isEmpty() && !message.forwardedFromId) { + if (!via.isEmpty() && !message.forwarded) { block.append(" via @" + via); } block.append(popTag()); } - if (message.forwardedFromId) { + if (message.forwarded) { auto forwardedUserpic = UserpicData(); - forwardedUserpic.colorIndex = PeerColorIndex( - BarePeerId(message.forwardedFromId)); + forwardedUserpic.colorIndex = message.forwardedFromId + ? PeerColorIndex(BarePeerId(message.forwardedFromId)) + : PeerColorIndex(message.id); forwardedUserpic.pixelSize = kHistoryUserpicSize; - FillUserpicNames( - forwardedUserpic, - peers.peer(message.forwardedFromId)); + if (message.forwardedFromId) { + FillUserpicNames( + forwardedUserpic, + peers.peer(message.forwardedFromId)); + } else { + FillUserpicNames(forwardedUserpic, message.forwardedFromName); + } const auto forwardedWrap = forwardedNeedsWrap(message, previous); if (forwardedWrap) { @@ -1179,7 +1202,7 @@ auto HtmlWriter::Wrap::pushMessage( block.append(SerializeString(message.signature)); block.append(popTag()); } - if (message.forwardedFromId) { + if (message.forwarded) { block.append(popTag()); } block.append(popTag()); @@ -1200,10 +1223,12 @@ bool HtmlWriter::Wrap::messageNeedsWrap( } else if (QDateTime::fromTime_t(previous->date).date() != QDateTime::fromTime_t(message.date).date()) { return true; - } else if (!message.forwardedFromId != !previous->forwardedFromId) { + } else if (message.forwarded != previous->forwarded) { return true; } else if (std::abs(message.date - previous->date) - > (message.forwardedFromId ? 1 : kJoinWithinSeconds)) { + > ((message.forwardedFromId || !message.forwardedFromName.isEmpty()) + ? 1 + : kJoinWithinSeconds)) { return true; } return false; @@ -1725,11 +1750,12 @@ MediaData HtmlWriter::Wrap::prepareMediaData( bool HtmlWriter::Wrap::forwardedNeedsWrap( const Data::Message &message, const MessageInfo *previous) const { - Expects(message.forwardedFromId != 0); + Expects(message.forwarded); if (messageNeedsWrap(message, previous)) { return true; - } else if (message.forwardedFromId != previous->forwardedFromId) { + } else if (!message.forwardedFromId + || message.forwardedFromId != previous->forwardedFromId) { return true; } else if (Data::IsChatPeerId(message.forwardedFromId)) { return true; diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 1c448c326..c5c674f26 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -471,6 +471,10 @@ QByteArray SerializeMessage( pushBare( "forwarded_from", wrapPeerName(message.forwardedFromId)); + } else if (!message.forwardedFromName.isEmpty()) { + pushBare( + "forwarded_from", + StringAllowNull(message.forwardedFromName)); } if (message.savedFromChatId) { pushBare("saved_from", wrapPeerName(message.savedFromChatId)); diff --git a/Telegram/SourceFiles/export/output/export_output_text.cpp b/Telegram/SourceFiles/export/output/export_output_text.cpp index b5fec1cc3..e9766cc75 100644 --- a/Telegram/SourceFiles/export/output/export_output_text.cpp +++ b/Telegram/SourceFiles/export/output/export_output_text.cpp @@ -342,6 +342,8 @@ QByteArray SerializeMessage( push("Author", message.signature); if (message.forwardedFromId) { push("Forwarded from", wrapPeerName(message.forwardedFromId)); + } else if (!message.forwardedFromName.isEmpty()) { + push("Forwarded from", message.forwardedFromName); } if (message.savedFromChatId) { push("Saved from", wrapPeerName(message.savedFromChatId)); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index c17def577..d7498ab5e 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_context_menu.h" #include "ui/widgets/popup_menu.h" #include "ui/image/image.h" +#include "ui/toast/toast.h" #include "ui/text_options.h" #include "window/window_controller.h" #include "window/window_peer_menu.h" @@ -686,12 +687,23 @@ void HistoryInner::paintEvent(QPaintEvent *e) { // paint the userpic if it intersects the painted rect if (userpicTop + st::msgPhotoSize > clip.top()) { const auto message = view->data()->toHistoryMessage(); - message->displayFrom()->paintUserpicLeft( - p, - st::historyPhotoLeft, - userpicTop, - width(), - st::msgPhotoSize); + if (const auto from = message->displayFrom()) { + from->paintUserpicLeft( + p, + st::historyPhotoLeft, + userpicTop, + width(), + st::msgPhotoSize); + } else if (const auto info = message->hiddenForwardedInfo()) { + info->userpic.paint( + p, + st::historyPhotoLeft, + userpicTop, + width(), + st::msgPhotoSize); + } else { + Unexpected("Corrupt forwarded information in message."); + } } return true; }); @@ -2535,9 +2547,10 @@ void HistoryInner::mouseActionUpdate() { const auto message = view->data()->toHistoryMessage(); Assert(message != nullptr); - dragState = TextState( - nullptr, - message->displayFrom()->openLink()); + const auto from = message->displayFrom(); + dragState = TextState(nullptr, from + ? from->openLink() + : hiddenUserpicLink(message->fullId())); _dragStateItem = App::histItemById(dragState.itemId); lnkhost = view; return false; @@ -2678,6 +2691,13 @@ void HistoryInner::mouseActionUpdate() { } } +ClickHandlerPtr HistoryInner::hiddenUserpicLink(FullMsgId id) { + static const auto result = std::make_shared([] { + Ui::Toast::Show(lang(lng_forwarded_hidden)); + }); + return result; +} + void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo, bool dragSelecting) { if (_dragSelFrom == dragSelFrom && _dragSelTo == dragSelTo && _dragSelecting == dragSelecting) { return; @@ -3066,7 +3086,9 @@ QString HistoryInner::tooltipText() const { if (media->hidesForwardedInfo()) { dateText += "\n" + lng_forwarded( lt_user, - forwarded->originalSender->shortName()); + (forwarded->originalSender + ? forwarded->originalSender->shortName() + : forwarded->hiddenSenderInfo->firstName)); } } } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 382ebb350..869b3e601 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -189,6 +189,8 @@ private: template void enumerateDates(Method method); + ClickHandlerPtr hiddenUserpicLink(FullMsgId id); + void scrollDateCheck(); void scrollDateHideByTimer(); bool canHaveFromUserpics() const; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 4da1682c0..db4910468 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -603,7 +603,7 @@ TimeId HistoryItem::dateOriginal() const { return date(); } -not_null HistoryItem::senderOriginal() const { +PeerData *HistoryItem::senderOriginal() const { if (const auto forwarded = Get()) { return forwarded->originalSender; } @@ -611,10 +611,19 @@ not_null HistoryItem::senderOriginal() const { return (peer->isChannel() && !peer->isMegagroup()) ? peer : from(); } +const HiddenSenderInfo *HistoryItem::hiddenForwardedInfo() const { + if (const auto forwarded = Get()) { + return forwarded->hiddenSenderInfo.get(); + } + return nullptr; +} + not_null HistoryItem::fromOriginal() const { if (const auto forwarded = Get()) { - if (const auto user = forwarded->originalSender->asUser()) { - return user; + if (forwarded->originalSender) { + if (const auto user = forwarded->originalSender->asUser()) { + return user; + } } } return from(); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 0fee5661e..21b241ad4 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -54,6 +54,8 @@ enum class Context : char; class ElementDelegate; } // namespace HistoryView +struct HiddenSenderInfo; + class HistoryItem : public RuntimeComposer { public: static not_null Create( @@ -166,6 +168,8 @@ public: } virtual void updateReplyMarkup(const MTPReplyMarkup *markup) { } + virtual void updateForwardedInfo(const MTPMessageFwdHeader *fwd) { + } virtual void addToUnreadMentions(UnreadMentionType type); virtual void eraseFromUnreadMentions() { @@ -257,7 +261,8 @@ public: not_null author() const; TimeId dateOriginal() const; - not_null senderOriginal() const; + PeerData *senderOriginal() const; + const HiddenSenderInfo *hiddenForwardedInfo() const; not_null fromOriginal() const; QString authorOriginal() const; MsgId idOriginal() const; diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index d84441ef3..4356ce00d 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "ui/effects/ripple_animation.h" #include "ui/image/image.h" +#include "ui/toast/toast.h" #include "ui/text_options.h" #include "history/history.h" #include "history/history_message.h" @@ -77,17 +78,37 @@ int HistoryMessageEdited::maxWidth() const { return text.maxWidth(); } +HiddenSenderInfo::HiddenSenderInfo(const QString &name) +: name(name) +, colorPeerId(Data::FakePeerIdForJustName(name)) +, userpic(Data::PeerUserpicColor(colorPeerId), name) { + nameText.setText(st::msgNameStyle, name, Ui::NameTextOptions()); + const auto parts = name.trimmed().split(' ', QString::SkipEmptyParts); + firstName = parts[0]; + for (const auto &part : parts.mid(1)) { + if (!lastName.isEmpty()) { + lastName.append(' '); + } + lastName.append(part); + } +} + void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { auto phrase = QString(); - auto fromChannel = (originalSender->isChannel() && !originalSender->isMegagroup()); + const auto fromChannel = originalSender + && originalSender->isChannel() + && !originalSender->isMegagroup(); + const auto name = originalSender + ? App::peerName(originalSender) + : hiddenSenderInfo->name; if (!originalAuthor.isEmpty()) { phrase = lng_forwarded_signed( lt_channel, - App::peerName(originalSender), + name, lt_user, originalAuthor); } else { - phrase = App::peerName(originalSender); + phrase = name; } if (via) { if (fromChannel) { @@ -121,9 +142,15 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const { Qt::LayoutDirectionAuto }; text.setText(st::fwdTextStyle, phrase, opts); + static const auto hidden = std::make_shared([] { + Ui::Toast::Show(lang(lng_forwarded_hidden)); + }); + text.setLink(1, fromChannel ? goToMessageClickHandler(originalSender, originalId) - : originalSender->openLink()); + : originalSender + ? originalSender->openLink() + : hidden); if (via) { text.setLink(2, via->link); } diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index f356e019e..7b48252ef 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "history/history_item.h" +#include "ui/empty_userpic.h" class HistoryDocument; struct WebPageData; @@ -50,11 +51,30 @@ struct HistoryMessageEdited : public RuntimeComponent { void create(const HistoryMessageVia *via) const; TimeId originalDate = 0; PeerData *originalSender = nullptr; + std::unique_ptr hiddenSenderInfo; QString originalAuthor; MsgId originalId = 0; mutable Text text = { 1 }; diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 02b9bd3ba..d5c76f34d 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -277,6 +277,7 @@ struct HistoryMessage::CreateConfig { int viewsCount = -1; QString author; PeerId senderOriginal = 0; + QString senderNameOriginal; MsgId originalId = 0; PeerId savedFromPeer = 0; MsgId savedFromMsgId = 0; @@ -291,6 +292,24 @@ struct HistoryMessage::CreateConfig { const HistoryMessageReplyMarkup *inlineMarkup = nullptr; }; +void HistoryMessage::FillForwardedInfo( + CreateConfig &config, + const MTPDmessageFwdHeader &data) { + config.originalDate = data.vdate.v; + if (data.has_from_id() || data.has_channel_id()) { + config.senderOriginal = data.has_channel_id() + ? peerFromChannel(data.vchannel_id) + : peerFromUser(data.vfrom_id); + } + if (data.has_from_name()) config.senderNameOriginal = qs(data.vfrom_name); + if (data.has_channel_post()) config.originalId = data.vchannel_post.v; + if (data.has_post_author()) config.authorOriginal = qs(data.vpost_author); + if (data.has_saved_from_peer() && data.has_saved_from_msg_id()) { + config.savedFromPeer = peerFromMTP(data.vsaved_from_peer); + config.savedFromMsgId = data.vsaved_from_msg_id.v; + } +} + HistoryMessage::HistoryMessage( not_null history, const MTPDmessage &data) @@ -300,22 +319,12 @@ HistoryMessage::HistoryMessage( data.vflags.v, data.vdate.v, data.has_from_id() ? data.vfrom_id.v : UserId(0)) { - CreateConfig config; + auto config = CreateConfig(); - if (data.has_fwd_from() && data.vfwd_from.type() == mtpc_messageFwdHeader) { - auto &f = data.vfwd_from.c_messageFwdHeader(); - config.originalDate = f.vdate.v; - if (f.has_from_id() || f.has_channel_id()) { - config.senderOriginal = f.has_channel_id() - ? peerFromChannel(f.vchannel_id) - : peerFromUser(f.vfrom_id); - if (f.has_channel_post()) config.originalId = f.vchannel_post.v; - if (f.has_post_author()) config.authorOriginal = qs(f.vpost_author); - if (f.has_saved_from_peer() && f.has_saved_from_msg_id()) { - config.savedFromPeer = peerFromMTP(f.vsaved_from_peer); - config.savedFromMsgId = f.vsaved_from_msg_id.v; - } - } + if (data.has_fwd_from()) { + data.vfwd_from.match([&](const MTPDmessageFwdHeader &data) { + FillForwardedInfo(config, data); + }); } if (data.has_reply_to_msg_id()) config.replyTo = data.vreply_to_msg_id.v; if (data.has_via_bot_id()) config.viaBotId = data.vvia_bot_id.v; @@ -350,7 +359,7 @@ HistoryMessage::HistoryMessage( mtpCastFlags(data.vflags.v), data.vdate.v, data.has_from_id() ? data.vfrom_id.v : UserId(0)) { - CreateConfig config; + auto config = CreateConfig(); if (data.has_reply_to_msg_id()) config.replyTo = data.vreply_to_msg_id.v; @@ -385,17 +394,22 @@ HistoryMessage::HistoryMessage( from) { const auto peer = history->peer; - CreateConfig config; + auto config = CreateConfig(); if (original->Has() || !original->history()->peer->isSelf()) { // Server doesn't add "fwd_from" to non-forwarded messages from chat with yourself. config.originalDate = original->dateOriginal(); - auto senderOriginal = original->senderOriginal(); - config.senderOriginal = senderOriginal->id; - config.authorOriginal = original->authorOriginal(); - if (senderOriginal->isChannel()) { - config.originalId = original->idOriginal(); + if (const auto info = original->hiddenForwardedInfo()) { + config.senderNameOriginal = info->name; + } else if (const auto senderOriginal = original->senderOriginal()) { + config.senderOriginal = senderOriginal->id; + if (senderOriginal->isChannel()) { + config.originalId = original->idOriginal(); + } + } else { + Unexpected("Corrupt forwarded information in message."); } + config.authorOriginal = original->authorOriginal(); } if (peer->isSelf()) { // @@ -455,7 +469,7 @@ HistoryMessage::HistoryMessage( const QString &postAuthor, const TextWithEntities &textWithEntities) : HistoryItem(history, id, flags, date, (flags & MTPDmessage::Flag::f_from_id) ? from : 0) { - createComponentsHelper(flags, replyTo, viaBotId, postAuthor, MTPnullMarkup); + createComponentsHelper(flags, replyTo, viaBotId, postAuthor, MTPReplyMarkup()); setText(textWithEntities); } @@ -522,7 +536,7 @@ void HistoryMessage::createComponentsHelper( UserId viaBotId, const QString &postAuthor, const MTPReplyMarkup &markup) { - CreateConfig config; + auto config = CreateConfig(); if (flags & MTPDmessage::Flag::f_via_bot_id) config.viaBotId = viaBotId; if (flags & MTPDmessage::Flag::f_reply_to_msg_id) config.replyTo = replyTo; @@ -540,10 +554,10 @@ int HistoryMessage::viewsCount() const { return HistoryItem::viewsCount(); } -not_null HistoryMessage::displayFrom() const { +PeerData *HistoryMessage::displayFrom() const { return history()->peer->isSelf() ? senderOriginal() - : author(); + : author().get(); } bool HistoryMessage::updateDependencyItem() { @@ -636,7 +650,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) { if (config.editDate != TimeId(0)) { mask |= HistoryMessageEdited::Bit(); } - if (config.senderOriginal) { + if (config.originalDate != 0) { mask |= HistoryMessageForwarded::Bit(); } if (config.mtpMarkup) { @@ -672,16 +686,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) { if (const auto msgsigned = Get()) { msgsigned->author = config.author; } - if (const auto forwarded = Get()) { - forwarded->originalDate = config.originalDate; - forwarded->originalSender = history()->owner().peer( - config.senderOriginal); - forwarded->originalId = config.originalId; - forwarded->originalAuthor = config.authorOriginal; - forwarded->savedFromPeer = history()->owner().peerLoaded( - config.savedFromPeer); - forwarded->savedFromMsgId = config.savedFromMsgId; - } + setupForwardedComponent(config); if (const auto markup = Get()) { if (config.mtpMarkup) { markup->create(*config.mtpMarkup); @@ -692,7 +697,28 @@ void HistoryMessage::createComponents(const CreateConfig &config) { _flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button; } } - _fromNameVersion = displayFrom()->nameVersion; + const auto from = displayFrom(); + _fromNameVersion = from ? from->nameVersion : 1; +} + +void HistoryMessage::setupForwardedComponent(const CreateConfig &config) { + const auto forwarded = Get(); + if (!forwarded) { + return; + } + forwarded->originalDate = config.originalDate; + forwarded->originalSender = config.senderOriginal + ? history()->owner().peer(config.senderOriginal).get() + : nullptr; + if (!forwarded->originalSender) { + forwarded->hiddenSenderInfo = std::make_unique( + config.senderNameOriginal); + } + forwarded->originalId = config.originalId; + forwarded->originalAuthor = config.authorOriginal; + forwarded->savedFromPeer = history()->owner().peerLoaded( + config.savedFromPeer); + forwarded->savedFromMsgId = config.savedFromMsgId; } QString FormatViewsCount(int views) { @@ -923,6 +949,25 @@ void HistoryMessage::updateSentMedia(const MTPMessageMedia *media) { history()->owner().requestItemResize(this); } +void HistoryMessage::updateForwardedInfo(const MTPMessageFwdHeader *fwd) { + const auto forwarded = Get(); + if (!fwd) { + if (forwarded) { + LOG(("API Error: Server removed forwarded information.")); + } + return; + } else if (!forwarded) { + LOG(("API Error: Server added forwarded information.")); + return; + } + fwd->match([&](const MTPDmessageFwdHeader &data) { + auto config = CreateConfig(); + FillForwardedInfo(config, data); + setupForwardedComponent(config); + history()->owner().requestItemResize(this); + }); +} + void HistoryMessage::addToUnreadMentions(UnreadMentionType type) { if (IsServerMsgId(id) && isUnreadMention()) { if (history()->addToUnreadMentions(id, type)) { diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index edbaf5584..9154b59b5 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -114,6 +114,7 @@ public: void updateReplyMarkup(const MTPReplyMarkup *markup) override { setReplyMarkup(markup); } + void updateForwardedInfo(const MTPMessageFwdHeader *fwd) override; void addToUnreadMentions(UnreadMentionType type) override; void eraseFromUnreadMentions() override; @@ -125,7 +126,7 @@ public: bool textHasLinks() const override; int viewsCount() const override; - not_null displayFrom() const; + PeerData *displayFrom() const; bool updateDependencyItem() override; MsgId dependencyMsgId() const override { return replyToId(); @@ -164,6 +165,11 @@ private: struct CreateConfig; void createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, UserId viaBotId, const QString &postAuthor, const MTPReplyMarkup &markup); void createComponents(const CreateConfig &config); + void setupForwardedComponent(const CreateConfig &config); + + static void FillForwardedInfo( + CreateConfig &config, + const MTPDmessageFwdHeader &data); void updateAdminBadgeState(); ClickHandlerPtr fastReplyLink() const; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 2acb4dff2..77d245c46 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2753,7 +2753,7 @@ void HistoryWidget::saveEditMsg() { MTP_int(_editMsgId), MTP_string(sending.text), MTPInputMedia(), - MTPnullMarkup, + MTPReplyMarkup(), sentEntities), rpcDone(&HistoryWidget::saveEditMsgDone, _history), rpcFail(&HistoryWidget::saveEditMsgFail, _history)); @@ -4268,13 +4268,13 @@ void HistoryWidget::sendFileConfirmed( MTP_int(newId.msg), MTP_int(messageFromId), peerToMTP(file->to.peer), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(caption.text), photo, - MTPnullMarkup, + MTPReplyMarkup(), localEntities, MTP_int(1), MTPint(), @@ -4293,13 +4293,13 @@ void HistoryWidget::sendFileConfirmed( MTP_int(newId.msg), MTP_int(messageFromId), peerToMTP(file->to.peer), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(caption.text), document, - MTPnullMarkup, + MTPReplyMarkup(), localEntities, MTP_int(1), MTPint(), @@ -4321,13 +4321,13 @@ void HistoryWidget::sendFileConfirmed( MTP_int(newId.msg), MTP_int(messageFromId), peerToMTP(file->to.peer), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(caption.text), document, - MTPnullMarkup, + MTPReplyMarkup(), localEntities, MTP_int(1), MTPint(), @@ -5476,7 +5476,7 @@ bool HistoryWidget::sendExistingPhoto( messagePostAuthor, photo, caption, - MTPnullMarkup); + MTPReplyMarkup()); _history->sendRequestId = MTP::send( MTPmessages_SendMedia( @@ -5489,7 +5489,7 @@ bool HistoryWidget::sendExistingPhoto( MTPint()), MTP_string(caption.text), MTP_long(randomId), - MTPnullMarkup, + MTPReplyMarkup(), sentEntities), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), @@ -6229,23 +6229,36 @@ void HistoryWidget::updateForwardingTexts() { int32 version = 0; QString from, text; if (const auto count = int(_toForward.size())) { - QMap fromUsersMap; - QVector fromUsers; - fromUsers.reserve(_toForward.size()); + auto insertedPeers = base::flat_set>(); + auto insertedNames = base::flat_set(); + auto fullname = QString(); + auto names = std::vector(); + names.reserve(_toForward.size()); for (const auto item : _toForward) { - const auto from = item->senderOriginal(); - if (!fromUsersMap.contains(from)) { - fromUsersMap.insert(from, true); - fromUsers.push_back(from); + if (const auto from = item->senderOriginal()) { + if (!insertedPeers.contains(from)) { + insertedPeers.emplace(from); + names.push_back(from->shortName()); + fullname = App::peerName(from); + } + version += from->nameVersion; + } else if (const auto info = item->hiddenForwardedInfo()) { + if (!insertedNames.contains(info->name)) { + insertedNames.emplace(info->name); + names.push_back(info->firstName); + fullname = info->name; + } + ++version; + } else { + Unexpected("Corrupt forwarded information in message."); } - version += from->nameVersion; } - if (fromUsers.size() > 2) { - from = lng_forwarding_from(lt_count, fromUsers.size() - 1, lt_user, fromUsers.at(0)->shortName()); - } else if (fromUsers.size() < 2) { - from = fromUsers.at(0)->name; + if (names.size() > 2) { + from = lng_forwarding_from(lt_count, names.size() - 1, lt_user, names[0]); + } else if (names.size() < 2) { + from = fullname; } else { - from = lng_forwarding_from_two(lt_user, fromUsers.at(0)->shortName(), lt_second_user, fromUsers.at(1)->shortName()); + from = lng_forwarding_from_two(lt_user, names[0], lt_second_user, names[1]); } if (count < 2) { @@ -6266,7 +6279,13 @@ void HistoryWidget::checkForwardingInfo() { if (!_toForward.empty()) { auto version = 0; for (const auto item : _toForward) { - version += item->senderOriginal()->nameVersion; + if (const auto from = item->senderOriginal()) { + version += from->nameVersion; + } else if (const auto info = item->hiddenForwardedInfo()) { + ++version; + } else { + Unexpected("Corrupt forwarded information in message."); + } } if (version != _toForwardNameVersion) { updateForwardingTexts(); diff --git a/Telegram/SourceFiles/history/media/history_media_contact.cpp b/Telegram/SourceFiles/history/media/history_media_contact.cpp index 9cc499e15..459581cb9 100644 --- a/Telegram/SourceFiles/history/media/history_media_contact.cpp +++ b/Telegram/SourceFiles/history/media/history_media_contact.cpp @@ -99,9 +99,12 @@ QSize HistoryContact::countOptimalSize() { if (_contact) { _contact->loadUserpic(); } else { + const auto full = _name.originalText(); _photoEmpty = std::make_unique( - Data::PeerUserpicColor(_userId ? _userId : _parent->data()->id), - _name.originalText()); + Data::PeerUserpicColor(_userId + ? peerFromUser(_userId) + : Data::FakePeerIdForJustName(full)), + full); } if (_contact && _contact->contactStatus() == UserData::ContactStatus::Contact) { diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 9a64f992d..be5ed9994 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -26,6 +26,25 @@ namespace { // A new message from the same sender is attached to previous within 15 minutes. constexpr int kAttachMessageToPreviousSecondsDelta = 900; +bool IsAttachedToPreviousInSavedMessages( + not_null previous, + not_null item) { + const auto forwarded = previous->Has(); + const auto sender = previous->senderOriginal(); + if (forwarded != item->Has()) { + return false; + } else if (sender != item->senderOriginal()) { + return false; + } else if (!forwarded || sender) { + return true; + } + const auto previousInfo = previous->hiddenForwardedInfo(); + const auto itemInfo = item->hiddenForwardedInfo(); + Assert(previousInfo != nullptr); + Assert(itemInfo != nullptr); + return (*previousInfo == *itemInfo); +} + } // namespace TextSelection UnshiftItemSelection( @@ -312,8 +331,7 @@ bool Element::computeIsAttachToPrevious(not_null previous) { || (!item->isPost() && !prev->isPost())); if (possible) { if (item->history()->peer->isSelf()) { - return prev->senderOriginal() == item->senderOriginal() - && (prev->Has() == item->Has()); + return IsAttachedToPreviousInSavedMessages(prev, item); } else { return prev->from() == item->from(); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 163d15ee2..9d647c2ce 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_peer_menu.h" #include "auth_session.h" #include "ui/widgets/popup_menu.h" +#include "ui/toast/toast.h" #include "lang/lang_keys.h" #include "boxes/peers/edit_participant_box.h" #include "data/data_session.h" @@ -1303,12 +1304,23 @@ void ListWidget::paintEvent(QPaintEvent *e) { const auto message = view->data()->toHistoryMessage(); Assert(message != nullptr); - message->from()->paintUserpicLeft( - p, - st::historyPhotoLeft, - userpicTop, - view->width(), - st::msgPhotoSize); + if (const auto from = message->displayFrom()) { + from->paintUserpicLeft( + p, + st::historyPhotoLeft, + userpicTop, + view->width(), + st::msgPhotoSize); + } else if (const auto info = message->hiddenForwardedInfo()) { + info->userpic.paint( + p, + st::historyPhotoLeft, + userpicTop, + view->width(), + st::msgPhotoSize); + } else { + Unexpected("Corrupt forwarded information in message."); + } } return true; }); @@ -2147,9 +2159,10 @@ void ListWidget::mouseActionUpdate() { const auto message = view->data()->toHistoryMessage(); Assert(message != nullptr); - dragState = TextState( - nullptr, - message->displayFrom()->openLink()); + const auto from = message->displayFrom(); + dragState = TextState(nullptr, from + ? from->openLink() + : hiddenUserpicLink(message->fullId())); _overItemExact = App::histItemById(dragState.itemId); lnkhost = view; return false; @@ -2221,6 +2234,13 @@ void ListWidget::mouseActionUpdate() { //} // #TODO select scroll } +ClickHandlerPtr ListWidget::hiddenUserpicLink(FullMsgId id) { + static const auto result = std::make_shared([] { + Ui::Toast::Show(lang(lng_forwarded_hidden)); + }); + return result; +} + style::cursor ListWidget::computeMouseCursor() const { if (ClickHandler::getPressed() || ClickHandler::getActive()) { return style::cur_pointer; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index e9cd1c211..4b8425bc7 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -409,6 +409,8 @@ private: template void enumerateDates(Method method); + ClickHandlerPtr hiddenUserpicLink(FullMsgId id); + static constexpr auto kMinimalIdsLimit = 24; not_null _delegate; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index a4b2da3ab..f087e361b 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/media/history_media.h" #include "history/media/history_media_web_page.h" #include "history/history.h" +#include "ui/toast/toast.h" #include "data/data_session.h" #include "data/data_user.h" #include "lang/lang_keys.h" @@ -149,7 +150,7 @@ void PaintBubble(Painter &p, QRect rect, int outerWidth, bool selected, bool out App::roundRect(p, rect, bg, cors, &sh, parts); } -style::color FromNameFg(not_null peer, bool selected) { +style::color FromNameFg(PeerId peerId, bool selected) { if (selected) { const style::color colors[] = { st::historyPeer1NameFgSelected, @@ -161,7 +162,7 @@ style::color FromNameFg(not_null peer, bool selected) { st::historyPeer7NameFgSelected, st::historyPeer8NameFgSelected, }; - return colors[Data::PeerColorIndex(peer->id)]; + return colors[Data::PeerColorIndex(peerId)]; } else { const style::color colors[] = { st::historyPeer1NameFg, @@ -173,7 +174,7 @@ style::color FromNameFg(not_null peer, bool selected) { st::historyPeer7NameFg, st::historyPeer8NameFg, }; - return colors[Data::PeerColorIndex(peer->id)]; + return colors[Data::PeerColorIndex(peerId)]; } } @@ -286,8 +287,12 @@ QSize Message::performCountOptimalSize() { // Count parts in maxWidth(), don't count them in minHeight(). // They will be added in resizeGetHeight() anyway. if (displayFromName()) { + const auto from = item->displayFrom(); + const auto &name = from + ? from->nameText + : item->hiddenForwardedInfo()->nameText; auto namew = st::msgPadding.left() - + item->displayFrom()->nameText.maxWidth() + + name.maxWidth() + st::msgPadding.right(); if (via && !displayForwardedFrom()) { namew += st::msgServiceFont->spacew + via->maxWidth; @@ -421,7 +426,9 @@ void Message::draw( } if (bubble) { - if (displayFromName() && item->displayFrom()->nameVersion > item->_fromNameVersion) { + if (displayFromName() + && item->displayFrom() + && item->displayFrom()->nameVersion > item->_fromNameVersion) { fromNameUpdated(g.width()); } @@ -531,13 +538,23 @@ void Message::paintFromName( } p.setFont(st::msgNameFont); - if (item->isPost()) { - p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg); - } else { - p.setPen(FromNameFg(item->displayFrom(), selected)); - } - item->displayFrom()->nameText.drawElided(p, availableLeft, trect.top(), availableWidth); - auto skipWidth = item->displayFrom()->nameText.maxWidth() + st::msgServiceFont->spacew; + const auto nameText = [&]() -> const Text* { + const auto from = item->displayFrom(); + if (item->isPost()) { + p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg); + return &from->nameText; + } else if (from) { + p.setPen(FromNameFg(from->id, selected)); + return &from->nameText; + } else if (const auto info = item->hiddenForwardedInfo()) { + p.setPen(FromNameFg(info->colorPeerId, selected)); + return &info->nameText; + } else { + Unexpected("Corrupt forwarded information in message."); + } + }(); + nameText->drawElided(p, availableLeft, trect.top(), availableWidth); + const auto skipWidth = nameText->maxWidth() + st::msgServiceFont->spacew; availableLeft += skipWidth; availableWidth -= skipWidth; @@ -861,19 +878,31 @@ bool Message::getStateFromName( if (replyWidth) { availableWidth -= st::msgPadding.right() + replyWidth; } - auto user = item->displayFrom(); + const auto from = item->displayFrom(); + const auto nameText = [&]() -> const Text* { + if (from) { + return &from->nameText; + } else if (const auto info = item->hiddenForwardedInfo()) { + return &info->nameText; + } else { + Unexpected("Corrupt forwarded information in message."); + } + }(); if (point.x() >= availableLeft && point.x() < availableLeft + availableWidth - && point.x() < availableLeft + user->nameText.maxWidth()) { - outResult->link = user->openLink(); + && point.x() < availableLeft + nameText->maxWidth()) { + static const auto hidden = std::make_shared([] { + Ui::Toast::Show(lang(lng_forwarded_hidden)); + }); + outResult->link = from ? from->openLink() : hidden; return true; } auto via = item->Get(); if (via && !displayForwardedFrom() - && point.x() >= availableLeft + item->displayFrom()->nameText.maxWidth() + st::msgServiceFont->spacew + && point.x() >= availableLeft + nameText->maxWidth() + st::msgServiceFont->spacew && point.x() < availableLeft + availableWidth - && point.x() < availableLeft + user->nameText.maxWidth() + st::msgServiceFont->spacew + via->width) { + && point.x() < availableLeft + nameText->maxWidth() + st::msgServiceFont->spacew + via->width) { outResult->link = via->link; return true; } @@ -1316,7 +1345,8 @@ bool Message::displayForwardedFrom() const { || !media || !media->isDisplayed() || !media->hideForwardedFrom() - || forwarded->originalSender->isChannel(); + || (forwarded->originalSender + && forwarded->originalSender->isChannel()); } return false; } @@ -1376,6 +1406,7 @@ bool Message::displayFastShare() const { if (const auto forwarded = item->Get()) { return !peer->isSelf() && !item->out() + && forwarded->originalSender && forwarded->originalSender->isChannel() && !forwarded->originalSender->isMegagroup(); } else if (user->botInfo && !item->out()) { @@ -1521,13 +1552,23 @@ void Message::fromNameUpdated(int width) const { } else if (replyWidth) { width -= st::msgPadding.right() + replyWidth; } - item->_fromNameVersion = item->displayFrom()->nameVersion; + const auto from = item->displayFrom(); + item->_fromNameVersion = from ? from->nameVersion : 1; if (const auto via = item->Get()) { if (!displayForwardedFrom()) { + const auto nameText = [&]() -> const Text* { + if (from) { + return &from->nameText; + } else if (const auto info = item->hiddenForwardedInfo()) { + return &info->nameText; + } else { + Unexpected("Corrupted forwarded information in message."); + } + }(); via->resize(width - st::msgPadding.left() - st::msgPadding.right() - - item->displayFrom()->nameText.maxWidth() + - nameText->maxWidth() - st::msgServiceFont->spacew); } } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index e38964f0b..02830d061 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -317,7 +317,7 @@ bool Result::hasThumbDisplay() const { void Result::addToHistory(History *history, MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate, UserId viaBotId, MsgId replyToId, const QString &postAuthor) const { flags |= MTPDmessage_ClientFlag::f_from_inline_bot; - MTPReplyMarkup markup = MTPnullMarkup; + auto markup = MTPReplyMarkup(); if (_mtpKeyboard) { flags |= MTPDmessage::Flag::f_reply_markup; markup = *_mtpKeyboard; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp index 0686ad0d6..f19de835c 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp @@ -46,7 +46,7 @@ void SendDataCommon::addToHistory( MTP_int(msgId), MTP_int(fromId), peerToMTP(history->peer->id), - MTPnullFwdHeader, + MTPMessageFwdHeader(), MTP_int(viaBotId), MTP_int(replyToId), mtpDate, diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 857cdd605..d2b362956 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -157,32 +157,29 @@ bool HasForceLogoutNotification(const MTPUpdates &updates) { bool ForwardedInfoDataLoaded( not_null session, const MTPMessageFwdHeader &header) { - if (header.type() != mtpc_messageFwdHeader) { - return true; - } - auto &info = header.c_messageFwdHeader(); - if (info.has_channel_id()) { - if (!session->data().channelLoaded(info.vchannel_id.v)) { - return false; - } - if (info.has_from_id()) { - const auto from = session->data().user(info.vfrom_id.v); - if (from->loadedStatus == PeerData::NotLoaded) { + return header.match([&](const MTPDmessageFwdHeader &data) { + if (data.has_channel_id()) { + if (!session->data().channelLoaded(data.vchannel_id.v)) { return false; } - } - } else { - if (info.has_from_id() && !session->data().userLoaded(info.vfrom_id.v)) { + if (data.has_from_id()) { + const auto from = session->data().user(data.vfrom_id.v); + if (from->loadedStatus == PeerData::NotLoaded) { + return false; + } + } + } else if (data.has_from_id() + && !session->data().userLoaded(data.vfrom_id.v)) { return false; } - } - return true; + return true; + }); } bool MentionUsersLoaded( not_null session, const MTPVector &entities) { - for_const (auto &entity, entities.v) { + for (const auto &entity : entities.v) { auto type = entity.type(); if (type == mtpc_messageEntityMentionName) { if (!session->data().userLoaded(entity.c_messageEntityMentionName().vuser_id.v)) { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 35f2b49e9..961476add 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -521,9 +521,9 @@ void OverlayWidget::updateControls() { } else { _dateText = lng_mediaview_date_time(lt_date, d.date().toString(qsl("dd.MM.yy")), lt_time, d.time().toString(cTimeFormat())); } - if (_from) { - _fromName.setText(st::mediaviewTextStyle, (_from->migrateTo() ? _from->migrateTo() : _from)->name, Ui::NameTextOptions()); - _nameNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromName.maxWidth(), width() / 3), st::mediaviewFont->height); + if (!_fromName.isEmpty()) { + _fromNameLabel.setText(st::mediaviewTextStyle, _fromName, Ui::NameTextOptions()); + _nameNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, qMin(_fromNameLabel.maxWidth(), width() / 3), st::mediaviewFont->height); _dateNav = myrtlrect(st::mediaviewTextLeft + _nameNav.width() + st::mediaviewTextSkip, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height); } else { _nameNav = QRect(); @@ -920,6 +920,7 @@ void OverlayWidget::clearData() { _menu = nullptr; setContext(std::nullopt); _from = nullptr; + _fromName = QString(); _photo = nullptr; _doc = nullptr; _fullScreenVideo = false; @@ -1523,6 +1524,22 @@ void OverlayWidget::refreshMediaViewer() { preloadData(0); } +void OverlayWidget::refreshFromLabel(HistoryItem *item) { + if (_msgid && item) { + _from = item->senderOriginal(); + if (const auto info = item->hiddenForwardedInfo()) { + _fromName = info->name; + } else { + Assert(_from != nullptr); + _fromName = App::peerName( + _from->migrateTo() ? _from->migrateTo() : _from); + } + } else { + _from = _user; + _fromName = _user ? App::peerName(_user) : QString(); + } +} + void OverlayWidget::refreshCaption(HistoryItem *item) { _caption = Text(); if (!item) { @@ -1720,11 +1737,7 @@ void OverlayWidget::displayPhoto(not_null photo, HistoryItem *item) _w = ConvertScale(photo->width()); _h = ConvertScale(photo->height()); contentSizeChanged(); - if (_msgid && item) { - _from = item->senderOriginal(); - } else { - _from = _user; - } + refreshFromLabel(item); _photo->download(fileOrigin()); displayFinished(); } @@ -1860,11 +1873,7 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) { _h = contentSize.height(); } contentSizeChanged(); - if (_msgid && item) { - _from = item->senderOriginal(); - } else { - _from = _user; - } + refreshFromLabel(item); _blurred = false; displayFinished(); } @@ -2614,10 +2623,10 @@ void OverlayWidget::paintEvent(QPaintEvent *e) { p.setFont(st::mediaviewFont); // name - if (_from && _nameNav.intersects(r)) { - float64 o = overLevel(OverName); + if (_nameNav.isValid() && _nameNav.intersects(r)) { + float64 o = _from ? overLevel(OverName) : 0.; p.setOpacity((o * st::mediaviewIconOverOpacity + (1 - o) * st::mediaviewIconOpacity) * co); - _fromName.drawElided(p, _nameNav.left(), _nameNav.top(), _nameNav.width()); + _fromNameLabel.drawElided(p, _nameNav.left(), _nameNav.top(), _nameNav.width()); if (o > 0) { p.setOpacity(o * co); @@ -3330,7 +3339,7 @@ void OverlayWidget::updateOver(QPoint pos) { updateOverState(OverLeftNav); } else if (_rightNavVisible && _rightNav.contains(pos)) { updateOverState(OverRightNav); - } else if (_nameNav.contains(pos)) { + } else if (_from && _nameNav.contains(pos)) { updateOverState(OverName); } else if (IsServerMsgId(_msgid.msg) && _dateNav.contains(pos)) { updateOverState(OverDate); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 6e9e3ce1e..ec04c918d 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -217,6 +217,7 @@ private: Data::FileOrigin fileOrigin() const; + void refreshFromLabel(HistoryItem *item); void refreshCaption(HistoryItem *item); void refreshMediaViewer(); void refreshNavVisibility(); @@ -387,7 +388,8 @@ private: bool _firstOpenedPeerPhoto = false; PeerData *_from = nullptr; - Text _fromName; + QString _fromName; + Text _fromNameLabel; std::optional _index; // Index in current _sharedMedia data. std::optional _fullIndex; // Index in full shared media. diff --git a/Telegram/SourceFiles/mtproto/type_utils.cpp b/Telegram/SourceFiles/mtproto/type_utils.cpp index 067e6ff4c..5d398cb59 100644 --- a/Telegram/SourceFiles/mtproto/type_utils.cpp +++ b/Telegram/SourceFiles/mtproto/type_utils.cpp @@ -7,17 +7,4 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "mtproto/type_utils.h" -const MTPReplyMarkup MTPnullMarkup = MTP_replyKeyboardMarkup( - MTP_flags(0), - MTP_vector(0)); const MTPVector MTPnullEntities = MTP_vector(0); -const MTPMessageFwdHeader MTPnullFwdHeader = MTP_messageFwdHeader( - MTP_flags(0), - MTPint(), - MTPstring(), - MTPint(), - MTPint(), - MTPint(), - MTPstring(), - MTPPeer(), - MTPint()); diff --git a/Telegram/SourceFiles/mtproto/type_utils.h b/Telegram/SourceFiles/mtproto/type_utils.h index 4cff19df1..10ee31ad6 100644 --- a/Telegram/SourceFiles/mtproto/type_utils.h +++ b/Telegram/SourceFiles/mtproto/type_utils.h @@ -142,6 +142,4 @@ enum class MTPDchannel_ClientFlag : uint32 { }; DEFINE_MTP_CLIENT_FLAGS(MTPDchannel) -extern const MTPReplyMarkup MTPnullMarkup; extern const MTPVector MTPnullEntities; -extern const MTPMessageFwdHeader MTPnullFwdHeader;