mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Display topic name in chats list.
This commit is contained in:
parent
fdf4129e5e
commit
34a2c5c8ce
28 changed files with 223 additions and 172 deletions
BIN
Telegram/Resources/icons/dialogs/dialogs_topic_arrow.png
Normal file
BIN
Telegram/Resources/icons/dialogs/dialogs_topic_arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 250 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_topic_arrow@2x.png
Normal file
BIN
Telegram/Resources/icons/dialogs/dialogs_topic_arrow@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 293 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_topic_arrow@3x.png
Normal file
BIN
Telegram/Resources/icons/dialogs/dialogs_topic_arrow@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 416 B |
|
@ -2049,6 +2049,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_dialogs_text_from_wrapped" = "{from}:";
|
"lng_dialogs_text_from_wrapped" = "{from}:";
|
||||||
"lng_dialogs_text_media" = "{media_part} {caption}";
|
"lng_dialogs_text_media" = "{media_part} {caption}";
|
||||||
"lng_dialogs_text_media_wrapped" = "{media},";
|
"lng_dialogs_text_media_wrapped" = "{media},";
|
||||||
|
"lng_dialogs_text_from_in_topic" = "{from} {topic}";
|
||||||
"lng_dialogs_show_all_chats" = "Show all chats";
|
"lng_dialogs_show_all_chats" = "Show all chats";
|
||||||
"lng_dialogs_hide_muted_chats" = "Hide muted chats";
|
"lng_dialogs_hide_muted_chats" = "Hide muted chats";
|
||||||
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
|
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
|
||||||
|
|
|
@ -21,9 +21,7 @@ using namespace TextUtilities;
|
||||||
|
|
||||||
[[nodiscard]] QString CustomEmojiEntityData(
|
[[nodiscard]] QString CustomEmojiEntityData(
|
||||||
const MTPDmessageEntityCustomEmoji &data) {
|
const MTPDmessageEntityCustomEmoji &data) {
|
||||||
return Data::SerializeCustomEmojiId({
|
return Data::SerializeCustomEmojiId(data.vdocument_id().v);
|
||||||
.id = data.vdocument_id().v,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::optional<MTPMessageEntity> CustomEmojiEntity(
|
[[nodiscard]] std::optional<MTPMessageEntity> CustomEmojiEntity(
|
||||||
|
@ -31,13 +29,13 @@ using namespace TextUtilities;
|
||||||
MTPint length,
|
MTPint length,
|
||||||
const QString &data) {
|
const QString &data) {
|
||||||
const auto parsed = Data::ParseCustomEmojiData(data);
|
const auto parsed = Data::ParseCustomEmojiData(data);
|
||||||
if (!parsed.id) {
|
if (!parsed) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return MTP_messageEntityCustomEmoji(
|
return MTP_messageEntityCustomEmoji(
|
||||||
offset,
|
offset,
|
||||||
length,
|
length,
|
||||||
MTP_long(parsed.id));
|
MTP_long(parsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::optional<MTPMessageEntity> MentionNameEntity(
|
[[nodiscard]] std::optional<MTPMessageEntity> MentionNameEntity(
|
||||||
|
|
|
@ -87,11 +87,11 @@ QString FieldTagMimeProcessor::operator()(QStringView mimeTag) {
|
||||||
} else if (Ui::InputField::IsCustomEmojiLink(tag)) {
|
} else if (Ui::InputField::IsCustomEmojiLink(tag)) {
|
||||||
const auto data = Ui::InputField::CustomEmojiEntityData(tag);
|
const auto data = Ui::InputField::CustomEmojiEntityData(tag);
|
||||||
const auto emoji = Data::ParseCustomEmojiData(data);
|
const auto emoji = Data::ParseCustomEmojiData(data);
|
||||||
if (!emoji.id) {
|
if (!emoji) {
|
||||||
i = all.erase(i);
|
i = all.erase(i);
|
||||||
continue;
|
continue;
|
||||||
} else if (!_session->premium()) {
|
} else if (!_session->premium()) {
|
||||||
const auto document = _session->data().document(emoji.id);
|
const auto document = _session->data().document(emoji);
|
||||||
if (document->isPremiumEmoji()) {
|
if (document->isPremiumEmoji()) {
|
||||||
if (!_allowPremiumEmoji
|
if (!_allowPremiumEmoji
|
||||||
|| premiumSkipped
|
|| premiumSkipped
|
||||||
|
|
|
@ -225,6 +225,13 @@ void Forum::applyReceivedTopics(
|
||||||
).first->second.get()
|
).first->second.get()
|
||||||
: i->second.get();
|
: i->second.get();
|
||||||
raw->applyTopic(data);
|
raw->applyTopic(data);
|
||||||
|
if (creating) {
|
||||||
|
if (const auto last = _history->chatListMessage()
|
||||||
|
; last && last->topicRootId() == rootId) {
|
||||||
|
_history->lastItemDialogsView().itemInvalidated(last);
|
||||||
|
_history->updateChatListEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(raw);
|
callback(raw);
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,14 @@ QImage ForumTopicIconFrame(
|
||||||
return background;
|
return background;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities ForumTopicIconWithTitle(
|
||||||
|
DocumentId iconId,
|
||||||
|
const QString &title) {
|
||||||
|
return iconId
|
||||||
|
? Data::SingleCustomEmoji(iconId).append(title)
|
||||||
|
: TextWithEntities{ title };
|
||||||
|
}
|
||||||
|
|
||||||
ForumTopic::ForumTopic(not_null<Forum*> forum, MsgId rootId)
|
ForumTopic::ForumTopic(not_null<Forum*> forum, MsgId rootId)
|
||||||
: Thread(&forum->history()->owner(), Type::ForumTopic)
|
: Thread(&forum->history()->owner(), Type::ForumTopic)
|
||||||
, _forum(forum)
|
, _forum(forum)
|
||||||
|
@ -570,6 +578,10 @@ QString ForumTopic::title() const {
|
||||||
return _title;
|
return _title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities ForumTopic::titleWithIcon() const {
|
||||||
|
return ForumTopicIconWithTitle(_iconId, _title);
|
||||||
|
}
|
||||||
|
|
||||||
void ForumTopic::applyTitle(const QString &title) {
|
void ForumTopic::applyTitle(const QString &title) {
|
||||||
if (_title == title) {
|
if (_title == title) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -44,6 +44,9 @@ class Forum;
|
||||||
int32 colorId,
|
int32 colorId,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
const style::ForumTopicIcon &st);
|
const style::ForumTopicIcon &st);
|
||||||
|
[[nodiscard]] TextWithEntities ForumTopicIconWithTitle(
|
||||||
|
DocumentId iconId,
|
||||||
|
const QString &title);
|
||||||
|
|
||||||
class ForumTopic final : public Thread {
|
class ForumTopic final : public Thread {
|
||||||
public:
|
public:
|
||||||
|
@ -107,6 +110,7 @@ public:
|
||||||
[[nodiscard]] MsgId lastKnownServerMessageId() const;
|
[[nodiscard]] MsgId lastKnownServerMessageId() const;
|
||||||
|
|
||||||
[[nodiscard]] QString title() const;
|
[[nodiscard]] QString title() const;
|
||||||
|
[[nodiscard]] TextWithEntities titleWithIcon() const;
|
||||||
void applyTitle(const QString &title);
|
void applyTitle(const QString &title);
|
||||||
[[nodiscard]] DocumentId iconId() const;
|
[[nodiscard]] DocumentId iconId() const;
|
||||||
void applyIconId(DocumentId iconId);
|
void applyIconId(DocumentId iconId);
|
||||||
|
|
|
@ -15,9 +15,7 @@ QString ReactionEntityData(const ReactionId &id) {
|
||||||
if (id.empty()) {
|
if (id.empty()) {
|
||||||
return {};
|
return {};
|
||||||
} else if (const auto custom = id.custom()) {
|
} else if (const auto custom = id.custom()) {
|
||||||
return SerializeCustomEmojiId({
|
return SerializeCustomEmojiId(custom);
|
||||||
.id = custom,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return u"default:"_q + id.emoji();
|
return u"default:"_q + id.emoji();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "chat_helpers/stickers_lottie.h"
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/text/text_custom_emoji.h"
|
#include "ui/text/text_custom_emoji.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
@ -91,7 +92,7 @@ class CustomEmojiLoader final
|
||||||
public:
|
public:
|
||||||
CustomEmojiLoader(
|
CustomEmojiLoader(
|
||||||
not_null<Session*> owner,
|
not_null<Session*> owner,
|
||||||
const CustomEmojiId id,
|
DocumentId id,
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride);
|
int sizeOverride);
|
||||||
CustomEmojiLoader(
|
CustomEmojiLoader(
|
||||||
|
@ -144,7 +145,7 @@ private:
|
||||||
|
|
||||||
[[nodiscard]] static std::variant<Resolve, Lookup, Load> InitialState(
|
[[nodiscard]] static std::variant<Resolve, Lookup, Load> InitialState(
|
||||||
not_null<Session*> owner,
|
not_null<Session*> owner,
|
||||||
const CustomEmojiId &id);
|
DocumentId id);
|
||||||
|
|
||||||
std::variant<Resolve, Lookup, Load> _state;
|
std::variant<Resolve, Lookup, Load> _state;
|
||||||
ushort _sizeOverride = 0;
|
ushort _sizeOverride = 0;
|
||||||
|
@ -154,7 +155,7 @@ private:
|
||||||
|
|
||||||
CustomEmojiLoader::CustomEmojiLoader(
|
CustomEmojiLoader::CustomEmojiLoader(
|
||||||
not_null<Session*> owner,
|
not_null<Session*> owner,
|
||||||
const CustomEmojiId id,
|
DocumentId id,
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride)
|
int sizeOverride)
|
||||||
: _state(InitialState(owner, id))
|
: _state(InitialState(owner, id))
|
||||||
|
@ -368,9 +369,9 @@ void CustomEmojiLoader::check() {
|
||||||
|
|
||||||
auto CustomEmojiLoader::InitialState(
|
auto CustomEmojiLoader::InitialState(
|
||||||
not_null<Session*> owner,
|
not_null<Session*> owner,
|
||||||
const CustomEmojiId &id)
|
DocumentId id)
|
||||||
-> std::variant<Resolve, Lookup, Load> {
|
-> std::variant<Resolve, Lookup, Load> {
|
||||||
const auto document = owner->document(id.id);
|
const auto document = owner->document(id);
|
||||||
if (document->sticker()) {
|
if (document->sticker()) {
|
||||||
return Lookup{ document };
|
return Lookup{ document };
|
||||||
}
|
}
|
||||||
|
@ -504,8 +505,8 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride) {
|
int sizeOverride) {
|
||||||
const auto parsed = ParseCustomEmojiData(data);
|
const auto parsed = ParseCustomEmojiData(data);
|
||||||
return parsed.id
|
return parsed
|
||||||
? create(parsed.id, std::move(update), tag, sizeOverride)
|
? create(parsed, std::move(update), tag, sizeOverride)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +533,7 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
void CustomEmojiManager::resolve(
|
void CustomEmojiManager::resolve(
|
||||||
QStringView data,
|
QStringView data,
|
||||||
not_null<Listener*> listener) {
|
not_null<Listener*> listener) {
|
||||||
resolve(ParseCustomEmojiData(data).id, listener);
|
resolve(ParseCustomEmojiData(data), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomEmojiManager::resolve(
|
void CustomEmojiManager::resolve(
|
||||||
|
@ -619,7 +620,7 @@ auto CustomEmojiManager::createLoaderWithSetId(
|
||||||
) -> LoaderWithSetId {
|
) -> LoaderWithSetId {
|
||||||
auto result = std::make_unique<CustomEmojiLoader>(
|
auto result = std::make_unique<CustomEmojiLoader>(
|
||||||
_owner,
|
_owner,
|
||||||
CustomEmojiId{ .id = documentId },
|
documentId,
|
||||||
tag,
|
tag,
|
||||||
sizeOverride);
|
sizeOverride);
|
||||||
if (const auto document = result->document()) {
|
if (const auto document = result->document()) {
|
||||||
|
@ -882,18 +883,24 @@ int FrameSizeFromTag(SizeTag tag) {
|
||||||
return Ui::Text::AdjustCustomEmojiSize(emoji / factor) * factor;
|
return Ui::Text::AdjustCustomEmojiSize(emoji / factor) * factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SerializeCustomEmojiId(const CustomEmojiId &id) {
|
QString SerializeCustomEmojiId(DocumentId id) {
|
||||||
return QString::number(id.id);
|
return QString::number(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SerializeCustomEmojiId(not_null<DocumentData*> document) {
|
QString SerializeCustomEmojiId(not_null<DocumentData*> document) {
|
||||||
return SerializeCustomEmojiId({
|
return SerializeCustomEmojiId(document->id);
|
||||||
.id = document->id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomEmojiId ParseCustomEmojiData(QStringView data) {
|
DocumentId ParseCustomEmojiData(QStringView data) {
|
||||||
return { .id = data.toULongLong() };
|
return data.toULongLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities SingleCustomEmoji(DocumentId id) {
|
||||||
|
return Ui::Text::SingleCustomEmoji(SerializeCustomEmojiId(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities SingleCustomEmoji(not_null<DocumentData*> document) {
|
||||||
|
return SingleCustomEmoji(document->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AllowEmojiWithoutPremium(not_null<PeerData*> peer) {
|
bool AllowEmojiWithoutPremium(not_null<PeerData*> peer) {
|
||||||
|
|
|
@ -21,10 +21,6 @@ namespace Data {
|
||||||
class Session;
|
class Session;
|
||||||
class CustomEmojiLoader;
|
class CustomEmojiLoader;
|
||||||
|
|
||||||
struct CustomEmojiId {
|
|
||||||
DocumentId id = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CustomEmojiSizeTag : uchar {
|
enum class CustomEmojiSizeTag : uchar {
|
||||||
Normal,
|
Normal,
|
||||||
Large,
|
Large,
|
||||||
|
@ -176,10 +172,14 @@ private:
|
||||||
|
|
||||||
[[nodiscard]] int FrameSizeFromTag(CustomEmojiManager::SizeTag tag);
|
[[nodiscard]] int FrameSizeFromTag(CustomEmojiManager::SizeTag tag);
|
||||||
|
|
||||||
[[nodiscard]] QString SerializeCustomEmojiId(const CustomEmojiId &id);
|
[[nodiscard]] QString SerializeCustomEmojiId(DocumentId id);
|
||||||
[[nodiscard]] QString SerializeCustomEmojiId(
|
[[nodiscard]] QString SerializeCustomEmojiId(
|
||||||
not_null<DocumentData*> document);
|
not_null<DocumentData*> document);
|
||||||
[[nodiscard]] CustomEmojiId ParseCustomEmojiData(QStringView data);
|
[[nodiscard]] DocumentId ParseCustomEmojiData(QStringView data);
|
||||||
|
|
||||||
|
[[nodiscard]] TextWithEntities SingleCustomEmoji(DocumentId id);
|
||||||
|
[[nodiscard]] TextWithEntities SingleCustomEmoji(
|
||||||
|
not_null<DocumentData*> document);
|
||||||
|
|
||||||
[[nodiscard]] bool AllowEmojiWithoutPremium(not_null<PeerData*> peer);
|
[[nodiscard]] bool AllowEmojiWithoutPremium(not_null<PeerData*> peer);
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ defaultDialogRow: DialogRow {
|
||||||
nameLeft: 68px;
|
nameLeft: 68px;
|
||||||
nameTop: 10px;
|
nameTop: 10px;
|
||||||
textLeft: 68px;
|
textLeft: 68px;
|
||||||
textTop: 35px;
|
textTop: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogsOnlineBadgeStroke: 2px;
|
dialogsOnlineBadgeStroke: 2px;
|
||||||
|
@ -460,3 +460,7 @@ chooseTopicListItem: PeerListItem(defaultPeerListItem) {
|
||||||
chooseTopicList: PeerList(defaultPeerList) {
|
chooseTopicList: PeerList(defaultPeerList) {
|
||||||
item: chooseTopicListItem;
|
item: chooseTopicListItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialogsTopicArrow: icon{{ "dialogs/dialogs_topic_arrow", dialogsTextFgService }};
|
||||||
|
dialogsTopicArrowSkip: 13px;
|
||||||
|
dialogsTopicArrowTop: 4px;
|
||||||
|
|
|
@ -921,7 +921,7 @@ void RowPainter::Paint(
|
||||||
view->prepare(
|
view->prepare(
|
||||||
item,
|
item,
|
||||||
[=] { entry->updateChatListEntry(); },
|
[=] { entry->updateChatListEntry(); },
|
||||||
{});
|
{ .ignoreTopic = (!history || !peer->isForum()) });
|
||||||
}
|
}
|
||||||
view->paint(p, rect, context);
|
view->paint(p, rect, context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "core/ui_integration.h"
|
#include "core/ui_integration.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "lang/lang_text_entity.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <ushort kTag>
|
template <ushort kTag>
|
||||||
struct TextWithTagOffset {
|
struct TextWithTagOffset {
|
||||||
TextWithTagOffset(QString text) : text(text) {
|
TextWithTagOffset(TextWithEntities text) : text(std::move(text)) {
|
||||||
|
}
|
||||||
|
TextWithTagOffset(QString text) : text({ std::move(text) }) {
|
||||||
}
|
}
|
||||||
static TextWithTagOffset FromString(const QString &text) {
|
static TextWithTagOffset FromString(const QString &text) {
|
||||||
return { text };
|
return { { text } };
|
||||||
}
|
}
|
||||||
|
|
||||||
QString text;
|
TextWithEntities text;
|
||||||
int offset = -1;
|
int offset = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,12 +55,12 @@ TextWithTagOffset<kTag> ReplaceTag<TextWithTagOffset<kTag>>::Call(
|
||||||
ushort tag,
|
ushort tag,
|
||||||
const TextWithTagOffset<kTag> &replacement) {
|
const TextWithTagOffset<kTag> &replacement) {
|
||||||
const auto replacementPosition = FindTagReplacementPosition(
|
const auto replacementPosition = FindTagReplacementPosition(
|
||||||
original.text,
|
original.text.text,
|
||||||
tag);
|
tag);
|
||||||
if (replacementPosition < 0) {
|
if (replacementPosition < 0) {
|
||||||
return std::move(original);
|
return std::move(original);
|
||||||
}
|
}
|
||||||
original.text = ReplaceTag<QString>::Replace(
|
original.text = ReplaceTag<TextWithEntities>::Replace(
|
||||||
std::move(original.text),
|
std::move(original.text),
|
||||||
replacement.text,
|
replacement.text,
|
||||||
replacementPosition);
|
replacementPosition);
|
||||||
|
@ -65,7 +68,8 @@ TextWithTagOffset<kTag> ReplaceTag<TextWithTagOffset<kTag>>::Call(
|
||||||
original.offset = replacementPosition;
|
original.offset = replacementPosition;
|
||||||
} else if (original.offset > replacementPosition) {
|
} else if (original.offset > replacementPosition) {
|
||||||
constexpr auto kReplaceCommandLength = 4;
|
constexpr auto kReplaceCommandLength = 4;
|
||||||
original.offset += replacement.text.size() - kReplaceCommandLength;
|
const auto replacementSize = replacement.text.text.size();
|
||||||
|
original.offset += replacementSize - kReplaceCommandLength;
|
||||||
}
|
}
|
||||||
return std::move(original);
|
return std::move(original);
|
||||||
}
|
}
|
||||||
|
@ -105,6 +109,7 @@ struct MessageView::LoadingContext {
|
||||||
|
|
||||||
MessageView::MessageView()
|
MessageView::MessageView()
|
||||||
: _senderCache(st::dialogsTextWidthMin)
|
: _senderCache(st::dialogsTextWidthMin)
|
||||||
|
, _topicCache(st::dialogsTextWidthMin)
|
||||||
, _textCache(st::dialogsTextWidthMin) {
|
, _textCache(st::dialogsTextWidthMin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,28 +135,46 @@ void MessageView::prepare(
|
||||||
ToPreviewOptions options) {
|
ToPreviewOptions options) {
|
||||||
options.existing = &_imagesCache;
|
options.existing = &_imagesCache;
|
||||||
auto preview = item->toPreview(options);
|
auto preview = item->toPreview(options);
|
||||||
if (!preview.images.empty() && preview.imagesInTextPosition > 0) {
|
const auto hasImages = !preview.images.empty();
|
||||||
auto sender = ::Ui::Text::Mid(
|
const auto hasArrow = (preview.arrowInTextPosition > 0)
|
||||||
preview.text,
|
&& (preview.imagesInTextPosition > preview.arrowInTextPosition);
|
||||||
0,
|
|
||||||
preview.imagesInTextPosition);
|
|
||||||
TextUtilities::Trim(sender);
|
|
||||||
_senderCache.setMarkedText(
|
|
||||||
st::dialogsTextStyle,
|
|
||||||
std::move(sender),
|
|
||||||
DialogTextOptions());
|
|
||||||
preview.text = ::Ui::Text::Mid(
|
|
||||||
preview.text,
|
|
||||||
preview.imagesInTextPosition);
|
|
||||||
} else {
|
|
||||||
_senderCache = { st::dialogsTextWidthMin };
|
|
||||||
}
|
|
||||||
TextUtilities::Trim(preview.text);
|
|
||||||
const auto history = item->history();
|
const auto history = item->history();
|
||||||
const auto context = Core::MarkedTextContext{
|
const auto context = Core::MarkedTextContext{
|
||||||
.session = &history->session(),
|
.session = &history->session(),
|
||||||
.customEmojiRepaint = customEmojiRepaint,
|
.customEmojiRepaint = customEmojiRepaint,
|
||||||
};
|
};
|
||||||
|
const auto senderTill = (preview.arrowInTextPosition > 0)
|
||||||
|
? preview.arrowInTextPosition
|
||||||
|
: preview.imagesInTextPosition;
|
||||||
|
if ((hasImages || hasArrow) && senderTill > 0) {
|
||||||
|
auto sender = Text::Mid(preview.text, 0, senderTill);
|
||||||
|
TextUtilities::Trim(sender);
|
||||||
|
_senderCache.setMarkedText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
std::move(sender),
|
||||||
|
DialogTextOptions());
|
||||||
|
const auto topicTill = preview.imagesInTextPosition;
|
||||||
|
if (hasArrow && hasImages) {
|
||||||
|
auto topic = Text::Mid(
|
||||||
|
preview.text,
|
||||||
|
senderTill,
|
||||||
|
topicTill - senderTill);
|
||||||
|
TextUtilities::Trim(topic);
|
||||||
|
_topicCache.setMarkedText(
|
||||||
|
st::dialogsTextStyle,
|
||||||
|
std::move(topic),
|
||||||
|
DialogTextOptions(),
|
||||||
|
context);
|
||||||
|
preview.text = Text::Mid(preview.text, topicTill);
|
||||||
|
} else {
|
||||||
|
preview.text = Text::Mid(preview.text, senderTill);
|
||||||
|
_topicCache = { st::dialogsTextWidthMin };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_topicCache = { st::dialogsTextWidthMin };
|
||||||
|
_senderCache = { st::dialogsTextWidthMin };
|
||||||
|
}
|
||||||
|
TextUtilities::Trim(preview.text);
|
||||||
_textCache.setMarkedText(
|
_textCache.setMarkedText(
|
||||||
st::dialogsTextStyle,
|
st::dialogsTextStyle,
|
||||||
DialogsPreviewText(std::move(preview.text)),
|
DialogsPreviewText(std::move(preview.text)),
|
||||||
|
@ -193,16 +216,46 @@ void MessageView::paint(
|
||||||
: st::dialogsTextPalette);
|
: st::dialogsTextPalette);
|
||||||
|
|
||||||
auto rect = geometry;
|
auto rect = geometry;
|
||||||
|
const auto lines = rect.height() / st::dialogsTextFont->height;
|
||||||
if (!_senderCache.isEmpty()) {
|
if (!_senderCache.isEmpty()) {
|
||||||
_senderCache.draw(p, {
|
_senderCache.draw(p, {
|
||||||
.position = rect.topLeft(),
|
.position = rect.topLeft(),
|
||||||
.availableWidth = rect.width(),
|
.availableWidth = rect.width(),
|
||||||
.palette = palette,
|
.palette = palette,
|
||||||
.elisionLines = rect.height() / st::dialogsTextFont->height,
|
.elisionLines = lines,
|
||||||
});
|
});
|
||||||
const auto skip = st::dialogsMiniPreviewSkip
|
rect.setLeft(rect.x() + _senderCache.maxWidth());
|
||||||
+ st::dialogsMiniPreviewRight;
|
if (!_topicCache.isEmpty() || _imagesCache.empty()) {
|
||||||
rect.setLeft(rect.x() + _senderCache.maxWidth() + skip);
|
const auto skip = st::dialogsTopicArrowSkip;
|
||||||
|
if (rect.width() >= skip) {
|
||||||
|
const auto &icon = st::dialogsTopicArrow;
|
||||||
|
icon.paint(
|
||||||
|
p,
|
||||||
|
rect.x() + (skip - icon.width()) / 2,
|
||||||
|
rect.y() + st::dialogsTopicArrowTop,
|
||||||
|
geometry.width());
|
||||||
|
}
|
||||||
|
rect.setLeft(rect.x() + skip);
|
||||||
|
}
|
||||||
|
if (!_topicCache.isEmpty()) {
|
||||||
|
if (!rect.isEmpty()) {
|
||||||
|
_topicCache.draw(p, {
|
||||||
|
.position = rect.topLeft(),
|
||||||
|
.availableWidth = rect.width(),
|
||||||
|
.palette = palette,
|
||||||
|
.spoiler = Text::DefaultSpoilerCache(),
|
||||||
|
.now = context.now,
|
||||||
|
.paused = context.paused,
|
||||||
|
.elisionLines = lines,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rect.setLeft(rect.x() + _topicCache.maxWidth());
|
||||||
|
}
|
||||||
|
if (!_imagesCache.empty()) {
|
||||||
|
const auto skip = st::dialogsMiniPreviewSkip
|
||||||
|
+ st::dialogsMiniPreviewRight;
|
||||||
|
rect.setLeft(rect.x() + skip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const auto &image : _imagesCache) {
|
for (const auto &image : _imagesCache) {
|
||||||
if (rect.width() < st::dialogsMiniPreview) {
|
if (rect.width() < st::dialogsMiniPreview) {
|
||||||
|
@ -229,30 +282,48 @@ void MessageView::paint(
|
||||||
.spoiler = Text::DefaultSpoilerCache(),
|
.spoiler = Text::DefaultSpoilerCache(),
|
||||||
.now = context.now,
|
.now = context.now,
|
||||||
.paused = context.paused,
|
.paused = context.paused,
|
||||||
.elisionLines = rect.height() / st::dialogsTextFont->height,
|
.elisionLines = lines,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryView::ItemPreview PreviewWithSender(
|
HistoryView::ItemPreview PreviewWithSender(
|
||||||
HistoryView::ItemPreview &&preview,
|
HistoryView::ItemPreview &&preview,
|
||||||
const TextWithEntities &sender) {
|
const QString &sender,
|
||||||
const auto textWithOffset = tr::lng_dialogs_text_with_from(
|
TextWithEntities topic) {
|
||||||
|
auto senderWithOffset = topic.empty()
|
||||||
|
? TextWithTagOffset<lt_from>::FromString(sender)
|
||||||
|
: tr::lng_dialogs_text_from_in_topic(
|
||||||
|
tr::now,
|
||||||
|
lt_from,
|
||||||
|
{ sender },
|
||||||
|
lt_topic,
|
||||||
|
std::move(topic),
|
||||||
|
TextWithTagOffset<lt_from>::FromString);
|
||||||
|
auto wrappedWithOffset = tr::lng_dialogs_text_from_wrapped(
|
||||||
|
tr::now,
|
||||||
|
lt_from,
|
||||||
|
std::move(senderWithOffset.text),
|
||||||
|
TextWithTagOffset<lt_from>::FromString);
|
||||||
|
const auto wrappedSize = wrappedWithOffset.text.text.size();
|
||||||
|
auto fullWithOffset = tr::lng_dialogs_text_with_from(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_from_part,
|
lt_from_part,
|
||||||
sender.text,
|
Ui::Text::PlainLink(std::move(wrappedWithOffset.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,
|
lt_message,
|
||||||
std::move(preview.text),
|
std::move(preview.text),
|
||||||
Ui::Text::WithEntities);
|
TextWithTagOffset<lt_from_part>::FromString);
|
||||||
preview.imagesInTextPosition = (textWithOffset.offset < 0)
|
preview.text = std::move(fullWithOffset.text);
|
||||||
|
preview.arrowInTextPosition = (fullWithOffset.offset < 0
|
||||||
|
|| wrappedWithOffset.offset < 0
|
||||||
|
|| senderWithOffset.offset < 0)
|
||||||
|
? -1
|
||||||
|
: (fullWithOffset.offset
|
||||||
|
+ wrappedWithOffset.offset
|
||||||
|
+ senderWithOffset.offset
|
||||||
|
+ sender.size());
|
||||||
|
preview.imagesInTextPosition = (fullWithOffset.offset < 0)
|
||||||
? 0
|
? 0
|
||||||
: textWithOffset.offset + sender.text.size();
|
: (fullWithOffset.offset + wrappedSize);
|
||||||
return std::move(preview);
|
return std::move(preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ private:
|
||||||
|
|
||||||
mutable const HistoryItem *_textCachedFor = nullptr;
|
mutable const HistoryItem *_textCachedFor = nullptr;
|
||||||
mutable Text::String _senderCache;
|
mutable Text::String _senderCache;
|
||||||
|
mutable Text::String _topicCache;
|
||||||
mutable Text::String _textCache;
|
mutable Text::String _textCache;
|
||||||
mutable std::vector<ItemPreviewImage> _imagesCache;
|
mutable std::vector<ItemPreviewImage> _imagesCache;
|
||||||
mutable std::unique_ptr<LoadingContext> _loadingContext;
|
mutable std::unique_ptr<LoadingContext> _loadingContext;
|
||||||
|
@ -65,6 +66,7 @@ private:
|
||||||
|
|
||||||
[[nodiscard]] HistoryView::ItemPreview PreviewWithSender(
|
[[nodiscard]] HistoryView::ItemPreview PreviewWithSender(
|
||||||
HistoryView::ItemPreview &&preview,
|
HistoryView::ItemPreview &&preview,
|
||||||
const TextWithEntities &sender);
|
const QString &sender,
|
||||||
|
TextWithEntities topic);
|
||||||
|
|
||||||
} // namespace Dialogs::Ui
|
} // namespace Dialogs::Ui
|
||||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_text_entities.h"
|
#include "api/api_text_entities.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_message_reaction_id.h"
|
#include "data/data_message_reaction_id.h"
|
||||||
|
@ -624,23 +625,10 @@ TextWithEntities GenerateDefaultBannedRightsChangeText(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
const MTPForumTopic &topic) {
|
const MTPForumTopic &topic) {
|
||||||
return topic.match([&](const MTPDforumTopic &data) {
|
return topic.match([&](const MTPDforumTopic &data) {
|
||||||
const auto wrapIcon = [](DocumentId id) {
|
|
||||||
return TextWithEntities{
|
|
||||||
"@",
|
|
||||||
{ EntityInText(
|
|
||||||
EntityType::CustomEmoji,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
Data::SerializeCustomEmojiId({ .id = id }))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
auto result = (data.vicon_emoji_id() && data.vicon_emoji_id()->v)
|
|
||||||
? wrapIcon(data.vicon_emoji_id()->v)
|
|
||||||
: TextWithEntities();
|
|
||||||
result.append(qs(data.vtitle()));
|
|
||||||
return Ui::Text::Link(
|
return Ui::Text::Link(
|
||||||
std::move(result),
|
Data::ForumTopicIconWithTitle(
|
||||||
|
data.vicon_emoji_id().value_or_empty(),
|
||||||
|
qs(data.vtitle())),
|
||||||
u"internal:url:https://t.me/c/%1/%2"_q.arg(
|
u"internal:url:https://t.me/c/%1/%2"_q.arg(
|
||||||
peerToChannel(channel->id).bare).arg(
|
peerToChannel(channel->id).bare).arg(
|
||||||
data.vid().v));
|
data.vid().v));
|
||||||
|
|
|
@ -1365,9 +1365,11 @@ ItemPreview HistoryItem::toPreview(ToPreviewOptions options) const {
|
||||||
if (!sender) {
|
if (!sender) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const auto fromWrapped = Ui::Text::PlainLink(
|
const auto topic = options.ignoreTopic ? nullptr : this->topic();
|
||||||
tr::lng_dialogs_text_from_wrapped(tr::now, lt_from, *sender));
|
return Dialogs::Ui::PreviewWithSender(
|
||||||
return Dialogs::Ui::PreviewWithSender(std::move(result), fromWrapped);
|
std::move(result),
|
||||||
|
*sender,
|
||||||
|
topic ? topic->titleWithIcon() : TextWithEntities());
|
||||||
}
|
}
|
||||||
|
|
||||||
TextWithEntities HistoryItem::inReplyText() const {
|
TextWithEntities HistoryItem::inReplyText() const {
|
||||||
|
|
|
@ -636,33 +636,19 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto wrapTopicIcon = [](DocumentId id) {
|
|
||||||
return TextWithEntities{
|
|
||||||
"@",
|
|
||||||
{ EntityInText(
|
|
||||||
EntityType::CustomEmoji,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
Data::SerializeCustomEmojiId({ .id = id }))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
auto prepareTopicCreate = [&](const MTPDmessageActionTopicCreate &action) {
|
auto prepareTopicCreate = [&](const MTPDmessageActionTopicCreate &action) {
|
||||||
auto result = PreparedText{};
|
auto result = PreparedText{};
|
||||||
auto title = TextWithEntities{
|
|
||||||
qs(action.vtitle())
|
|
||||||
};
|
|
||||||
if (const auto icon = action.vicon_emoji_id().value_or_empty()) {
|
|
||||||
title = wrapTopicIcon(icon).append(' ').append(std::move(title));
|
|
||||||
}
|
|
||||||
const auto topicUrl = u"internal:url:https://t.me/c/%1/%2"_q
|
const auto topicUrl = u"internal:url:https://t.me/c/%1/%2"_q
|
||||||
.arg(peerToChannel(history()->peer->id).bare)
|
.arg(peerToChannel(history()->peer->id).bare)
|
||||||
.arg(id.bare);
|
.arg(id.bare);
|
||||||
result.text = tr::lng_action_topic_created(
|
result.text = tr::lng_action_topic_created(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_topic,
|
lt_topic,
|
||||||
Ui::Text::Link(std::move(title), topicUrl),
|
Ui::Text::Link(
|
||||||
|
Data::ForumTopicIconWithTitle(
|
||||||
|
action.vicon_emoji_id().value_or_empty(),
|
||||||
|
qs(action.vtitle())),
|
||||||
|
topicUrl),
|
||||||
Ui::Text::WithEntities);
|
Ui::Text::WithEntities);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
@ -684,7 +670,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
lt_link,
|
lt_link,
|
||||||
{ tr::lng_action_topic_placeholder(tr::now) },
|
{ tr::lng_action_topic_placeholder(tr::now) },
|
||||||
lt_emoji,
|
lt_emoji,
|
||||||
wrapTopicIcon(iconId),
|
Data::SingleCustomEmoji(iconId),
|
||||||
Ui::Text::WithEntities);
|
Ui::Text::WithEntities);
|
||||||
} else {
|
} else {
|
||||||
result.links.push_back(fromLink());
|
result.links.push_back(fromLink());
|
||||||
|
@ -699,14 +685,6 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.links.push_back(fromLink());
|
result.links.push_back(fromLink());
|
||||||
auto title = TextWithEntities{
|
|
||||||
qs(*action.vtitle())
|
|
||||||
};
|
|
||||||
if (const auto icon = action.vicon_emoji_id().value_or_empty()) {
|
|
||||||
title = wrapTopicIcon(icon)
|
|
||||||
.append(' ')
|
|
||||||
.append(std::move(title));
|
|
||||||
}
|
|
||||||
result.text = tr::lng_action_topic_renamed(
|
result.text = tr::lng_action_topic_renamed(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_from,
|
lt_from,
|
||||||
|
@ -714,7 +692,9 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
lt_link,
|
lt_link,
|
||||||
{ tr::lng_action_topic_placeholder(tr::now) },
|
{ tr::lng_action_topic_placeholder(tr::now) },
|
||||||
lt_title,
|
lt_title,
|
||||||
std::move(title),
|
Data::ForumTopicIconWithTitle(
|
||||||
|
action.vicon_emoji_id().value_or_empty(),
|
||||||
|
qs(*action.vtitle())),
|
||||||
Ui::Text::WithEntities);
|
Ui::Text::WithEntities);
|
||||||
}
|
}
|
||||||
if (result.text.empty()) {
|
if (result.text.empty()) {
|
||||||
|
|
|
@ -1311,7 +1311,7 @@ std::vector<StickerSetIdentifier> CollectEmojiPacks(
|
||||||
for (const auto &entity : item->originalText().entities) {
|
for (const auto &entity : item->originalText().entities) {
|
||||||
if (entity.type() == EntityType::CustomEmoji) {
|
if (entity.type() == EntityType::CustomEmoji) {
|
||||||
const auto data = Data::ParseCustomEmojiData(entity.data());
|
const auto data = Data::ParseCustomEmojiData(entity.data());
|
||||||
push(data.id);
|
push(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -690,17 +690,6 @@ auto Element::contextDependentServiceText() -> TextWithLinks {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const auto from = item->from();
|
const auto from = item->from();
|
||||||
const auto wrapIcon = [](DocumentId id) {
|
|
||||||
return TextWithEntities{
|
|
||||||
"@",
|
|
||||||
{ EntityInText(
|
|
||||||
EntityType::CustomEmoji,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
Data::SerializeCustomEmojiId({ .id = id }))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const auto topicUrl = u"internal:url:https://t.me/c/%1/%2"_q
|
const auto topicUrl = u"internal:url:https://t.me/c/%1/%2"_q
|
||||||
.arg(peerToChannel(peerId).bare)
|
.arg(peerToChannel(peerId).bare)
|
||||||
.arg(topicRootId.bare);
|
.arg(topicRootId.bare);
|
||||||
|
@ -715,11 +704,9 @@ auto Element::contextDependentServiceText() -> TextWithLinks {
|
||||||
const auto wrapTopic = [&](
|
const auto wrapTopic = [&](
|
||||||
const QString &title,
|
const QString &title,
|
||||||
std::optional<DocumentId> iconId) {
|
std::optional<DocumentId> iconId) {
|
||||||
auto result = TextWithEntities{ title };
|
return Ui::Text::Link(
|
||||||
auto full = (iconId && *iconId)
|
Data::ForumTopicIconWithTitle(iconId.value_or(0), title),
|
||||||
? wrapIcon(*iconId).append(' ').append(std::move(result))
|
topicUrl);
|
||||||
: result;
|
|
||||||
return Ui::Text::Link(std::move(full), topicUrl);
|
|
||||||
};
|
};
|
||||||
const auto wrapParentTopic = [&] {
|
const auto wrapParentTopic = [&] {
|
||||||
const auto forum = history()->asForum();
|
const auto forum = history()->asForum();
|
||||||
|
@ -783,7 +770,7 @@ auto Element::contextDependentServiceText() -> TextWithLinks {
|
||||||
lt_link,
|
lt_link,
|
||||||
placeholderLink(),
|
placeholderLink(),
|
||||||
lt_emoji,
|
lt_emoji,
|
||||||
wrapIcon(iconId),
|
Data::SingleCustomEmoji(iconId),
|
||||||
Ui::Text::WithEntities),
|
Ui::Text::WithEntities),
|
||||||
{ from->createOpenLink() },
|
{ from->createOpenLink() },
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct ItemPreviewImage {
|
||||||
struct ItemPreview {
|
struct ItemPreview {
|
||||||
TextWithEntities text;
|
TextWithEntities text;
|
||||||
std::vector<ItemPreviewImage> images;
|
std::vector<ItemPreviewImage> images;
|
||||||
|
int arrowInTextPosition = -1;
|
||||||
int imagesInTextPosition = 0;
|
int imagesInTextPosition = 0;
|
||||||
std::any loadingContext;
|
std::any loadingContext;
|
||||||
};
|
};
|
||||||
|
@ -31,7 +32,7 @@ struct ToPreviewOptions {
|
||||||
bool hideCaption = false;
|
bool hideCaption = false;
|
||||||
bool generateImages = true;
|
bool generateImages = true;
|
||||||
bool ignoreGroup = false;
|
bool ignoreGroup = false;
|
||||||
bool ignoreSpoilers = false;
|
bool ignoreTopic = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -92,7 +92,7 @@ CustomEmoji::CustomEmoji(
|
||||||
tag));
|
tag));
|
||||||
} else {
|
} else {
|
||||||
const auto &data = element.entityData;
|
const auto &data = element.entityData;
|
||||||
const auto id = Data::ParseCustomEmojiData(data).id;
|
const auto id = Data::ParseCustomEmojiData(data);
|
||||||
const auto document = owner->document(id);
|
const auto document = owner->document(id);
|
||||||
if (document->sticker()) {
|
if (document->sticker()) {
|
||||||
_lines.back().push_back(createStickerPart(document));
|
_lines.back().push_back(createStickerPart(document));
|
||||||
|
|
|
@ -16,25 +16,28 @@ TextWithEntities ReplaceTag<TextWithEntities>::Call(TextWithEntities &&original,
|
||||||
if (replacementPosition < 0) {
|
if (replacementPosition < 0) {
|
||||||
return std::move(original);
|
return std::move(original);
|
||||||
}
|
}
|
||||||
|
return Replace(std::move(original), replacement, replacementPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities ReplaceTag<TextWithEntities>::Replace(TextWithEntities &&original, const TextWithEntities &replacement, int start) {
|
||||||
auto result = TextWithEntities();
|
auto result = TextWithEntities();
|
||||||
result.text = ReplaceTag<QString>::Replace(std::move(original.text), replacement.text, replacementPosition);
|
result.text = ReplaceTag<QString>::Replace(std::move(original.text), replacement.text, start);
|
||||||
auto originalEntitiesCount = original.entities.size();
|
auto originalEntitiesCount = original.entities.size();
|
||||||
auto replacementEntitiesCount = replacement.entities.size();
|
auto replacementEntitiesCount = replacement.entities.size();
|
||||||
if (originalEntitiesCount != 0 || replacementEntitiesCount != 0) {
|
if (originalEntitiesCount != 0 || replacementEntitiesCount != 0) {
|
||||||
result.entities.reserve(originalEntitiesCount + replacementEntitiesCount);
|
result.entities.reserve(originalEntitiesCount + replacementEntitiesCount);
|
||||||
|
|
||||||
auto replacementEnd = replacementPosition + int(replacement.text.size());
|
auto replacementEnd = start + int(replacement.text.size());
|
||||||
auto replacementEntity = replacement.entities.cbegin();
|
auto replacementEntity = replacement.entities.cbegin();
|
||||||
auto addReplacementEntitiesUntil = [&replacementEntity, &replacement, &result, replacementPosition, replacementEnd](int untilPosition) {
|
auto addReplacementEntitiesUntil = [&](int untilPosition) {
|
||||||
while (replacementEntity != replacement.entities.cend()) {
|
while (replacementEntity != replacement.entities.cend()) {
|
||||||
auto newOffset = replacementPosition + replacementEntity->offset();
|
auto newOffset = start + replacementEntity->offset();
|
||||||
if (newOffset >= untilPosition) {
|
if (newOffset >= untilPosition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto newEnd = newOffset + replacementEntity->length();
|
auto newEnd = newOffset + replacementEntity->length();
|
||||||
newOffset = std::clamp(newOffset, replacementPosition, replacementEnd);
|
newOffset = std::clamp(newOffset, start, replacementEnd);
|
||||||
newEnd = std::clamp(newEnd, replacementPosition, replacementEnd);
|
newEnd = std::clamp(newEnd, start, replacementEnd);
|
||||||
if (auto newLength = newEnd - newOffset) {
|
if (auto newLength = newEnd - newOffset) {
|
||||||
result.entities.push_back({ replacementEntity->type(), newOffset, newLength, replacementEntity->data() });
|
result.entities.push_back({ replacementEntity->type(), newOffset, newLength, replacementEntity->data() });
|
||||||
}
|
}
|
||||||
|
@ -46,10 +49,10 @@ TextWithEntities ReplaceTag<TextWithEntities>::Call(TextWithEntities &&original,
|
||||||
// Transform the entity by the replacement.
|
// Transform the entity by the replacement.
|
||||||
auto offset = entity.offset();
|
auto offset = entity.offset();
|
||||||
auto end = offset + entity.length();
|
auto end = offset + entity.length();
|
||||||
if (offset > replacementPosition) {
|
if (offset > start) {
|
||||||
offset = offset + replacement.text.size() - kTagReplacementSize;
|
offset = offset + replacement.text.size() - kTagReplacementSize;
|
||||||
}
|
}
|
||||||
if (end > replacementPosition) {
|
if (end > start) {
|
||||||
end = end + replacement.text.size() - kTagReplacementSize;
|
end = end + replacement.text.size() - kTagReplacementSize;
|
||||||
}
|
}
|
||||||
offset = std::clamp(offset, 0, int(result.text.size()));
|
offset = std::clamp(offset, 0, int(result.text.size()));
|
||||||
|
|
|
@ -27,6 +27,7 @@ struct ReplaceTag;
|
||||||
template <>
|
template <>
|
||||||
struct ReplaceTag<TextWithEntities> {
|
struct ReplaceTag<TextWithEntities> {
|
||||||
static TextWithEntities Call(TextWithEntities &&original, ushort tag, const TextWithEntities &replacement);
|
static TextWithEntities Call(TextWithEntities &&original, ushort tag, const TextWithEntities &replacement);
|
||||||
|
static TextWithEntities Replace(TextWithEntities &&original, const TextWithEntities &replacement, int start);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -848,7 +848,7 @@ TextWithEntities Manager::ComposeReactionEmoji(
|
||||||
EntityType::CustomEmoji,
|
EntityType::CustomEmoji,
|
||||||
0,
|
0,
|
||||||
text.size(),
|
text.size(),
|
||||||
Data::SerializeCustomEmojiId(Data::CustomEmojiId{ id }))
|
Data::SerializeCustomEmojiId(id))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -968,24 +968,9 @@ void Notification::updateNotifyDisplay() {
|
||||||
|
|
||||||
const auto topicWithChat = [&]() -> TextWithEntities {
|
const auto topicWithChat = [&]() -> TextWithEntities {
|
||||||
const auto name = _history->peer->name();
|
const auto name = _history->peer->name();
|
||||||
const auto wrapIcon = [](DocumentId id) {
|
return _topic
|
||||||
return TextWithEntities{
|
? _topic->titleWithIcon().append(u" ("_q + name + ')')
|
||||||
"@",
|
: TextWithEntities{ name };
|
||||||
{ EntityInText(
|
|
||||||
EntityType::CustomEmoji,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
Data::SerializeCustomEmojiId({.id = id }))
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (!_topic) {
|
|
||||||
return { name };
|
|
||||||
}
|
|
||||||
auto start = _topic->iconId()
|
|
||||||
? wrapIcon(_topic->iconId())
|
|
||||||
: TextWithEntities();
|
|
||||||
return start.append(_topic->title() + u" ("_q + name + ')');
|
|
||||||
};
|
};
|
||||||
auto title = options.hideNameAndPhoto
|
auto title = options.hideNameAndPhoto
|
||||||
? TextWithEntities{ u"Telegram Desktop"_q }
|
? TextWithEntities{ u"Telegram Desktop"_q }
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c3616927ebfcbe98375189be87821bea202d9587
|
Subproject commit 4539d0bab4ffc335de79b77ee9632f6a7b59d48b
|
Loading…
Add table
Reference in a new issue