From 493f0450b42a37ef947ce9d209603b44905596d1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 23 May 2024 22:58:09 +0400 Subject: [PATCH] Implement factcheck edition. --- Telegram/Resources/icons/menu/factcheck.png | Bin 0 -> 588 bytes .../Resources/icons/menu/factcheck@2x.png | Bin 0 -> 1359 bytes .../Resources/icons/menu/factcheck@3x.png | Bin 0 -> 2267 bytes Telegram/Resources/langs/lang.strings | 6 +- .../data/components/factchecks.cpp | 61 +++++++++++++ .../SourceFiles/data/components/factchecks.h | 10 +++ .../admin_log/history_admin_log_inner.cpp | 3 +- .../history/history_inner_widget.cpp | 26 ++++++ Telegram/SourceFiles/history/history_item.cpp | 14 ++- Telegram/SourceFiles/history/history_item.h | 1 + .../history/history_item_components.cpp | 10 ++- .../history/history_item_components.h | 9 ++ .../history/history_item_edition.cpp | 1 + .../history/history_item_edition.h | 1 + .../history/view/history_view_message.cpp | 37 ++++---- .../ui/boxes/edit_factcheck_box.cpp | 81 ++++++++++++++++++ .../SourceFiles/ui/boxes/edit_factcheck_box.h | 15 ++++ Telegram/SourceFiles/ui/chat/chat.style | 15 ++++ Telegram/SourceFiles/ui/menu_icons.style | 1 + Telegram/cmake/td_ui.cmake | 2 + 20 files changed, 264 insertions(+), 29 deletions(-) create mode 100644 Telegram/Resources/icons/menu/factcheck.png create mode 100644 Telegram/Resources/icons/menu/factcheck@2x.png create mode 100644 Telegram/Resources/icons/menu/factcheck@3x.png create mode 100644 Telegram/SourceFiles/ui/boxes/edit_factcheck_box.cpp create mode 100644 Telegram/SourceFiles/ui/boxes/edit_factcheck_box.h diff --git a/Telegram/Resources/icons/menu/factcheck.png b/Telegram/Resources/icons/menu/factcheck.png new file mode 100644 index 0000000000000000000000000000000000000000..e9115a4cf1bc6bf28f2a3011f43af86c5ef4190e GIT binary patch literal 588 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 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6b28b450e..efb548724 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3217,6 +3217,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_reply_msg" = "Reply"; "lng_context_quote_and_reply" = "Quote & Reply"; "lng_context_edit_msg" = "Edit"; +"lng_context_add_factcheck" = "Add Fact Check"; +"lng_context_edit_factcheck" = "Edit Fact Check"; "lng_context_forward_msg" = "Forward Message"; "lng_context_send_now_msg" = "Send now"; "lng_context_reschedule" = "Reschedule"; @@ -3287,12 +3289,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_context_spoiler_effect" = "Hide with Spoiler"; "lng_context_disable_spoiler" = "Remove Spoiler"; -"lng_context_add_factcheck" = "Add Fact Check"; "lng_factcheck_title" = "Fact Check"; "lng_factcheck_placeholder" = "Add Facts or Context"; "lng_factcheck_whats_this" = "what's this?"; "lng_factcheck_about" = "This clarification was provided by a fact checking agency assigned by the department of the government of your country ({country}) responsible for combatting misinformation."; +"lng_factcheck_add_done" = "Fact check added."; +"lng_factcheck_edit_done" = "Fact check edited."; +"lng_factcheck_remove_done" = "Fact check removed."; "lng_translate_show_original" = "Show Original"; "lng_translate_bar_to" = "Translate to {name}"; diff --git a/Telegram/SourceFiles/data/components/factchecks.cpp b/Telegram/SourceFiles/data/components/factchecks.cpp index 0423d1d43..af72d8aff 100644 --- a/Telegram/SourceFiles/data/components/factchecks.cpp +++ b/Telegram/SourceFiles/data/components/factchecks.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/components/factchecks.h" +#include "api/api_text_entities.h" #include "apiwrap.h" #include "base/random.h" #include "data/data_session.h" @@ -17,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/history_item_components.h" #include "lang/lang_keys.h" +#include "main/main_app_config.h" #include "main/main_session.h" namespace Data { @@ -135,4 +137,63 @@ std::unique_ptr Factchecks::makeMedia( MediaWebPageFlags()); } +bool Factchecks::canEdit(not_null item) const { + if (!canEdit() + || !item->isRegular() + || !item->history()->peer->isBroadcast()) { + return false; + } + const auto media = item->media(); + if (!media || media->webpage() || media->photo()) { + return true; + } else if (const auto document = media->document()) { + return !document->isVideoMessage() && !document->sticker(); + } + return false; +} + +bool Factchecks::canEdit() const { + return _session->appConfig().get(u"can_edit_factcheck"_q, false); +} + +int Factchecks::lengthLimit() const { + return _session->appConfig().get(u"factcheck_length_limit"_q, 1024); +} + +void Factchecks::save( + FullMsgId itemId, + TextWithEntities text, + Fn done) { + const auto item = _session->data().message(itemId); + if (!item) { + return; + } else if (text.empty()) { + _session->api().request(MTPmessages_DeleteFactCheck( + item->history()->peer->input, + MTP_int(item->id.bare) + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + done(QString()); + }).fail([=](const MTP::Error &error) { + done(error.type()); + }).send(); + } else { + _session->api().request(MTPmessages_EditFactCheck( + item->history()->peer->input, + MTP_int(item->id.bare), + MTP_textWithEntities( + MTP_string(text.text), + Api::EntitiesToMTP( + _session, + text.entities, + Api::ConvertOption::SkipLocal)) + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + done(QString()); + }).fail([=](const MTP::Error &error) { + done(error.type()); + }).send(); + } +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/components/factchecks.h b/Telegram/SourceFiles/data/components/factchecks.h index 452706f9b..7054a3c57 100644 --- a/Telegram/SourceFiles/data/components/factchecks.h +++ b/Telegram/SourceFiles/data/components/factchecks.h @@ -32,7 +32,17 @@ public: not_null view, not_null factcheck); + [[nodiscard]] bool canEdit(not_null item) const; + [[nodiscard]] int lengthLimit() const; + + void save( + FullMsgId itemId, + TextWithEntities text, + Fn done); + private: + [[nodiscard]] bool canEdit() const; + void subscribeIfNotYet(); void request(); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index 8fa440bf6..cb099afe4 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -1306,8 +1306,7 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { && !link && (view->hasVisibleText() || mediaHasTextForCopy - || (item->Has() - && !item->Get()->data.text.empty()) + || !item->factcheckText().empty() || item->Has())) { _menu->addAction(tr::lng_context_copy_text(tr::now), [=] { copyContextText(itemId); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 1687b5049..e6950859d 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/reaction_fly_animation.h" #include "ui/text/text_options.h" #include "ui/text/text_isolated_emoji.h" +#include "ui/boxes/edit_factcheck_box.h" #include "ui/boxes/report_box.h" #include "ui/layers/generic_box.h" #include "ui/controls/delete_message_context_action.h" @@ -72,6 +73,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_who_reacted.h" #include "api/api_views.h" #include "lang/lang_keys.h" +#include "data/components/factchecks.h" #include "data/components/sponsored_messages.h" #include "data/data_session.h" #include "data/data_document.h" @@ -2171,6 +2173,30 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } }, &st::menuIconEdit); } + if (session->factchecks().canEdit(item)) { + const auto text = item->factcheckText(); + const auto phrase = text.empty() + ? tr::lng_context_add_factcheck(tr::now) + : tr::lng_context_edit_factcheck(tr::now); + _menu->addAction(phrase, [=] { + controller->show(Box(EditFactcheckBox, text, [=]( + TextWithEntities result) { + const auto done = [=](QString error) { + controller->showToast(!error.isEmpty() + ? error + : result.empty() + ? tr::lng_factcheck_remove_done(tr::now) + : text.empty() + ? tr::lng_factcheck_add_done(tr::now) + : tr::lng_factcheck_edit_done(tr::now)); + }; + session->factchecks().save( + itemId, + result, + crl::guard(controller, done)); + })); + }, &st::menuIconFactcheck); + } const auto pinItem = (item->canPin() && item->isPinned()) ? item : groupLeaderOrSelf(item); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 3a2ed484a..30cc8a9c3 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1508,14 +1508,18 @@ void HistoryItem::setFactcheck(MessageFactcheck info) { } else { AddComponents(HistoryMessageFactcheck::Bit()); const auto factcheck = Get(); + const auto textChanged = (factcheck->data.text != info.text); if (factcheck->data.hash == info.hash && (info.needCheck || !factcheck->data.needCheck)) { return; - } else if (factcheck->data.text != info.text + } else if (textChanged || factcheck->data.country != info.country || factcheck->data.hash != info.hash) { factcheck->data = std::move(info); factcheck->requested = false; + if (textChanged) { + factcheck->page = nullptr; + } history()->owner().requestItemResize(this); } } @@ -1526,6 +1530,13 @@ bool HistoryItem::hasUnrequestedFactcheck() const { return factcheck && factcheck->data.needCheck && !factcheck->requested; } +TextWithEntities HistoryItem::factcheckText() const { + if (const auto factcheck = Get()) { + return factcheck->data.text; + } + return {}; +} + PeerData *HistoryItem::specialNotificationPeer() const { return (mentionsMe() && !_history->peer->isUser()) ? from().get() @@ -1725,6 +1736,7 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) { } applyTTL(edition.ttl); + setFactcheck(FromMTP(this, edition.mtpFactcheck)); finishEdition(keyboardTop); } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 5a864d076..3118bf3bc 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -208,6 +208,7 @@ public: const TextWithEntities &content); void setFactcheck(MessageFactcheck info); [[nodiscard]] bool hasUnrequestedFactcheck() const; + [[nodiscard]] TextWithEntities factcheckText() const; [[nodiscard]] not_null notificationThread() const; [[nodiscard]] not_null history() const { diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 54e42a16e..fd1a04942 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -1065,6 +1065,12 @@ HistoryMessageLogEntryOriginal::~HistoryMessageLogEntryOriginal() = default; MessageFactcheck FromMTP( not_null item, const tl::conditional &factcheck) { + return FromMTP(&item->history()->session(), factcheck); +} + +MessageFactcheck FromMTP( + not_null session, + const tl::conditional &factcheck) { auto result = MessageFactcheck(); if (!factcheck) { return result; @@ -1074,9 +1080,7 @@ MessageFactcheck FromMTP( const auto &data = text->data(); result.text = { qs(data.vtext()), - Api::EntitiesFromMTP( - &item->history()->session(), - data.ventities().v), + Api::EntitiesFromMTP(session, data.ventities().v), }; } if (const auto country = data.vcountry()) { diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index fa7ffbf3a..906fe18ce 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL struct WebPageData; class VoiceSeekClickHandler; +class ReplyKeyboard; namespace Ui { struct ChatPaintContext; @@ -31,6 +32,7 @@ struct GeometryDescriptor; namespace Data { class Session; class Story; +class SavedSublist; } // namespace Data namespace Media::Player { @@ -47,6 +49,10 @@ class Document; class TranscribeButton; } // namespace HistoryView +namespace style { +struct BotKeyboardButton; +} // namespace style + struct HistoryMessageVia : public RuntimeComponent { void create(not_null owner, UserId userId); void resize(int32 availw) const; @@ -579,6 +585,9 @@ struct MessageFactcheck { [[nodiscard]] MessageFactcheck FromMTP( not_null item, const tl::conditional &factcheck); +[[nodiscard]] MessageFactcheck FromMTP( + not_null session, + const tl::conditional &factcheck); struct HistoryMessageFactcheck : public RuntimeComponent { diff --git a/Telegram/SourceFiles/history/history_item_edition.cpp b/Telegram/SourceFiles/history/history_item_edition.cpp index 4349a3c93..d66d0cf7b 100644 --- a/Telegram/SourceFiles/history/history_item_edition.cpp +++ b/Telegram/SourceFiles/history/history_item_edition.cpp @@ -24,6 +24,7 @@ HistoryMessageEdition::HistoryMessageEdition( replyMarkup = HistoryMessageMarkupData(message.vreply_markup()); mtpMedia = message.vmedia(); mtpReactions = message.vreactions(); + mtpFactcheck = message.vfactcheck(); views = message.vviews().value_or(-1); forwards = message.vforwards().value_or(-1); if (const auto mtpReplies = message.vreplies()) { diff --git a/Telegram/SourceFiles/history/history_item_edition.h b/Telegram/SourceFiles/history/history_item_edition.h index b8f577d80..a44109299 100644 --- a/Telegram/SourceFiles/history/history_item_edition.h +++ b/Telegram/SourceFiles/history/history_item_edition.h @@ -36,4 +36,5 @@ struct HistoryMessageEdition { HistoryMessageRepliesData replies; const MTPMessageMedia *mtpMedia = nullptr; const MTPMessageReactions *mtpReactions = nullptr; + const MTPFactCheck *mtpFactcheck = nullptr; }; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 564ea3b7b..b860c2c58 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -917,8 +917,8 @@ QSize Message::performCountOptimalSize() { minHeight += st::msgPadding.top(); if (mediaDisplayed) minHeight += st::mediaInBubbleSkip; if (entry) minHeight += st::mediaInBubbleSkip; - if (check) minHeight += st::mediaInBubbleSkip; } + if (check) minHeight += st::mediaInBubbleSkip; if (mediaDisplayed) { // Parts don't participate in maxWidth() in case of media message. if (media->enforceBubbleWidth()) { @@ -1308,7 +1308,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { trect.setHeight(trect.height() - entry->height()); } if (check) { - trect.setHeight(trect.height() - check->height()); + trect.setHeight(trect.height() - check->height() - st::mediaInBubbleSkip); } if (displayInfo) { trect.setHeight(trect.height() @@ -1371,7 +1371,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { } if (check) { auto checkLeft = inner.left(); - auto checkTop = trect.y() + trect.height(); + auto checkTop = trect.y() + trect.height() + st::mediaInBubbleSkip; p.translate(checkLeft, checkTop); auto checkContext = context.translated(checkLeft, -checkTop); checkContext.selection = skipTextSelection(context.selection); @@ -1986,7 +1986,7 @@ PointState Message::pointState(QPoint point) const { //} if (check) { auto checkHeight = check->height(); - trect.setHeight(trect.height() - checkHeight); + trect.setHeight(trect.height() - checkHeight - st::mediaInBubbleSkip); } if (entry) { auto entryHeight = entry->height(); @@ -2428,9 +2428,9 @@ TextState Message::textState( } if (check) { auto checkHeight = check->height(); - trect.setHeight(trect.height() - checkHeight); + trect.setHeight(trect.height() - checkHeight - st::mediaInBubbleSkip); auto checkLeft = inner.left(); - auto checkTop = trect.y() + trect.height(); + auto checkTop = trect.y() + trect.height() + st::mediaInBubbleSkip; if (point.y() >= checkTop && point.y() < checkTop + checkHeight) { result = check->textState( point - QPoint(checkLeft, checkTop), @@ -4333,7 +4333,7 @@ int Message::resizeContentGetHeight(int newWidth) { if (contentWidth == maxWidth()) { if (mediaDisplayed) { if (check) { - newHeight += check->resizeGetHeight(contentWidth); + newHeight += check->resizeGetHeight(contentWidth) + st::mediaInBubbleSkip; } if (entry) { newHeight += entry->resizeGetHeight(contentWidth); @@ -4365,24 +4365,16 @@ int Message::resizeContentGetHeight(int newWidth) { if (!mediaOnTop) { newHeight += st::msgPadding.top(); if (mediaDisplayed) newHeight += st::mediaInBubbleSkip; - if (check) newHeight += st::mediaInBubbleSkip; if (entry) newHeight += st::mediaInBubbleSkip; } if (mediaDisplayed) { newHeight += media->height(); - if (check) { - newHeight += check->resizeGetHeight(contentWidth); - } - if (entry) { - newHeight += entry->resizeGetHeight(contentWidth); - } - } else { - if (check) { - newHeight += check->resizeGetHeight(contentWidth); - } - if (entry) { - newHeight += entry->resizeGetHeight(contentWidth); - } + } + if (check) { + newHeight += check->resizeGetHeight(contentWidth) + st::mediaInBubbleSkip; + } + if (entry) { + newHeight += entry->resizeGetHeight(contentWidth); } if (reactionsInBubble) { if (!mediaDisplayed || _viewButton) { @@ -4518,7 +4510,8 @@ void Message::refreshInfoSkipBlock() { return media->storyExpired(); } return false; - } else if (item->Has()) { + } else if (item->Has() + || factcheckBlock()) { return false; } else if (media && media->isDisplayed() && !_invertMedia) { return false; diff --git a/Telegram/SourceFiles/ui/boxes/edit_factcheck_box.cpp b/Telegram/SourceFiles/ui/boxes/edit_factcheck_box.cpp new file mode 100644 index 000000000..f13c3e976 --- /dev/null +++ b/Telegram/SourceFiles/ui/boxes/edit_factcheck_box.cpp @@ -0,0 +1,81 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "ui/boxes/edit_factcheck_box.h" + +#include "lang/lang_keys.h" +#include "ui/widgets/fields/input_field.h" +#include "styles/style_chat.h" +#include "styles/style_layers.h" + +void EditFactcheckBox( + not_null box, + TextWithEntities current, + Fn save) { + box->setTitle(tr::lng_factcheck_title()); + + const auto field = box->addRow(object_ptr( + box, + st::factcheckField, + Ui::InputField::Mode::NoNewlines, + tr::lng_factcheck_placeholder(), + TextWithTags{ + current.text, + TextUtilities::ConvertEntitiesToTextTags(current.entities) + })); + + enum class State { + Initial, + Changed, + Removed, + }; + const auto state = box->lifetime().make_state>( + State::Initial); + field->changes() | rpl::start_with_next([=] { + const auto now = field->getLastText().trimmed(); + *state = !now.isEmpty() + ? State::Changed + : current.empty() + ? State::Initial + : State::Removed; + }, field->lifetime()); + + state->value() | rpl::start_with_next([=](State state) { + box->clearButtons(); + if (state == State::Removed) { + box->addButton(tr::lng_box_remove(), [=] { + box->closeBox(); + save({}); + }, st::attentionBoxButton); + } else if (state == State::Initial) { + box->addButton(tr::lng_settings_save(), [=] { + if (current.empty()) { + field->showError(); + } else { + box->closeBox(); + } + }); + } else { + box->addButton(tr::lng_settings_save(), [=] { + auto result = field->getTextWithAppliedMarkdown(); + + box->closeBox(); + save({ + result.text, + TextUtilities::ConvertTextTagsToEntities(result.tags) + }); + }); + } + box->addButton(tr::lng_cancel(), [=] { + box->closeBox(); + }); + }, box->lifetime()); + + box->setFocusCallback([=] { + field->setFocusFast(); + }); +} diff --git a/Telegram/SourceFiles/ui/boxes/edit_factcheck_box.h b/Telegram/SourceFiles/ui/boxes/edit_factcheck_box.h new file mode 100644 index 000000000..f09f52eb4 --- /dev/null +++ b/Telegram/SourceFiles/ui/boxes/edit_factcheck_box.h @@ -0,0 +1,15 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "ui/layers/generic_box.h" + +void EditFactcheckBox( + not_null box, + TextWithEntities current, + Fn save); diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 6c398f236..9dbf43303 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1135,3 +1135,18 @@ effectPreviewLoading: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) { factcheckIconExpand: icon {{ "fast_to_original-rotate_cw", historyPeer1NameFg }}; factcheckIconCollapse: icon {{ "fast_to_original-rotate_ccw", historyPeer1NameFg }}; +factcheckField: InputField(defaultInputField) { + textBg: transparent; + textMargins: margins(0px, 0px, 0px, 4px); + + placeholderFg: placeholderFg; + placeholderFgActive: placeholderFgActive; + placeholderFgError: placeholderFgActive; + placeholderMargins: margins(2px, 0px, 2px, 0px); + placeholderScale: 0.; + placeholderFont: normalFont; + + heightMin: 24px; + + font: normalFont; +} diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index eee9919fd..8f2c0f861 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -153,6 +153,7 @@ menuIconTagFilter: icon{{ "menu/tag_filter", menuIconColor }}; menuIconTagRename: icon{{ "menu/tag_rename", menuIconColor }}; menuIconGroupsHide: icon {{ "menu/hide_members", menuIconColor }}; menuIconFont: icon {{ "menu/fonts", menuIconColor }}; +menuIconFactcheck: icon {{ "menu/factcheck", menuIconColor }}; menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }}; menuIconTTLAnyTextPosition: point(11px, 22px); diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 0a97c6b6d..3c0c026a3 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -261,6 +261,8 @@ PRIVATE ui/boxes/country_select_box.h ui/boxes/edit_birthday_box.cpp ui/boxes/edit_birthday_box.h + ui/boxes/edit_factcheck_box.cpp + ui/boxes/edit_factcheck_box.h ui/boxes/edit_invite_link.cpp ui/boxes/edit_invite_link.h ui/boxes/rate_call_box.cpp