From 11cf0486cb9b818ab3668455109026f8f3985249 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 29 Jan 2024 11:07:53 +0400 Subject: [PATCH] Implement required paywalls in tags. --- .../Resources/icons/dialogs/tags_arrow.png | Bin 0 -> 1629 bytes .../Resources/icons/dialogs/tags_arrow@2x.png | Bin 0 -> 196 bytes .../Resources/icons/dialogs/tags_arrow@3x.png | Bin 0 -> 244 bytes Telegram/Resources/langs/lang.strings | 8 + .../SourceFiles/core/local_url_handlers.cpp | 16 ++ Telegram/SourceFiles/dialogs/dialogs.style | 4 + .../dialogs/dialogs_inner_widget.cpp | 13 +- .../dialogs/dialogs_search_tags.cpp | 155 +++++++++++++++--- .../SourceFiles/dialogs/dialogs_search_tags.h | 19 ++- .../history/history_inner_widget.cpp | 4 +- .../history/view/history_view_list_widget.cpp | 2 +- .../history/view/history_view_message.cpp | 35 ++-- .../history_view_reactions_selector.cpp | 28 ++++ .../history_view_reactions_selector.h | 3 + .../media/stories/media_stories_reactions.cpp | 4 +- .../SourceFiles/window/section_widget.cpp | 11 +- 16 files changed, 242 insertions(+), 60 deletions(-) create mode 100644 Telegram/Resources/icons/dialogs/tags_arrow.png create mode 100644 Telegram/Resources/icons/dialogs/tags_arrow@2x.png create mode 100644 Telegram/Resources/icons/dialogs/tags_arrow@3x.png diff --git a/Telegram/Resources/icons/dialogs/tags_arrow.png b/Telegram/Resources/icons/dialogs/tags_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..78a86bf65b86ee0977cd7e403da51dc29e6fbee1 GIT binary patch literal 1629 zcmbVNJ&fE$6n0P|g+!5%QV@|uvYaLaY>$7}9>qk*?ZK^tkJH|w91_KjXU4nMtv$x} z-R_>ahK>dai3UUgB@GoF1yF!Q9nl6M(L+T;aXjyOojY{-5th~-+uwZed+&RG`_cB+ zn^!KqbV-t=E4|HbAFlQKg^SO@`OBO07vb`JzWHt`NtdtIzjM;(UtE)<3%?|T-D)>{ z3saG5go%i2vor^^B;CC?%L(1%l^pR=k_F12-+iyh2@90_PKd&MosW~v!-DS|ZVl++ z9`%`W?=|`E3-IUP+csN3-SI_mhl?Y5DSr z4ZKS#9w^|Nts+B3-T+)PJ#g(6WMhPu&`_`>o}Y%Aehqa@Y#FDZ&@+rwLWmt@kgxoCyjXkD@X!cHB6Qps{^RbtBtVN!*E4;!%&= zapb#*tk~Wz68O-_*me(vBTeQR+B_t^aLif?)5;SwaJ_*&Ew>ZdOTC)X8&}|f%FOHFQbk+dwMgOl~i+3l+(FzVT zu3om&6>i%3%rl@aVEX?0&(U?5+_=|W8(e!phr{7^zaRZ@!FHVEYt_e2Iv9?Pgg&ebxsLQ0Np-Iq5uE@ literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/dialogs/tags_arrow@3x.png b/Telegram/Resources/icons/dialogs/tags_arrow@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..086a6b8ecdd0472b4366bb5815cfca8e0d1fb237 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^azJdr!2~2bzr=0^Qk(@Ik;M!Q+`=Ht$S`Y;1W<69 zr;B4qMC;q@8#$d71=t>>=WHnw+FsPKn^C8f`R+kkojV6wSuU%5aEjZt`#|$=Y3ZMQ zArt;vyp#AFwS|qrrR3aMOHK7765p+tiYyh8v^{oXdB7{n=YJ)Q?n+#)etv1~*85d! zLrX5YipPGDukz|_*mvc6)V*pwS%!1cawf$bhf5V=uAlh& rW;o6InAfVUZbz;~aWr1q8$ZwL$1jHeg`AB*7c+Re`njxgN@xNA controller, not_null theme) { @@ -1020,6 +1032,10 @@ const std::vector &InternalUrlHandlers() { { u"^copy:(.+)$"_q, CopyPeerId + }, + { + u"about_tags"_q, + ShowSearchTagsPromo } }; return Result; diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index c45ea636f..a58443444 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -626,3 +626,7 @@ searchedBarPosition: point(17px, 7px); dialogsSearchTagSkip: point(8px, 4px); dialogsSearchTagBottom: 10px; +dialogsSearchTagLocked: icon{{ "emoji/premium_lock", lightButtonFgOver }}; +dialogsSearchTagPromo: defaultTextStyle; +dialogsSearchTagArrow: icon{{ "dialogs/tags_arrow", windowSubTextFg }}; +dialogsSearchTagArrowPadding: margins(0px, 3px, 0px, 0px); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 46bf60b9d..26ddf92a2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -18,8 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_search_tags.h" #include "history/history.h" #include "history/history_item.h" -#include "core/shortcuts.h" #include "core/application.h" +#include "core/click_handler_types.h" +#include "core/shortcuts.h" #include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" #include "ui/widgets/scroll_area.h" @@ -1783,7 +1784,11 @@ void InnerWidget::mousePressReleased( } } if (auto activated = ClickHandler::unpressed()) { - ActivateClickHandler(window(), activated, ClickContext{ button }); + ActivateClickHandler(window(), activated, ClickContext{ + button, + QVariant::fromValue(ClickHandlerContext{ + .sessionWindow = _controller, + }) }); } } @@ -3002,8 +3007,8 @@ void InnerWidget::searchInChat( update(0, searchInChatOffset(), width(), height); }, _searchTags->lifetime()); - _searchTags->heightValue() | rpl::filter( - rpl::mappers::_1 > 0 + _searchTags->heightValue() | rpl::skip( + 1 ) | rpl::start_with_next([=] { refresh(); moveCancelSearchButtons(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp index ece874547..936dd61b3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp @@ -8,13 +8,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_search_tags.h" #include "base/qt/qt_key_modifiers.h" +#include "boxes/premium_preview_box.h" +#include "core/click_handler_types.h" +#include "core/ui_integration.h" #include "data/stickers/data_custom_emoji.h" #include "data/data_document.h" #include "data/data_message_reactions.h" +#include "data/data_peer_values.h" #include "data/data_session.h" #include "history/view/reactions/history_view_reactions.h" +#include "main/main_session.h" +#include "lang/lang_keys.h" #include "ui/effects/animation_value.h" +#include "ui/text/text_utilities.h" +#include "ui/painter.h" #include "ui/power_saving.h" +#include "window/window_session_controller.h" #include "styles/style_chat.h" #include "styles/style_dialogs.h" @@ -32,6 +41,45 @@ namespace { return TextUtilities::SingleLine(result); } +[[nodiscard]] ClickHandlerPtr MakePromoLink() { + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + ShowPremiumPreviewBox( + controller, + PremiumPreview::TagsForMessages); + } + }); +} + +[[nodiscard]] Ui::Text::String FillAdditionalText( + not_null owner, + int width) { + auto emoji = Ui::Text::SingleCustomEmoji( + owner->customEmojiManager().registerInternalEmoji( + st::dialogsSearchTagArrow, + st::dialogsSearchTagArrowPadding)); + auto result = Ui::Text::String(); + const auto context = Core::MarkedTextContext{ + .session = &owner->session(), + .customEmojiRepaint = [] {}, + .customEmojiLoopLimit = 1, + }; + const auto attempt = [&](const auto &phrase) { + result.setMarkedText( + st::dialogsSearchTagPromo, + phrase(tr::now, lt_arrow, emoji, Ui::Text::WithEntities), + kMarkupTextOptions, + context); + return result.maxWidth() < width; + }; + if (attempt(tr::lng_add_tag_phrase_long) + || attempt(tr::lng_add_tag_phrase)) { + return result; + } + return {}; +} + } // namespace struct SearchTags::Tag { @@ -43,6 +91,7 @@ struct SearchTags::Tag { QRect geometry; ClickHandlerPtr link; bool selected = false; + bool promo = false; }; SearchTags::SearchTags( @@ -51,10 +100,13 @@ SearchTags::SearchTags( std::vector selected) : _owner(owner) , _added(selected) { - std::move( - tags - ) | rpl::start_with_next([=](const std::vector &list) { - fill(list); + rpl::combine( + std::move(tags), + Data::AmPremiumValue(&owner->session()) + ) | rpl::start_with_next([=]( + const std::vector &list, + bool premium) { + fill(list, premium); }, _lifetime); // Mark the `selected` reactions as selected in `_tags`. @@ -73,12 +125,19 @@ SearchTags::SearchTags( SearchTags::~SearchTags() = default; -void SearchTags::fill(const std::vector &list) { +void SearchTags::fill( + const std::vector &list, + bool premium) { const auto selected = collectSelected(); _tags.clear(); _tags.reserve(list.size()); const auto link = [&](Data::ReactionId id) { - return std::make_shared(crl::guard(this, [=] { + return std::make_shared(crl::guard(this, [=]( + ClickContext context) { + if (!premium) { + MakePromoLink()->onClick(context); + return; + } const auto i = ranges::find(_tags, id, &Tag::id); if (i != end(_tags)) { if (!i->selected && !base::IsShiftPressed()) { @@ -109,6 +168,18 @@ void SearchTags::fill(const std::vector &list) { _owner->reactions().preloadImageFor(id); } }; + if (!premium) { + const auto text = (list.empty() && _added.empty()) + ? tr::lng_add_tag_button(tr::now) + : tr::lng_unlock_tags(tr::now); + _tags.push_back({ + .id = Data::ReactionId(), + .text = text, + .textWidth = st::reactionInlineTagFont->width(text), + .link = MakePromoLink(), + .promo = true, + }); + } for (const auto &reaction : list) { if (reaction.count > 0 || ranges::contains(_added, reaction.id) @@ -131,10 +202,11 @@ void SearchTags::layout() { Expects(_width > 0); if (_tags.empty()) { + _additionalText = {}; _height = 0; return; } - const auto &bg = validateBg(false); + const auto &bg = validateBg(false, false); const auto skip = st::dialogsSearchTagSkip; const auto size = bg.size() / bg.devicePixelRatio(); const auto xbase = size.width(); @@ -147,10 +219,17 @@ void SearchTags::layout() { x = 0; y += ybase + skip.y(); } - tag.geometry = QRect(x, y, width, xbase); + tag.geometry = QRect(x, y, width, ybase); x += width + skip.x(); } _height = y + ybase + st::dialogsSearchTagBottom; + if (_tags.size() == 1 && _tags.front().promo) { + _additionalLeft = x; + const auto additionalWidth = _width - _additionalLeft; + _additionalText = FillAdditionalText(_owner, additionalWidth); + } else { + _additionalText = {}; + } } void SearchTags::resizeToWidth(int width) { @@ -177,6 +256,14 @@ ClickHandlerPtr SearchTags::lookupHandler(QPoint point) const { for (const auto &tag : _tags) { if (tag.geometry.contains(point.x(), point.y())) { return tag.link; + } else if (tag.promo + && !_additionalText.isEmpty() + && tag.geometry.united(QRect( + _additionalLeft, + tag.geometry.y(), + _additionalText.maxWidth(), + tag.geometry.height())).contains(point.x(), point.y())) { + return tag.link; } } return nullptr; @@ -227,7 +314,7 @@ void SearchTags::paintCustomFrame( } void SearchTags::paint( - QPainter &p, + Painter &p, QPoint position, crl::time now, bool paused) const { @@ -236,9 +323,9 @@ void SearchTags::paint( const auto padding = st::reactionInlinePadding; for (const auto &tag : _tags) { const auto geometry = tag.geometry.translated(position); - paintBackground(p, geometry, tag.selected); + paintBackground(p, geometry, tag); paintText(p, geometry, tag); - if (!tag.custom && tag.image.isNull()) { + if (!tag.custom && !tag.promo && tag.image.isNull()) { tag.image = _owner->reactions().resolveImageFor( tag.id, ::Data::Reactions::ImageSize::InlineList); @@ -247,7 +334,9 @@ void SearchTags::paint( const auto image = QRect( inner.topLeft() + QPoint(skip, skip), QSize(st::reactionInlineImage, st::reactionInlineImage)); - if (const auto custom = tag.custom.get()) { + if (tag.promo) { + st::dialogsSearchTagLocked.paintInCenter(p, image); + } else if (const auto custom = tag.custom.get()) { const auto textFg = tag.selected ? st::dialogsNameFgActive->c : st::dialogsNameFgOver->c; @@ -262,13 +351,26 @@ void SearchTags::paint( p.drawImage(image.topLeft(), tag.image); } } + paintAdditionalText(p, position); +} + +void SearchTags::paintAdditionalText(Painter &p, QPoint position) const { + if (_additionalText.isEmpty()) { + return; + } + const auto x = position.x() + _additionalLeft; + const auto tag = _tags.front().geometry; + const auto height = st::dialogsSearchTagPromo.font->height; + const auto y = position.y() + tag.y() + (tag.height() - height) / 2; + p.setPen(st::windowSubTextFg); + _additionalText.drawLeft(p, x, y, _width - x, _width); } void SearchTags::paintBackground( QPainter &p, QRect geometry, - bool selected) const { - const auto &image = validateBg(selected); + const Tag &tag) const { + const auto &image = validateBg(tag.selected, tag.promo); const auto ratio = int(image.devicePixelRatio()); const auto size = image.size() / ratio; if (const auto fill = geometry.width() - size.width(); fill > 0) { @@ -282,7 +384,7 @@ void SearchTags::paintBackground( QRect(QPoint(), QSize(left, size.height()) * ratio)); p.fillRect( QRect(x + left, y, fill, size.height()), - bgColor(selected)); + bgColor(tag.selected, tag.promo)); p.drawImage( QRect(x + left + fill, y, right, size.height()), image, @@ -292,30 +394,39 @@ void SearchTags::paintBackground( } } -void SearchTags::paintText(QPainter &p, QRect geometry, const Tag &tag) const { +void SearchTags::paintText( + QPainter &p, + QRect geometry, + const Tag &tag) const { using namespace HistoryView::Reactions; if (tag.text.isEmpty()) { return; } - p.setPen(tag.selected ? st::dialogsTextFgActive : st::windowSubTextFg); + p.setPen(tag.promo + ? st::lightButtonFgOver + : tag.selected + ? st::dialogsTextFgActive + : st::windowSubTextFg); p.setFont(st::reactionInlineTagFont); const auto x = geometry.x() + st::reactionInlineTagNamePosition.x(); const auto y = geometry.y() + st::reactionInlineTagNamePosition.y(); p.drawText(x, y + st::reactionInlineTagFont->ascent, tag.text); } -QColor SearchTags::bgColor(bool selected) const { - return selected +QColor SearchTags::bgColor(bool selected, bool promo) const { + return promo + ? st::lightButtonBgOver->c + : selected ? st::dialogsBgActive->c : st::dialogsBgOver->c; } -const QImage &SearchTags::validateBg(bool selected) const { +const QImage &SearchTags::validateBg(bool selected, bool promo) const { using namespace HistoryView::Reactions; - auto &image = selected ? _selectedBg : _normalBg; + auto &image = promo ? _promoBg : selected ? _selectedBg : _normalBg; if (image.isNull()) { - const auto tagBg = bgColor(selected); + const auto tagBg = bgColor(selected, promo); const auto dotBg = st::transparent->c; image = InlineList::PrepareTagBg(tagBg, dotBg); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.h b/Telegram/SourceFiles/dialogs/dialogs_search_tags.h index 01b56e5e9..d1a63fbf1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_tags.h +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.h @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/weak_ptr.h" +class Painter; + namespace Data { class Session; struct Reaction; @@ -39,7 +41,7 @@ public: -> rpl::producer>; void paint( - QPainter &p, + Painter &p, QPoint position, crl::time now, bool paused) const; @@ -49,7 +51,7 @@ public: private: struct Tag; - void fill(const std::vector &list); + void fill(const std::vector &list, bool premium); void paintCustomFrame( QPainter &p, not_null emoji, @@ -59,25 +61,26 @@ private: const QColor &textColor) const; void layout(); [[nodiscard]] std::vector collectSelected() const; - [[nodiscard]] QColor bgColor(bool selected) const; - [[nodiscard]] const QImage &validateBg(bool selected) const; - void paintBackground( - QPainter &p, - QRect geometry, - bool selected) const; + [[nodiscard]] QColor bgColor(bool selected, bool promo) const; + [[nodiscard]] const QImage &validateBg(bool selected, bool promo) const; + void paintAdditionalText(Painter &p, QPoint position) const; + void paintBackground(QPainter &p, QRect geometry, const Tag &tag) const; void paintText(QPainter &p, QRect geometry, const Tag &tag) const; const not_null _owner; std::vector _added; std::vector _tags; + Ui::Text::String _additionalText; rpl::event_stream<> _selectedChanges; rpl::event_stream<> _repaintRequests; mutable QImage _normalBg; mutable QImage _selectedBg; + mutable QImage _promoBg; mutable QImage _customCache; mutable int _customSkip = 0; rpl::variable _height; int _width = 0; + int _additionalLeft = 0; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 2ead069d3..24cbe0ace 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2636,9 +2636,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { desiredPosition, reactItem, [=](ChosenReaction reaction) { reactionChosen(reaction); }, - (reactItem->reactionsAreTags() - ? TextWithEntities{ u"Organize your Saved Messages with tags. Learn More..."_q } - : TextWithEntities()), + ItemReactionsAbout(reactItem), _controller->cachedReactionIconFactory().createMethod()) : AttachSelectorResult::Skipped; if (attached == AttachSelectorResult::Failed) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 82044ad63..957b87a48 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2633,7 +2633,7 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { desiredPosition, reactItem, [=](ChosenReaction reaction) { reactionChosen(reaction); }, - TextWithEntities(), + ItemReactionsAbout(reactItem), _controller->cachedReactionIconFactory().createMethod()) : AttachSelectorResult::Skipped; if (attached == AttachSelectorResult::Failed) { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 4a974d619..3db8124cb 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_reply.h" #include "history/view/history_view_view_button.h" // ViewButton. #include "history/history.h" +#include "boxes/premium_preview_box.h" #include "boxes/share_box.h" #include "ui/effects/glare.h" #include "ui/effects/reaction_fly_animation.h" @@ -49,13 +50,13 @@ namespace { constexpr auto kPlayStatusLimit = 2; const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_"; -[[nodiscard]] std::optional ExtractController( +[[nodiscard]] Window::SessionController *ExtractController( const ClickContext &context) { const auto my = context.other.value(); if (const auto controller = my.sessionWindow.get()) { return controller; } - return std::nullopt; + return nullptr; } class KeyboardStyle : public ReplyKeyboard::Style { @@ -2288,11 +2289,8 @@ ClickHandlerPtr Message::createGoToCommentsLink() const { const auto fullId = data()->fullId(); const auto sessionId = data()->history()->session().uniqueId(); return std::make_shared([=](ClickContext context) { - const auto controller = ExtractController(context).value_or(nullptr); - if (!controller) { - return; - } - if (controller->session().uniqueId() != sessionId) { + const auto controller = ExtractController(context); + if (!controller || controller->session().uniqueId() != sessionId) { return; } if (const auto item = controller->session().data().message(fullId)) { @@ -2984,12 +2982,20 @@ void Message::refreshReactions() { return std::make_shared([=]( ClickContext context) { if (const auto strong = weak.get()) { - if (strong->data()->reactionsAreTags()) { - const auto tag = Data::SearchTagToQuery(id); - HashtagClickHandler(tag).onClick(context); + const auto item = strong->data(); + if (item->reactionsAreTags()) { + if (item->history()->session().premium()) { + const auto tag = Data::SearchTagToQuery(id); + HashtagClickHandler(tag).onClick(context); + } else if (const auto controller + = ExtractController(context)) { + ShowPremiumPreviewBox( + controller, + PremiumPreview::TagsForMessages); + } return; } - strong->data()->toggleReaction( + item->toggleReaction( id, HistoryItem::ReactionSource::Existing); if (const auto now = weak.get()) { @@ -3586,11 +3592,8 @@ ClickHandlerPtr Message::prepareRightActionLink() const { }; return std::make_shared([=]( ClickContext context) { - const auto controller = ExtractController(context).value_or(nullptr); - if (!controller) { - return; - } - if (controller->session().uniqueId() != sessionId) { + const auto controller = ExtractController(context); + if (!controller || controller->session().uniqueId() != sessionId) { return; } diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp index f0aa8a86f..da65f0902 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp @@ -12,13 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/popup_menu.h" #include "ui/widgets/shadow.h" #include "ui/text/text_custom_emoji.h" +#include "ui/text/text_utilities.h" #include "ui/platform/ui_platform_utility.h" #include "ui/painter.h" +#include "history/history.h" #include "history/history_item.h" #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_session.h" #include "data/stickers/data_custom_emoji.h" +#include "lang/lang_keys.h" #include "main/main_session.h" #include "chat_helpers/emoji_list_widget.h" #include "chat_helpers/stickers_list_footer.h" @@ -277,6 +280,13 @@ Selector::Selector( , _skipy((st::reactStripHeight - st::reactStripSize) / 2) { setMouseTracking(true); + if (_about) { + _about->setClickHandlerFilter([=](const auto &...) { + _escapes.fire({}); + return true; + }); + } + _useTransparency = child || Ui::Platform::TranslucentWindowsSupported(); } @@ -1173,6 +1183,10 @@ AttachSelectorResult AttachSelectorToMenu( chosen(std::move(reaction)); }, selector->lifetime()); + selector->escapes() | rpl::start_with_next([=] { + menu->hideMenu(); + }, selector->lifetime()); + const auto weak = base::make_weak(controller); controller->enableGifPauseReason( Window::GifPauseReason::MediaPreview); @@ -1249,4 +1263,18 @@ auto AttachSelectorToMenu( return selector; } +TextWithEntities ItemReactionsAbout(not_null item) { + return !item->reactionsAreTags() + ? TextWithEntities() + : item->history()->session().premium() + ? TextWithEntities{ tr::lng_add_tag_about(tr::now) } + : tr::lng_subscribe_tag_about( + tr::now, + lt_link, + Ui::Text::Link( + tr::lng_subscribe_tag_link(tr::now), + u"internal:about_tags"_q), + Ui::Text::WithEntities); +} + } // namespace HistoryView::Reactions diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h index a9fb7c3e1..1d136c15b 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h @@ -265,4 +265,7 @@ AttachSelectorResult AttachSelectorToMenu( IconFactory iconFactory ) -> base::expected, AttachSelectorResult>; +[[nodiscard]] TextWithEntities ItemReactionsAbout( + not_null item); + } // namespace HistoryView::Reactions diff --git a/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp b/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp index 420e0bee1..bea75eb90 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp @@ -27,7 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history.h" #include "main/main_session.h" #include "media/stories/media_stories_controller.h" -#include "lang/lang_tag.h" +#include "lang/lang_keys.h" #include "ui/chat/chat_style.h" #include "ui/effects/emoji_fly_animation.h" #include "ui/effects/path_shift_gradient.h" @@ -676,7 +676,7 @@ void Reactions::Panel::create() { _controller->uiShow(), std::move(reactions), TextWithEntities{ (mode == Mode::Message - ? u"Send reaction as a private message"_q + ? tr::lng_stories_reaction_as_message(tr::now) : QString()) }, _controller->cachedReactionIconFactory().createMethod(), [=](bool fast) { hide(mode); }); diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index 2600fae5a..dcba6476c 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -525,13 +525,16 @@ bool ShowReactPremiumError( not_null controller, not_null item, const Data::ReactionId &id) { - if (controller->session().premium() + if (item->reactionsAreTags()) { + if (controller->session().premium()) { + return false; + } + ShowPremiumPreviewBox(controller, PremiumPreview::TagsForMessages); + return true; + } else if (controller->session().premium() || ranges::contains(item->chosenReactions(), id) || item->history()->peer->isBroadcast()) { return false; - } else if (item->reactionsAreTags()) { - ShowPremiumPreviewBox(controller, PremiumPreview::TagsForMessages); - return true; } else if (!id.custom()) { return false; }