From e6c22ec1ca32545ff54fca37e4f2cc59106beb8d Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 22 Apr 2024 13:12:26 +0300 Subject: [PATCH] Added api support for custom emoji in polls. --- .../SourceFiles/boxes/create_poll_box.cpp | 16 +++++++-- .../SourceFiles/data/data_media_types.cpp | 26 +++++++------- Telegram/SourceFiles/data/data_poll.cpp | 29 ++++++++++----- Telegram/SourceFiles/data/data_poll.h | 4 +-- .../view/history_view_context_menu.cpp | 6 ++-- .../history/view/media/history_view_poll.cpp | 36 +++++++++++++------ .../polls/info_polls_results_inner_widget.cpp | 16 ++++----- .../window/notifications_manager.cpp | 2 +- 8 files changed, 83 insertions(+), 52 deletions(-) diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp index 373899be4..7ec93239b 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.cpp +++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp @@ -456,10 +456,16 @@ void Options::Option::removePlaceholder() const { PollAnswer Options::Option::toPollAnswer(int index) const { Expects(index >= 0 && index < kMaxOptionsCount); + const auto text = field()->getTextWithTags(); + auto result = PollAnswer{ - field()->getLastText().trimmed(), - QByteArray(1, ('0' + index)) + TextWithEntities{ + .text = text.text, + .entities = TextUtilities::ConvertTextTagsToEntities(text.tags), + }, + QByteArray(1, ('0' + index)), }; + TextUtilities::Trim(result.text); result.correct = _correct ? _correct->entity()->Checkbox::checked() : false; return result; } @@ -1029,9 +1035,13 @@ object_ptr CreatePollBox::setupContent() { }; const auto collectResult = [=] { + const auto textWithTags = question->getTextWithTags(); using Flag = PollData::Flag; auto result = PollData(&_controller->session().data(), id); - result.question = question->getLastText().trimmed(); + result.question.text = textWithTags.text; + result.question.entities = TextUtilities::ConvertTextTagsToEntities( + textWithTags.tags); + TextUtilities::Trim(result.question); result.answers = options->toPollAnswers(); const auto solutionWithTags = quiz->checked() ? solution->getTextWithAppliedMarkdown() diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index f82b4522f..e6dd5006a 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -1857,23 +1857,21 @@ TextWithEntities MediaPoll::notificationText() const { } QString MediaPoll::pinnedTextSubstring() const { - return QChar(171) + _poll->question + QChar(187); + return QChar(171) + _poll->question.text + QChar(187); } TextForMimeData MediaPoll::clipboardText() const { - const auto text = u"[ "_q - + tr::lng_in_dlg_poll(tr::now) - + u" : "_q - + _poll->question - + u" ]"_q - + ranges::accumulate( - ranges::views::all( - _poll->answers - ) | ranges::views::transform([](const PollAnswer &answer) { - return "\n- " + answer.text; - }), - QString()); - return TextForMimeData::Simple(text); + auto result = TextWithEntities(); + result + .append(u"[ "_q) + .append(tr::lng_in_dlg_poll(tr::now)) + .append(u" : "_q) + .append(_poll->question) + .append(u" ]"_q); + for (const auto &answer : _poll->answers) { + result.append(u"\n- "_q).append(answer.text); + } + return TextForMimeData::Rich(std::move(result)); } bool MediaPoll::updateInlineResultMedia(const MTPMessageMedia &media) { diff --git a/Telegram/SourceFiles/data/data_poll.cpp b/Telegram/SourceFiles/data/data_poll.cpp index a7c386d0c..64a3176d5 100644 --- a/Telegram/SourceFiles/data/data_poll.cpp +++ b/Telegram/SourceFiles/data/data_poll.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_poll.h" +#include "api/api_text_entities.h" #include "data/data_user.h" #include "data/data_session.h" #include "base/call_delayed.h" @@ -69,7 +70,12 @@ bool PollData::closeByTimer() { bool PollData::applyChanges(const MTPDpoll &poll) { Expects(poll.vid().v == id); - const auto newQuestion = qs(poll.vquestion().data().vtext()); + const auto newQuestion = TextWithEntities{ + .text = qs(poll.vquestion().data().vtext()), + .entities = Api::EntitiesFromMTP( + &session(), + poll.vquestion().data().ventities().v), + }; const auto newFlags = (poll.is_closed() ? Flag::Closed : Flag(0)) | (poll.is_public_voters() ? Flag::PublicVotes : Flag(0)) | (poll.is_multiple_choice() ? Flag::MultiChoice : Flag(0)) @@ -78,11 +84,16 @@ bool PollData::applyChanges(const MTPDpoll &poll) { const auto newClosePeriod = poll.vclose_period().value_or_empty(); auto newAnswers = ranges::views::all( poll.vanswers().v - ) | ranges::views::transform([](const MTPPollAnswer &data) { - return data.match([](const MTPDpollAnswer &answer) { + ) | ranges::views::transform([&](const MTPPollAnswer &data) { + return data.match([&](const MTPDpollAnswer &answer) { auto result = PollAnswer(); result.option = answer.voption().v; - result.text = qs(answer.vtext().data().vtext()); + result.text = TextWithEntities{ + .text = qs(answer.vtext().data().vtext()), + .entities = Api::EntitiesFromMTP( + &session(), + answer.vtext().data().ventities().v), + }; return result; }); }) | ranges::views::take( @@ -251,11 +262,11 @@ bool PollData::quiz() const { } MTPPoll PollDataToMTP(not_null poll, bool close) { - const auto convert = [](const PollAnswer &answer) { + const auto convert = [&](const PollAnswer &answer) { return MTP_pollAnswer( MTP_textWithEntities( - MTP_string(answer.text), - MTP_vector()), + MTP_string(answer.text.text), + Api::EntitiesToMTP(&poll->session(), answer.text.entities)), MTP_bytes(answer.option)); }; auto answers = QVector(); @@ -275,8 +286,8 @@ MTPPoll PollDataToMTP(not_null poll, bool close) { MTP_long(poll->id), MTP_flags(flags), MTP_textWithEntities( - MTP_string(poll->question), - MTP_vector()), + MTP_string(poll->question.text), + Api::EntitiesToMTP(&poll->session(), poll->question.entities)), MTP_vector(answers), MTP_int(poll->closePeriod), MTP_int(poll->closeDate)); diff --git a/Telegram/SourceFiles/data/data_poll.h b/Telegram/SourceFiles/data/data_poll.h index 4f428479b..49dd02173 100644 --- a/Telegram/SourceFiles/data/data_poll.h +++ b/Telegram/SourceFiles/data/data_poll.h @@ -16,7 +16,7 @@ class Session; } // namespace Main struct PollAnswer { - QString text; + TextWithEntities text; QByteArray option; int votes = 0; bool chosen = false; @@ -65,7 +65,7 @@ struct PollData { [[nodiscard]] bool quiz() const; PollId id = 0; - QString question; + TextWithEntities question; std::vector answers; std::vector> recentVoters; std::vector sendingVotes; diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 94e34092d..a7a24e44b 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -1307,15 +1307,15 @@ void AddPollActions( const auto radio = QString::fromUtf8(kRadio); auto text = poll->question; for (const auto &answer : poll->answers) { - text += '\n' + radio + answer.text; + text.append('\n').append(radio).append(answer.text); } - if (!Ui::SkipTranslate({ text })) { + if (!Ui::SkipTranslate(text)) { menu->addAction(tr::lng_context_translate(tr::now), [=] { controller->show(Box( Ui::TranslateBox, item->history()->peer, MsgId(), - TextWithEntities{ .text = text }, + std::move(text), item->forbidsForward())); }, &st::menuIconTranslate); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index 82ca69e8f..6f924fc2e 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/view/media/history_view_poll.h" +#include "core/ui_integration.h" // Core::MarkedTextContext. #include "lang/lang_keys.h" #include "history/history.h" #include "history/history_item.h" @@ -154,7 +155,10 @@ struct Poll::SendingAnimation { struct Poll::Answer { Answer(); - void fillData(not_null poll, const PollAnswer &original); + void fillData( + not_null poll, + const PollAnswer &original, + Core::MarkedTextContext context); Ui::Text::String text; QByteArray option; @@ -201,16 +205,18 @@ Poll::Answer::Answer() : text(st::msgMinWidth / 2) { void Poll::Answer::fillData( not_null poll, - const PollAnswer &original) { + const PollAnswer &original, + Core::MarkedTextContext context) { chosen = original.chosen; correct = poll->quiz() ? original.correct : chosen; - if (!text.isEmpty() && text.toString() == original.text) { + if (!text.isEmpty() && text.toTextWithEntities() == original.text) { return; } - text.setText( + text.setMarkedText( st::historyPollAnswerStyle, original.text, - Ui::WebpageTextTitleOptions()); + Ui::WebpageTextTitleOptions(), + context); } Poll::CloseInformation::CloseInformation( @@ -383,13 +389,18 @@ void Poll::updateTexts() { const auto willStartAnimation = checkAnimationStart(); const auto voted = _voted; - if (_question.toString() != _poll->question) { + if (_question.toTextWithEntities() != _poll->question) { auto options = Ui::WebpageTextTitleOptions(); options.maxw = options.maxh = 0; - _question.setText( + _question.setMarkedText( st::historyPollQuestionStyle, _poll->question, - options); + options, + Core::MarkedTextContext{ + .session = &_poll->session(), + .customEmojiRepaint = [=] { repaint(); }, + .customEmojiLoopLimit = 2, + }); } if (_flags != _poll->flags() || _subtitle.isEmpty()) { using Flag = PollData::Flag; @@ -514,6 +525,11 @@ void Poll::updateRecentVoters() { } void Poll::updateAnswers() { + const auto context = Core::MarkedTextContext{ + .session = &_poll->session(), + .customEmojiRepaint = [=] { repaint(); }, + .customEmojiLoopLimit = 2, + }; const auto changed = !ranges::equal( _answers, _poll->answers, @@ -523,7 +539,7 @@ void Poll::updateAnswers() { if (!changed) { auto &&answers = ranges::views::zip(_answers, _poll->answers); for (auto &&[answer, original] : answers) { - answer.fillData(_poll, original); + answer.fillData(_poll, original, context); } return; } @@ -532,7 +548,7 @@ void Poll::updateAnswers() { ) | ranges::views::transform([&](const PollAnswer &answer) { auto result = Answer(); result.option = answer.option; - result.fillData(_poll, answer); + result.fillData(_poll, answer, context); return result; }) | ranges::to_vector; diff --git a/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp b/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp index 3d42cb8c0..9fa9ac483 100644 --- a/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp +++ b/Telegram/SourceFiles/info/polls/info_polls_results_inner_widget.cpp @@ -8,17 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/polls/info_polls_results_inner_widget.h" #include "info/polls/info_polls_results_widget.h" -#include "info/info_controller.h" #include "lang/lang_keys.h" #include "data/data_poll.h" -#include "data/data_peer.h" #include "data/data_user.h" #include "data/data_session.h" #include "ui/controls/peer_list_dummy.h" -#include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/wrap/vertical_layout.h" -#include "ui/wrap/padding_wrap.h" #include "ui/wrap/slide_wrap.h" #include "ui/text/text_utilities.h" #include "boxes/peer_list_box.h" @@ -26,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history.h" #include "history/history_item.h" #include "styles/style_layers.h" -#include "styles/style_boxes.h" #include "styles/style_info.h" namespace Info { @@ -461,10 +456,11 @@ ListController *CreateAnswerRows( container.get(), object_ptr( container, - (answer.text - + QString::fromUtf8(" \xe2\x80\x94 ") - + QString::number(percent) - + "%"), + rpl::single( + TextWithEntities(answer.text) + .append(QString::fromUtf8(" \xe2\x80\x94 ")) + .append(QString::number(percent)) + .append('%')), st::boxDividerLabel), style::margins( st::pollResultsHeaderPadding.left(), @@ -613,7 +609,7 @@ void InnerWidget::setupContent() { _content->add( object_ptr( _content, - _poll->question, + rpl::single(_poll->question), st::pollResultsQuestion), style::margins{ st::boxRowPadding.left(), diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 9ab93b934..052abca8f 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -994,7 +994,7 @@ TextWithEntities Manager::ComposeReactionNotification( lt_reaction, reactionWithEntities, lt_title, - Ui::Text::WithEntities(poll->question), + poll->question, Ui::Text::WithEntities); } else if (media->game()) { return simple(tr::lng_reaction_game);