Rewrite sponsored to use fake sender names.

This commit is contained in:
John Preston 2021-12-31 15:47:23 +03:00
parent 68886e1b61
commit 611be90880
19 changed files with 250 additions and 125 deletions

View file

@ -42,6 +42,8 @@ class CloudImageView;
int PeerColorIndex(PeerId peerId); int PeerColorIndex(PeerId peerId);
int PeerColorIndex(BareId bareId); int PeerColorIndex(BareId bareId);
style::color PeerUserpicColor(PeerId peerId); style::color PeerUserpicColor(PeerId peerId);
// Must be used only for PeerColor-s.
PeerId FakePeerIdForJustName(const QString &name); PeerId FakePeerIdForJustName(const QString &name);
class RestrictionCheckResult { class RestrictionCheckResult {

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_text_entities.h" #include "api/api_text_entities.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "base/unixtime.h" #include "base/unixtime.h"
#include "data/data_user.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_peer_id.h" #include "data/data_peer_id.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -71,23 +72,10 @@ bool SponsoredMessages::append(not_null<History*> history) {
return false; return false;
} }
const auto flags = MessageFlags(0) entryIt->item.reset(history->addNewLocalMessage(
| (history->peer->isChannel() ? MessageFlag::Post : MessageFlags(0))
| MessageFlag::HasFromId
| MessageFlag::IsSponsored
| MessageFlag::Local;
auto local = history->addNewLocalMessage(
_session->data().nextLocalMessageId(), _session->data().nextLocalMessageId(),
flags, entryIt->sponsored.from,
UserId(0), entryIt->sponsored.textWithEntities));
MsgId(0),
HistoryItem::NewMessageDate(0),
entryIt->sponsored.fromId,
QString(),
entryIt->sponsored.textWithEntities,
MTP_messageMediaEmpty(),
HistoryMessageMarkupData());
entryIt->item.reset(std::move(local));
return true; return true;
} }
@ -163,36 +151,49 @@ void SponsoredMessages::append(
}); });
const auto randomId = data.vrandom_id().v; const auto randomId = data.vrandom_id().v;
const auto hash = qs(data.vchat_invite_hash().value_or_empty()); const auto hash = qs(data.vchat_invite_hash().value_or_empty());
const auto fromId = [&] { const auto makeFrom = [](not_null<PeerData*> peer) {
const auto channel = peer->asChannel();
return SponsoredFrom{
.peer = peer,
.title = peer->name,
.isBroadcast = (channel && channel->isBroadcast()),
.isMegagroup = (channel && channel->isMegagroup()),
.isChannel = (channel != nullptr),
.isPublic = (channel && channel->isPublic()),
.isBot = (peer->isUser() && peer->asUser()->isBot()),
};
};
const auto from = [&]() -> SponsoredFrom {
if (data.vfrom_id()) { if (data.vfrom_id()) {
return peerFromMTP(*data.vfrom_id()); return makeFrom(
_session->data().peer(peerFromMTP(*data.vfrom_id())));
} }
Assert(data.vchat_invite()); Assert(data.vchat_invite());
return data.vchat_invite()->match([](const MTPDchatInvite &data) { return data.vchat_invite()->match([](const MTPDchatInvite &data) {
return Data::FakePeerIdForJustName(qs(data.vtitle())); return SponsoredFrom{
.title = qs(data.vtitle()),
.isBroadcast = data.is_broadcast(),
.isMegagroup = data.is_megagroup(),
.isChannel = data.is_channel(),
.isPublic = data.is_public(),
};
}, [&](const MTPDchatInviteAlready &data) { }, [&](const MTPDchatInviteAlready &data) {
const auto chat = _session->data().processChat(data.vchat()); const auto chat = _session->data().processChat(data.vchat());
if (!chat) {
return PeerId(0);
}
if (const auto channel = chat->asChannel()) { if (const auto channel = chat->asChannel()) {
channel->clearInvitePeek(); channel->clearInvitePeek();
} }
return chat->id; return makeFrom(chat);
}, [&](const MTPDchatInvitePeek &data) { }, [&](const MTPDchatInvitePeek &data) {
const auto chat = _session->data().processChat(data.vchat()); const auto chat = _session->data().processChat(data.vchat());
if (!chat) {
return PeerId(0);
}
if (const auto channel = chat->asChannel()) { if (const auto channel = chat->asChannel()) {
channel->setInvitePeek(hash, data.vexpires().v); channel->setInvitePeek(hash, data.vexpires().v);
} }
return chat->id; return makeFrom(chat);
}); });
}(); }();
auto sharedMessage = SponsoredMessage{ auto sharedMessage = SponsoredMessage{
.randomId = randomId, .randomId = randomId,
.fromId = fromId, .from = from,
.textWithEntities = { .textWithEntities = {
.text = qs(data.vmessage()), .text = qs(data.vmessage()),
.entities = Api::EntitiesFromMTP( .entities = Api::EntitiesFromMTP(
@ -263,17 +264,17 @@ void SponsoredMessages::view(const FullMsgId &fullId) {
}).send(); }).send();
} }
SponsoredMessages::ChannelPost SponsoredMessages::channelPost( SponsoredMessages::Details SponsoredMessages::lookupDetails(
const FullMsgId &fullId) const { const FullMsgId &fullId) const {
const auto entryPtr = find(fullId); const auto entryPtr = find(fullId);
if (!entryPtr) { if (!entryPtr) {
return { .msgId = ShowAtUnreadMsgId, .hash = std::nullopt }; return {};
} }
const auto msgId = entryPtr->sponsored.msgId; const auto &hash = entryPtr->sponsored.chatInviteHash;
const auto hash = entryPtr->sponsored.chatInviteHash;
return { return {
.msgId = msgId ? msgId : ShowAtUnreadMsgId,
.hash = hash.isEmpty() ? std::nullopt : std::make_optional(hash), .hash = hash.isEmpty() ? std::nullopt : std::make_optional(hash),
.peer = entryPtr->sponsored.from.peer,
.msgId = entryPtr->sponsored.msgId,
}; };
} }

View file

@ -20,9 +20,19 @@ namespace Data {
class Session; class Session;
struct SponsoredMessage final { struct SponsoredFrom {
PeerData *peer = nullptr;
QString title;
bool isBroadcast = false;
bool isMegagroup = false;
bool isChannel = false;
bool isPublic = false;
bool isBot = false;
};
struct SponsoredMessage {
QByteArray randomId; QByteArray randomId;
PeerId fromId; SponsoredFrom from;
TextWithEntities textWithEntities; TextWithEntities textWithEntities;
History *history = nullptr; History *history = nullptr;
MsgId msgId; MsgId msgId;
@ -31,9 +41,10 @@ struct SponsoredMessage final {
class SponsoredMessages final { class SponsoredMessages final {
public: public:
struct ChannelPost { struct Details {
MsgId msgId;
std::optional<QString> hash; std::optional<QString> hash;
PeerData *peer = nullptr;
MsgId msgId;
}; };
using RandomId = QByteArray; using RandomId = QByteArray;
explicit SponsoredMessages(not_null<Session*> owner); explicit SponsoredMessages(not_null<Session*> owner);
@ -45,7 +56,7 @@ public:
void request(not_null<History*> history); void request(not_null<History*> history);
[[nodiscard]] bool append(not_null<History*> history); [[nodiscard]] bool append(not_null<History*> history);
void clearItems(not_null<History*> history); void clearItems(not_null<History*> history);
[[nodiscard]] ChannelPost channelPost(const FullMsgId &fullId) const; [[nodiscard]] Details lookupDetails(const FullMsgId &fullId) const;
void view(const FullMsgId &fullId); void view(const FullMsgId &fullId);

View file

@ -280,9 +280,6 @@ enum class MessageFlag : uint32 {
// Contact sign-up message, notification should be skipped for Silent. // Contact sign-up message, notification should be skipped for Silent.
IsContactSignUp = (1U << 30), IsContactSignUp = (1U << 30),
// In channels.
IsSponsored = (1U << 31),
}; };
inline constexpr bool is_flag_type(MessageFlag) { return true; } inline constexpr bool is_flag_type(MessageFlag) { return true; }
using MessageFlags = base::flags<MessageFlag>; using MessageFlags = base::flags<MessageFlag>;

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_chat_filters.h" #include "data/data_chat_filters.h"
#include "data/data_scheduled_messages.h" #include "data/data_scheduled_messages.h"
#include "data/data_sponsored_messages.h"
#include "data/data_send_action.h" #include "data/data_send_action.h"
#include "data/data_folder.h" #include "data/data_folder.h"
#include "data/data_photo.h" #include "data/data_photo.h"
@ -673,6 +674,18 @@ not_null<HistoryItem*> History::addNewLocalMessage(
true); true);
} }
not_null<HistoryItem*> History::addNewLocalMessage(
MsgId id,
Data::SponsoredFrom from,
const TextWithEntities &textWithEntities) {
return addNewItem(
makeMessage(
id,
from,
textWithEntities),
true);
}
void History::setUnreadMentionsCount(int count) { void History::setUnreadMentionsCount(int count) {
const auto had = _unreadMentionsCount && (*_unreadMentionsCount > 0); const auto had = _unreadMentionsCount && (*_unreadMentionsCount > 0);
if (_unreadMentions.size() > count) { if (_unreadMentions.size() > count) {

View file

@ -35,6 +35,7 @@ struct Draft;
class Session; class Session;
class Folder; class Folder;
class ChatFilter; class ChatFilter;
struct SponsoredFrom;
enum class ForwardOptions { enum class ForwardOptions {
PreserveInfo, PreserveInfo,
@ -190,6 +191,10 @@ public:
const QString &postAuthor, const QString &postAuthor,
not_null<GameData*> game, not_null<GameData*> game,
HistoryMessageMarkupData &&markup); HistoryMessageMarkupData &&markup);
not_null<HistoryItem*> addNewLocalMessage(
MsgId id,
Data::SponsoredFrom from,
const TextWithEntities &textWithEntities); // sponsored
// Used only internally and for channel admin log. // Used only internally and for channel admin log.
not_null<HistoryItem*> createItem( not_null<HistoryItem*> createItem(

View file

@ -896,7 +896,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
userpicTop, userpicTop,
width(), width(),
st::msgPhotoSize); st::msgPhotoSize);
} else if (const auto info = view->data()->hiddenForwardedInfo()) { } else if (const auto info = view->data()->hiddenSenderInfo()) {
info->userpic.paint( info->userpic.paint(
p, p,
st::historyPhotoLeft, st::historyPhotoLeft,

View file

@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_sponsored_messages.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -294,6 +295,10 @@ HistoryItem *HistoryItem::lookupDiscussionPostOriginal() const {
PeerData *HistoryItem::displayFrom() const { PeerData *HistoryItem::displayFrom() const {
if (const auto sender = discussionPostOriginalSender()) { if (const auto sender = discussionPostOriginalSender()) {
return sender; return sender;
} else if (const auto sponsored = Get<HistoryMessageSponsored>()) {
if (sponsored->sender) {
return nullptr;
}
} else if (const auto forwarded = Get<HistoryMessageForwarded>()) { } else if (const auto forwarded = Get<HistoryMessageForwarded>()) {
if (history()->peer->isSelf() || history()->peer->isRepliesChat() || forwarded->imported) { if (history()->peer->isSelf() || history()->peer->isRepliesChat() || forwarded->imported) {
return forwarded->originalSender; return forwarded->originalSender;
@ -484,7 +489,7 @@ bool HistoryItem::isScheduled() const {
} }
bool HistoryItem::isSponsored() const { bool HistoryItem::isSponsored() const {
return (_flags & MessageFlag::IsSponsored); return Has<HistoryMessageSponsored>();
} }
bool HistoryItem::skipNotification() const { bool HistoryItem::skipNotification() const {
@ -900,8 +905,10 @@ PeerData *HistoryItem::senderOriginal() const {
return (peer->isChannel() && !peer->isMegagroup()) ? peer : from(); return (peer->isChannel() && !peer->isMegagroup()) ? peer : from();
} }
const HiddenSenderInfo *HistoryItem::hiddenForwardedInfo() const { const HiddenSenderInfo *HistoryItem::hiddenSenderInfo() const {
if (const auto forwarded = Get<HistoryMessageForwarded>()) { if (const auto sponsored = Get<HistoryMessageSponsored>()) {
return sponsored->sender.get();
} else if (const auto forwarded = Get<HistoryMessageForwarded>()) {
return forwarded->hiddenSenderInfo.get(); return forwarded->hiddenSenderInfo.get();
} }
return nullptr; return nullptr;
@ -1118,6 +1125,8 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
const auto sender = [&]() -> std::optional<QString> { const auto sender = [&]() -> std::optional<QString> {
if (options.hideSender || isPost() || isEmpty()) { if (options.hideSender || isPost() || isEmpty()) {
return {}; return {};
} else if (const auto sponsored = Get<HistoryMessageSponsored>()) {
return sponsored->sender->name;
} else if (!_history->peer->isUser()) { } else if (!_history->peer->isUser()) {
if (const auto from = displayFrom()) { if (const auto from = displayFrom()) {
return fromSender(from); return fromSender(from);

View file

@ -387,7 +387,7 @@ public:
[[nodiscard]] TimeId dateOriginal() const; [[nodiscard]] TimeId dateOriginal() const;
[[nodiscard]] PeerData *senderOriginal() const; [[nodiscard]] PeerData *senderOriginal() const;
[[nodiscard]] const HiddenSenderInfo *hiddenForwardedInfo() const; [[nodiscard]] const HiddenSenderInfo *hiddenSenderInfo() const;
[[nodiscard]] not_null<PeerData*> fromOriginal() const; [[nodiscard]] not_null<PeerData*> fromOriginal() const;
[[nodiscard]] QString authorOriginal() const; [[nodiscard]] QString authorOriginal() const;
[[nodiscard]] MsgId idOriginal() const; [[nodiscard]] MsgId idOriginal() const;

View file

@ -102,6 +102,17 @@ struct HistoryMessageForwarded : public RuntimeComponent<HistoryMessageForwarded
bool imported = false; bool imported = false;
}; };
struct HistoryMessageSponsored : public RuntimeComponent<HistoryMessageSponsored, HistoryItem> {
enum class Type : uchar {
User,
Group,
Broadcast,
Bot,
};
std::unique_ptr<HiddenSenderInfo> sender;
Type type = Type::User;
};
struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply, HistoryItem> { struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply, HistoryItem> {
HistoryMessageReply() = default; HistoryMessageReply() = default;
HistoryMessageReply(const HistoryMessageReply &other) = delete; HistoryMessageReply(const HistoryMessageReply &other) = delete;

View file

@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_web_page.h" #include "data/data_web_page.h"
#include "data/data_sponsored_messages.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -582,7 +583,7 @@ HistoryMessage::HistoryMessage(
&& (!originalMedia || !originalMedia->forceForwardedInfo())); && (!originalMedia || !originalMedia->forceForwardedInfo()));
if (!dropForwardInfo) { if (!dropForwardInfo) {
config.originalDate = original->dateOriginal(); config.originalDate = original->dateOriginal();
if (const auto info = original->hiddenForwardedInfo()) { if (const auto info = original->hiddenSenderInfo()) {
config.senderNameOriginal = info->name; config.senderNameOriginal = info->name;
} else if (const auto senderOriginal = original->senderOriginal()) { } else if (const auto senderOriginal = original->senderOriginal()) {
config.senderOriginal = senderOriginal->id; config.senderOriginal = senderOriginal->id;
@ -768,6 +769,29 @@ HistoryMessage::HistoryMessage(
setEmptyText(); setEmptyText();
} }
HistoryMessage::HistoryMessage(
not_null<History*> history,
MsgId id,
Data::SponsoredFrom from,
const TextWithEntities &textWithEntities)
: HistoryItem(
history,
id,
((history->peer->isChannel() ? MessageFlag::Post : MessageFlag(0))
//| (from.peer ? MessageFlag::HasFromId : MessageFlag(0))
| MessageFlag::Local),
HistoryItem::NewMessageDate(0),
/*from.peer ? from.peer->id : */PeerId(0)) {
createComponentsHelper(
_flags,
MsgId(0), // replyTo
UserId(0), // viaBotId
QString(), // postAuthor
HistoryMessageMarkupData());
setText(textWithEntities);
setSponsoredFrom(from);
}
void HistoryMessage::createComponentsHelper( void HistoryMessage::createComponentsHelper(
MessageFlags flags, MessageFlags flags,
MsgId replyTo, MsgId replyTo,
@ -1915,6 +1939,23 @@ void HistoryMessage::setUnreadRepliesCount(
Data::MessageUpdate::Flag::RepliesUnreadCount); Data::MessageUpdate::Flag::RepliesUnreadCount);
} }
void HistoryMessage::setSponsoredFrom(const Data::SponsoredFrom &from) {
AddComponents(HistoryMessageSponsored::Bit());
const auto sponsored = Get<HistoryMessageSponsored>();
sponsored->sender = std::make_unique<HiddenSenderInfo>(
from.title,
false);
using Type = HistoryMessageSponsored::Type;
sponsored->type = from.isBot
? Type::Bot
: from.isBroadcast
? Type::Broadcast
: (from.peer && from.peer->isUser())
? Type::User
: Type::Group;
}
void HistoryMessage::setReplyToTop(MsgId replyToTop) { void HistoryMessage::setReplyToTop(MsgId replyToTop) {
const auto reply = Get<HistoryMessageReply>(); const auto reply = Get<HistoryMessageReply>();
if (!reply if (!reply

View file

@ -14,6 +14,10 @@ struct SendAction;
struct SendOptions; struct SendOptions;
} // namespace Api } // namespace Api
namespace Data {
struct SponsoredFrom;
} // namespace Data
namespace HistoryView { namespace HistoryView {
class Message; class Message;
} // namespace HistoryView } // namespace HistoryView
@ -115,6 +119,11 @@ public:
const QString &postAuthor, const QString &postAuthor,
not_null<GameData*> game, not_null<GameData*> game,
HistoryMessageMarkupData &&markup); // local game HistoryMessageMarkupData &&markup); // local game
HistoryMessage(
not_null<History*> history,
MsgId id,
Data::SponsoredFrom from,
const TextWithEntities &textWithEntities); // sponsored
void refreshMedia(const MTPMessageMedia *media); void refreshMedia(const MTPMessageMedia *media);
void refreshSentMedia(const MTPMessageMedia *media); void refreshSentMedia(const MTPMessageMedia *media);
@ -251,6 +260,7 @@ private:
void setUnreadRepliesCount( void setUnreadRepliesCount(
not_null<HistoryMessageViews*> views, not_null<HistoryMessageViews*> views,
int count); int count);
void setSponsoredFrom(const Data::SponsoredFrom &from);
static void FillForwardedInfo( static void FillForwardedInfo(
CreateConfig &config, CreateConfig &config,

View file

@ -7006,7 +7006,7 @@ void HistoryWidget::updateForwardingTexts() {
fullname = from->name; fullname = from->name;
} }
version += from->nameVersion; version += from->nameVersion;
} else if (const auto info = item->hiddenForwardedInfo()) { } else if (const auto info = item->hiddenSenderInfo()) {
if (!insertedNames.contains(info->name)) { if (!insertedNames.contains(info->name)) {
insertedNames.emplace(info->name); insertedNames.emplace(info->name);
names.push_back(info->firstName); names.push_back(info->firstName);
@ -7058,7 +7058,7 @@ void HistoryWidget::checkForwardingInfo() {
for (const auto item : _toForward.items) { for (const auto item : _toForward.items) {
if (const auto from = item->senderOriginal()) { if (const auto from = item->senderOriginal()) {
version += from->nameVersion; version += from->nameVersion;
} else if (const auto info = item->hiddenForwardedInfo()) { } else if (const auto info = item->hiddenSenderInfo()) {
++version; ++version;
} else { } else {
Unexpected("Corrupt forwarded information in message."); Unexpected("Corrupt forwarded information in message.");

View file

@ -45,7 +45,7 @@ namespace {
// A new message from the same sender is attached to previous within 15 minutes. // A new message from the same sender is attached to previous within 15 minutes.
constexpr int kAttachMessageToPreviousSecondsDelta = 900; constexpr int kAttachMessageToPreviousSecondsDelta = 900;
bool IsAttachedToPreviousInSavedMessages( [[nodiscard]] bool IsAttachedToPreviousInSavedMessages(
not_null<HistoryItem*> previous, not_null<HistoryItem*> previous,
HistoryMessageForwarded *prevForwarded, HistoryMessageForwarded *prevForwarded,
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
@ -65,6 +65,22 @@ bool IsAttachedToPreviousInSavedMessages(
return (*previousInfo == *itemInfo); return (*previousInfo == *itemInfo);
} }
[[nodiscard]] Window::SessionController *ContextOrSessionWindow(
const ClickHandlerContext &context,
not_null<Main::Session*> session) {
if (const auto controller = context.sessionWindow.get()) {
return controller;
}
const auto &windows = session->windows();
if (windows.empty()) {
session->domain().activate(&session->account());
if (windows.empty()) {
return nullptr;
}
}
return windows.front();
}
} // namespace } // namespace
std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient( std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient(
@ -599,7 +615,26 @@ ClickHandlerPtr Element::fromLink() const {
return _fromLink; return _fromLink;
} }
const auto item = data(); const auto item = data();
if (const auto from = item->displayFrom()) { if (item->isSponsored()) {
const auto session = &item->history()->session();
_fromLink = std::make_shared<LambdaClickHandler>([=](
ClickContext context) {
if (context.button != Qt::LeftButton) {
return;
}
const auto my = context.other.value<ClickHandlerContext>();
if (const auto window = ContextOrSessionWindow(my, session)) {
auto &sponsored = session->data().sponsoredMessages();
const auto details = sponsored.lookupDetails(my.itemId);
if (const auto &hash = details.hash) {
Api::CheckChatInvite(window, *hash);
} else if (const auto peer = details.peer) {
window->showPeerInfo(peer);
}
}
});
return _fromLink;
} else if (const auto from = item->displayFrom()) {
_fromLink = std::make_shared<LambdaClickHandler>([=]( _fromLink = std::make_shared<LambdaClickHandler>([=](
ClickContext context) { ClickContext context) {
if (context.button != Qt::LeftButton) { if (context.button != Qt::LeftButton) {
@ -607,29 +642,8 @@ ClickHandlerPtr Element::fromLink() const {
} }
const auto my = context.other.value<ClickHandlerContext>(); const auto my = context.other.value<ClickHandlerContext>();
const auto session = &from->session(); const auto session = &from->session();
const auto window = [&]() -> Window::SessionController* { if (const auto window = ContextOrSessionWindow(my, session)) {
if (const auto controller = my.sessionWindow.get()) { window->showPeerInfo(from);
return controller;
}
const auto &windows = session->windows();
if (windows.empty()) {
session->domain().activate(&session->account());
if (windows.empty()) {
return nullptr;
}
}
return windows.front();
}();
if (window) {
const auto inviteHash = item->isSponsored()
? session->data().sponsoredMessages().channelPost(
my.itemId).hash
: std::nullopt;
if (inviteHash) {
Api::CheckChatInvite(window, *inviteHash);
} else {
window->showPeerInfo(from);
}
} }
}); });
_fromLink->setProperty(kPeerLinkPeerIdProperty, from->id.value); _fromLink->setProperty(kPeerLinkPeerIdProperty, from->id.value);

View file

@ -1753,7 +1753,7 @@ void ListWidget::paintEvent(QPaintEvent *e) {
userpicTop, userpicTop,
view->width(), view->width(),
st::msgPhotoSize); st::msgPhotoSize);
} else if (const auto info = view->data()->hiddenForwardedInfo()) { } else if (const auto info = view->data()->hiddenSenderInfo()) {
info->userpic.paint( info->userpic.paint(
p, p,
st::historyPhotoLeft, st::historyPhotoLeft,

View file

@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
#include "data/data_sponsored_messages.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -415,7 +416,7 @@ QSize Message::performCountOptimalSize() {
const auto from = item->displayFrom(); const auto from = item->displayFrom();
const auto &name = from const auto &name = from
? from->nameText() ? from->nameText()
: item->hiddenForwardedInfo()->nameText; : item->hiddenSenderInfo()->nameText;
auto namew = st::msgPadding.left() auto namew = st::msgPadding.left()
+ name.maxWidth() + name.maxWidth()
+ st::msgPadding.right(); + st::msgPadding.right();
@ -935,17 +936,19 @@ void Message::paintFromName(
const auto nameText = [&]() -> const Ui::Text::String * { const auto nameText = [&]() -> const Ui::Text::String * {
const auto from = item->displayFrom(); const auto from = item->displayFrom();
if (context.outbg || item->isPost()) { const auto service = (context.outbg || item->isPost());
p.setPen(stm->msgServiceFg); if (from) {
p.setPen(service
? stm->msgServiceFg
: FromNameFg(context, from->id));
return &from->nameText(); return &from->nameText();
} else if (from) { } else if (const auto info = item->hiddenSenderInfo()) {
p.setPen(FromNameFg(context, from->id)); p.setPen(service
return &from->nameText(); ? stm->msgServiceFg
} else if (const auto info = item->hiddenForwardedInfo()) { : FromNameFg(context, info->colorPeerId));
p.setPen(FromNameFg(context, info->colorPeerId));
return &info->nameText; return &info->nameText;
} else { } else {
Unexpected("Corrupt forwarded information in message."); Unexpected("Corrupt sender information in message.");
} }
}(); }();
nameText->drawElided(p, availableLeft, trect.top(), availableWidth); nameText->drawElided(p, availableLeft, trect.top(), availableWidth);
@ -1524,7 +1527,7 @@ bool Message::getStateFromName(
const auto nameText = [&]() -> const Ui::Text::String * { const auto nameText = [&]() -> const Ui::Text::String * {
if (from) { if (from) {
return &from->nameText(); return &from->nameText();
} else if (const auto info = item->hiddenForwardedInfo()) { } else if (const auto info = item->hiddenSenderInfo()) {
return &info->nameText; return &info->nameText;
} else { } else {
Unexpected("Corrupt forwarded information in message."); Unexpected("Corrupt forwarded information in message.");
@ -2076,14 +2079,11 @@ int Message::viewButtonHeight() const {
} }
void Message::updateViewButtonExistence() { void Message::updateViewButtonExistence() {
const auto has = [&] { const auto item = data();
const auto item = data(); const auto sponsored = item->Get<HistoryMessageSponsored>();
if (item->isSponsored()) { const auto media = sponsored ? nullptr : item->media();
return true; const auto has = sponsored
} || (media && ViewButton::MediaHasViewButton(media));
const auto media = item->media();
return media && ViewButton::MediaHasViewButton(media);
}();
if (!has) { if (!has) {
_viewButton = nullptr; _viewButton = nullptr;
return; return;
@ -2091,13 +2091,9 @@ void Message::updateViewButtonExistence() {
return; return;
} }
auto callback = [=] { history()->owner().requestViewRepaint(this); }; auto callback = [=] { history()->owner().requestViewRepaint(this); };
_viewButton = data()->isSponsored() _viewButton = sponsored
? std::make_unique<ViewButton>( ? std::make_unique<ViewButton>(sponsored, std::move(callback))
data()->displayFrom(), : std::make_unique<ViewButton>(media, std::move(callback));
std::move(callback))
: std::make_unique<ViewButton>(
data()->media(),
std::move(callback));
} }
void Message::initLogEntryOriginal() { void Message::initLogEntryOriginal() {
@ -2572,7 +2568,7 @@ void Message::fromNameUpdated(int width) const {
const auto nameText = [&]() -> const Ui::Text::String * { const auto nameText = [&]() -> const Ui::Text::String * {
if (from) { if (from) {
return &from->nameText(); return &from->nameText();
} else if (const auto info = item->hiddenForwardedInfo()) { } else if (const auto info = item->hiddenSenderInfo()) {
return &info->nameText; return &info->nameText;
} else { } else {
Unexpected("Corrupted forwarded information in message."); Unexpected("Corrupted forwarded information in message.");

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_sponsored_messages.h" #include "data/data_sponsored_messages.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_web_page.h" #include "data/data_web_page.h"
#include "history/history_item_components.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -30,20 +31,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView { namespace HistoryView {
namespace { namespace {
inline auto PeerToPhrase(not_null<PeerData*> peer) { using SponsoredType = HistoryMessageSponsored::Type;
inline auto SponsoredPhrase(SponsoredType type) {
const auto phrase = [&] { const auto phrase = [&] {
if (const auto user = peer->asUser()) { switch (type) {
return user->isBot() case SponsoredType::Bot: return tr::lng_view_button_bot;
? tr::lng_view_button_bot case SponsoredType::Group: return tr::lng_view_button_group;
: tr::lng_view_button_user; case SponsoredType::Broadcast: return tr::lng_view_button_channel;
} else if (peer->isChat()) { case SponsoredType::User: return tr::lng_view_button_user;
return tr::lng_view_button_group;
} else if (peer->isChannel()) {
return tr::lng_view_button_channel;
} }
Unexpected("Invalid peer in ViewButton."); Unexpected("SponsoredType in SponsoredPhrase.");
}()(tr::now); }();
return Ui::Text::Upper(phrase); return Ui::Text::Upper(phrase(tr::now));
} }
inline auto WebPageToPhrase(not_null<WebPageData*> webpage) { inline auto WebPageToPhrase(not_null<WebPageData*> webpage) {
@ -75,8 +75,11 @@ inline auto WebPageToPhrase(not_null<WebPageData*> webpage) {
} // namespace } // namespace
struct ViewButton::Inner { struct ViewButton::Inner {
Inner(not_null<PeerData*> peer, Fn<void()> updateCallback); Inner(
not_null<HistoryMessageSponsored*> sponsored,
Fn<void()> updateCallback);
Inner(not_null<Data::Media*> media, Fn<void()> updateCallback); Inner(not_null<Data::Media*> media, Fn<void()> updateCallback);
void updateMask(int height); void updateMask(int height);
void toggleRipple(bool pressed); void toggleRipple(bool pressed);
@ -114,22 +117,28 @@ bool ViewButton::MediaHasViewButton(
&& webpage->document->isWallPaper()); && webpage->document->isWallPaper());
} }
ViewButton::Inner::Inner(not_null<PeerData*> peer, Fn<void()> updateCallback) ViewButton::Inner::Inner(
not_null<HistoryMessageSponsored*> sponsored,
Fn<void()> updateCallback)
: margins(st::historyViewButtonMargins) : margins(st::historyViewButtonMargins)
, link(std::make_shared<LambdaClickHandler>([=](ClickContext context) { , link(std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>(); const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) { if (const auto controller = my.sessionWindow.get()) {
const auto &data = controller->session().data(); const auto &data = controller->session().data();
const auto link = data.sponsoredMessages().channelPost(my.itemId); const auto itemId = my.itemId;
if (link.hash) { const auto details = data.sponsoredMessages().lookupDetails(itemId);
Api::CheckChatInvite(controller, *link.hash); if (details.hash) {
} else { Api::CheckChatInvite(controller, *details.hash);
controller->showPeer(peer, link.msgId); } else if (details.peer) {
controller->showPeerHistory(
details.peer,
Window::SectionShow::Way::Forward,
details.msgId);
} }
} }
})) }))
, updateCallback(std::move(updateCallback)) , updateCallback(std::move(updateCallback))
, text(st::historyViewButtonTextStyle, PeerToPhrase(peer)) { , text(st::historyViewButtonTextStyle, SponsoredPhrase(sponsored->type)) {
} }
ViewButton::Inner::Inner( ViewButton::Inner::Inner(
@ -170,8 +179,10 @@ void ViewButton::Inner::toggleRipple(bool pressed) {
} }
} }
ViewButton::ViewButton(not_null<PeerData*> peer, Fn<void()> updateCallback) ViewButton::ViewButton(
: _inner(std::make_unique<Inner>(peer, std::move(updateCallback))) { not_null<HistoryMessageSponsored*> sponsored,
Fn<void()> updateCallback)
: _inner(std::make_unique<Inner>(sponsored, std::move(updateCallback))) {
} }
ViewButton::ViewButton( ViewButton::ViewButton(

View file

@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/chat_style.h" #include "ui/chat/chat_style.h"
struct HistoryMessageSponsored;
namespace Data { namespace Data {
class Media; class Media;
} // namespace Data } // namespace Data
@ -21,7 +23,9 @@ struct TextState;
class ViewButton { class ViewButton {
public: public:
ViewButton(not_null<PeerData*> peer, Fn<void()> updateCallback); ViewButton(
not_null<HistoryMessageSponsored*> sponsored,
Fn<void()> updateCallback);
ViewButton(not_null<Data::Media*> media, Fn<void()> updateCallback); ViewButton(not_null<Data::Media*> media, Fn<void()> updateCallback);
~ViewButton(); ~ViewButton();

View file

@ -2130,7 +2130,7 @@ void OverlayWidget::refreshMediaViewer() {
void OverlayWidget::refreshFromLabel() { void OverlayWidget::refreshFromLabel() {
if (_message) { if (_message) {
_from = _message->senderOriginal(); _from = _message->senderOriginal();
if (const auto info = _message->hiddenForwardedInfo()) { if (const auto info = _message->hiddenSenderInfo()) {
_fromName = info->name; _fromName = info->name;
} else { } else {
Assert(_from != nullptr); Assert(_from != nullptr);