mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support gifting premium for stars.
This commit is contained in:
parent
bd70a05861
commit
7d2878d81c
26 changed files with 321 additions and 112 deletions
BIN
Telegram/Resources/icons/payments/premium_emoji.png
Normal file
BIN
Telegram/Resources/icons/payments/premium_emoji.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 370 B |
BIN
Telegram/Resources/icons/payments/premium_emoji@2x.png
Normal file
BIN
Telegram/Resources/icons/payments/premium_emoji@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 712 B |
BIN
Telegram/Resources/icons/payments/premium_emoji@3x.png
Normal file
BIN
Telegram/Resources/icons/payments/premium_emoji@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 926 B |
|
@ -3329,6 +3329,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_premium_about" = "Give {name} access to exclusive features with Telegram Premium. {features}";
|
"lng_gift_premium_about" = "Give {name} access to exclusive features with Telegram Premium. {features}";
|
||||||
"lng_gift_premium_features" = "See Features >";
|
"lng_gift_premium_features" = "See Features >";
|
||||||
"lng_gift_premium_label" = "Premium";
|
"lng_gift_premium_label" = "Premium";
|
||||||
|
"lng_gift_premium_by_stars" = "or {amount}";
|
||||||
"lng_gift_stars_subtitle" = "Gift Stars";
|
"lng_gift_stars_subtitle" = "Gift Stars";
|
||||||
"lng_gift_stars_about" = "Give {name} gifts that can be kept on your profile or converted to Stars. {link}";
|
"lng_gift_stars_about" = "Give {name} gifts that can be kept on your profile or converted to Stars. {link}";
|
||||||
"lng_gift_stars_link" = "What are Stars >";
|
"lng_gift_stars_link" = "What are Stars >";
|
||||||
|
@ -3340,6 +3341,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_send_title" = "Send a Gift";
|
"lng_gift_send_title" = "Send a Gift";
|
||||||
"lng_gift_send_message" = "Enter Message";
|
"lng_gift_send_message" = "Enter Message";
|
||||||
"lng_gift_send_anonymous" = "Hide My Name";
|
"lng_gift_send_anonymous" = "Hide My Name";
|
||||||
|
"lng_gift_send_pay_with_stars" = "Pay with {amount}";
|
||||||
|
"lng_gift_send_stars_balance" = "Your balance is {amount}. {link}";
|
||||||
|
"lng_gift_send_stars_balance_link" = "Get More Stars >";
|
||||||
"lng_gift_send_anonymous_self" = "Hide my name and message from visitors to my profile.";
|
"lng_gift_send_anonymous_self" = "Hide my name and message from visitors to my profile.";
|
||||||
"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message.";
|
"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message.";
|
||||||
"lng_gift_send_anonymous_about_paid" = "You can hide your name from visitors to {user}'s profile. {recipient} will still see your name.";
|
"lng_gift_send_anonymous_about_paid" = "You can hide your name from visitors to {user}'s profile. {recipient} will still see your name.";
|
||||||
|
|
|
@ -479,6 +479,9 @@ rpl::producer<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
|
||||||
for (const auto &tlOption : result.v) {
|
for (const auto &tlOption : result.v) {
|
||||||
const auto &data = tlOption.data();
|
const auto &data = tlOption.data();
|
||||||
tlMapOptions[data.vusers().v].push_back(tlOption);
|
tlMapOptions[data.vusers().v].push_back(tlOption);
|
||||||
|
if (qs(data.vcurrency()) == Ui::kCreditsCurrency) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const auto token = Token{ data.vusers().v, data.vmonths().v };
|
const auto token = Token{ data.vusers().v, data.vmonths().v };
|
||||||
_stores[token] = Store{
|
_stores[token] = Store{
|
||||||
|
|
|
@ -30,11 +30,6 @@ ShortInfoBox {
|
||||||
labeledOneLine: FlatLabel;
|
labeledOneLine: FlatLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
boxStarIconEmoji: IconEmoji {
|
|
||||||
icon: icon{{ "payments/small_star", windowFg }};
|
|
||||||
padding: margins(0px, -2px, 0px, 0px);
|
|
||||||
}
|
|
||||||
|
|
||||||
countryRowHeight: 36px;
|
countryRowHeight: 36px;
|
||||||
countryRowNameFont: semiboldFont;
|
countryRowNameFont: semiboldFont;
|
||||||
countryRowNameFg: boxTextFg;
|
countryRowNameFg: boxTextFg;
|
||||||
|
|
|
@ -512,7 +512,7 @@ TextWithEntities CreditsEmoji(not_null<Main::Session*> session) {
|
||||||
|
|
||||||
TextWithEntities CreditsEmojiSmall(not_null<Main::Session*> session) {
|
TextWithEntities CreditsEmojiSmall(not_null<Main::Session*> session) {
|
||||||
return Ui::Text::IconEmoji(
|
return Ui::Text::IconEmoji(
|
||||||
&st::boxStarIconEmoji,
|
&st::starIconEmoji,
|
||||||
QString(QChar(0x2B50)));
|
QString(QChar(0x2B50)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,7 +570,7 @@ not_null<FlatLabel*> SetButtonMarkedLabel(
|
||||||
}, st, textFg);
|
}, st, textFg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendStarGift(
|
void SendStarsForm(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
std::shared_ptr<Payments::CreditsFormData> data,
|
std::shared_ptr<Payments::CreditsFormData> data,
|
||||||
Fn<void(std::optional<QString>)> done) {
|
Fn<void(std::optional<QString>)> done) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ not_null<FlatLabel*> SetButtonMarkedLabel(
|
||||||
const style::FlatLabel &st,
|
const style::FlatLabel &st,
|
||||||
const style::color *textFg = nullptr);
|
const style::color *textFg = nullptr);
|
||||||
|
|
||||||
void SendStarGift(
|
void SendStarsForm(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
std::shared_ptr<Payments::CreditsFormData> data,
|
std::shared_ptr<Payments::CreditsFormData> data,
|
||||||
Fn<void(std::optional<QString>)> done);
|
Fn<void(std::optional<QString>)> done);
|
||||||
|
|
|
@ -128,6 +128,7 @@ struct GiftDetails {
|
||||||
uint64 randomId = 0;
|
uint64 randomId = 0;
|
||||||
bool anonymous = false;
|
bool anonymous = false;
|
||||||
bool upgraded = false;
|
bool upgraded = false;
|
||||||
|
bool byStars = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PreviewDelegate final : public DefaultElementDelegate {
|
class PreviewDelegate final : public DefaultElementDelegate {
|
||||||
|
@ -497,7 +498,14 @@ void PreviewWrap::prepare(rpl::producer<GiftDetails> details) {
|
||||||
std::move(details) | rpl::start_with_next([=](GiftDetails details) {
|
std::move(details) | rpl::start_with_next([=](GiftDetails details) {
|
||||||
const auto &descriptor = details.descriptor;
|
const auto &descriptor = details.descriptor;
|
||||||
const auto cost = v::match(descriptor, [&](GiftTypePremium data) {
|
const auto cost = v::match(descriptor, [&](GiftTypePremium data) {
|
||||||
return FillAmountAndCurrency(data.cost, data.currency, true);
|
const auto stars = (details.byStars && data.stars)
|
||||||
|
? data.stars
|
||||||
|
: (data.currency == kCreditsCurrency)
|
||||||
|
? data.cost
|
||||||
|
: 0;
|
||||||
|
return stars
|
||||||
|
? tr::lng_gift_stars_title(tr::now, lt_count, stars)
|
||||||
|
: FillAmountAndCurrency(data.cost, data.currency, true);
|
||||||
}, [&](GiftTypeStars data) {
|
}, [&](GiftTypeStars data) {
|
||||||
const auto stars = data.info.stars
|
const auto stars = data.info.stars
|
||||||
+ (details.upgraded ? data.info.starsToUpgrade : 0);
|
+ (details.upgraded ? data.info.starsToUpgrade : 0);
|
||||||
|
@ -1118,16 +1126,35 @@ void SendGift(
|
||||||
std::shared_ptr<Api::PremiumGiftCodeOptions> api,
|
std::shared_ptr<Api::PremiumGiftCodeOptions> api,
|
||||||
const GiftDetails &details,
|
const GiftDetails &details,
|
||||||
Fn<void(Payments::CheckoutResult)> done) {
|
Fn<void(Payments::CheckoutResult)> done) {
|
||||||
|
const auto processNonPanelPaymentFormFactory
|
||||||
|
= Payments::ProcessNonPanelPaymentFormFactory(window, done);
|
||||||
v::match(details.descriptor, [&](const GiftTypePremium &gift) {
|
v::match(details.descriptor, [&](const GiftTypePremium &gift) {
|
||||||
auto invoice = api->invoice(1, gift.months);
|
if (details.byStars && gift.stars) {
|
||||||
invoice.purpose = Payments::InvoicePremiumGiftCodeUsers{
|
auto invoice = Payments::InvoicePremiumGiftCode{
|
||||||
.users = { peer->asUser() },
|
.purpose = Payments::InvoicePremiumGiftCodeUsers{
|
||||||
.message = details.text,
|
.users = { peer->asUser() },
|
||||||
};
|
.message = details.text,
|
||||||
Payments::CheckoutProcess::Start(std::move(invoice), done);
|
},
|
||||||
|
.currency = Ui::kCreditsCurrency,
|
||||||
|
.randomId = details.randomId,
|
||||||
|
.amount = uint64(gift.stars),
|
||||||
|
.storeQuantity = 1,
|
||||||
|
.users = 1,
|
||||||
|
.months = gift.months,
|
||||||
|
};
|
||||||
|
Payments::CheckoutProcess::Start(
|
||||||
|
std::move(invoice),
|
||||||
|
done,
|
||||||
|
processNonPanelPaymentFormFactory);
|
||||||
|
} else {
|
||||||
|
auto invoice = api->invoice(1, gift.months);
|
||||||
|
invoice.purpose = Payments::InvoicePremiumGiftCodeUsers{
|
||||||
|
.users = { peer->asUser() },
|
||||||
|
.message = details.text,
|
||||||
|
};
|
||||||
|
Payments::CheckoutProcess::Start(std::move(invoice), done);
|
||||||
|
}
|
||||||
}, [&](const GiftTypeStars &gift) {
|
}, [&](const GiftTypeStars &gift) {
|
||||||
const auto processNonPanelPaymentFormFactory
|
|
||||||
= Payments::ProcessNonPanelPaymentFormFactory(window, done);
|
|
||||||
Payments::CheckoutProcess::Start(Payments::InvoiceStarGift{
|
Payments::CheckoutProcess::Start(Payments::InvoiceStarGift{
|
||||||
.giftId = gift.info.id,
|
.giftId = gift.info.id,
|
||||||
.randomId = details.randomId,
|
.randomId = details.randomId,
|
||||||
|
@ -1459,9 +1486,14 @@ void SendGiftBox(
|
||||||
auto cost = state->details.value(
|
auto cost = state->details.value(
|
||||||
) | rpl::map([session](const GiftDetails &details) {
|
) | rpl::map([session](const GiftDetails &details) {
|
||||||
return v::match(details.descriptor, [&](const GiftTypePremium &data) {
|
return v::match(details.descriptor, [&](const GiftTypePremium &data) {
|
||||||
if (data.currency == kCreditsCurrency) {
|
const auto stars = (details.byStars && data.stars)
|
||||||
|
? data.stars
|
||||||
|
: (data.currency == kCreditsCurrency)
|
||||||
|
? data.cost
|
||||||
|
: 0;
|
||||||
|
if (stars) {
|
||||||
return CreditsEmojiSmall(session).append(
|
return CreditsEmojiSmall(session).append(
|
||||||
Lang::FormatCountDecimal(std::abs(data.cost)));
|
Lang::FormatCountDecimal(std::abs(stars)));
|
||||||
}
|
}
|
||||||
return TextWithEntities{
|
return TextWithEntities{
|
||||||
FillAmountAndCurrency(data.cost, data.currency),
|
FillAmountAndCurrency(data.cost, data.currency),
|
||||||
|
@ -1580,10 +1612,56 @@ void SendGiftBox(
|
||||||
}, container->lifetime());
|
}, container->lifetime());
|
||||||
AddSkip(container);
|
AddSkip(container);
|
||||||
}
|
}
|
||||||
v::match(descriptor, [&](const GiftTypePremium &) {
|
v::match(descriptor, [&](const GiftTypePremium &data) {
|
||||||
AddDividerText(messageInner, tr::lng_gift_send_premium_about(
|
AddDividerText(messageInner, tr::lng_gift_send_premium_about(
|
||||||
lt_user,
|
lt_user,
|
||||||
rpl::single(peer->shortName())));
|
rpl::single(peer->shortName())));
|
||||||
|
|
||||||
|
if (const auto byStars = data.stars) {
|
||||||
|
const auto star = Ui::Text::IconEmoji(&st::starIconEmojiColored);
|
||||||
|
AddSkip(container);
|
||||||
|
container->add(
|
||||||
|
object_ptr<SettingsButton>(
|
||||||
|
container,
|
||||||
|
tr::lng_gift_send_pay_with_stars(
|
||||||
|
lt_amount,
|
||||||
|
rpl::single(base::duplicate(star).append(Lang::FormatCountDecimal(byStars))),
|
||||||
|
Ui::Text::WithEntities),
|
||||||
|
st::settingsButtonNoIcon)
|
||||||
|
)->toggleOn(rpl::single(false))->toggledValue(
|
||||||
|
) | rpl::start_with_next([=](bool toggled) {
|
||||||
|
auto now = state->details.current();
|
||||||
|
now.byStars = toggled;
|
||||||
|
state->details = std::move(now);
|
||||||
|
}, container->lifetime());
|
||||||
|
AddSkip(container);
|
||||||
|
|
||||||
|
const auto balance = AddDividerText(
|
||||||
|
container,
|
||||||
|
tr::lng_gift_send_stars_balance(
|
||||||
|
lt_amount,
|
||||||
|
peer->session().credits().balanceValue(
|
||||||
|
) | rpl::map([=](StarsAmount amount) {
|
||||||
|
return base::duplicate(star).append(
|
||||||
|
Lang::FormatStarsAmountDecimal(amount));
|
||||||
|
}),
|
||||||
|
lt_link,
|
||||||
|
tr::lng_gift_send_stars_balance_link(
|
||||||
|
) | Ui::Text::ToLink(),
|
||||||
|
Ui::Text::WithEntities));
|
||||||
|
struct State {
|
||||||
|
Settings::BuyStarsHandler buyStars;
|
||||||
|
rpl::variable<bool> loading;
|
||||||
|
};
|
||||||
|
const auto state = balance->lifetime().make_state<State>();
|
||||||
|
state->loading = state->buyStars.loadingValue();
|
||||||
|
balance->setClickHandlerFilter([=](const auto &...) {
|
||||||
|
if (!state->loading.current()) {
|
||||||
|
state->buyStars.handler(window->uiShow())();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}, [&](const GiftTypeStars &) {
|
}, [&](const GiftTypeStars &) {
|
||||||
AddDividerText(container, peer->isSelf()
|
AddDividerText(container, peer->isSelf()
|
||||||
? tr::lng_gift_send_anonymous_self()
|
? tr::lng_gift_send_anonymous_self()
|
||||||
|
@ -1618,9 +1696,13 @@ void SendGiftBox(
|
||||||
const auto weak = MakeWeak(box);
|
const auto weak = MakeWeak(box);
|
||||||
const auto done = [=](Payments::CheckoutResult result) {
|
const auto done = [=](Payments::CheckoutResult result) {
|
||||||
if (result == Payments::CheckoutResult::Paid) {
|
if (result == Payments::CheckoutResult::Paid) {
|
||||||
|
if (details.byStars
|
||||||
|
|| v::is<GiftTypeStars>(details.descriptor)) {
|
||||||
|
window->session().credits().load(true);
|
||||||
|
}
|
||||||
const auto copy = state->media;
|
const auto copy = state->media;
|
||||||
window->showPeerHistory(peer);
|
window->showPeerHistory(peer);
|
||||||
ShowSentToast(window, descriptor, details);
|
ShowSentToast(window, details.descriptor, details);
|
||||||
}
|
}
|
||||||
if (const auto strong = weak.data()) {
|
if (const auto strong = weak.data()) {
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
|
@ -1853,6 +1935,8 @@ void GiftBox(
|
||||||
box->setCustomCornersFilling(RectPart::FullTop);
|
box->setCustomCornersFilling(RectPart::FullTop);
|
||||||
box->addButton(tr::lng_create_group_back(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_create_group_back(), [=] { box->closeBox(); });
|
||||||
|
|
||||||
|
window->session().credits().load();
|
||||||
|
|
||||||
FillBg(box);
|
FillBg(box);
|
||||||
|
|
||||||
const auto &stUser = st::premiumGiftsUserpicButton;
|
const auto &stUser = st::premiumGiftsUserpicButton;
|
||||||
|
|
|
@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
#include "styles/style_credits.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
#include "base/qt/qt_common_adapters.h"
|
#include "base/qt/qt_common_adapters.h"
|
||||||
|
|
||||||
|
@ -1282,7 +1283,7 @@ void SelectTextInFieldWithMargins(
|
||||||
}
|
}
|
||||||
|
|
||||||
TextWithEntities PaidSendButtonText(tr::now_t, int stars) {
|
TextWithEntities PaidSendButtonText(tr::now_t, int stars) {
|
||||||
return Ui::Text::IconEmoji(&st::boxStarIconEmoji).append(
|
return Ui::Text::IconEmoji(&st::starIconEmoji).append(
|
||||||
Lang::FormatCountToShort(stars).string);
|
Lang::FormatCountToShort(stars).string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,14 @@ const auto CommandByName = base::flat_map<QString, Command>{
|
||||||
{ u"first_chat"_q , Command::ChatFirst },
|
{ u"first_chat"_q , Command::ChatFirst },
|
||||||
{ u"last_chat"_q , Command::ChatLast },
|
{ u"last_chat"_q , Command::ChatLast },
|
||||||
{ u"self_chat"_q , Command::ChatSelf },
|
{ u"self_chat"_q , Command::ChatSelf },
|
||||||
|
{ u"pinned_chat1"_q , Command::ChatPinned1 },
|
||||||
|
{ u"pinned_chat2"_q , Command::ChatPinned2 },
|
||||||
|
{ u"pinned_chat3"_q , Command::ChatPinned3 },
|
||||||
|
{ u"pinned_chat4"_q , Command::ChatPinned4 },
|
||||||
|
{ u"pinned_chat5"_q , Command::ChatPinned5 },
|
||||||
|
{ u"pinned_chat6"_q , Command::ChatPinned6 },
|
||||||
|
{ u"pinned_chat7"_q , Command::ChatPinned7 },
|
||||||
|
{ u"pinned_chat8"_q , Command::ChatPinned8 },
|
||||||
|
|
||||||
{ u"previous_folder"_q , Command::FolderPrevious },
|
{ u"previous_folder"_q , Command::FolderPrevious },
|
||||||
{ u"next_folder"_q , Command::FolderNext },
|
{ u"next_folder"_q , Command::FolderNext },
|
||||||
|
|
|
@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
#include "styles/style_credits.h" // giftBoxByStarsStyle
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1027,6 +1028,14 @@ TextWithEntities CustomEmojiManager::creditsEmoji(QMargins padding) {
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities CustomEmojiManager::ministarEmoji(QMargins padding) {
|
||||||
|
return Ui::Text::SingleCustomEmoji(
|
||||||
|
registerInternalEmoji(
|
||||||
|
Ui::GenerateStars(st::giftBoxByStarsStyle.font->height, 1),
|
||||||
|
padding,
|
||||||
|
false));
|
||||||
|
}
|
||||||
|
|
||||||
QString CustomEmojiManager::registerInternalEmoji(
|
QString CustomEmojiManager::registerInternalEmoji(
|
||||||
QImage emoji,
|
QImage emoji,
|
||||||
QMargins padding,
|
QMargins padding,
|
||||||
|
|
|
@ -100,6 +100,7 @@ public:
|
||||||
[[nodiscard]] uint64 coloredSetId() const;
|
[[nodiscard]] uint64 coloredSetId() const;
|
||||||
|
|
||||||
[[nodiscard]] TextWithEntities creditsEmoji(QMargins padding = {});
|
[[nodiscard]] TextWithEntities creditsEmoji(QMargins padding = {});
|
||||||
|
[[nodiscard]] TextWithEntities ministarEmoji(QMargins padding = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr auto kSizeCount = int(SizeTag::kCount);
|
static constexpr auto kSizeCount = int(SizeTag::kCount);
|
||||||
|
|
|
@ -85,13 +85,11 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
v::match(descriptor, [&](const GiftTypePremium &data) {
|
v::match(descriptor, [&](const GiftTypePremium &data) {
|
||||||
const auto months = data.months;
|
const auto months = data.months;
|
||||||
const auto years = (months % 12) ? 0 : months / 12;
|
|
||||||
_text = Ui::Text::String(st::giftBoxGiftHeight / 4);
|
_text = Ui::Text::String(st::giftBoxGiftHeight / 4);
|
||||||
_text.setMarkedText(
|
_text.setMarkedText(
|
||||||
st::defaultTextStyle,
|
st::defaultTextStyle,
|
||||||
Ui::Text::Bold(years
|
Ui::Text::Bold(
|
||||||
? tr::lng_years(tr::now, lt_count, years)
|
tr::lng_months(tr::now, lt_count, months)
|
||||||
: tr::lng_months(tr::now, lt_count, months)
|
|
||||||
).append('\n').append(
|
).append('\n').append(
|
||||||
tr::lng_gift_premium_label(tr::now)
|
tr::lng_gift_premium_label(tr::now)
|
||||||
));
|
));
|
||||||
|
@ -101,6 +99,18 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
|
||||||
data.cost,
|
data.cost,
|
||||||
data.currency,
|
data.currency,
|
||||||
true));
|
true));
|
||||||
|
if (const auto stars = data.stars) {
|
||||||
|
const auto starsText = QString::number(stars);
|
||||||
|
_byStars.setMarkedText(
|
||||||
|
st::giftBoxByStarsStyle,
|
||||||
|
tr::lng_gift_premium_by_stars(
|
||||||
|
tr::now,
|
||||||
|
lt_amount,
|
||||||
|
_delegate->ministar().append(' ' + starsText),
|
||||||
|
Ui::Text::WithEntities),
|
||||||
|
kMarkupTextOptions,
|
||||||
|
_delegate->textContext());
|
||||||
|
}
|
||||||
_userpic = nullptr;
|
_userpic = nullptr;
|
||||||
if (!_stars) {
|
if (!_stars) {
|
||||||
_stars.emplace(this, true, starsType);
|
_stars.emplace(this, true, starsType);
|
||||||
|
@ -170,7 +180,9 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
|
||||||
QSize(buttonw, buttonh)
|
QSize(buttonw, buttonh)
|
||||||
).marginsAdded(st::giftBoxButtonPadding);
|
).marginsAdded(st::giftBoxButtonPadding);
|
||||||
const auto skipy = _delegate->buttonSize().height()
|
const auto skipy = _delegate->buttonSize().height()
|
||||||
- st::giftBoxButtonBottom
|
- (_byStars.isEmpty()
|
||||||
|
? st::giftBoxButtonBottom
|
||||||
|
: st::giftBoxButtonBottomByStars)
|
||||||
- inner.height();
|
- inner.height();
|
||||||
const auto skipx = (width() - inner.width()) / 2;
|
const auto skipx = (width() - inner.width()) / 2;
|
||||||
const auto outer = (width() - 2 * skipx);
|
const auto outer = (width() - 2 * skipx);
|
||||||
|
@ -355,7 +367,9 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
||||||
? st::giftBoxSmallStickerTop
|
? st::giftBoxSmallStickerTop
|
||||||
: _text.isEmpty()
|
: _text.isEmpty()
|
||||||
? st::giftBoxStickerStarTop
|
? st::giftBoxStickerStarTop
|
||||||
: st::giftBoxStickerTop),
|
: _byStars.isEmpty()
|
||||||
|
? st::giftBoxStickerTop
|
||||||
|
: st::giftBoxStickerTopByStars),
|
||||||
size.width(),
|
size.width(),
|
||||||
size.height()),
|
size.height()),
|
||||||
frame);
|
frame);
|
||||||
|
@ -367,7 +381,9 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
||||||
? st::giftBoxSmallStickerTop
|
? st::giftBoxSmallStickerTop
|
||||||
: _text.isEmpty()
|
: _text.isEmpty()
|
||||||
? st::giftBoxStickerStarTop
|
? st::giftBoxStickerStarTop
|
||||||
: st::giftBoxStickerTop));
|
: _byStars.isEmpty()
|
||||||
|
? st::giftBoxStickerTop
|
||||||
|
: st::giftBoxStickerTopByStars));
|
||||||
_delegate->hiddenMark()->paint(
|
_delegate->hiddenMark()->paint(
|
||||||
p,
|
p,
|
||||||
frame,
|
frame,
|
||||||
|
@ -473,8 +489,9 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
||||||
if (!_text.isEmpty()) {
|
if (!_text.isEmpty()) {
|
||||||
p.setPen(st::windowFg);
|
p.setPen(st::windowFg);
|
||||||
_text.draw(p, {
|
_text.draw(p, {
|
||||||
.position = (position
|
.position = (position + QPoint(0, _byStars.isEmpty()
|
||||||
+ QPoint(0, st::giftBoxPremiumTextTop)),
|
? st::giftBoxPremiumTextTop
|
||||||
|
: st::giftBoxPremiumTextTopByStars)),
|
||||||
.availableWidth = singlew,
|
.availableWidth = singlew,
|
||||||
.align = style::al_top,
|
.align = style::al_top,
|
||||||
});
|
});
|
||||||
|
@ -492,6 +509,17 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
||||||
+ QPoint(padding.left(), padding.top())),
|
+ QPoint(padding.left(), padding.top())),
|
||||||
.availableWidth = _price.maxWidth(),
|
.availableWidth = _price.maxWidth(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!_byStars.isEmpty()) {
|
||||||
|
p.setPen(st::creditsFg);
|
||||||
|
_byStars.draw(p, {
|
||||||
|
.position = QPoint(
|
||||||
|
position.x(),
|
||||||
|
_button.y() + _button.height() + st::giftBoxByStarsSkip),
|
||||||
|
.availableWidth = singlew,
|
||||||
|
.align = style::al_top,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,6 +543,12 @@ TextWithEntities Delegate::star() {
|
||||||
return owner->customEmojiManager().creditsEmoji();
|
return owner->customEmojiManager().creditsEmoji();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities Delegate::ministar() {
|
||||||
|
const auto owner = &_window->session().data();
|
||||||
|
const auto top = st::giftBoxByStarsStarTop;
|
||||||
|
return owner->customEmojiManager().ministarEmoji({ 0, top, 0, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
std::any Delegate::textContext() {
|
std::any Delegate::textContext() {
|
||||||
return Core::MarkedTextContext{
|
return Core::MarkedTextContext{
|
||||||
.session = &_window->session(),
|
.session = &_window->session(),
|
||||||
|
|
|
@ -102,6 +102,7 @@ enum class GiftButtonMode {
|
||||||
class GiftButtonDelegate {
|
class GiftButtonDelegate {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] virtual TextWithEntities star() = 0;
|
[[nodiscard]] virtual TextWithEntities star() = 0;
|
||||||
|
[[nodiscard]] virtual TextWithEntities ministar() = 0;
|
||||||
[[nodiscard]] virtual std::any textContext() = 0;
|
[[nodiscard]] virtual std::any textContext() = 0;
|
||||||
[[nodiscard]] virtual QSize buttonSize() = 0;
|
[[nodiscard]] virtual QSize buttonSize() = 0;
|
||||||
[[nodiscard]] virtual QMargins buttonExtend() = 0;
|
[[nodiscard]] virtual QMargins buttonExtend() = 0;
|
||||||
|
@ -144,6 +145,7 @@ private:
|
||||||
GiftDescriptor _descriptor;
|
GiftDescriptor _descriptor;
|
||||||
Ui::Text::String _text;
|
Ui::Text::String _text;
|
||||||
Ui::Text::String _price;
|
Ui::Text::String _price;
|
||||||
|
Ui::Text::String _byStars;
|
||||||
std::shared_ptr<Ui::DynamicImage> _userpic;
|
std::shared_ptr<Ui::DynamicImage> _userpic;
|
||||||
QImage _uniqueBackgroundCache;
|
QImage _uniqueBackgroundCache;
|
||||||
std::unique_ptr<Ui::Text::CustomEmoji> _uniquePatternEmoji;
|
std::unique_ptr<Ui::Text::CustomEmoji> _uniquePatternEmoji;
|
||||||
|
@ -170,6 +172,7 @@ public:
|
||||||
~Delegate();
|
~Delegate();
|
||||||
|
|
||||||
TextWithEntities star() override;
|
TextWithEntities star() override;
|
||||||
|
TextWithEntities ministar() override;
|
||||||
std::any textContext() override;
|
std::any textContext() override;
|
||||||
QSize buttonSize() override;
|
QSize buttonSize() override;
|
||||||
QMargins buttonExtend() override;
|
QMargins buttonExtend() override;
|
||||||
|
|
|
@ -66,7 +66,6 @@ void CheckoutProcess::Start(
|
||||||
Mode mode,
|
Mode mode,
|
||||||
Fn<void(CheckoutResult)> reactivate,
|
Fn<void(CheckoutResult)> reactivate,
|
||||||
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess) {
|
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess) {
|
||||||
const auto hasNonPanelPaymentFormProcess = !!nonPanelPaymentFormProcess;
|
|
||||||
auto &processes = LookupSessionProcesses(&item->history()->session());
|
auto &processes = LookupSessionProcesses(&item->history()->session());
|
||||||
const auto media = item->media();
|
const auto media = item->media();
|
||||||
const auto invoice = media ? media->invoice() : nullptr;
|
const auto invoice = media ? media->invoice() : nullptr;
|
||||||
|
@ -87,9 +86,7 @@ void CheckoutProcess::Start(
|
||||||
i->second->setReactivateCallback(std::move(reactivate));
|
i->second->setReactivateCallback(std::move(reactivate));
|
||||||
i->second->setNonPanelPaymentFormProcess(
|
i->second->setNonPanelPaymentFormProcess(
|
||||||
std::move(nonPanelPaymentFormProcess));
|
std::move(nonPanelPaymentFormProcess));
|
||||||
if (!hasNonPanelPaymentFormProcess) {
|
i->second->requestActivate();
|
||||||
i->second->requestActivate();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto j = processes.byItem.emplace(
|
const auto j = processes.byItem.emplace(
|
||||||
|
@ -100,9 +97,7 @@ void CheckoutProcess::Start(
|
||||||
std::move(reactivate),
|
std::move(reactivate),
|
||||||
std::move(nonPanelPaymentFormProcess),
|
std::move(nonPanelPaymentFormProcess),
|
||||||
PrivateTag{})).first;
|
PrivateTag{})).first;
|
||||||
if (!hasNonPanelPaymentFormProcess) {
|
j->second->requestActivate();
|
||||||
j->second->requestActivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckoutProcess::Start(
|
void CheckoutProcess::Start(
|
||||||
|
@ -110,16 +105,13 @@ void CheckoutProcess::Start(
|
||||||
const QString &slug,
|
const QString &slug,
|
||||||
Fn<void(CheckoutResult)> reactivate,
|
Fn<void(CheckoutResult)> reactivate,
|
||||||
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess) {
|
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess) {
|
||||||
const auto hasNonPanelPaymentFormProcess = !!nonPanelPaymentFormProcess;
|
|
||||||
auto &processes = LookupSessionProcesses(session);
|
auto &processes = LookupSessionProcesses(session);
|
||||||
const auto i = processes.bySlug.find(slug);
|
const auto i = processes.bySlug.find(slug);
|
||||||
if (i != end(processes.bySlug)) {
|
if (i != end(processes.bySlug)) {
|
||||||
i->second->setReactivateCallback(std::move(reactivate));
|
i->second->setReactivateCallback(std::move(reactivate));
|
||||||
i->second->setNonPanelPaymentFormProcess(
|
i->second->setNonPanelPaymentFormProcess(
|
||||||
std::move(nonPanelPaymentFormProcess));
|
std::move(nonPanelPaymentFormProcess));
|
||||||
if (!hasNonPanelPaymentFormProcess) {
|
i->second->requestActivate();
|
||||||
i->second->requestActivate();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto j = processes.bySlug.emplace(
|
const auto j = processes.bySlug.emplace(
|
||||||
|
@ -130,20 +122,21 @@ void CheckoutProcess::Start(
|
||||||
std::move(reactivate),
|
std::move(reactivate),
|
||||||
std::move(nonPanelPaymentFormProcess),
|
std::move(nonPanelPaymentFormProcess),
|
||||||
PrivateTag{})).first;
|
PrivateTag{})).first;
|
||||||
if (!hasNonPanelPaymentFormProcess) {
|
j->second->requestActivate();
|
||||||
j->second->requestActivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckoutProcess::Start(
|
void CheckoutProcess::Start(
|
||||||
InvoicePremiumGiftCode giftCodeInvoice,
|
InvoicePremiumGiftCode giftCodeInvoice,
|
||||||
Fn<void(CheckoutResult)> reactivate) {
|
Fn<void(CheckoutResult)> reactivate,
|
||||||
|
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess) {
|
||||||
const auto randomId = giftCodeInvoice.randomId;
|
const auto randomId = giftCodeInvoice.randomId;
|
||||||
auto id = InvoiceId{ std::move(giftCodeInvoice) };
|
auto id = InvoiceId{ std::move(giftCodeInvoice) };
|
||||||
auto &processes = LookupSessionProcesses(SessionFromId(id));
|
auto &processes = LookupSessionProcesses(SessionFromId(id));
|
||||||
const auto i = processes.byRandomId.find(randomId);
|
const auto i = processes.byRandomId.find(randomId);
|
||||||
if (i != end(processes.byRandomId)) {
|
if (i != end(processes.byRandomId)) {
|
||||||
i->second->setReactivateCallback(std::move(reactivate));
|
i->second->setReactivateCallback(std::move(reactivate));
|
||||||
|
i->second->setNonPanelPaymentFormProcess(
|
||||||
|
std::move(nonPanelPaymentFormProcess));
|
||||||
i->second->requestActivate();
|
i->second->requestActivate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +146,7 @@ void CheckoutProcess::Start(
|
||||||
std::move(id),
|
std::move(id),
|
||||||
Mode::Payment,
|
Mode::Payment,
|
||||||
std::move(reactivate),
|
std::move(reactivate),
|
||||||
nullptr,
|
std::move(nonPanelPaymentFormProcess),
|
||||||
PrivateTag{})).first;
|
PrivateTag{})).first;
|
||||||
j->second->requestActivate();
|
j->second->requestActivate();
|
||||||
}
|
}
|
||||||
|
@ -372,7 +365,9 @@ void CheckoutProcess::setNonPanelPaymentFormProcess(
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckoutProcess::requestActivate() {
|
void CheckoutProcess::requestActivate() {
|
||||||
_panel->requestActivate();
|
if (!_nonPanelPaymentFormProcess) {
|
||||||
|
_panel->requestActivate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::PanelDelegate*> CheckoutProcess::panelDelegate() {
|
not_null<Ui::PanelDelegate*> CheckoutProcess::panelDelegate() {
|
||||||
|
|
|
@ -88,7 +88,8 @@ public:
|
||||||
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess);
|
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess);
|
||||||
static void Start(
|
static void Start(
|
||||||
InvoicePremiumGiftCode giftCodeInvoice,
|
InvoicePremiumGiftCode giftCodeInvoice,
|
||||||
Fn<void(CheckoutResult)> reactivate);
|
Fn<void(CheckoutResult)> reactivate,
|
||||||
|
Fn<void(NonPanelPaymentForm)> nonPanelPaymentFormProcess = nullptr);
|
||||||
static void Start(
|
static void Start(
|
||||||
InvoiceCredits creditsInvoice,
|
InvoiceCredits creditsInvoice,
|
||||||
Fn<void(CheckoutResult)> reactivate);
|
Fn<void(CheckoutResult)> reactivate);
|
||||||
|
|
|
@ -219,6 +219,13 @@ MTPinputStorePaymentPurpose InvoiceCreditsGiveawayToTL(
|
||||||
MTP_int(invoice.users));
|
MTP_int(invoice.users));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPremiumForStarsInvoice(const InvoiceId &id) {
|
||||||
|
const auto giftCode = std::get_if<InvoicePremiumGiftCode>(&id.value);
|
||||||
|
return giftCode
|
||||||
|
&& !giftCode->creditsAmount
|
||||||
|
&& (giftCode->currency == ::Ui::kCreditsCurrency);
|
||||||
|
}
|
||||||
|
|
||||||
Form::Form(InvoiceId id, bool receipt)
|
Form::Form(InvoiceId id, bool receipt)
|
||||||
: _id(id)
|
: _id(id)
|
||||||
, _session(SessionFromId(id))
|
, _session(SessionFromId(id))
|
||||||
|
@ -412,12 +419,29 @@ MTPInputInvoice Form::inputInvoice() const {
|
||||||
MTP_long(giftCode.amount));
|
MTP_long(giftCode.amount));
|
||||||
const auto users = std::get_if<InvoicePremiumGiftCodeUsers>(
|
const auto users = std::get_if<InvoicePremiumGiftCodeUsers>(
|
||||||
&giftCode.purpose);
|
&giftCode.purpose);
|
||||||
if (users) {
|
auto message = (users && !users->message.empty())
|
||||||
|
? MTP_textWithEntities(
|
||||||
|
MTP_string(users->message.text),
|
||||||
|
Api::EntitiesToMTP(
|
||||||
|
&users->users.front()->session(),
|
||||||
|
users->message.entities,
|
||||||
|
Api::ConvertOption::SkipLocal))
|
||||||
|
: std::optional<MTPTextWithEntities>();
|
||||||
|
if (users
|
||||||
|
&& users->users.size() == 1
|
||||||
|
&& giftCode.currency == ::Ui::kCreditsCurrency) {
|
||||||
|
using Flag = MTPDinputInvoicePremiumGiftStars::Flag;
|
||||||
|
return MTP_inputInvoicePremiumGiftStars(
|
||||||
|
MTP_flags(message ? Flag::f_message : Flag()),
|
||||||
|
users->users.front()->inputUser,
|
||||||
|
MTP_int(giftCode.months),
|
||||||
|
message.value_or(MTPTextWithEntities()));
|
||||||
|
} else if (users) {
|
||||||
using Flag = MTPDinputStorePaymentPremiumGiftCode::Flag;
|
using Flag = MTPDinputStorePaymentPremiumGiftCode::Flag;
|
||||||
return MTP_inputInvoicePremiumGiftCode(
|
return MTP_inputInvoicePremiumGiftCode(
|
||||||
MTP_inputStorePaymentPremiumGiftCode(
|
MTP_inputStorePaymentPremiumGiftCode(
|
||||||
MTP_flags((users->boostPeer ? Flag::f_boost_peer : Flag())
|
MTP_flags((users->boostPeer ? Flag::f_boost_peer : Flag())
|
||||||
| (users->message.empty() ? Flag(0) : Flag::f_message)),
|
| (message ? Flag::f_message : Flag())),
|
||||||
MTP_vector_from_range(ranges::views::all(
|
MTP_vector_from_range(ranges::views::all(
|
||||||
users->users
|
users->users
|
||||||
) | ranges::views::transform([](not_null<UserData*> user) {
|
) | ranges::views::transform([](not_null<UserData*> user) {
|
||||||
|
@ -426,12 +450,7 @@ MTPInputInvoice Form::inputInvoice() const {
|
||||||
users->boostPeer ? users->boostPeer->input : MTPInputPeer(),
|
users->boostPeer ? users->boostPeer->input : MTPInputPeer(),
|
||||||
MTP_string(giftCode.currency),
|
MTP_string(giftCode.currency),
|
||||||
MTP_long(giftCode.amount),
|
MTP_long(giftCode.amount),
|
||||||
MTP_textWithEntities(
|
message.value_or(MTPTextWithEntities())),
|
||||||
MTP_string(users->message.text),
|
|
||||||
Api::EntitiesToMTP(
|
|
||||||
&users->users.front()->session(),
|
|
||||||
users->message.entities,
|
|
||||||
Api::ConvertOption::SkipLocal))),
|
|
||||||
option);
|
option);
|
||||||
} else {
|
} else {
|
||||||
return MTP_inputInvoicePremiumGiftCode(
|
return MTP_inputInvoicePremiumGiftCode(
|
||||||
|
|
|
@ -287,6 +287,8 @@ struct FormUpdate : std::variant<
|
||||||
[[nodiscard]] MTPinputStorePaymentPurpose InvoiceCreditsGiveawayToTL(
|
[[nodiscard]] MTPinputStorePaymentPurpose InvoiceCreditsGiveawayToTL(
|
||||||
const InvoicePremiumGiftCode &invoice);
|
const InvoicePremiumGiftCode &invoice);
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsPremiumForStarsInvoice(const InvoiceId &id);
|
||||||
|
|
||||||
class Form final : public base::has_weak_ptr {
|
class Form final : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
Form(InvoiceId id, bool receipt);
|
Form(InvoiceId id, bool receipt);
|
||||||
|
|
|
@ -57,7 +57,8 @@ void ProcessCreditsPayment(
|
||||||
onstack(CheckoutResult::Cancelled);
|
onstack(CheckoutResult::Cancelled);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (form->starGiftForm) {
|
} else if (form->starGiftForm
|
||||||
|
|| IsPremiumForStarsInvoice(form->id)) {
|
||||||
const auto done = [=](std::optional<QString> error) {
|
const auto done = [=](std::optional<QString> error) {
|
||||||
const auto onstack = maybeReturnToBot;
|
const auto onstack = maybeReturnToBot;
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -86,7 +87,7 @@ void ProcessCreditsPayment(
|
||||||
onstack(CheckoutResult::Paid);
|
onstack(CheckoutResult::Paid);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ui::SendStarGift(&show->session(), form, done);
|
Ui::SendStarsForm(&show->session(), form, done);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto unsuccessful = std::make_shared<bool>(true);
|
const auto unsuccessful = std::make_shared<bool>(true);
|
||||||
|
|
|
@ -429,8 +429,7 @@ void Credits::setupContent() {
|
||||||
Ui::AddSkip(content);
|
Ui::AddSkip(content);
|
||||||
|
|
||||||
struct State final {
|
struct State final {
|
||||||
rpl::variable<bool> confirmButtonBusy = false;
|
BuyStarsHandler buyStars;
|
||||||
std::optional<Api::CreditsTopupOptions> api;
|
|
||||||
};
|
};
|
||||||
const auto state = content->lifetime().make_state<State>();
|
const auto state = content->lifetime().make_state<State>();
|
||||||
|
|
||||||
|
@ -438,60 +437,21 @@ void Credits::setupContent() {
|
||||||
object_ptr<Ui::RoundButton>(
|
object_ptr<Ui::RoundButton>(
|
||||||
content,
|
content,
|
||||||
rpl::conditional(
|
rpl::conditional(
|
||||||
state->confirmButtonBusy.value(),
|
state->buyStars.loadingValue(),
|
||||||
rpl::single(QString()),
|
rpl::single(QString()),
|
||||||
tr::lng_credits_buy_button()),
|
tr::lng_credits_buy_button()),
|
||||||
st::creditsSettingsBigBalanceButton),
|
st::creditsSettingsBigBalanceButton),
|
||||||
st::boxRowPadding);
|
st::boxRowPadding);
|
||||||
button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
|
||||||
const auto show = _controller->uiShow();
|
const auto show = _controller->uiShow();
|
||||||
const auto optionsBox = [=](not_null<Ui::GenericBox*> box) {
|
button->setClickedCallback(state->buyStars.handler(show, paid));
|
||||||
box->setStyle(st::giveawayGiftCodeBox);
|
|
||||||
box->setWidth(st::boxWideWidth);
|
|
||||||
box->setTitle(tr::lng_credits_summary_options_subtitle());
|
|
||||||
const auto inner = box->verticalLayout();
|
|
||||||
const auto self = show->session().user();
|
|
||||||
const auto options = state->api
|
|
||||||
? state->api->options()
|
|
||||||
: Data::CreditTopupOptions();
|
|
||||||
const auto amount = StarsAmount();
|
|
||||||
FillCreditOptions(show, inner, self, amount, paid, nullptr, options);
|
|
||||||
|
|
||||||
const auto button = box->addButton(tr::lng_close(), [=] {
|
|
||||||
box->closeBox();
|
|
||||||
});
|
|
||||||
const auto buttonWidth = st::boxWideWidth
|
|
||||||
- rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding);
|
|
||||||
button->widthValue() | rpl::filter([=] {
|
|
||||||
return (button->widthNoMargins() != buttonWidth);
|
|
||||||
}) | rpl::start_with_next([=] {
|
|
||||||
button->resizeToWidth(buttonWidth);
|
|
||||||
}, button->lifetime());
|
|
||||||
};
|
|
||||||
button->setClickedCallback([=] {
|
|
||||||
if (state->api && !state->api->options().empty()) {
|
|
||||||
state->confirmButtonBusy = false;
|
|
||||||
show->show(Box(optionsBox));
|
|
||||||
} else {
|
|
||||||
state->confirmButtonBusy = true;
|
|
||||||
state->api.emplace(show->session().user());
|
|
||||||
state->api->request(
|
|
||||||
) | rpl::start_with_error_done([=](const QString &error) {
|
|
||||||
state->confirmButtonBusy = false;
|
|
||||||
show->showToast(error);
|
|
||||||
}, [=] {
|
|
||||||
state->confirmButtonBusy = false;
|
|
||||||
show->show(Box(optionsBox));
|
|
||||||
}, content->lifetime());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
{
|
{
|
||||||
using namespace Info::Statistics;
|
using namespace Info::Statistics;
|
||||||
const auto loadingAnimation = InfiniteRadialAnimationWidget(
|
const auto loadingAnimation = InfiniteRadialAnimationWidget(
|
||||||
button,
|
button,
|
||||||
button->height() / 2);
|
button->height() / 2);
|
||||||
AddChildToWidgetCenter(button, loadingAnimation);
|
AddChildToWidgetCenter(button, loadingAnimation);
|
||||||
loadingAnimation->showOn(state->confirmButtonBusy.value());
|
loadingAnimation->showOn(state->buyStars.loadingValue());
|
||||||
}
|
}
|
||||||
const auto paddings = rect::m::sum::h(st::boxRowPadding);
|
const auto paddings = rect::m::sum::h(st::boxRowPadding);
|
||||||
button->widthValue() | rpl::filter([=] {
|
button->widthValue() | rpl::filter([=] {
|
||||||
|
@ -699,4 +659,62 @@ Type CreditsId() {
|
||||||
return Credits::Id();
|
return Credits::Id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fn<void()> BuyStarsHandler::handler(
|
||||||
|
std::shared_ptr<::Main::SessionShow> show,
|
||||||
|
Fn<void()> paid) {
|
||||||
|
const auto optionsBox = [=](not_null<Ui::GenericBox*> box) {
|
||||||
|
box->setStyle(st::giveawayGiftCodeBox);
|
||||||
|
box->setWidth(st::boxWideWidth);
|
||||||
|
box->setTitle(tr::lng_credits_summary_options_subtitle());
|
||||||
|
const auto inner = box->verticalLayout();
|
||||||
|
const auto self = show->session().user();
|
||||||
|
const auto options = _api
|
||||||
|
? _api->options()
|
||||||
|
: Data::CreditTopupOptions();
|
||||||
|
const auto amount = StarsAmount();
|
||||||
|
const auto weak = Ui::MakeWeak(box);
|
||||||
|
FillCreditOptions(show, inner, self, amount, [=] {
|
||||||
|
if (const auto strong = weak.data()) {
|
||||||
|
strong->closeBox();
|
||||||
|
}
|
||||||
|
if (const auto onstack = paid) {
|
||||||
|
onstack();
|
||||||
|
}
|
||||||
|
}, nullptr, options);
|
||||||
|
|
||||||
|
const auto button = box->addButton(tr::lng_close(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
const auto buttonWidth = st::boxWideWidth
|
||||||
|
- rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding);
|
||||||
|
button->widthValue() | rpl::filter([=] {
|
||||||
|
return (button->widthNoMargins() != buttonWidth);
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
button->resizeToWidth(buttonWidth);
|
||||||
|
}, button->lifetime());
|
||||||
|
};
|
||||||
|
return crl::guard(this, [=] {
|
||||||
|
if (_api && !_api->options().empty()) {
|
||||||
|
_loading = false;
|
||||||
|
show->show(Box(crl::guard(this, optionsBox)));
|
||||||
|
} else {
|
||||||
|
_loading = true;
|
||||||
|
const auto user = show->session().user();
|
||||||
|
_api = std::make_unique<Api::CreditsTopupOptions>(user);
|
||||||
|
_api->request(
|
||||||
|
) | rpl::start_with_error_done([=](const QString &error) {
|
||||||
|
_loading = false;
|
||||||
|
show->showToast(error);
|
||||||
|
}, [=] {
|
||||||
|
_loading = false;
|
||||||
|
show->show(Box(crl::guard(this, optionsBox)));
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<bool> BuyStarsHandler::loadingValue() const {
|
||||||
|
return _loading.value();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Settings
|
} // namespace Settings
|
||||||
|
|
|
@ -9,9 +9,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "settings/settings_type.h"
|
#include "settings/settings_type.h"
|
||||||
|
|
||||||
|
namespace Api {
|
||||||
|
class CreditsTopupOptions;
|
||||||
|
} // namespace Api
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
class SessionShow;
|
||||||
|
} // namespace Main
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
[[nodiscard]] Type CreditsId();
|
[[nodiscard]] Type CreditsId();
|
||||||
|
|
||||||
} // namespace Settings
|
class BuyStarsHandler final : public base::has_weak_ptr {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] Fn<void()> handler(
|
||||||
|
std::shared_ptr<::Main::SessionShow> show,
|
||||||
|
Fn<void()> paid = nullptr);
|
||||||
|
[[nodiscard]] rpl::producer<bool> loadingValue() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Api::CreditsTopupOptions> _api;
|
||||||
|
rpl::variable<bool> _loading;
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
|
|
|
@ -569,8 +569,8 @@ void FillCreditOptions(
|
||||||
if (const auto strong = weak.data()) {
|
if (const auto strong = weak.data()) {
|
||||||
strong->window()->setFocus();
|
strong->window()->setFocus();
|
||||||
if (result == Payments::CheckoutResult::Paid) {
|
if (result == Payments::CheckoutResult::Paid) {
|
||||||
if (paid) {
|
if (const auto onstack = paid) {
|
||||||
paid();
|
onstack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
#include "styles/style_credits.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -54,7 +55,7 @@ void SendButton::setState(State state) {
|
||||||
|| _state.starsToSend != state.starsToSend) {
|
|| _state.starsToSend != state.starsToSend) {
|
||||||
_starsToSendText.setMarkedText(
|
_starsToSendText.setMarkedText(
|
||||||
_st.stars.style,
|
_st.stars.style,
|
||||||
Text::IconEmoji(&st::boxStarIconEmoji).append(
|
Text::IconEmoji(&st::starIconEmoji).append(
|
||||||
Lang::FormatCountToShort(state.starsToSend).string),
|
Lang::FormatCountToShort(state.starsToSend).string),
|
||||||
kMarkupTextOptions);
|
kMarkupTextOptions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,11 +63,12 @@ creditsBoxButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
starIconEmoji: IconEmoji {
|
starIconEmoji: IconEmoji {
|
||||||
icon: icon{{ "payments/small_star", windowFg }};
|
icon: icon{{ "payments/premium_emoji", creditsBg1 }};
|
||||||
padding: margins(0px, -3px, 0px, 0px);
|
padding: margins(4px, 1px, 4px, 0px);
|
||||||
|
}
|
||||||
|
starIconEmojiColored: IconEmoji(starIconEmoji) {
|
||||||
|
useIconColor: true;
|
||||||
}
|
}
|
||||||
starIconSmall: icon{{ "payments/small_star", windowFg }};
|
|
||||||
starIconSmallPadding: margins(0px, -3px, 0px, 0px);
|
|
||||||
|
|
||||||
creditsHistoryEntryTypeAds: icon {{ "folders/folders_channels", premiumButtonFg }};
|
creditsHistoryEntryTypeAds: icon {{ "folders/folders_channels", premiumButtonFg }};
|
||||||
|
|
||||||
|
@ -123,10 +124,17 @@ giftBoxGiftHeight: 164px;
|
||||||
giftBoxGiftSmall: 108px;
|
giftBoxGiftSmall: 108px;
|
||||||
giftBoxGiftRadius: 12px;
|
giftBoxGiftRadius: 12px;
|
||||||
giftBoxGiftBadgeFont: font(10px semibold);
|
giftBoxGiftBadgeFont: font(10px semibold);
|
||||||
|
giftBoxByStarsStyle: TextStyle(defaultTextStyle) {
|
||||||
|
font: font(10px);
|
||||||
|
}
|
||||||
|
giftBoxByStarsSkip: 2px;
|
||||||
|
giftBoxByStarsStarTop: 3px;
|
||||||
giftBoxPremiumIconSize: 64px;
|
giftBoxPremiumIconSize: 64px;
|
||||||
giftBoxPremiumIconTop: 10px;
|
giftBoxPremiumIconTop: 10px;
|
||||||
giftBoxPremiumTextTop: 84px;
|
giftBoxPremiumTextTop: 84px;
|
||||||
|
giftBoxPremiumTextTopByStars: 78px;
|
||||||
giftBoxButtonBottom: 12px;
|
giftBoxButtonBottom: 12px;
|
||||||
|
giftBoxButtonBottomByStars: 18px;
|
||||||
giftBoxButtonPadding: margins(8px, 4px, 8px, 4px);
|
giftBoxButtonPadding: margins(8px, 4px, 8px, 4px);
|
||||||
giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px);
|
giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px);
|
||||||
giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px);
|
giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px);
|
||||||
|
@ -135,6 +143,7 @@ giftBoxButtonMargin: margins(12px, 8px, 12px, 12px);
|
||||||
giftBoxStickerTop: 0px;
|
giftBoxStickerTop: 0px;
|
||||||
giftBoxStickerStarTop: 24px;
|
giftBoxStickerStarTop: 24px;
|
||||||
giftBoxSmallStickerTop: 16px;
|
giftBoxSmallStickerTop: 16px;
|
||||||
|
giftBoxStickerTopByStars: -4px;
|
||||||
giftBoxStickerSize: size(80px, 80px);
|
giftBoxStickerSize: size(80px, 80px);
|
||||||
giftBoxUserpicSize: 24px;
|
giftBoxUserpicSize: 24px;
|
||||||
giftBoxUserpicSkip: 2px;
|
giftBoxUserpicSkip: 2px;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit da0d634ec373d8ba0b8f66f3381a87e43edffdf2
|
Subproject commit 76f25481470faee2e0a24aa7be8c6d58564addea
|
Loading…
Add table
Reference in a new issue