mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-22 18:27:17 +00:00
Implement paid global search requests.
This commit is contained in:
parent
608481df38
commit
b5c1046dca
@ -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_message" = "Buy **Stars** to send messages to {user}.";
|
||||||
"lng_credits_small_balance_for_messages" = "Buy **Stars** to send messages.";
|
"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_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_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_purchase_blocked" = "Sorry, you can't purchase this item with Telegram Stars.";
|
||||||
"lng_credits_enough" = "You have enough stars at the moment. {link}";
|
"lng_credits_enough" = "You have enough stars at the moment. {link}";
|
||||||
|
@ -841,13 +841,13 @@ postsSearchIntroTitle: FlatLabel(defaultFlatLabel) {
|
|||||||
}
|
}
|
||||||
align: align(top);
|
align: align(top);
|
||||||
}
|
}
|
||||||
postsSearchIntroTitleMargin: margins(20px, 0px, 20px, 12px);
|
postsSearchIntroTitleMargin: margins(20px, 0px, 20px, 4px);
|
||||||
postsSearchIntroSubtitle: FlatLabel(defaultFlatLabel) {
|
postsSearchIntroSubtitle: FlatLabel(defaultFlatLabel) {
|
||||||
textFg: windowSubTextFg;
|
textFg: windowSubTextFg;
|
||||||
minWidth: 64px;
|
minWidth: 64px;
|
||||||
align: align(top);
|
align: align(top);
|
||||||
}
|
}
|
||||||
postsSearchIntroSubtitleMargin: margins(20px, 4px, 20px, 12px);
|
postsSearchIntroSubtitleMargin: margins(20px, 4px, 20px, 16px);
|
||||||
postsSearchIntroButton: RoundButton(defaultActiveButton) {
|
postsSearchIntroButton: RoundButton(defaultActiveButton) {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
|
@ -164,7 +164,8 @@ constexpr auto kPreviewPostsLimit = 3;
|
|||||||
: state.fromPeer;
|
: state.fromPeer;
|
||||||
const auto waiting = trimmed.isEmpty()
|
const auto waiting = trimmed.isEmpty()
|
||||||
&& state.tags.empty()
|
&& state.tags.empty()
|
||||||
&& !fromPeer;
|
&& !fromPeer
|
||||||
|
&& state.tab != ChatSearchTab::PublicPosts;
|
||||||
const auto suggestAllChats = !waiting
|
const auto suggestAllChats = !waiting
|
||||||
&& state.tab == ChatSearchTab::MyMessages
|
&& state.tab == ChatSearchTab::MyMessages
|
||||||
&& state.filter != ChatTypeFilter::All;
|
&& state.filter != ChatTypeFilter::All;
|
||||||
|
@ -43,25 +43,38 @@ void PostsSearch::requestMore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PostsSearch::setQuery(const QString &query) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
_query = query;
|
_query = prepared;
|
||||||
const auto i = _entries.find(query);
|
const auto i = _entries.find(prepared);
|
||||||
if (i != end(_entries)) {
|
if (i != end(_entries)) {
|
||||||
pushStateUpdate(i->second);
|
pushStateUpdate(i->second);
|
||||||
} else if (query.isEmpty()) {
|
} else if (prepared.isEmpty()) {
|
||||||
applyQuery();
|
applyQuery();
|
||||||
} else {
|
} else {
|
||||||
_timer.callOnce(kQueryDelay);
|
_timer.callOnce(kQueryDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostsSearch::setAllowedStars(int stars) {
|
int PostsSearch::setAllowedStars(int stars) {
|
||||||
if (_query) {
|
if (!_query) {
|
||||||
_entries[*_query].allowedStars = stars;
|
return 0;
|
||||||
requestSearch(*_query);
|
} 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) {
|
void PostsSearch::pushStateUpdate(const Entry &entry) {
|
||||||
@ -118,17 +131,20 @@ void PostsSearch::requestSearch(const QString &query) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto useStars = entry.allowedStars;
|
||||||
|
entry.allowedStars = 0;
|
||||||
|
|
||||||
using Flag = MTPchannels_SearchPosts::Flag;
|
using Flag = MTPchannels_SearchPosts::Flag;
|
||||||
entry.searchId = _api.request(MTPchannels_SearchPosts(
|
entry.searchId = _api.request(MTPchannels_SearchPosts(
|
||||||
MTP_flags(Flag::f_query
|
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(), // hashtag
|
||||||
MTP_string(query),
|
MTP_string(query),
|
||||||
MTP_int(entry.offsetRate),
|
MTP_int(entry.offsetRate),
|
||||||
(entry.offsetPeer ? entry.offsetPeer->input : MTP_inputPeerEmpty()),
|
(entry.offsetPeer ? entry.offsetPeer->input : MTP_inputPeerEmpty()),
|
||||||
MTP_int(entry.offsetId),
|
MTP_int(entry.offsetId),
|
||||||
MTP_int(kPerPage),
|
MTP_int(kPerPage),
|
||||||
MTP_long(entry.allowedStars)
|
MTP_long(useStars)
|
||||||
)).done([=](const MTPmessages_Messages &result) {
|
)).done([=](const MTPmessages_Messages &result) {
|
||||||
auto &entry = _entries[query];
|
auto &entry = _entries[query];
|
||||||
entry.searchId = 0;
|
entry.searchId = 0;
|
||||||
@ -207,7 +223,11 @@ void PostsSearch::requestSearch(const QString &query) {
|
|||||||
entry.pages.clear();
|
entry.pages.clear();
|
||||||
}
|
}
|
||||||
entry.pages.push_back(std::move(messages));
|
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);
|
const auto full = entry.loaded ? count : std::max(count, totalCount);
|
||||||
entry.totalCount = full;
|
entry.totalCount = full;
|
||||||
if (initial && _query == query) {
|
if (initial && _query == query) {
|
||||||
@ -229,7 +249,7 @@ void PostsSearch::requestSearch(const QString &query) {
|
|||||||
|
|
||||||
void PostsSearch::setFloodStateFrom(const MTPDsearchPostsFlood &data) {
|
void PostsSearch::setFloodStateFrom(const MTPDsearchPostsFlood &data) {
|
||||||
_recheckTimer.cancel();
|
_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();
|
const auto next = data.vwait_till().value_or_empty();
|
||||||
if (!left && next > 0) {
|
if (!left && next > 0) {
|
||||||
const auto now = base::unixtime::now();
|
const auto now = base::unixtime::now();
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
[[nodiscard]] rpl::producer<PostsSearchState> stateUpdates() const;
|
[[nodiscard]] rpl::producer<PostsSearchState> stateUpdates() const;
|
||||||
|
|
||||||
void setQuery(const QString &query);
|
void setQuery(const QString &query);
|
||||||
void setAllowedStars(int stars);
|
int setAllowedStars(int stars);
|
||||||
void requestMore();
|
void requestMore();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -38,11 +38,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "settings/settings_common.h"
|
#include "settings/settings_common.h"
|
||||||
|
#include "settings/settings_credits_graphics.h"
|
||||||
#include "settings/settings_premium.h"
|
#include "settings/settings_premium.h"
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
#include "ui/controls/swipe_handler.h"
|
#include "ui/controls/swipe_handler.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
@ -1821,8 +1823,9 @@ bool Suggestions::consumeSearchQuery(const QString &query) {
|
|||||||
const auto tab = key.tab;
|
const auto tab = key.tab;
|
||||||
const auto type = (key.tab == Tab::Media) ? key.mediaType : Type::kCount;
|
const auto type = (key.tab == Tab::Media) ? key.mediaType : Type::kCount;
|
||||||
if (tab == Tab::Posts) {
|
if (tab == Tab::Posts) {
|
||||||
|
const auto changed = (_searchQuery != query);
|
||||||
setPostsSearchQuery(query);
|
setPostsSearchQuery(query);
|
||||||
return !query.isEmpty();
|
return changed || !query.isEmpty();
|
||||||
} else if (tab != Tab::Downloads
|
} else if (tab != Tab::Downloads
|
||||||
&& type != Type::File
|
&& type != Type::File
|
||||||
&& type != Type::Link
|
&& type != Type::Link
|
||||||
@ -1881,6 +1884,7 @@ void Suggestions::setPostsSearchQuery(const QString &query) {
|
|||||||
if (!_postsSearch) {
|
if (!_postsSearch) {
|
||||||
setupPostsSearch();
|
setupPostsSearch();
|
||||||
}
|
}
|
||||||
|
_searchQuery = query;
|
||||||
_searchQueryTimer.cancel();
|
_searchQueryTimer.cancel();
|
||||||
_postsSearch->setQuery(query);
|
_postsSearch->setQuery(query);
|
||||||
}
|
}
|
||||||
@ -1938,8 +1942,32 @@ void Suggestions::setupPostsIntro(const PostsSearchIntroState &intro) {
|
|||||||
Settings::ShowPremium(
|
Settings::ShowPremium(
|
||||||
_controller,
|
_controller,
|
||||||
u"posts_search"_q);
|
u"posts_search"_q);
|
||||||
|
} else if (!stars) {
|
||||||
|
_postsSearch->setAllowedStars(0);
|
||||||
} else {
|
} 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());
|
}, _postsSearchIntro->lifetime());
|
||||||
|
|
||||||
|
@ -162,6 +162,7 @@ void PostsSearchIntro::setup() {
|
|||||||
st::resaleButtonTitle,
|
st::resaleButtonTitle,
|
||||||
st::resaleButtonSubtitle);
|
st::resaleButtonSubtitle);
|
||||||
}
|
}
|
||||||
|
_content->resizeToWidth(width());
|
||||||
}, _button->lifetime());
|
}, _button->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2493,7 +2493,7 @@ void SmallBalanceBox(
|
|||||||
return owner->peer(peerFromChannel(value.channelId))->name();
|
return owner->peer(peerFromChannel(value.channelId))->name();
|
||||||
}, [](SmallBalanceSubscription value) {
|
}, [](SmallBalanceSubscription value) {
|
||||||
return value.name;
|
return value.name;
|
||||||
}, [](SmallBalanceDeepLink value) {
|
}, [](SmallBalanceDeepLink) {
|
||||||
return QString();
|
return QString();
|
||||||
}, [&](SmallBalanceStarGift value) {
|
}, [&](SmallBalanceStarGift value) {
|
||||||
return owner->peer(value.recipientId)->shortName();
|
return owner->peer(value.recipientId)->shortName();
|
||||||
@ -2505,6 +2505,8 @@ void SmallBalanceBox(
|
|||||||
return value.recipientId
|
return value.recipientId
|
||||||
? owner->peer(value.recipientId)->shortName()
|
? owner->peer(value.recipientId)->shortName()
|
||||||
: QString();
|
: QString();
|
||||||
|
}, [](SmallBalanceForSearch) {
|
||||||
|
return QString();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto needed = show->session().credits().balanceValue(
|
auto needed = show->session().credits().balanceValue(
|
||||||
@ -2556,6 +2558,9 @@ void SmallBalanceBox(
|
|||||||
lt_channel,
|
lt_channel,
|
||||||
rpl::single(Ui::Text::Bold(name)),
|
rpl::single(Ui::Text::Bold(name)),
|
||||||
Ui::Text::RichLangValue)
|
Ui::Text::RichLangValue)
|
||||||
|
: v::is<SmallBalanceForSearch>(source)
|
||||||
|
? tr::lng_credits_small_balance_for_search(
|
||||||
|
Ui::Text::RichLangValue)
|
||||||
: name.isEmpty()
|
: name.isEmpty()
|
||||||
? tr::lng_credits_small_balance_fallback(
|
? tr::lng_credits_small_balance_fallback(
|
||||||
Ui::Text::RichLangValue)
|
Ui::Text::RichLangValue)
|
||||||
|
@ -242,6 +242,8 @@ struct SmallBalanceForMessage {
|
|||||||
struct SmallBalanceForSuggest {
|
struct SmallBalanceForSuggest {
|
||||||
PeerId recipientId;
|
PeerId recipientId;
|
||||||
};
|
};
|
||||||
|
struct SmallBalanceForSearch {
|
||||||
|
};
|
||||||
struct SmallBalanceSource : std::variant<
|
struct SmallBalanceSource : std::variant<
|
||||||
SmallBalanceBot,
|
SmallBalanceBot,
|
||||||
SmallBalanceReaction,
|
SmallBalanceReaction,
|
||||||
@ -249,7 +251,8 @@ struct SmallBalanceSource : std::variant<
|
|||||||
SmallBalanceDeepLink,
|
SmallBalanceDeepLink,
|
||||||
SmallBalanceStarGift,
|
SmallBalanceStarGift,
|
||||||
SmallBalanceForMessage,
|
SmallBalanceForMessage,
|
||||||
SmallBalanceForSuggest> {
|
SmallBalanceForSuggest,
|
||||||
|
SmallBalanceForSearch> {
|
||||||
using variant::variant;
|
using variant::variant;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,10 +22,12 @@ void SetButtonTwoLabels(
|
|||||||
button,
|
button,
|
||||||
std::move(title),
|
std::move(title),
|
||||||
st);
|
st);
|
||||||
|
buttonTitle->show();
|
||||||
const auto buttonSubtitle = Ui::CreateChild<Ui::FlatLabel>(
|
const auto buttonSubtitle = Ui::CreateChild<Ui::FlatLabel>(
|
||||||
button,
|
button,
|
||||||
std::move(subtitle),
|
std::move(subtitle),
|
||||||
subst);
|
subst);
|
||||||
|
buttonSubtitle->show();
|
||||||
buttonSubtitle->setOpacity(0.6);
|
buttonSubtitle->setOpacity(0.6);
|
||||||
if (textFg) {
|
if (textFg) {
|
||||||
buttonTitle->setTextColorOverride((*textFg)->c);
|
buttonTitle->setTextColorOverride((*textFg)->c);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user