diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 436160e9d..2237f68ca 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4561,6 +4561,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_view_button_external_link" = "Open link"; "lng_view_button_boost" = "Boost"; "lng_view_button_giftcode" = "Open"; +"lng_view_button_iv" = "Instant View"; "lng_sponsored_hide_ads" = "Hide"; "lng_sponsored_title" = "What are sponsored messages?"; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index b5376fab2..b088bfee9 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -3544,9 +3544,13 @@ void Session::webpageApplyFields( process(block, process); } } + const auto type = story ? WebPageType::Story : ParseWebPageType(data); + auto iv = (data.vcached_page() && !IgnoreIv(type)) + ? std::make_unique(data, *data.vcached_page()) + : nullptr; webpageApplyFields( page, - (story ? WebPageType::Story : ParseWebPageType(data)), + type, qs(data.vurl()), qs(data.vdisplay_url()), siteName, @@ -3564,9 +3568,7 @@ void Session::webpageApplyFields( ? processDocument(*document).get() : lookupThemeDocument()), WebPageCollage(this, data), - (data.vcached_page() - ? std::make_unique(data, *data.vcached_page()) - : nullptr), + std::move(iv), data.vduration().value_or_empty(), qs(data.vauthor().value_or_empty()), data.is_has_large_media(), diff --git a/Telegram/SourceFiles/data/data_web_page.cpp b/Telegram/SourceFiles/data/data_web_page.cpp index 9f17fdfdc..3f30e746f 100644 --- a/Telegram/SourceFiles/data/data_web_page.cpp +++ b/Telegram/SourceFiles/data/data_web_page.cpp @@ -171,6 +171,10 @@ WebPageType ParseWebPageType( } } +bool IgnoreIv(WebPageType type) { + return (type == WebPageType::Message); +} + WebPageType ParseWebPageType(const MTPDwebPage &page) { return ParseWebPageType( qs(page.vtype().value_or_empty()), diff --git a/Telegram/SourceFiles/data/data_web_page.h b/Telegram/SourceFiles/data/data_web_page.h index 7b4f7db70..2a13dfb6f 100644 --- a/Telegram/SourceFiles/data/data_web_page.h +++ b/Telegram/SourceFiles/data/data_web_page.h @@ -53,6 +53,7 @@ enum class WebPageType : uint8 { Livestream, }; [[nodiscard]] WebPageType ParseWebPageType(const MTPDwebPage &type); +[[nodiscard]] bool IgnoreIv(WebPageType type); struct WebPageCollage { using Item = std::variant; diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index bab288d4f..c50c9ddf7 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "iv/iv_instance.h" #include "core/click_handler_types.h" #include "core/ui_integration.h" +#include "data/stickers/data_custom_emoji.h" #include "data/data_file_click_handler.h" #include "data/data_photo_media.h" #include "data/data_session.h" @@ -135,12 +136,11 @@ constexpr auto kMaxOriginalEntryLines = 8192; }); } -[[nodiscard]] QString PageToPhrase(not_null webpage) { - if (webpage->iv) { - return u"Instant View"_q; - } - const auto type = webpage->type; - return Ui::Text::Upper((type == WebPageType::Theme) +[[nodiscard]] TextWithEntities PageToPhrase(not_null page) { + const auto type = page->type; + const auto text = Ui::Text::Upper(page->iv + ? tr::lng_view_button_iv(tr::now) + : (type == WebPageType::Theme) ? tr::lng_view_button_theme(tr::now) : (type == WebPageType::Story) ? tr::lng_view_button_story(tr::now) @@ -170,6 +170,15 @@ constexpr auto kMaxOriginalEntryLines = 8192; : (type == WebPageType::BotApp) ? tr::lng_view_button_bot_app(tr::now) : QString()); + if (page->iv) { + const auto manager = &page->owner().customEmojiManager(); + const auto &icon = st::historyIvIcon; + const auto padding = st::historyIvIconPadding; + return Ui::Text::SingleCustomEmoji( + manager->registerInternalEmoji(icon, padding) + ).append(text); + } + return { text }; } [[nodiscard]] bool HasButton(not_null webpage) { @@ -238,15 +247,23 @@ QSize WebPage::countOptimalSize() { } // Detect _openButtonWidth before counting paddings. - _openButton = QString(); - _openButtonWidth = 0; + _openButton = Ui::Text::String(); if (HasButton(_data)) { - _openButton = PageToPhrase(_data); - _openButtonWidth = st::semiboldFont->width(_openButton); + const auto context = Core::MarkedTextContext{ + .session = &_data->session(), + .customEmojiRepaint = [] {}, + .customEmojiLoopLimit = 1, + }; + _openButton.setMarkedText( + st::semiboldTextStyle, + PageToPhrase(_data), + kMarkupTextOptions, + context); } else if (_sponsoredData) { if (!_sponsoredData->buttonText.isEmpty()) { - _openButton = Ui::Text::Upper(_sponsoredData->buttonText); - _openButtonWidth = st::semiboldFont->width(_openButton); + _openButton.setText( + st::semiboldTextStyle, + Ui::Text::Upper(_sponsoredData->buttonText)); } } @@ -453,9 +470,9 @@ QSize WebPage::countOptimalSize() { _duration = Ui::FormatDurationText(_data->duration); _durationWidth = st::msgDateFont->width(_duration); } - if (_openButtonWidth) { + if (!_openButton.isEmpty()) { maxWidth += rect::m::sum::h(st::historyPageButtonPadding) - + _openButtonWidth; + + _openButton.maxWidth(); } maxWidth += rect::m::sum::h(padding); minHeight += rect::m::sum::v(padding); @@ -910,7 +927,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const { } } - if (_openButtonWidth) { + if (!_openButton.isEmpty()) { p.setFont(st::semiboldFont); p.setPen(cache->icon); const auto end = inner.y() + inner.height() + _st.padding.bottom(); @@ -918,11 +935,13 @@ void WebPage::draw(Painter &p, const PaintContext &context) const { auto color = cache->icon; color.setAlphaF(color.alphaF() * 0.3); p.fillRect(inner.x(), end, inner.width(), line, color); - const auto top = end + st::historyPageButtonPadding.top(); - p.drawText( - inner.x() + (inner.width() - _openButtonWidth) / 2, - top + st::semiboldFont->ascent, - _openButton); + _openButton.draw(p, { + .position = QPoint( + inner.x() + (inner.width() - _openButton.maxWidth()) / 2, + end + st::historyPageButtonPadding.top()), + .availableWidth = paintw, + .now = context.now, + }); } } @@ -1225,7 +1244,9 @@ QMargins WebPage::inBubblePadding() const { } QMargins WebPage::innerMargin() const { - const auto button = _openButtonWidth ? st::historyPageButtonHeight : 0; + const auto button = _openButton.isEmpty() + ? 0 + : st::historyPageButtonHeight; return _st.padding + QMargins(0, 0, 0, button); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.h b/Telegram/SourceFiles/history/view/media/history_view_web_page.h index 6f6003124..b048cfc39 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.h +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.h @@ -147,10 +147,9 @@ private: Ui::Text::String _siteName; Ui::Text::String _title; Ui::Text::String _description; + Ui::Text::String _openButton; - QString _openButton; QString _duration; - int _openButtonWidth = 0; int _durationWidth = 0; mutable QPoint _lastPoint; diff --git a/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp b/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp index d451feb1b..d46d05615 100644 --- a/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp +++ b/Telegram/SourceFiles/settings/business/settings_quick_replies.cpp @@ -31,6 +31,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Settings { namespace { +constexpr auto kShortcutLimit = 32; + class QuickReplies : public BusinessSection { public: QuickReplies( @@ -162,7 +164,7 @@ void QuickReplies::setupContent( } [[nodiscard]] bool ValidShortcutName(const QString &name) { - if (name.isEmpty() || name.size() > 32) { + if (name.isEmpty() || name.size() > kShortcutLimit) { return false; } for (const auto &ch : name) { @@ -207,6 +209,39 @@ void EditShortcutNameBox( field->setFocusFast(); }); field->selectAll(); + field->setMaxLength(kShortcutLimit * 2); + + struct State { + rpl::variable length; + }; + const auto state = field->lifetime().make_state(); + state->length = rpl::single( + int(name.size()) + ) | rpl::then(field->changes() | rpl::map([=] { + return int(field->getLastText().size()); + })); + const auto warning = Ui::CreateChild( + field, + state->length.value() | rpl::map([](int count) { + return (count > kShortcutLimit * 3 / 4) + ? QString::number(kShortcutLimit - count) + : QString(); + }), + st::editTagLimit); + state->length.value() | rpl::map( + rpl::mappers::_1 > kShortcutLimit + ) | rpl::start_with_next([=](bool exceeded) { + warning->setTextColorOverride(exceeded + ? st::attentionButtonFg->c + : std::optional()); + }, warning->lifetime()); + rpl::combine( + field->sizeValue(), + warning->sizeValue() + ) | rpl::start_with_next([=] { + warning->moveToRight(0, 0); + }, warning->lifetime()); + warning->setAttribute(Qt::WA_TransparentForMouseEvents); const auto callback = [=] { const auto name = field->getLastText().trimmed(); diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 9dcb8e191..2ab04e1e6 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -622,7 +622,7 @@ settingsAddReplyLabel: FlatLabel(defaultFlatLabel) { } settingsAddReplyField: InputField(defaultInputField) { textBg: transparent; - textMargins: margins(0px, 10px, 0px, 2px); + textMargins: margins(0px, 10px, 32px, 2px); placeholderFg: placeholderFg; placeholderFgActive: placeholderFgActive; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 655ea9896..a24ce6867 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1058,3 +1058,6 @@ boostMessageIcon: icon {{ "stories/boost_mini", windowFg }}; boostMessageIconPadding: margins(0px, 2px, 0px, 0px); boostsMessageIcon: icon {{ "stories/boosts_mini", windowFg }}; boostsMessageIconPadding: margins(0px, 2px, 0px, 0px); + +historyIvIcon: icon{{ "boosts/boost_mini2", windowFg }}; +historyIvIconPadding: margins(2px, 3px, 2px, 0px);