Support tg://stars_topup links.

This commit is contained in:
John Preston 2024-08-14 16:47:39 +02:00
parent 80b3754be1
commit eec9c8a46b
8 changed files with 97 additions and 6 deletions

View file

@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"cloud_lng_forwarded_psa_covid" = "COVID-19 Notification from {channel}";
"cloud_lng_tooltip_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. Learn more about this initiative at https://telegram.org/blog/coronavirus";
"cloud_lng_topup_purpose_subs" = "Buy **Stars** to keep your channel subscriptions.";
"cloud_lng_passport_in_ar" = "Arabic";
"cloud_lng_passport_in_az" = "Azerbaijani";
"cloud_lng_passport_in_bg" = "Bulgarian";

View file

@ -2453,7 +2453,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_credits_small_balance_about" = "Buy **Stars** and use them on **{bot}** and other miniapps.";
"lng_credits_small_balance_reaction" = "Buy **Stars** and send them to {channel} to support their posts.";
"lng_credits_small_balance_subscribe" = "Buy **Stars** and subscribe to **{channel}** and other channels.";
"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 ({balance}). {link}";
"lng_credits_enough_link" = "Topup anyway";
"lng_credits_gift_title" = "Gift Telegram Stars";

View file

@ -310,7 +310,8 @@ void ConfirmSubscriptionBox(
state->loading.force_assign(true);
const auto done = [=](Settings::SmallBalanceResult result) {
if (result == Settings::SmallBalanceResult::Success) {
if (result == Settings::SmallBalanceResult::Success
|| result == Settings::SmallBalanceResult::Already) {
sendCredits();
} else {
state->api = std::nullopt;

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_url.h"
#include "lang/lang_cloud_manager.h"
#include "lang/lang_keys.h"
#include "core/ui_integration.h" // MarkedTextContext.
#include "core/update_checker.h"
#include "core/application.h"
#include "core/click_handler_types.h"
@ -46,6 +47,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h"
#include "window/themes/window_theme_editor_box.h" // GenerateSlug.
#include "payments/payments_checkout_process.h"
#include "settings/settings_credits.h"
#include "settings/settings_credits_graphics.h"
#include "settings/settings_information.h"
#include "settings/settings_global_ttl.h"
#include "settings/settings_folders.h"
@ -1170,6 +1173,61 @@ bool ResolveBoost(
return true;
}
bool ResolveTopUp(
Window::SessionController *controller,
const Match &match,
const QVariant &context) {
if (!controller) {
return false;
}
const auto params = url_parse_params(
match->captured(1),
qthelp::UrlParamNameTransform::ToLower);
const auto amount = std::clamp(
params.value(u"balance"_q).toULongLong(),
qulonglong(1),
qulonglong(1'000'000));
const auto purpose = params.value(u"purpose"_q);
const auto weak = base::make_weak(controller);
const auto done = [=](::Settings::SmallBalanceResult result) {
if (result == ::Settings::SmallBalanceResult::Already) {
if (const auto strong = weak.get()) {
auto balance = TextWithEntities{ u"hello"_q };
const auto context = [=](not_null<QWidget*> toast) {
return Core::MarkedTextContext{
.session = &strong->session(),
.customEmojiRepaint = [=] { toast->update(); },
};
};
const auto filter = [=](const auto &...) {
strong->showSettings(::Settings::CreditsId());
return false;
};
strong->showToast(Ui::Toast::Config{
.text = tr::lng_credits_enough(
tr::now,
lt_balance,
balance,
lt_link,
Ui::Text::Link(
Ui::Text::Bold(
tr::lng_credits_enough_link(tr::now))),
Ui::Text::RichLangValue),
.textContext = context,
.filter = filter,
});
}
}
};
::Settings::MaybeRequestBalanceIncrease(
controller->uiShow(),
amount,
::Settings::SmallBalanceDeepLink{ .purpose = purpose },
[](auto) {});
return true;
}
bool ResolveChatLink(
Window::SessionController *controller,
const Match &match,
@ -1276,6 +1334,10 @@ const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
u"^message/?\\?slug=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"_q,
ResolveChatLink
},
{
u"^stars_topup/?\\?(.+)(#|$)"_q,
ResolveTopUp
},
{
u"^([^\\?]+)(\\?|#|$)"_q,
HandleUnknown

View file

@ -310,10 +310,11 @@ void WebPage::setupAdditionalData() {
: 0;
if (!_attach) {
const auto maybePhoto = details.mediaPhotoId
? _data->session().data().photo(details.mediaPhotoId)
? _data->session().data().photo(details.mediaPhotoId).get()
: nullptr;
const auto maybeDocument = details.mediaDocumentId
? _data->session().data().document(details.mediaDocumentId)
? _data->session().data().document(
details.mediaDocumentId).get()
: nullptr;
_attach = CreateAttach(
_parent,

View file

@ -60,7 +60,8 @@ void TryAddingPaidReaction(
return;
}
const auto done = [=](Settings::SmallBalanceResult result) {
if (result == Settings::SmallBalanceResult::Success) {
if (result == Settings::SmallBalanceResult::Success
|| result == Settings::SmallBalanceResult::Already) {
if (const auto item = checkItem()) {
item->addPaidReaction(count, anonymous);
if (const auto view = count ? weakView.get() : nullptr) {

View file

@ -82,6 +82,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Settings {
namespace {
const auto kTopUpPrefix = "cloud_lng_topup_purpose_";
[[nodiscard]] uint64 UniqueIdFromOption(
const Data::CreditTopupOption &d) {
const auto string = QString::number(d.credits)
@ -97,6 +99,15 @@ namespace {
return session->appConfig().get<int>(key, 1000);
}
[[nodiscard]] rpl::producer<TextWithEntities> DeepLinkBalanceAbout(
const QString &purpose) {
const auto phrase = Lang::GetNonDefaultValue(
kTopUpPrefix + purpose.toUtf8());
return phrase.isEmpty()
? tr::lng_credits_small_balance_fallback(Ui::Text::RichLangValue)
: rpl::single(Ui::Text::RichLangValue(phrase));
}
class Balance final
: public Ui::RpWidget
, public Ui::AbstractTooltipShower {
@ -1025,6 +1036,8 @@ void SmallBalanceBox(
return owner->peer(peerFromChannel(value.channelId))->name();
}, [](SmallBalanceSubscription value) {
return value.name;
}, [](SmallBalanceDeepLink value) {
return QString();
});
auto needed = show->session().credits().balanceValue(
@ -1051,6 +1064,9 @@ void SmallBalanceBox(
lt_channel,
rpl::single(Ui::Text::Bold(name)),
Ui::Text::RichLangValue)
: v::is<SmallBalanceDeepLink>(source)
? DeepLinkBalanceAbout(
v::get<SmallBalanceDeepLink>(source).purpose)
: tr::lng_credits_small_balance_about(
lt_bot,
rpl::single(TextWithEntities{ name }),
@ -1424,7 +1440,7 @@ void MaybeRequestBalanceIncrease(
const auto balance = session->credits().balance();
if (credits <= balance) {
if (const auto onstack = done) {
onstack(SmallBalanceResult::Success);
onstack(SmallBalanceResult::Already);
}
} else if (show->session().premiumPossible()) {
const auto success = [=] {

View file

@ -111,10 +111,14 @@ struct SmallBalanceReaction {
struct SmallBalanceSubscription {
QString name;
};
struct SmallBalanceDeepLink {
QString purpose;
};
struct SmallBalanceSource : std::variant<
SmallBalanceBot,
SmallBalanceReaction,
SmallBalanceSubscription> {
SmallBalanceSubscription,
SmallBalanceDeepLink> {
using variant::variant;
};
@ -126,6 +130,7 @@ void SmallBalanceBox(
Fn<void()> paid);
enum class SmallBalanceResult {
Already,
Success,
Blocked,
Cancelled,