2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-22 02:07:24 +00:00

Implement paid global search requests.

This commit is contained in:
John Preston 2025-07-31 13:24:11 +04:00
parent 608481df38
commit b5c1046dca
10 changed files with 81 additions and 20 deletions

View File

@ -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}";

View File

@ -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;

View File

@ -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;

View File

@ -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<not_null<HistoryItem*>>::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();

View File

@ -31,7 +31,7 @@ public:
[[nodiscard]] rpl::producer<PostsSearchState> stateUpdates() const;
void setQuery(const QString &query);
void setAllowedStars(int stars);
int setAllowedStars(int stars);
void requestMore();
private:

View File

@ -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());

View File

@ -162,6 +162,7 @@ void PostsSearchIntro::setup() {
st::resaleButtonTitle,
st::resaleButtonSubtitle);
}
_content->resizeToWidth(width());
}, _button->lifetime());
}

View File

@ -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<SmallBalanceForSearch>(source)
? tr::lng_credits_small_balance_for_search(
Ui::Text::RichLangValue)
: name.isEmpty()
? tr::lng_credits_small_balance_fallback(
Ui::Text::RichLangValue)

View File

@ -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;
};

View File

@ -22,10 +22,12 @@ void SetButtonTwoLabels(
button,
std::move(title),
st);
buttonTitle->show();
const auto buttonSubtitle = Ui::CreateChild<Ui::FlatLabel>(
button,
std::move(subtitle),
subst);
buttonSubtitle->show();
buttonSubtitle->setOpacity(0.6);
if (textFg) {
buttonTitle->setTextColorOverride((*textFg)->c);