diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b363967f1a..2711328e0a 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2945,6 +2945,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_credits_small_balance_for_message" = "Buy **Stars** to send messages to {user}."; "lng_credits_small_balance_for_messages" = "Buy **Stars** to send messages."; "lng_credits_small_balance_for_suggest" = "Buy **Stars** to suggest post to {channel}."; +"lng_credits_small_balance_for_search" = "Buy **Stars** to search through public posts."; "lng_credits_small_balance_fallback" = "Buy **Stars** to unlock content and services on Telegram."; "lng_credits_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars."; "lng_credits_enough" = "You have enough stars at the moment. {link}"; diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 7b81b4c577..849c98f8d6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -841,13 +841,13 @@ postsSearchIntroTitle: FlatLabel(defaultFlatLabel) { } align: align(top); } -postsSearchIntroTitleMargin: margins(20px, 0px, 20px, 12px); +postsSearchIntroTitleMargin: margins(20px, 0px, 20px, 4px); postsSearchIntroSubtitle: FlatLabel(defaultFlatLabel) { textFg: windowSubTextFg; minWidth: 64px; align: align(top); } -postsSearchIntroSubtitleMargin: margins(20px, 4px, 20px, 12px); +postsSearchIntroSubtitleMargin: margins(20px, 4px, 20px, 16px); postsSearchIntroButton: RoundButton(defaultActiveButton) { width: 200px; height: 42px; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 4a7f9f57b4..679eef689b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -164,7 +164,8 @@ constexpr auto kPreviewPostsLimit = 3; : state.fromPeer; const auto waiting = trimmed.isEmpty() && state.tags.empty() - && !fromPeer; + && !fromPeer + && state.tab != ChatSearchTab::PublicPosts; const auto suggestAllChats = !waiting && state.tab == ChatSearchTab::MyMessages && state.filter != ChatTypeFilter::All; diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_posts.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_posts.cpp index e1fcbe87b1..d8442d92bf 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_posts.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_search_posts.cpp @@ -43,25 +43,38 @@ void PostsSearch::requestMore() { } void PostsSearch::setQuery(const QString &query) { - if (_query == query) { + const auto words = TextUtilities::PrepareSearchWords(query); + const auto prepared = words.isEmpty() ? QString() : words.join(' '); + if (_query == prepared) { return; } - _query = query; - const auto i = _entries.find(query); + _query = prepared; + const auto i = _entries.find(prepared); if (i != end(_entries)) { pushStateUpdate(i->second); - } else if (query.isEmpty()) { + } else if (prepared.isEmpty()) { applyQuery(); } else { _timer.callOnce(kQueryDelay); } } -void PostsSearch::setAllowedStars(int stars) { - if (_query) { - _entries[*_query].allowedStars = stars; - requestSearch(*_query); +int PostsSearch::setAllowedStars(int stars) { + if (!_query) { + return 0; + } else if (_floodState) { + if (_floodState->freeSearchesLeft > 0) { + stars = 0; + } else if (_floodState->nextFreeSearchTime > 0 + && _floodState->nextFreeSearchTime <= base::unixtime::now()) { + stars = 0; + } else { + stars = std::min(int(_floodState->starsPerPaidSearch), stars); + } } + _entries[*_query].allowedStars = stars; + requestSearch(*_query); + return stars; } void PostsSearch::pushStateUpdate(const Entry &entry) { @@ -118,17 +131,20 @@ void PostsSearch::requestSearch(const QString &query) { return; } + const auto useStars = entry.allowedStars; + entry.allowedStars = 0; + using Flag = MTPchannels_SearchPosts::Flag; entry.searchId = _api.request(MTPchannels_SearchPosts( MTP_flags(Flag::f_query - | (entry.allowedStars ? Flag::f_allow_paid_stars : Flag())), + | (useStars ? Flag::f_allow_paid_stars : Flag())), MTP_string(), // hashtag MTP_string(query), MTP_int(entry.offsetRate), (entry.offsetPeer ? entry.offsetPeer->input : MTP_inputPeerEmpty()), MTP_int(entry.offsetId), MTP_int(kPerPage), - MTP_long(entry.allowedStars) + MTP_long(useStars) )).done([=](const MTPmessages_Messages &result) { auto &entry = _entries[query]; entry.searchId = 0; @@ -207,7 +223,11 @@ void PostsSearch::requestSearch(const QString &query) { entry.pages.clear(); } entry.pages.push_back(std::move(messages)); - const auto count = int(entry.pages.size()); + const auto count = int(ranges::accumulate( + entry.pages, + size_type(), + ranges::plus(), + &std::vector>::size)); const auto full = entry.loaded ? count : std::max(count, totalCount); entry.totalCount = full; if (initial && _query == query) { @@ -229,7 +249,7 @@ void PostsSearch::requestSearch(const QString &query) { void PostsSearch::setFloodStateFrom(const MTPDsearchPostsFlood &data) { _recheckTimer.cancel(); - const auto left = data.vremains().v; + const auto left = std::max(data.vremains().v, 0); const auto next = data.vwait_till().value_or_empty(); if (!left && next > 0) { const auto now = base::unixtime::now(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_posts.h b/Telegram/SourceFiles/dialogs/dialogs_search_posts.h index 630c461ab2..27988e0a5e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_posts.h +++ b/Telegram/SourceFiles/dialogs/dialogs_search_posts.h @@ -31,7 +31,7 @@ public: [[nodiscard]] rpl::producer stateUpdates() const; void setQuery(const QString &query); - void setAllowedStars(int stars); + int setAllowedStars(int stars); void requestMore(); private: diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp index 5786dc9054..7ecfddff4f 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp @@ -38,11 +38,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "main/main_session.h" #include "settings/settings_common.h" +#include "settings/settings_credits_graphics.h" #include "settings/settings_premium.h" #include "storage/storage_shared_media.h" #include "ui/boxes/confirm_box.h" #include "ui/controls/swipe_handler.h" #include "ui/effects/ripple_animation.h" +#include "ui/toast/toast.h" #include "ui/text/text_utilities.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "ui/widgets/buttons.h" @@ -1821,8 +1823,9 @@ bool Suggestions::consumeSearchQuery(const QString &query) { const auto tab = key.tab; const auto type = (key.tab == Tab::Media) ? key.mediaType : Type::kCount; if (tab == Tab::Posts) { + const auto changed = (_searchQuery != query); setPostsSearchQuery(query); - return !query.isEmpty(); + return changed || !query.isEmpty(); } else if (tab != Tab::Downloads && type != Type::File && type != Type::Link @@ -1881,6 +1884,7 @@ void Suggestions::setPostsSearchQuery(const QString &query) { if (!_postsSearch) { setupPostsSearch(); } + _searchQuery = query; _searchQueryTimer.cancel(); _postsSearch->setQuery(query); } @@ -1938,8 +1942,32 @@ void Suggestions::setupPostsIntro(const PostsSearchIntroState &intro) { Settings::ShowPremium( _controller, u"posts_search"_q); + } else if (!stars) { + _postsSearch->setAllowedStars(0); } else { - _postsSearch->setAllowedStars(stars); + using namespace Settings; + const auto done = [=](Settings::SmallBalanceResult result) { + if (result == Settings::SmallBalanceResult::Success + || result == Settings::SmallBalanceResult::Already) { + const auto spent = _postsSearch->setAllowedStars(stars); + if (spent > 0) { + _controller->showToast({ + .text = tr::lng_posts_paid_spent( + tr::now, + lt_count, + spent, + Ui::Text::RichLangValue), + .attach = RectPart::Top, + .duration = Ui::Toast::kDefaultDuration * 2, + }); + } + } + }; + MaybeRequestBalanceIncrease( + _controller->uiShow(), + stars, + SmallBalanceForSearch{}, + done); } }, _postsSearchIntro->lifetime()); diff --git a/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp b/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp index b0fe7cbd5b..20c58948ca 100644 --- a/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp +++ b/Telegram/SourceFiles/dialogs/ui/posts_search_intro.cpp @@ -162,6 +162,7 @@ void PostsSearchIntro::setup() { st::resaleButtonTitle, st::resaleButtonSubtitle); } + _content->resizeToWidth(width()); }, _button->lifetime()); } diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index c49994a9bd..f36da05f9c 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -2493,7 +2493,7 @@ void SmallBalanceBox( return owner->peer(peerFromChannel(value.channelId))->name(); }, [](SmallBalanceSubscription value) { return value.name; - }, [](SmallBalanceDeepLink value) { + }, [](SmallBalanceDeepLink) { return QString(); }, [&](SmallBalanceStarGift value) { return owner->peer(value.recipientId)->shortName(); @@ -2505,6 +2505,8 @@ void SmallBalanceBox( return value.recipientId ? owner->peer(value.recipientId)->shortName() : QString(); + }, [](SmallBalanceForSearch) { + return QString(); }); auto needed = show->session().credits().balanceValue( @@ -2556,6 +2558,9 @@ void SmallBalanceBox( lt_channel, rpl::single(Ui::Text::Bold(name)), Ui::Text::RichLangValue) + : v::is(source) + ? tr::lng_credits_small_balance_for_search( + Ui::Text::RichLangValue) : name.isEmpty() ? tr::lng_credits_small_balance_fallback( Ui::Text::RichLangValue) diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.h b/Telegram/SourceFiles/settings/settings_credits_graphics.h index a2329e5902..8dd4e12504 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -242,6 +242,8 @@ struct SmallBalanceForMessage { struct SmallBalanceForSuggest { PeerId recipientId; }; +struct SmallBalanceForSearch { +}; struct SmallBalanceSource : std::variant< SmallBalanceBot, SmallBalanceReaction, @@ -249,7 +251,8 @@ struct SmallBalanceSource : std::variant< SmallBalanceDeepLink, SmallBalanceStarGift, SmallBalanceForMessage, - SmallBalanceForSuggest> { + SmallBalanceForSuggest, + SmallBalanceForSearch> { using variant::variant; }; diff --git a/Telegram/SourceFiles/ui/controls/button_two_labels.cpp b/Telegram/SourceFiles/ui/controls/button_two_labels.cpp index 2a9bf513f4..d27529ff93 100644 --- a/Telegram/SourceFiles/ui/controls/button_two_labels.cpp +++ b/Telegram/SourceFiles/ui/controls/button_two_labels.cpp @@ -22,10 +22,12 @@ void SetButtonTwoLabels( button, std::move(title), st); + buttonTitle->show(); const auto buttonSubtitle = Ui::CreateChild( button, std::move(subtitle), subst); + buttonSubtitle->show(); buttonSubtitle->setOpacity(0.6); if (textFg) { buttonTitle->setTextColorOverride((*textFg)->c);