Removed text commands from history item components.

This commit is contained in:
23rd 2021-12-26 19:29:25 +03:00 committed by John Preston
parent d6801517bb
commit b55ed7214a
20 changed files with 717 additions and 406 deletions

View File

@ -73,6 +73,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "inline_bots/inline_bot_result.h"
#include "chat_helpers/message_field.h"
#include "ui/item_text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/emoji_config.h"
#include "ui/chat/attach/attach_prepare.h"
#include "ui/toasts/common_toasts.h"
@ -470,13 +471,14 @@ void ApiWrap::sendMessageFail(
Ui::show(Box<Ui::InformBox>(
PeerFloodErrorText(&session(), PeerFloodType::Send)));
} else if (error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
const auto link = textcmdLink(
session().createInternalLinkFull(qsl("spambot")),
tr::lng_cant_more_info(tr::now));
const auto link = Ui::Text::Link(
tr::lng_cant_more_info(tr::now),
session().createInternalLinkFull(qsl("spambot")));
Ui::show(Box<Ui::InformBox>(tr::lng_error_public_groups_denied(
tr::now,
lt_more_info,
link)));
link,
Ui::Text::WithEntities)));
} else if (error.type().startsWith(qstr("SLOWMODE_WAIT_"))) {
const auto chop = qstr("SLOWMODE_WAIT_").size();
const auto left = base::StringViewMid(error.type(), chop).toInt();

View File

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/special_buttons.h"
#include "ui/special_fields.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/unread_badge.h"
#include "ui/ui_utility.h"
#include "data/data_channel.h"
@ -112,16 +113,19 @@ style::InputField CreateBioFieldStyle() {
return result;
}
QString PeerFloodErrorText(
TextWithEntities PeerFloodErrorText(
not_null<Main::Session*> session,
PeerFloodType type) {
const auto link = textcmdLink(
session->createInternalLinkFull(qsl("spambot")),
tr::lng_cant_more_info(tr::now));
if (type == PeerFloodType::InviteGroup) {
return tr::lng_cant_invite_not_contact(tr::now, lt_more_info, link);
}
return tr::lng_cant_send_to_not_contact(tr::now, lt_more_info, link);
const auto link = Ui::Text::Link(
tr::lng_cant_more_info(tr::now),
session->createInternalLinkFull(qsl("spambot")));
return ((type == PeerFloodType::InviteGroup)
? tr::lng_cant_invite_not_contact
: tr::lng_cant_send_to_not_contact)(
tr::now,
lt_more_info,
link,
Ui::Text::WithEntities);
}
void ShowAddParticipantsError(
@ -167,6 +171,14 @@ void ShowAddParticipantsError(
}
}
const auto hasBot = ranges::any_of(users, &UserData::isBot);
if (error == u"PEER_FLOOD"_q) {
const auto type = (chat->isChat() || chat->isMegagroup())
? PeerFloodType::InviteGroup
: PeerFloodType::InviteChannel;
const auto text = PeerFloodErrorText(&chat->session(), type);
Ui::show(Box<Ui::InformBox>(text), Ui::LayerOption::KeepOther);
return;
}
const auto text = [&] {
if (error == u"USER_BOT"_q) {
return tr::lng_cant_invite_bot_to_channel(tr::now);
@ -184,11 +196,6 @@ void ShowAddParticipantsError(
return tr::lng_bot_already_in_group(tr::now);
} else if (error == u"BOT_GROUPS_BLOCKED"_q) {
return tr::lng_error_cant_add_bot(tr::now);
} else if (error == u"PEER_FLOOD"_q) {
const auto type = (chat->isChat() || chat->isMegagroup())
? PeerFloodType::InviteGroup
: PeerFloodType::InviteChannel;
return PeerFloodErrorText(&chat->session(), type);
} else if (error == u"ADMINS_TOO_MUCH"_q) {
return ((chat->isChat() || chat->isMegagroup())
? tr::lng_error_admin_limit
@ -1521,10 +1528,11 @@ RevokePublicLinkBox::Inner::Inner(
st::contactsNameStyle,
peer->name,
Ui::NameTextOptions());
row.status.setText(
row.status.setMarkedText(
st::defaultTextStyle,
_session->createInternalLink(
textcmdLink(1, peer->userName())),
Ui::Text::Link(
peer->userName(),
_session->createInternalLink(peer->userName())),
Ui::DialogTextOptions());
_rows.push_back(std::move(row));
}

View File

@ -46,7 +46,7 @@ enum class PeerFloodType {
[[nodiscard]] style::InputField CreateBioFieldStyle();
[[nodiscard]] QString PeerFloodErrorText(
[[nodiscard]] TextWithEntities PeerFloodErrorText(
not_null<Main::Session*> session,
PeerFloodType type);
void ShowAddParticipantsError(

View File

@ -66,44 +66,27 @@ constexpr auto kMaxPreviewImages = 3;
using ItemPreview = HistoryView::ItemPreview;
using ItemPreviewImage = HistoryView::ItemPreviewImage;
[[nodiscard]] QString WithCaptionDialogsText(
[[nodiscard]] TextWithEntities WithCaptionNotificationText(
const QString &attachType,
const QString &caption,
bool hasMiniImages,
const HistoryView::ToPreviewOptions &options) {
if (caption.isEmpty()) {
return textcmdLink(1, TextUtilities::Clean(attachType));
const TextWithEntities &caption,
bool hasMiniImages = false) {
if (caption.text.isEmpty()) {
return Ui::Text::PlainLink(attachType);
}
return hasMiniImages
? TextUtilities::Clean(caption, !options.ignoreSpoilers)
? caption
: tr::lng_dialogs_text_media(
tr::now,
lt_media_part,
textcmdLink(1, tr::lng_dialogs_text_media_wrapped(
tr::lng_dialogs_text_media_wrapped(
tr::now,
lt_media,
TextUtilities::Clean(attachType))),
Ui::Text::PlainLink(attachType),
Ui::Text::WithEntities),
lt_caption,
TextUtilities::Clean(caption, !options.ignoreSpoilers));
}
[[nodiscard]] QString WithCaptionNotificationText(
const QString &attachType,
const QString &caption) {
if (caption.isEmpty()) {
return attachType;
}
return tr::lng_dialogs_text_media(
tr::now,
lt_media_part,
tr::lng_dialogs_text_media_wrapped(
tr::now,
lt_media,
attachType),
lt_caption,
caption);
caption,
Ui::Text::WithEntities);
}
[[nodiscard]] QImage PreparePreviewImage(
@ -352,15 +335,7 @@ bool Media::canBeGrouped() const {
}
ItemPreview Media::toPreview(ToPreviewOptions options) const {
auto result = notificationText();
auto text = result.isEmpty()
? QString()
: textcmdLink(
1,
TextUtilities::Clean(
std::move(result),
!options.ignoreSpoilers));
return { .text = std::move(text) };
return { .text = notificationText() };
}
bool Media::hasReplyPreview() const {
@ -428,9 +403,8 @@ std::unique_ptr<HistoryView::Media> Media::createView(
ItemPreview Media::toGroupPreview(
const HistoryItemsList &items,
ToPreviewOptions options) const {
const auto genericText = textcmdLink(
1,
TextUtilities::Clean(tr::lng_in_dlg_album(tr::now)));
const auto genericText = Ui::Text::PlainLink(
tr::lng_in_dlg_album(tr::now));
auto result = ItemPreview();
auto loadingContext = std::vector<std::any>();
for (const auto &item : items) {
@ -452,17 +426,17 @@ ItemPreview Media::toGroupPreview(
if (single.loadingContext.has_value()) {
loadingContext.push_back(std::move(single.loadingContext));
}
const auto original = item->originalText().text;
if (!original.isEmpty()) {
if (result.text.isEmpty()) {
result.text = TextUtilities::Clean(original);
const auto original = item->originalText();
if (!original.text.isEmpty()) {
if (result.text.text.isEmpty()) {
result.text = original;
} else {
result.text = genericText;
}
}
}
}
if (result.text.isEmpty()) {
if (result.text.text.isEmpty()) {
result.text = genericText;
}
if (!loadingContext.empty()) {
@ -536,10 +510,10 @@ bool MediaPhoto::replyPreviewLoaded() const {
return _photo->replyPreviewLoaded();
}
QString MediaPhoto::notificationText() const {
TextWithEntities MediaPhoto::notificationText() const {
return WithCaptionNotificationText(
tr::lng_in_dlg_photo(tr::now),
TextUtilities::TextWithSpoilerCommands(parent()->originalText()));
parent()->originalText());
}
ItemPreview MediaPhoto::toPreview(ToPreviewOptions options) const {
@ -569,13 +543,11 @@ ItemPreview MediaPhoto::toPreview(ToPreviewOptions options) const {
}
const auto type = tr::lng_in_dlg_photo(tr::now);
const auto caption = options.hideCaption
? QString()
: options.ignoreSpoilers
? parent()->originalText().text
: TextUtilities::TextWithSpoilerCommands(parent()->originalText());
? TextWithEntities()
: parent()->originalText();
const auto hasMiniImages = !images.empty();
return {
.text = WithCaptionDialogsText(type, caption, hasMiniImages, options),
.text = WithCaptionNotificationText(type, caption, hasMiniImages),
.images = std::move(images),
.loadingContext = std::move(context),
};
@ -791,23 +763,22 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
return tr::lng_in_dlg_file(tr::now);
}();
const auto caption = options.hideCaption
? QString()
: options.ignoreSpoilers
? parent()->originalText().text
: TextUtilities::TextWithSpoilerCommands(parent()->originalText());
? TextWithEntities()
: parent()->originalText();
const auto hasMiniImages = !images.empty();
return {
.text = WithCaptionDialogsText(type, caption, hasMiniImages, options),
.text = WithCaptionNotificationText(type, caption, hasMiniImages),
.images = std::move(images),
.loadingContext = std::move(context),
};
}
QString MediaFile::notificationText() const {
TextWithEntities MediaFile::notificationText() const {
if (const auto sticker = _document->sticker()) {
return _emoji.isEmpty()
const auto text = _emoji.isEmpty()
? tr::lng_in_dlg_sticker(tr::now)
: tr::lng_in_dlg_sticker_emoji(tr::now, lt_emoji, _emoji);
return Ui::Text::PlainLink(text);
}
const auto type = [&] {
if (_document->isVideoMessage()) {
@ -825,9 +796,7 @@ QString MediaFile::notificationText() const {
}
return tr::lng_in_dlg_file(tr::now);
}();
return WithCaptionNotificationText(
type,
TextUtilities::TextWithSpoilerCommands(parent()->originalText()));
return WithCaptionNotificationText(type, parent()->originalText());
}
QString MediaFile::pinnedTextSubstring() const {
@ -1035,8 +1004,8 @@ const SharedContact *MediaContact::sharedContact() const {
return &_contact;
}
QString MediaContact::notificationText() const {
return tr::lng_in_dlg_contact(tr::now);
TextWithEntities MediaContact::notificationText() const {
return tr::lng_in_dlg_contact(tr::now, Ui::Text::WithEntities);
}
QString MediaContact::pinnedTextSubstring() const {
@ -1124,13 +1093,16 @@ Data::CloudImage *MediaLocation::location() const {
ItemPreview MediaLocation::toPreview(ToPreviewOptions options) const {
const auto type = tr::lng_maps_point(tr::now);
const auto hasMiniImages = false;
const auto text = TextWithEntities{ .text = _title };
return {
.text = WithCaptionDialogsText(type, _title, hasMiniImages, options),
.text = WithCaptionNotificationText(type, text, hasMiniImages),
};
}
QString MediaLocation::notificationText() const {
return WithCaptionNotificationText(tr::lng_maps_point(tr::now), _title);
TextWithEntities MediaLocation::notificationText() const {
return WithCaptionNotificationText(
tr::lng_maps_point(tr::now),
{ .text = _title});
}
QString MediaLocation::pinnedTextSubstring() const {
@ -1194,7 +1166,7 @@ const Call *MediaCall::call() const {
return &_call;
}
QString MediaCall::notificationText() const {
TextWithEntities MediaCall::notificationText() const {
auto result = Text(parent(), _call.finishReason, _call.video);
if (_call.duration > 0) {
result = tr::lng_call_type_and_duration(
@ -1204,7 +1176,7 @@ QString MediaCall::notificationText() const {
lt_duration,
Ui::FormatDurationWords(_call.duration));
}
return result;
return { .text = result };
}
QString MediaCall::pinnedTextSubstring() const {
@ -1212,8 +1184,7 @@ QString MediaCall::pinnedTextSubstring() const {
}
TextForMimeData MediaCall::clipboardText() const {
return TextForMimeData::Simple(
qstr("[ ") + notificationText() + qstr(" ]"));
return { .rich = notificationText() };
}
bool MediaCall::allowsForward() const {
@ -1321,8 +1292,8 @@ ItemPreview MediaWebPage::toPreview(ToPreviewOptions options) const {
return { .text = notificationText() };
}
QString MediaWebPage::notificationText() const {
return TextUtilities::TextWithSpoilerCommands(parent()->originalText());
TextWithEntities MediaWebPage::notificationText() const {
return parent()->originalText();
}
QString MediaWebPage::pinnedTextSubstring() const {
@ -1390,7 +1361,7 @@ bool MediaGame::replyPreviewLoaded() const {
return true;
}
QString MediaGame::notificationText() const {
TextWithEntities MediaGame::notificationText() const {
// Add a game controller emoji before game title.
auto result = QString();
result.reserve(_game->title.size() + 3);
@ -1401,7 +1372,7 @@ QString MediaGame::notificationText() const {
).append(
QChar(' ')
).append(_game->title);
return result;
return { .text = result };
}
GameData *MediaGame::game() const {
@ -1496,8 +1467,8 @@ bool MediaInvoice::replyPreviewLoaded() const {
return true;
}
QString MediaInvoice::notificationText() const {
return _invoice.title;
TextWithEntities MediaInvoice::notificationText() const {
return { .text = _invoice.title };
}
QString MediaInvoice::pinnedTextSubstring() const {
@ -1541,8 +1512,8 @@ PollData *MediaPoll::poll() const {
return _poll;
}
QString MediaPoll::notificationText() const {
return _poll->question;
TextWithEntities MediaPoll::notificationText() const {
return Ui::Text::PlainLink(_poll->question);
}
QString MediaPoll::pinnedTextSubstring() const {
@ -1616,16 +1587,16 @@ bool MediaDice::allowsRevoke(TimeId now) const {
return (now >= parent()->date() + kFastRevokeRestriction);
}
QString MediaDice::notificationText() const {
return _emoji;
TextWithEntities MediaDice::notificationText() const {
return { .text = _emoji };
}
QString MediaDice::pinnedTextSubstring() const {
return QChar(171) + notificationText() + QChar(187);
return QChar(171) + notificationText().text + QChar(187);
}
TextForMimeData MediaDice::clipboardText() const {
return { notificationText() };
return { .rich = notificationText() };
}
bool MediaDice::forceForwardedInfo() const {

View File

@ -100,7 +100,7 @@ public:
// Returns text with link-start and link-end commands for service-color highlighting.
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
virtual ItemPreview toPreview(ToPreviewOptions way) const;
virtual QString notificationText() const = 0;
virtual TextWithEntities notificationText() const = 0;
virtual QString pinnedTextSubstring() const = 0;
virtual TextForMimeData clipboardText() const = 0;
virtual bool allowsForward() const;
@ -161,7 +161,7 @@ public:
Image *replyPreview() const override;
bool replyPreviewLoaded() const override;
ItemPreview toPreview(ToPreviewOptions options) const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
bool allowsEditCaption() const override;
@ -199,7 +199,7 @@ public:
Image *replyPreview() const override;
bool replyPreviewLoaded() const override;
ItemPreview toPreview(ToPreviewOptions options) const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
bool allowsEditCaption() const override;
@ -234,7 +234,7 @@ public:
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
const SharedContact *sharedContact() const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
@ -265,7 +265,7 @@ public:
Data::CloudImage *location() const override;
ItemPreview toPreview(ToPreviewOptions options) const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
@ -292,7 +292,7 @@ public:
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
const Call *call() const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
bool allowsForward() const override;
@ -331,7 +331,7 @@ public:
Image *replyPreview() const override;
bool replyPreviewLoaded() const override;
ItemPreview toPreview(ToPreviewOptions options) const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
bool allowsEdit() const override;
@ -361,7 +361,7 @@ public:
bool hasReplyPreview() const override;
Image *replyPreview() const override;
bool replyPreviewLoaded() const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
QString errorTextForForward(not_null<PeerData*> peer) const override;
@ -396,7 +396,7 @@ public:
bool hasReplyPreview() const override;
Image *replyPreview() const override;
bool replyPreviewLoaded() const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
@ -423,7 +423,7 @@ public:
PollData *poll() const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
QString errorTextForForward(not_null<PeerData*> peer) const override;
@ -450,7 +450,7 @@ public:
[[nodiscard]] int value() const;
bool allowsRevoke(TimeId now) const override;
QString notificationText() const override;
TextWithEntities notificationText() const override;
QString pinnedTextSubstring() const override;
TextForMimeData clipboardText() const override;
bool forceForwardedInfo() const override;

View File

@ -32,7 +32,7 @@ constexpr auto kMessagesPerPage = 50;
history->nextNonHistoryEntryId(),
MessageFlag::FakeHistoryItem,
date,
HistoryService::PreparedText{ text });
HistoryService::PreparedText{ { .text = text } });
}
} // namespace
@ -287,7 +287,7 @@ void RepliesList::injectRootDivider(
text());
} else if (_dividerWithComments != withComments) {
_dividerWithComments = withComments;
_divider->setServiceText(HistoryService::PreparedText{ text() });
_divider->setServiceText(HistoryService::PreparedText{ { text() } });
}
slice->ids.push_back(_divider->fullId());
}

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_item_preview.h"
#include "main/main_session.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/image/image.h"
#include "lang/lang_keys.h"
#include "styles/style_dialogs.h"
@ -109,17 +110,25 @@ void MessageView::paint(
options.existing = &_imagesCache;
auto preview = item->toPreview(options);
if (!preview.images.empty() && preview.imagesInTextPosition > 0) {
_senderCache.setText(
auto sender = ::Ui::Text::Mid(
preview.text,
0,
preview.imagesInTextPosition);
TextUtilities::Trim(sender);
_senderCache.setMarkedText(
st::dialogsTextStyle,
preview.text.mid(0, preview.imagesInTextPosition).trimmed(),
std::move(sender),
DialogTextOptions());
preview.text = preview.text.mid(preview.imagesInTextPosition);
preview.text = ::Ui::Text::Mid(
preview.text,
preview.imagesInTextPosition);
} else {
_senderCache = { st::dialogsTextWidthMin };
}
_textCache.setText(
TextUtilities::Trim(preview.text);
_textCache.setMarkedText(
st::dialogsTextStyle,
preview.text.trimmed(),
preview.text,
DialogTextOptions());
_textCachedFor = item;
_imagesCache = std::move(preview.images);
@ -191,18 +200,24 @@ void MessageView::paint(
HistoryView::ItemPreview PreviewWithSender(
HistoryView::ItemPreview &&preview,
const QString &sender) {
auto textWithOffset = tr::lng_dialogs_text_with_from(
const TextWithEntities &sender) {
const auto textWithOffset = tr::lng_dialogs_text_with_from(
tr::now,
lt_from_part,
sender.text,
lt_message,
preview.text.text,
TextWithTagOffset<lt_from_part>::FromString);
preview.text = tr::lng_dialogs_text_with_from(
tr::now,
lt_from_part,
sender,
lt_message,
std::move(preview.text),
TextWithTagOffset<lt_from_part>::FromString);
preview.text = std::move(textWithOffset.text);
Ui::Text::WithEntities);
preview.imagesInTextPosition = (textWithOffset.offset < 0)
? 0
: textWithOffset.offset + sender.size();
: textWithOffset.offset + sender.text.size();
return std::move(preview);
}

View File

@ -59,6 +59,6 @@ private:
[[nodiscard]] HistoryView::ItemPreview PreviewWithSender(
HistoryView::ItemPreview &&preview,
const QString &sender);
const TextWithEntities &sender);
} // namespace Dialogs::Ui

View File

@ -319,11 +319,11 @@ QString GenerateInviteLinkText(const MTPExportedChatInvite &data) {
) : label;
}
QString GenerateInviteLinkLink(const MTPExportedChatInvite &data) {
TextWithEntities GenerateInviteLinkLink(const MTPExportedChatInvite &data) {
const auto text = GenerateInviteLinkText(data);
return text.endsWith(Ui::kQEllipsis)
? text
: textcmdLink(InternalInviteLinkUrl(data), text);
? TextWithEntities{ .text = text }
: Ui::Text::Link(text, InternalInviteLinkUrl(data));
}
TextWithEntities GenerateInviteLinkChangeText(
@ -669,12 +669,12 @@ void GenerateItems(
const auto fromName = from->name;
const auto fromLink = from->createOpenLink();
const auto fromLinkText = textcmdLink(1, fromName);
const auto fromLinkText = Ui::Text::Link(fromName, {});
const auto addSimpleServiceMessage = [&](
const QString &text,
const TextWithEntities &text,
PhotoData *photo = nullptr) {
auto message = HistoryService::PreparedText { text };
auto message = HistoryService::PreparedText{ text };
message.links.push_back(fromLink);
addPart(history->makeServiceMessage(
history->nextNonHistoryEntryId(),
@ -693,8 +693,9 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_title,
qs(action.vnew_value()));
addSimpleServiceMessage(text);
{ .text = qs(action.vnew_value()) },
Ui::Text::WithEntities);
addSimpleServiceMessage(std::move(text));
};
const auto makeSimpleTextMessage = [&](TextWithEntities &&text) {
@ -731,7 +732,7 @@ void GenerateItems(
: (newValue.isEmpty()
? tr::lng_admin_log_removed_description_channel
: tr::lng_admin_log_changed_description_channel)
)(tr::now, lt_from, fromLinkText);
)(tr::now, lt_from, fromLinkText, Ui::Text::WithEntities);
addSimpleServiceMessage(text);
const auto body = makeSimpleTextMessage(
@ -756,7 +757,7 @@ void GenerateItems(
: (newValue.isEmpty()
? tr::lng_admin_log_removed_link_channel
: tr::lng_admin_log_changed_link_channel)
)(tr::now, lt_from, fromLinkText);
)(tr::now, lt_from, fromLinkText, Ui::Text::WithEntities);
addSimpleServiceMessage(text);
const auto body = makeSimpleTextMessage(newValue.isEmpty()
@ -784,7 +785,8 @@ void GenerateItems(
: tr::lng_admin_log_changed_photo_channel)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text, photo);
}, [&](const MTPDphotoEmpty &data) {
const auto text = (channel->isMegagroup()
@ -792,7 +794,8 @@ void GenerateItems(
: tr::lng_admin_log_removed_photo_channel)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
});
};
@ -801,16 +804,24 @@ void GenerateItems(
const auto enabled = (action.vnew_value().type() == mtpc_boolTrue);
const auto text = (enabled
? tr::lng_admin_log_invites_enabled
: tr::lng_admin_log_invites_disabled);
addSimpleServiceMessage(text(tr::now, lt_from, fromLinkText));
: tr::lng_admin_log_invites_disabled)(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createToggleSignatures = [&](const LogSign &action) {
const auto enabled = (action.vnew_value().type() == mtpc_boolTrue);
const auto text = (enabled
? tr::lng_admin_log_signatures_enabled
: tr::lng_admin_log_signatures_disabled);
addSimpleServiceMessage(text(tr::now, lt_from, fromLinkText));
: tr::lng_admin_log_signatures_disabled)(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createUpdatePinned = [&](const LogPin &action) {
@ -821,7 +832,8 @@ void GenerateItems(
: tr::lng_admin_log_unpinned_message)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
const auto detachExistingItem = false;
@ -836,7 +848,8 @@ void GenerateItems(
const auto text = tr::lng_admin_log_unpinned_message(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
});
};
@ -854,7 +867,8 @@ void GenerateItems(
: tr::lng_admin_log_edited_caption)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
auto oldValue = ExtractEditedText(
@ -885,7 +899,8 @@ void GenerateItems(
const auto text = tr::lng_admin_log_deleted_message(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
const auto detachExistingItem = false;
@ -901,15 +916,23 @@ void GenerateItems(
const auto createParticipantJoin = [&]() {
const auto text = (channel->isMegagroup()
? tr::lng_admin_log_participant_joined
: tr::lng_admin_log_participant_joined_channel);
addSimpleServiceMessage(text(tr::now, lt_from, fromLinkText));
: tr::lng_admin_log_participant_joined_channel)(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createParticipantLeave = [&]() {
const auto text = (channel->isMegagroup()
? tr::lng_admin_log_participant_left
: tr::lng_admin_log_participant_left_channel);
addSimpleServiceMessage(text(tr::now, lt_from, fromLinkText));
: tr::lng_admin_log_participant_left_channel)(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createParticipantInvite = [&](const LogInvite &action) {
@ -947,7 +970,8 @@ void GenerateItems(
const auto text = tr::lng_admin_log_removed_stickers_group(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
} else {
const auto text = tr::lng_admin_log_changed_stickers_group(
@ -955,9 +979,10 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_sticker_set,
textcmdLink(
2,
tr::lng_admin_log_changed_stickers_set(tr::now)));
Ui::Text::Link(
tr::lng_admin_log_changed_stickers_set(tr::now),
{}),
Ui::Text::WithEntities);
const auto setLink = std::make_shared<LambdaClickHandler>([=](
ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
@ -986,8 +1011,12 @@ void GenerateItems(
const auto hidden = (action.vnew_value().type() == mtpc_boolTrue);
const auto text = (hidden
? tr::lng_admin_log_history_made_hidden
: tr::lng_admin_log_history_made_visible);
addSimpleServiceMessage(text(tr::now, lt_from, fromLinkText));
: tr::lng_admin_log_history_made_visible)(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createDefaultBannedRights = [&](
@ -1003,7 +1032,8 @@ void GenerateItems(
const auto text = tr::lng_admin_log_stopped_poll(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
const auto detachExistingItem = false;
@ -1025,7 +1055,8 @@ void GenerateItems(
: tr::lng_admin_log_removed_linked_channel)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
} else {
const auto text = (broadcast
@ -1035,7 +1066,8 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_chat,
textcmdLink(2, now->name));
Ui::Text::Link(now->name, {}),
Ui::Text::WithEntities);
const auto chatLink = std::make_shared<LambdaClickHandler>([=] {
Ui::showPeerHistory(now, ShowAtUnreadMsgId);
});
@ -1056,24 +1088,26 @@ void GenerateItems(
const auto address = qs(data.vaddress());
const auto link = data.vgeo_point().match([&](
const MTPDgeoPoint &data) {
return textcmdLink(
LocationClickHandler::Url(Data::LocationPoint(data)),
address);
return Ui::Text::Link(
address,
LocationClickHandler::Url(Data::LocationPoint(data)));
}, [&](const MTPDgeoPointEmpty &) {
return address;
return TextWithEntities{ .text = address };
});
const auto text = tr::lng_admin_log_changed_location_chat(
tr::now,
lt_from,
fromLinkText,
lt_address,
link);
link,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
}, [&](const MTPDchannelLocationEmpty &) {
const auto text = tr::lng_admin_log_removed_location_chat(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
});
};
@ -1094,13 +1128,15 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_duration,
duration);
{ .text = duration },
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
} else {
const auto text = tr::lng_admin_log_removed_slow_mode(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
}
};
@ -1111,7 +1147,8 @@ void GenerateItems(
: tr::lng_admin_log_started_group_call)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
@ -1121,7 +1158,8 @@ void GenerateItems(
: tr::lng_admin_log_discarded_group_call)(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
@ -1133,7 +1171,7 @@ void GenerateItems(
};
const auto addServiceMessageWithLink = [&](
const QString &text,
const TextWithEntities &text,
const ClickHandlerPtr &link) {
auto message = HistoryService::PreparedText{ text };
message.links.push_back(fromLink);
@ -1150,9 +1188,9 @@ void GenerateItems(
const auto participantPeer = groupCallParticipantPeer(
data.vparticipant());
const auto participantPeerLink = participantPeer->createOpenLink();
const auto participantPeerLinkText = textcmdLink(
2,
participantPeer->name);
const auto participantPeerLinkText = Ui::Text::Link(
participantPeer->name,
{});
const auto text = (broadcast
? tr::lng_admin_log_muted_participant_channel
: tr::lng_admin_log_muted_participant)(
@ -1160,7 +1198,8 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_user,
participantPeerLinkText);
participantPeerLinkText,
Ui::Text::WithEntities);
addServiceMessageWithLink(text, participantPeerLink);
};
@ -1168,9 +1207,9 @@ void GenerateItems(
const auto participantPeer = groupCallParticipantPeer(
data.vparticipant());
const auto participantPeerLink = participantPeer->createOpenLink();
const auto participantPeerLinkText = textcmdLink(
2,
participantPeer->name);
const auto participantPeerLinkText = Ui::Text::Link(
participantPeer->name,
{});
const auto text = (broadcast
? tr::lng_admin_log_unmuted_participant_channel
: tr::lng_admin_log_unmuted_participant)(
@ -1178,7 +1217,8 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_user,
participantPeerLinkText);
participantPeerLinkText,
Ui::Text::WithEntities);
addServiceMessageWithLink(text, participantPeerLink);
};
@ -1193,12 +1233,13 @@ void GenerateItems(
: tr::lng_admin_log_allowed_unmute_self))(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto addInviteLinkServiceMessage = [&](
const QString &text,
const TextWithEntities &text,
const MTPExportedChatInvite &data,
ClickHandlerPtr additional = nullptr) {
auto message = HistoryService::PreparedText{ text };
@ -1230,7 +1271,8 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_link,
GenerateInviteLinkLink(data.vinvite())),
GenerateInviteLinkLink(data.vinvite()),
Ui::Text::WithEntities),
data.vinvite());
};
@ -1241,7 +1283,8 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_link,
GenerateInviteLinkLink(data.vinvite())),
GenerateInviteLinkLink(data.vinvite()),
Ui::Text::WithEntities),
data.vinvite());
};
@ -1252,7 +1295,8 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_link,
GenerateInviteLinkLink(data.vinvite())),
GenerateInviteLinkLink(data.vinvite()),
Ui::Text::WithEntities),
data.vinvite());
};
@ -1267,9 +1311,9 @@ void GenerateItems(
const auto participantPeer = groupCallParticipantPeer(
data.vparticipant());
const auto participantPeerLink = participantPeer->createOpenLink();
const auto participantPeerLinkText = textcmdLink(
2,
participantPeer->name);
const auto participantPeerLinkText = Ui::Text::Link(
participantPeer->name,
{});
const auto volume = data.vparticipant().match([&](
const MTPDgroupCallParticipant &data) {
return data.vvolume().value_or(10000);
@ -1278,27 +1322,29 @@ void GenerateItems(
auto text = (broadcast
? tr::lng_admin_log_participant_volume_channel
: tr::lng_admin_log_participant_volume)(
tr::now,
lt_from,
fromLinkText,
lt_user,
participantPeerLinkText,
lt_percent,
volumeText);
tr::now,
lt_from,
fromLinkText,
lt_user,
participantPeerLinkText,
lt_percent,
{ .text = volumeText },
Ui::Text::WithEntities);
addServiceMessageWithLink(text, participantPeerLink);
};
const auto createChangeHistoryTTL = [&](const LogTTL &data) {
const auto was = data.vprev_value().v;
const auto now = data.vnew_value().v;
const auto wrap = [](int duration) {
return (duration == 5)
const auto wrap = [](int duration) -> TextWithEntities {
const auto text = (duration == 5)
? u"5 seconds"_q
: (duration < 2 * 86400)
? tr::lng_manage_messages_ttl_after1(tr::now)
: (duration < 8 * 86400)
? tr::lng_manage_messages_ttl_after2(tr::now)
: tr::lng_manage_messages_ttl_after3(tr::now);
return { .text = text };
};
const auto text = !was
? tr::lng_admin_log_messages_ttl_set(
@ -1306,14 +1352,16 @@ void GenerateItems(
lt_from,
fromLinkText,
lt_duration,
wrap(now))
wrap(now),
Ui::Text::WithEntities)
: !now
? tr::lng_admin_log_messages_ttl_removed(
tr::now,
lt_from,
fromLinkText,
lt_duration,
wrap(was))
wrap(was),
Ui::Text::WithEntities)
: tr::lng_admin_log_messages_ttl_changed(
tr::now,
lt_from,
@ -1321,7 +1369,8 @@ void GenerateItems(
lt_previous,
wrap(was),
lt_duration,
wrap(now));
wrap(now),
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
@ -1332,7 +1381,6 @@ void GenerateItems(
? tr::lng_admin_log_participant_approved_by_link
: tr::lng_admin_log_participant_approved_by_link_channel);
const auto linkText = GenerateInviteLinkLink(data.vinvite());
const auto adminIndex = linkText.endsWith(Ui::kQEllipsis) ? 2 : 3;
addInviteLinkServiceMessage(
text(
tr::now,
@ -1341,7 +1389,8 @@ void GenerateItems(
lt_link,
linkText,
lt_user,
textcmdLink(adminIndex, user->name)),
Ui::Text::Link(user->name, {}),
Ui::Text::WithEntities),
data.vinvite(),
user->createOpenLink());
};
@ -1350,15 +1399,20 @@ void GenerateItems(
const auto disabled = (data.vnew_value().type() == mtpc_boolTrue);
const auto text = (disabled
? tr::lng_admin_log_forwards_disabled
: tr::lng_admin_log_forwards_enabled);
addSimpleServiceMessage(text(tr::now, lt_from, fromLinkText));
: tr::lng_admin_log_forwards_enabled)(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};
const auto createSendMessage = [&](const LogActionSendMessage &data) {
const auto text = tr::lng_admin_log_sent_message(
tr::now,
lt_from,
fromLinkText);
fromLinkText,
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
const auto detachExistingItem = false;
@ -1371,14 +1425,25 @@ void GenerateItems(
ExtractSentDate(data.vmessage()));
};
const auto createChangeAvailableReactions = [&](const LogEventActionChangeAvailableReactions &data) {
const auto createChangeAvailableReactions = [&](
const LogEventActionChangeAvailableReactions &data) {
auto list = QStringList();
for (const auto &emoji : data.vnew_value().v) {
list.append(qs(emoji));
}
const auto text = list.isEmpty()
? tr::lng_admin_log_reactions_disabled(tr::now, lt_from, fromLinkText)
: tr::lng_admin_log_reactions_updated(tr::now, lt_from, fromLinkText, lt_emoji, list.join(", "));
? tr::lng_admin_log_reactions_disabled(
tr::now,
lt_from,
fromLinkText,
Ui::Text::WithEntities)
: tr::lng_admin_log_reactions_updated(
tr::now,
lt_from,
fromLinkText,
lt_emoji,
{ .text = list.join(", ") },
Ui::Text::WithEntities);
addSimpleServiceMessage(text);
};

View File

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h"
#include "ui/text/text_isolated_emoji.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "storage/file_upload.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
@ -1074,23 +1075,20 @@ bool HistoryItem::isEmpty() const {
&& !Has<HistoryMessageLogEntryOriginal>();
}
QString HistoryItem::notificationText() const {
TextWithEntities HistoryItem::notificationText() const {
const auto result = [&] {
if (_media && !isService()) {
return _media->notificationText();
} else if (!emptyText()) {
return TextUtilities::TextWithSpoilerCommands(
_text.toTextWithEntities());
return _text.toTextWithEntities();
}
return QString();
return TextWithEntities();
}();
return (result.size() <= kNotificationTextLimit)
? result
: TextUtilities::CutTextWithCommands(
result,
kNotificationTextLimit,
textcmdStartSpoiler(),
textcmdStopSpoiler());
if (result.text.size() <= kNotificationTextLimit) {
return result;
}
return Ui::Text::Mid(result, 0, kNotificationTextLimit).append(
Ui::kQEllipsis);
}
ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
@ -1099,12 +1097,7 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
return _media->toPreview(options);
} else if (!emptyText()) {
return {
.text = TextUtilities::Clean(
options.ignoreSpoilers
? _text.toString()
: TextUtilities::TextWithSpoilerCommands(
_text.toTextWithEntities()),
!options.ignoreSpoilers),
.text = _text.toTextWithEntities()
};
}
return {};
@ -1140,16 +1133,12 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
if (!sender) {
return result;
}
const auto fromWrapped = textcmdLink(
1,
tr::lng_dialogs_text_from_wrapped(
tr::now,
lt_from,
TextUtilities::Clean(*sender)));
const auto fromWrapped = Ui::Text::PlainLink(
tr::lng_dialogs_text_from_wrapped(tr::now, lt_from, *sender));
return Dialogs::Ui::PreviewWithSender(std::move(result), fromWrapped);
}
QString HistoryItem::inReplyText() const {
TextWithEntities HistoryItem::inReplyText() const {
return toPreview({
.hideSender = true,
.generateImages = false,
@ -1274,7 +1263,7 @@ not_null<HistoryItem*> HistoryItem::Create(
data.vfrom_id() ? peerFromMTP(*data.vfrom_id()) : PeerId(0));
} else if (checked == MediaCheckResult::Empty) {
const auto text = HistoryService::PreparedText{
tr::lng_message_empty(tr::now)
tr::lng_message_empty(tr::now, Ui::Text::WithEntities)
};
return history->makeServiceMessage(
id,
@ -1293,7 +1282,7 @@ not_null<HistoryItem*> HistoryItem::Create(
return history->makeServiceMessage(id, data, localFlags);
}, [&](const MTPDmessageEmpty &data) -> HistoryItem* {
const auto text = HistoryService::PreparedText{
tr::lng_message_empty(tr::now)
tr::lng_message_empty(tr::now, Ui::Text::WithEntities)
};
return history->makeServiceMessage(id, localFlags, TimeId(0), text);
});

View File

@ -290,7 +290,7 @@ public:
[[nodiscard]] virtual QString notificationHeader() const {
return QString();
}
[[nodiscard]] virtual QString notificationText() const;
[[nodiscard]] virtual TextWithEntities notificationText() const;
using ToPreviewOptions = HistoryView::ToPreviewOptions;
using ItemPreview = HistoryView::ItemPreview;
@ -299,7 +299,7 @@ public:
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
[[nodiscard]] virtual ItemPreview toPreview(
ToPreviewOptions options) const;
[[nodiscard]] virtual QString inReplyText() const;
[[nodiscard]] virtual TextWithEntities inReplyText() const;
[[nodiscard]] virtual Ui::Text::IsolatedEmoji isolatedEmoji() const;
[[nodiscard]] virtual TextWithEntities originalText() const {
return TextWithEntities();

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "ui/toast/toast.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/chat/chat_style.h"
#include "ui/chat/chat_theme.h"
#include "history/history.h"
@ -106,20 +107,21 @@ HiddenSenderInfo::HiddenSenderInfo(const QString &name, bool external)
}
void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
auto phrase = QString();
auto phrase = TextWithEntities();
const auto fromChannel = originalSender
&& originalSender->isChannel()
&& !originalSender->isMegagroup();
const auto name = originalSender
? originalSender->name
: hiddenSenderInfo->name;
const auto name = TextWithEntities{
.text = originalSender ? originalSender->name : hiddenSenderInfo->name
};
if (!originalAuthor.isEmpty()) {
phrase = tr::lng_forwarded_signed(
tr::now,
lt_channel,
name,
lt_user,
originalAuthor);
{ .text = originalAuthor },
Ui::Text::WithEntities);
} else {
phrase = name;
}
@ -128,16 +130,18 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
phrase = tr::lng_forwarded_channel_via(
tr::now,
lt_channel,
textcmdLink(1, phrase),
Ui::Text::Link(phrase.text, QString()), // Link 1.
lt_inline_bot,
textcmdLink(2, '@' + via->bot->username));
Ui::Text::Link('@' + via->bot->username, {}), // Link 2.
Ui::Text::WithEntities);
} else {
phrase = tr::lng_forwarded_via(
tr::now,
lt_user,
textcmdLink(1, phrase),
Ui::Text::Link(phrase.text, QString()), // Link 1.
lt_inline_bot,
textcmdLink(2, '@' + via->bot->username));
Ui::Text::Link('@' + via->bot->username, {}), // Link 2.
Ui::Text::WithEntities);
}
} else {
if (fromChannel || !psaType.isEmpty()) {
@ -145,19 +149,29 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
? QString()
: Lang::GetNonDefaultValue(
kPsaForwardedPrefix + psaType.toUtf8());
phrase = !custom.isEmpty()
? custom.replace("{channel}", textcmdLink(1, phrase))
: (psaType.isEmpty()
if (!custom.isEmpty()) {
custom = custom.replace("{channel}", phrase.text);
const auto index = int(custom.indexOf(phrase.text));
const auto size = int(phrase.text.size());
phrase = TextWithEntities{
.text = custom,
.entities = {{ EntityType::CustomUrl, index, size, {} }},
};
} else {
phrase = (psaType.isEmpty()
? tr::lng_forwarded_channel
: tr::lng_forwarded_psa_default)(
tr::now,
lt_channel,
textcmdLink(1, phrase));
Ui::Text::Link(phrase.text, QString()), // Link 1.
Ui::Text::WithEntities);
}
} else {
phrase = tr::lng_forwarded(
tr::now,
lt_user,
textcmdLink(1, phrase));
Ui::Text::Link(phrase.text, QString()), // Link 1.
Ui::Text::WithEntities);
}
}
TextParseOptions opts = {
@ -166,7 +180,7 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
0,
Qt::LayoutDirectionAuto
};
text.setText(st::fwdTextStyle, phrase, opts);
text.setMarkedText(st::fwdTextStyle, phrase, opts);
static const auto hidden = std::make_shared<LambdaClickHandler>([] {
Ui::Toast::Show(tr::lng_forwarded_hidden(tr::now));
});
@ -210,7 +224,7 @@ bool HistoryMessageReply::updateData(
}
if (replyToMsg) {
replyToText.setText(
replyToText.setMarkedText(
st::messageTextStyle,
replyToMsg->inReplyText(),
Ui::DialogTextOptions());

View File

@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/payments_checkout_process.h" // CheckoutProcess::Start.
#include "ui/text/format_values.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
namespace {
@ -111,31 +112,65 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto u = history()->owner().user(users[0].v);
if (u == _from) {
result.links.push_back(fromLink());
result.text = tr::lng_action_user_joined(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_user_joined(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.links.push_back(u->createOpenLink());
result.text = tr::lng_action_add_user(tr::now, lt_from, fromLinkText(), lt_user, textcmdLink(2, u->name));
result.text = tr::lng_action_add_user(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_user,
Ui::Text::Link(u->name, {}), // Link 2.
Ui::Text::WithEntities);
}
} else if (users.isEmpty()) {
result.links.push_back(fromLink());
result.text = tr::lng_action_add_user(tr::now, lt_from, fromLinkText(), lt_user, qsl("somebody"));
result.text = tr::lng_action_add_user(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_user,
{ .text = qsl("somebody") },
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
for (auto i = 0, l = int(users.size()); i != l; ++i) {
auto user = history()->owner().user(users[i].v);
result.links.push_back(user->createOpenLink());
auto linkText = textcmdLink(i + 2, user->name);
auto linkText = Ui::Text::Link(user->name, {});
if (i == 0) {
result.text = linkText;
} else if (i + 1 == l) {
result.text = tr::lng_action_add_users_and_last(tr::now, lt_accumulated, result.text, lt_user, linkText);
result.text = tr::lng_action_add_users_and_last(
tr::now,
lt_accumulated,
result.text,
lt_user,
linkText,
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_add_users_and_one(tr::now, lt_accumulated, result.text, lt_user, linkText);
result.text = tr::lng_action_add_users_and_one(
tr::now,
lt_accumulated,
result.text,
lt_user,
linkText,
Ui::Text::WithEntities);
}
}
result.text = tr::lng_action_add_users_many(tr::now, lt_from, fromLinkText(), lt_users, result.text);
result.text = tr::lng_action_add_users_many(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_users,
result.text,
Ui::Text::WithEntities);
}
return result;
};
@ -143,24 +178,42 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) {
auto result = PreparedText{};
result.links.push_back(fromLink());
result.text = tr::lng_action_user_joined_by_link(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_user_joined_by_link(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
return result;
};
auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) {
auto result = PreparedText{};
result.links.push_back(fromLink());
result.text = tr::lng_action_created_chat(tr::now, lt_from, fromLinkText(), lt_title, TextUtilities::Clean(qs(action.vtitle())));
result.text = tr::lng_action_created_chat(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_title,
{ .text = qs(action.vtitle()) },
Ui::Text::WithEntities);
return result;
};
auto prepareChannelCreate = [this](const MTPDmessageActionChannelCreate &action) {
auto result = PreparedText {};
if (isPost()) {
result.text = tr::lng_action_created_channel(tr::now);
result.text = tr::lng_action_created_channel(
tr::now,
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_created_chat(tr::now, lt_from, fromLinkText(), lt_title, TextUtilities::Clean(qs(action.vtitle())));
result.text = tr::lng_action_created_chat(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_title,
{ .text = qs(action.vtitle()) },
Ui::Text::WithEntities);
}
return result;
};
@ -168,10 +221,16 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareChatDeletePhoto = [this] {
auto result = PreparedText{};
if (isPost()) {
result.text = tr::lng_action_removed_photo_channel(tr::now);
result.text = tr::lng_action_removed_photo_channel(
tr::now,
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_removed_photo(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_removed_photo(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
}
return result;
};
@ -180,12 +239,22 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto result = PreparedText{};
if (peerFromUser(action.vuser_id()) == _from->id) {
result.links.push_back(fromLink());
result.text = tr::lng_action_user_left(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_user_left(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
} else {
auto user = history()->owner().user(action.vuser_id().v);
result.links.push_back(fromLink());
result.links.push_back(user->createOpenLink());
result.text = tr::lng_action_kick_user(tr::now, lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name));
result.text = tr::lng_action_kick_user(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_user,
Ui::Text::Link(user->name, {}), // Link 2.
Ui::Text::WithEntities);
}
return result;
};
@ -193,10 +262,16 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareChatEditPhoto = [this](const MTPDmessageActionChatEditPhoto &action) {
auto result = PreparedText{};
if (isPost()) {
result.text = tr::lng_action_changed_photo_channel(tr::now);
result.text = tr::lng_action_changed_photo_channel(
tr::now,
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_changed_photo(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_changed_photo(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
}
return result;
};
@ -204,10 +279,20 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) {
auto result = PreparedText{};
if (isPost()) {
result.text = tr::lng_action_changed_title_channel(tr::now, lt_title, TextUtilities::Clean(qs(action.vtitle())));
result.text = tr::lng_action_changed_title_channel(
tr::now,
lt_title,
{ .text = (qs(action.vtitle())) },
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_changed_title(tr::now, lt_from, fromLinkText(), lt_title, TextUtilities::Clean(qs(action.vtitle())));
result.text = tr::lng_action_changed_title(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_title,
{ .text = qs(action.vtitle()) },
Ui::Text::WithEntities);
}
return result;
};
@ -215,17 +300,23 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareScreenshotTaken = [this] {
auto result = PreparedText{};
if (out()) {
result.text = tr::lng_action_you_took_screenshot(tr::now);
result.text = tr::lng_action_you_took_screenshot(
tr::now,
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_took_screenshot(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_took_screenshot(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
}
return result;
};
auto prepareCustomAction = [&](const MTPDmessageActionCustomAction &action) {
auto result = PreparedText{};
result.text = qs(action.vmessage());
result.text = { .text = qs(action.vmessage()) };
return result;
};
@ -235,7 +326,8 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
result.text = tr::lng_action_bot_allowed_from_domain(
tr::now,
lt_domain,
textcmdLink(qstr("http://") + domain, domain));
Ui::Text::Link(domain, qstr("http://") + domain),
Ui::Text::WithEntities);
return result;
};
@ -272,16 +364,21 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
result.text = tr::lng_action_secure_values_sent(
tr::now,
lt_user,
textcmdLink(1, history()->peer->name),
Ui::Text::Link(history()->peer->name, {}), // Link 1.
lt_documents,
documents.join(", "));
{ .text = documents.join(", ") },
Ui::Text::WithEntities);
return result;
};
auto prepareContactSignUp = [this] {
auto result = PreparedText{};
result.links.push_back(fromLink());
result.text = tr::lng_action_user_registered(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_user_registered(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
return result;
};
@ -313,28 +410,31 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
return tr::lng_action_you_proximity_reached(
tr::now,
lt_distance,
distance,
{ .text = distance },
lt_user,
textcmdLink(1, toPeer->name));
Ui::Text::Link(toPeer->name, {}), // Link 1.
Ui::Text::WithEntities);
} else if (toId == selfId) {
result.links.push_back(fromPeer->createOpenLink());
return tr::lng_action_proximity_reached_you(
tr::now,
lt_from,
textcmdLink(1, fromPeer->name),
Ui::Text::Link(fromPeer->name, {}), // Link 1.
lt_distance,
distance);
{ .text = distance },
Ui::Text::WithEntities);
} else {
result.links.push_back(fromPeer->createOpenLink());
result.links.push_back(toPeer->createOpenLink());
return tr::lng_action_proximity_reached(
tr::now,
lt_from,
textcmdLink(1, fromPeer->name),
Ui::Text::Link(fromPeer->name, {}), // Link 1.
lt_distance,
distance,
{ .text = distance },
lt_user,
textcmdLink(2, toPeer->name));
Ui::Text::Link(toPeer->name, {}), // Link 2.
Ui::Text::WithEntities);
}
}();
return result;
@ -358,26 +458,31 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
result.text = tr::lng_action_group_call_finished(
tr::now,
lt_duration,
text);
{ .text = text },
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_group_call_finished_group(
tr::now,
lt_from,
fromLinkText(),
fromLinkText(), // Link 1.
lt_duration,
text);
{ .text = text },
Ui::Text::WithEntities);
}
return result;
}
if (history()->peer->isBroadcast()) {
result.text = tr::lng_action_group_call_started_channel(tr::now);
result.text = tr::lng_action_group_call_started_channel(
tr::now,
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_group_call_started_group(
tr::now,
lt_from,
fromLinkText());
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
}
return result;
};
@ -410,22 +515,44 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
: tr::lng_ttl_about_duration3(tr::now);
if (isPost()) {
if (!period) {
result.text = tr::lng_action_ttl_removed_channel(tr::now);
result.text = tr::lng_action_ttl_removed_channel(
tr::now,
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_ttl_changed_channel(tr::now, lt_duration, duration);
result.text = tr::lng_action_ttl_changed_channel(
tr::now,
lt_duration,
{ .text = duration },
Ui::Text::WithEntities);
}
} else if (_from->isSelf()) {
if (!period) {
result.text = tr::lng_action_ttl_removed_you(tr::now);
result.text = tr::lng_action_ttl_removed_you(
tr::now,
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_ttl_changed_you(tr::now, lt_duration, duration);
result.text = tr::lng_action_ttl_changed_you(
tr::now,
lt_duration,
{ .text = duration },
Ui::Text::WithEntities);
}
} else {
result.links.push_back(fromLink());
if (!period) {
result.text = tr::lng_action_ttl_removed(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_ttl_removed(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_ttl_changed(tr::now, lt_from, fromLinkText(), lt_duration, duration);
result.text = tr::lng_action_ttl_changed(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_duration,
{ .text = duration },
Ui::Text::WithEntities);
}
}
return result;
@ -436,17 +563,33 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
const auto text = qs(action.vemoticon());
if (!text.isEmpty()) {
if (_from->isSelf()) {
result.text = tr::lng_action_you_theme_changed(tr::now, lt_emoji, text);
result.text = tr::lng_action_you_theme_changed(
tr::now,
lt_emoji,
{ .text = text },
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_theme_changed(tr::now, lt_from, fromLinkText(), lt_emoji, text);
result.text = tr::lng_action_theme_changed(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_emoji,
{ .text = text },
Ui::Text::WithEntities);
}
} else {
if (_from->isSelf()) {
result.text = tr::lng_action_you_theme_disabled(tr::now);
result.text = tr::lng_action_you_theme_disabled(
tr::now,
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_theme_disabled(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_theme_disabled(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
}
}
return result;
@ -455,7 +598,11 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareChatJoinedByRequest = [this](const MTPDmessageActionChatJoinedByRequest &action) {
auto result = PreparedText{};
result.links.push_back(fromLink());
result.text = tr::lng_action_user_joined_by_request(tr::now, lt_from, fromLinkText());
result.text = tr::lng_action_user_joined_by_request(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
return result;
};
@ -504,10 +651,14 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
return prepareProximityReached(data);
}, [](const MTPDmessageActionPaymentSentMe &) {
LOG(("API Error: messageActionPaymentSentMe received."));
return PreparedText{ tr::lng_message_empty(tr::now) };
return PreparedText{
tr::lng_message_empty(tr::now, Ui::Text::WithEntities)
};
}, [](const MTPDmessageActionSecureValuesSentMe &) {
LOG(("API Error: messageActionSecureValuesSentMe received."));
return PreparedText{ tr::lng_message_empty(tr::now) };
return PreparedText{
tr::lng_message_empty(tr::now, Ui::Text::WithEntities)
};
}, [&](const MTPDmessageActionGroupCall &data) {
return prepareGroupCall(data);
}, [&](const MTPDmessageActionInviteToGroupCall &data) {
@ -521,7 +672,9 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}, [&](const MTPDmessageActionChatJoinedByRequest &data) {
return prepareChatJoinedByRequest(data);
}, [](const MTPDmessageActionEmpty &) {
return PreparedText{ tr::lng_message_empty(tr::now) };
return PreparedText{
tr::lng_message_empty(tr::now, Ui::Text::WithEntities)
};
});
setServiceText(messageText);
@ -638,36 +791,74 @@ HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
const QVector<MTPlong> &users,
CallId linkCallId) {
const auto owner = &history()->owner();
auto chatText = tr::lng_action_invite_user_chat(tr::now);
auto chatText = tr::lng_action_invite_user_chat(
tr::now,
Ui::Text::WithEntities);
auto result = PreparedText{};
result.links.push_back(fromLink());
auto linkIndex = 1;
if (linkCallId) {
const auto peer = history()->peer;
result.links.push_back(GroupCallClickHandler(peer, linkCallId));
chatText = textcmdLink(++linkIndex, chatText);
chatText = Ui::Text::Link(chatText.text, {});
}
if (users.size() == 1) {
auto user = owner->user(users[0].v);
result.links.push_back(user->createOpenLink());
result.text = tr::lng_action_invite_user(tr::now, lt_from, fromLinkText(), lt_user, textcmdLink(++linkIndex, user->name), lt_chat, chatText);
result.text = tr::lng_action_invite_user(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_user,
Ui::Text::Link(user->name, {}), // Link N.
lt_chat,
chatText,
Ui::Text::WithEntities);
} else if (users.isEmpty()) {
result.text = tr::lng_action_invite_user(tr::now, lt_from, fromLinkText(), lt_user, qsl("somebody"), lt_chat, chatText);
result.text = tr::lng_action_invite_user(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_user,
{ .text = qsl("somebody") },
lt_chat,
chatText,
Ui::Text::WithEntities);
} else {
for (auto i = 0, l = int(users.size()); i != l; ++i) {
auto user = owner->user(users[i].v);
result.links.push_back(user->createOpenLink());
auto linkText = textcmdLink(++linkIndex, user->name);
auto linkText = Ui::Text::Link(user->name, {});
if (i == 0) {
result.text = linkText;
} else if (i + 1 == l) {
result.text = tr::lng_action_invite_users_and_last(tr::now, lt_accumulated, result.text, lt_user, linkText);
result.text = tr::lng_action_invite_users_and_last(
tr::now,
lt_accumulated,
result.text,
lt_user,
linkText,
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_invite_users_and_one(tr::now, lt_accumulated, result.text, lt_user, linkText);
result.text = tr::lng_action_invite_users_and_one(
tr::now,
lt_accumulated,
result.text,
lt_user,
linkText,
Ui::Text::WithEntities);
}
}
result.text = tr::lng_action_invite_users_many(tr::now, lt_from, fromLinkText(), lt_users, result.text, lt_chat, chatText);
result.text = tr::lng_action_invite_users_many(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_users,
result.text,
lt_chat,
chatText,
Ui::Text::WithEntities);
}
return result;
}
@ -692,38 +883,63 @@ HistoryService::PreparedText HistoryService::preparePinnedText() {
result.links.push_back(fromLink());
result.links.push_back(pinned->lnk);
if (mediaText.isEmpty()) {
auto original = TextUtilities::TextWithSpoilerCommands(
pinned->msg->originalText());
auto original = pinned->msg->originalText();
auto cutAt = 0;
auto limit = kPinnedMessageTextLimit;
auto size = original.size();
auto size = original.text.size();
for (; limit != 0;) {
--limit;
if (cutAt >= size) break;
if (original.at(cutAt).isLowSurrogate() && cutAt + 1 < size && original.at(cutAt + 1).isHighSurrogate()) {
if (original.text.at(cutAt).isLowSurrogate()
&& (cutAt + 1 < size)
&& original.text.at(cutAt + 1).isHighSurrogate()) {
cutAt += 2;
} else {
++cutAt;
}
}
if (!limit && cutAt + 5 < size) {
original = TextUtilities::CutTextWithCommands(
std::move(original),
cutAt,
textcmdStartSpoiler(),
textcmdStopSpoiler());
original = Ui::Text::Mid(original, 0, cutAt).append(
Ui::kQEllipsis);
}
result.text = tr::lng_action_pinned_message(tr::now, lt_from, fromLinkText(), lt_text, textcmdLink(2, original));
original = Ui::Text::Wrapped(
std::move(original),
EntityType::CustomUrl);
result.text = tr::lng_action_pinned_message(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_text,
std::move(original), // Link 2.
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_pinned_media(tr::now, lt_from, fromLinkText(), lt_media, textcmdLink(2, mediaText));
result.text = tr::lng_action_pinned_media(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_media,
Ui::Text::Link(mediaText, {}), // Link 2.
Ui::Text::WithEntities);
}
} else if (pinned && pinned->msgId) {
result.links.push_back(fromLink());
result.links.push_back(pinned->lnk);
result.text = tr::lng_action_pinned_media(tr::now, lt_from, fromLinkText(), lt_media, textcmdLink(2, tr::lng_contacts_loading(tr::now)));
result.text = tr::lng_action_pinned_media(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_media,
Ui::Text::Link(tr::lng_contacts_loading(tr::now), {}), // Link 2.
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_pinned_media(tr::now, lt_from, fromLinkText(), lt_media, tr::lng_deleted_message(tr::now));
result.text = tr::lng_action_pinned_media(
tr::now,
lt_from,
fromLinkText(), // Link 1.
lt_media,
{ .text = tr::lng_deleted_message(tr::now) },
Ui::Text::WithEntities);
}
return result;
}
@ -732,7 +948,7 @@ HistoryService::PreparedText HistoryService::prepareGameScoreText() {
auto result = PreparedText {};
auto gamescore = Get<HistoryServiceGameScore>();
auto computeGameTitle = [&]() -> QString {
auto computeGameTitle = [&]() -> TextWithEntities {
if (gamescore && gamescore->msg) {
if (const auto media = gamescore->msg->media()) {
if (const auto game = media->game()) {
@ -745,51 +961,55 @@ HistoryService::PreparedText HistoryService::prepareGameScoreText() {
column,
gamescore->msg->fullId()));
auto titleText = game->title;
return textcmdLink(result.links.size(), titleText);
return Ui::Text::Link(titleText, {});
}
}
return tr::lng_deleted_message(tr::now);
return tr::lng_deleted_message(tr::now, Ui::Text::WithEntities);
} else if (gamescore && gamescore->msgId) {
return tr::lng_contacts_loading(tr::now);
return tr::lng_contacts_loading(tr::now, Ui::Text::WithEntities);
}
return QString();
return {};
};
const auto scoreNumber = gamescore ? gamescore->score : 0;
if (_from->isSelf()) {
auto gameTitle = computeGameTitle();
if (gameTitle.isEmpty()) {
if (gameTitle.text.isEmpty()) {
result.text = tr::lng_action_game_you_scored_no_game(
tr::now,
lt_count,
scoreNumber);
scoreNumber,
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_game_you_scored(
tr::now,
lt_count,
scoreNumber,
lt_game,
gameTitle);
gameTitle,
Ui::Text::WithEntities);
}
} else {
result.links.push_back(fromLink());
auto gameTitle = computeGameTitle();
if (gameTitle.isEmpty()) {
if (gameTitle.text.isEmpty()) {
result.text = tr::lng_action_game_score_no_game(
tr::now,
lt_count,
scoreNumber,
lt_from,
fromLinkText());
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_game_score(
tr::now,
lt_count,
scoreNumber,
lt_from,
fromLinkText(),
fromLinkText(), // Link 1.
lt_game,
gameTitle);
gameTitle,
Ui::Text::WithEntities);
}
}
return result;
@ -804,17 +1024,31 @@ HistoryService::PreparedText HistoryService::preparePaymentSentText() {
if (payment->msg) {
if (const auto media = payment->msg->media()) {
if (const auto invoice = media->invoice()) {
return textcmdLink(1, invoice->title);
return Ui::Text::Link(invoice->title, {});
}
}
}
return QString();
return TextWithEntities();
}();
if (invoiceTitle.isEmpty()) {
result.text = tr::lng_action_payment_done(tr::now, lt_amount, payment->amount, lt_user, history()->peer->name);
if (invoiceTitle.text.isEmpty()) {
result.text = tr::lng_action_payment_done(
tr::now,
lt_amount,
{ .text = payment->amount },
lt_user,
{ .text = history()->peer->name },
Ui::Text::WithEntities);
} else {
result.text = tr::lng_action_payment_done_for(tr::now, lt_amount, payment->amount, lt_user, history()->peer->name, lt_invoice, invoiceTitle);
result.text = tr::lng_action_payment_done_for(
tr::now,
lt_amount,
{ .text = payment->amount },
lt_user,
{ .text = history()->peer->name },
lt_invoice,
invoiceTitle,
Ui::Text::WithEntities);
if (payment->msg) {
result.links.push_back(payment->lnk);
}
@ -839,15 +1073,17 @@ HistoryService::PreparedText HistoryService::prepareCallScheduledText(
result.text = tr::lng_action_group_call_scheduled_channel(
tr::now,
lt_date,
date);
{ .text = date },
Ui::Text::WithEntities);
} else {
result.links.push_back(fromLink());
result.text = tr::lng_action_group_call_scheduled_group(
tr::now,
lt_from,
fromLinkText(),
fromLinkText(), // Link 1.
lt_date,
date);
{ .text = date },
Ui::Text::WithEntities);
}
};
const auto time = scheduled.time().toString(cTimeFormat());
@ -948,21 +1184,21 @@ ItemPreview HistoryService::toPreview(ToPreviewOptions options) const {
// Because larger version is shown exactly to the left of the preview.
//auto media = _media ? _media->toPreview(options) : ItemPreview();
return {
.text = textcmdLink(
1,
TextUtilities::Clean(notificationText(), true)),
.text = Ui::Text::Wrapped(notificationText(), EntityType::PlainLink),
//.images = std::move(media.images),
//.loadingContext = std::move(media.loadingContext),
};
}
QString HistoryService::inReplyText() const {
const auto result = HistoryService::notificationText();
TextWithEntities HistoryService::inReplyText() const {
auto result = HistoryService::notificationText();
const auto &name = author()->name;
const auto text = result.trimmed().startsWith(name)
? result.trimmed().mid(name.size()).trimmed()
: result;
return textcmdLink(1, text);
TextUtilities::Trim(result);
if (result.text.startsWith(name)) {
result = Ui::Text::Mid(result, name.size());
TextUtilities::Trim(result);
}
return Ui::Text::Wrapped(result, EntityType::PlainLink);
}
std::unique_ptr<HistoryView::Element> HistoryService::createView(
@ -971,8 +1207,8 @@ std::unique_ptr<HistoryView::Element> HistoryService::createView(
return delegate->elementCreate(this, replacing);
}
QString HistoryService::fromLinkText() const {
return textcmdLink(1, _from->name);
TextWithEntities HistoryService::fromLinkText() const {
return Ui::Text::Link(_from->name, {});
}
ClickHandlerPtr HistoryService::fromLink() const {
@ -980,7 +1216,7 @@ ClickHandlerPtr HistoryService::fromLink() const {
}
void HistoryService::setServiceText(const PreparedText &prepared) {
_text.setText(
_text.setMarkedText(
st::serviceTextStyle,
prepared.text,
Ui::ItemTextServiceOptions());
@ -1018,7 +1254,7 @@ crl::time HistoryService::getSelfDestructIn(crl::time now) {
}
Unexpected("Type in HistoryServiceSelfDestruct::Type");
};
setServiceText({ text() });
setServiceText({ TextWithEntities{ .text = text() } });
return 0;
}
return selfdestruct->destructAt - now;
@ -1041,15 +1277,23 @@ void HistoryService::createFromMtp(const MTPDmessage &message) {
setSelfDestruct(HistoryServiceSelfDestruct::Type::Photo, ttl->v);
if (out()) {
setServiceText({ tr::lng_ttl_photo_sent(tr::now) });
setServiceText({
tr::lng_ttl_photo_sent(tr::now, Ui::Text::WithEntities)
});
} else {
auto result = PreparedText();
result.links.push_back(fromLink());
result.text = tr::lng_ttl_photo_received(tr::now, lt_from, fromLinkText());
result.text = tr::lng_ttl_photo_received(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
setServiceText(std::move(result));
}
} else {
setServiceText({ tr::lng_ttl_photo_expired(tr::now) });
setServiceText({
tr::lng_ttl_photo_expired(tr::now, Ui::Text::WithEntities)
});
}
} break;
case mtpc_messageMediaDocument: {
@ -1060,15 +1304,23 @@ void HistoryService::createFromMtp(const MTPDmessage &message) {
setSelfDestruct(HistoryServiceSelfDestruct::Type::Video, ttl->v);
if (out()) {
setServiceText({ tr::lng_ttl_video_sent(tr::now) });
setServiceText({
tr::lng_ttl_video_sent(tr::now, Ui::Text::WithEntities)
});
} else {
auto result = PreparedText();
result.links.push_back(fromLink());
result.text = tr::lng_ttl_video_received(tr::now, lt_from, fromLinkText());
result.text = tr::lng_ttl_video_received(
tr::now,
lt_from,
fromLinkText(), // Link 1.
Ui::Text::WithEntities);
setServiceText(std::move(result));
}
} else {
setServiceText({ tr::lng_ttl_video_expired(tr::now) });
setServiceText({
tr::lng_ttl_video_expired(tr::now, Ui::Text::WithEntities)
});
}
} break;
@ -1264,11 +1516,14 @@ HistoryService::PreparedText GenerateJoinedText(
: tr::lng_action_add_you)(
tr::now,
lt_from,
textcmdLink(1, inviter->name));
Ui::Text::Link(inviter->name, {}),
Ui::Text::WithEntities);
return result;
} else if (history->peer->isMegagroup()) {
if (viaRequest) {
return { tr::lng_action_you_joined_by_request(tr::now) };
return { tr::lng_action_you_joined_by_request(
tr::now,
Ui::Text::WithEntities) };
}
auto self = history->session().user();
auto result = HistoryService::PreparedText{};
@ -1276,12 +1531,15 @@ HistoryService::PreparedText GenerateJoinedText(
result.text = tr::lng_action_user_joined(
tr::now,
lt_from,
textcmdLink(1, self->name));
Ui::Text::Link(self->name, {}),
Ui::Text::WithEntities);
return result;
}
return { viaRequest
? tr::lng_action_you_joined_by_request_channel(tr::now)
: tr::lng_action_you_joined(tr::now) };
? tr::lng_action_you_joined_by_request_channel(
tr::now,
Ui::Text::WithEntities)
: tr::lng_action_you_joined(tr::now, Ui::Text::WithEntities) };
}
not_null<HistoryService*> GenerateJoinedMessage(

View File

@ -63,7 +63,7 @@ class ServiceMessagePainter;
class HistoryService : public HistoryItem {
public:
struct PreparedText {
QString text;
TextWithEntities text;
QList<ClickHandlerPtr> links;
};
@ -112,7 +112,7 @@ public:
return true;
}
ItemPreview toPreview(ToPreviewOptions options) const override;
QString inReplyText() const override;
TextWithEntities inReplyText() const override;
std::unique_ptr<HistoryView::Element> createView(
not_null<HistoryView::ElementDelegate*> delegate,
@ -129,7 +129,7 @@ protected:
void markMediaAsReadHook() override;
QString fromLinkText() const;
TextWithEntities fromLinkText() const;
ClickHandlerPtr fromLink() const;
void removeMedia();

View File

@ -6952,7 +6952,7 @@ void HistoryWidget::messageDataReceived(
}
void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
_replyEditMsgText.setText(
_replyEditMsgText.setMarkedText(
st::messageTextStyle,
item->inReplyText(),
Ui::DialogTextOptions());
@ -7000,7 +7000,8 @@ void HistoryWidget::updateForwarding() {
void HistoryWidget::updateForwardingTexts() {
int32 version = 0;
QString from, text;
QString from;
TextWithEntities text;
const auto keepNames = (_toForward.options
== Data::ForwardOptions::PreserveInfo);
const auto keepCaptions = (_toForward.options
@ -7047,13 +7048,12 @@ void HistoryWidget::updateForwardingTexts() {
.generateImages = false,
}).text;
} else {
text = textcmdLink(
1,
text = Ui::Text::PlainLink(
tr::lng_forward_messages(tr::now, lt_count, count));
}
}
_toForwardFrom.setText(st::msgNameStyle, from, Ui::NameTextOptions());
_toForwardText.setText(
_toForwardText.setMarkedText(
st::messageTextStyle,
text,
Ui::DialogTextOptions());

View File

@ -325,7 +325,7 @@ void FieldHeader::init() {
void FieldHeader::updateShownMessageText() {
Expects(_shownMessage != nullptr);
_shownMessageText.setText(
_shownMessageText.setMarkedText(
st::messageTextStyle,
_shownMessage->inReplyText(),
Ui::DialogTextOptions());

View File

@ -19,7 +19,7 @@ struct ItemPreviewImage {
};
struct ItemPreview {
QString text;
TextWithEntities text;
std::vector<ItemPreviewImage> images;
int imagesInTextPosition = 0;
std::any loadingContext;

View File

@ -24,7 +24,7 @@ namespace {
[[nodiscard]] Ui::MessageBarContent ContentWithoutPreview(
not_null<HistoryItem*> item) {
return Ui::MessageBarContent{
.text = { item->inReplyText() },
.text = item->inReplyText(),
};
}

View File

@ -47,30 +47,18 @@ constexpr auto kSystemAlertDuration = crl::time(1000);
constexpr auto kSystemAlertDuration = crl::time(0);
#endif // Q_OS_MAC
QString TextWithPermanentSpoiler(QString textWithCommands) {
const auto start = textcmdStartSpoiler();
const auto stop = textcmdStopSpoiler();
while (true) {
const auto startIndex = textWithCommands.indexOf(start);
if (startIndex == -1) {
break;
QString TextWithPermanentSpoiler(const TextWithEntities &textWithEntities) {
auto text = textWithEntities.text;
for (const auto &e : textWithEntities.entities) {
if (e.type() == EntityType::Spoiler) {
auto replacement = QString().fill(QChar(0x259A), e.length());
text = text.replace(
e.offset(),
e.length(),
std::move(replacement));
}
const auto stopIndex = textWithCommands.indexOf(stop);
if (stopIndex == -1) {
break;
}
if (stopIndex < startIndex) {
break;
}
const auto length = stopIndex - startIndex - start.size();
textWithCommands.remove(stopIndex, stop.size());
textWithCommands.remove(startIndex, start.size());
textWithCommands.replace(
startIndex,
length,
QString(QChar(0x259A)).repeated(length));
}
return textWithCommands;
return text;
}
} // namespace

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/emoji_config.h"
#include "ui/empty_userpic.h"
#include "ui/ui_utility.h"
@ -811,9 +812,9 @@ void Notification::updateNotifyDisplay() {
.generateImages = false,
}).text
: ((!_author.isEmpty()
? textcmdLink(1, _author)
: QString())
+ (_forwardedCount > 1
? Ui::Text::PlainLink(_author)
: TextWithEntities()
).append(_forwardedCount > 1
? ('\n' + tr::lng_forward_messages(
tr::now,
lt_count,
@ -826,7 +827,7 @@ void Notification::updateNotifyDisplay() {
0,
Qt::LayoutDirectionAuto,
};
itemTextCache.setText(st::dialogsTextStyle, text, Options);
itemTextCache.setMarkedText(st::dialogsTextStyle, text, Options);
itemTextCache.drawElided(
p,
r.left(),