"Add {bot}" button in existing starrefs list.

This commit is contained in:
John Preston 2024-12-02 17:11:08 +04:00
parent 1e14667006
commit 82cec83d87
7 changed files with 128 additions and 30 deletions

View file

@ -1641,6 +1641,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_star_ref_duration_about" = "Set the duration for which affiliates will earn commissions from referred users.";
"lng_star_ref_existing_title" = "View existing programs";
"lng_star_ref_existing_about" = "Explore what other mini apps offer.";
"lng_star_ref_add_bot" = "Add {bot}";
"lng_star_ref_end" = "End Affiliate Program";
"lng_star_ref_start" = "Start Affiliate Program";
"lng_star_ref_start_disabled" = "Available in {time}";
@ -1690,6 +1691,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_star_ref_one_about_for_months#other" = "for **{count} months**";
"lng_star_ref_one_about_for_years#one" = "for **{count} year**";
"lng_star_ref_one_about_for_years#other" = "for **{count} years**";
"lng_star_ref_one_daily_revenue" = "Daily revenue per user: {amount}";
"lng_star_ref_one_join" = "Join Program";
"lng_star_ref_one_join_text" = "By joining this program, you agree to the {terms} of Affiliate Programs.";
"lng_star_ref_joined_title" = "Program joined";

View file

@ -739,6 +739,9 @@ StarRefProgram ParseStarRefProgram(const MTPStarRefProgram *program) {
const auto &data = program->data();
result.commission = data.vcommission_permille().v;
result.durationMonths = data.vduration_months().value_or_empty();
result.revenuePerUser = data.vdaily_revenue_per_user()
? Data::FromTL(*data.vdaily_revenue_per_user())
: StarsAmount();
result.endDate = data.vend_date().value_or_empty();
return result;
}

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "core/stars_amount.h"
#include "data/data_birthday.h"
#include "data/data_peer.h"
#include "data/data_chat_participant_status.h"
@ -20,6 +21,7 @@ struct BusinessDetails;
} // namespace Data
struct StarRefProgram {
StarsAmount revenuePerUser;
TimeId endDate = 0;
ushort commission = 0;
uint8 durationMonths = 0;

View file

@ -9,7 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "boxes/peers/replace_boost_box.h" // CreateUserpicsTransfer.
#include "boxes/send_credits_box.h" // Ui::CreditsEmoji.
#include "chat_helpers/stickers_lottie.h"
#include "core/ui_integration.h"
#include "data/data_document.h"
#include "data/data_session.h"
#include "history/view/media/history_view_sticker.h"
@ -499,8 +501,32 @@ object_ptr<Ui::BoxContent> StarRefLinkBox(
st::starrefCenteredText),
st::boxRowPadding);
Ui::AddSkip(box->verticalLayout(), st::defaultVerticalListSkip * 4);
Ui::AddSkip(box->verticalLayout(), st::defaultVerticalListSkip * 3);
if (const auto average = program.revenuePerUser) {
const auto layout = box->verticalLayout();
const auto session = &peer->session();
const auto makeContext = [session](Fn<void()> update) {
return Core::MarkedTextContext{
.session = session,
.customEmojiRepaint = std::move(update),
};
};
auto text = Ui::Text::Colorized(Ui::CreditsEmoji(session));
text.append(Lang::FormatStarsAmountDecimal(average));
layout->add(
object_ptr<Ui::FlatLabel>(
box,
tr::lng_star_ref_one_daily_revenue(
lt_amount,
rpl::single(Ui::Text::Wrapped(text, EntityType::Bold)),
Ui::Text::WithEntities),
st::starrefRevenueText,
st::defaultPopupMenu,
makeContext),
st::boxRowPadding);
Ui::AddSkip(layout, st::defaultVerticalListSkip);
}
#if 0
box->addRow(
object_ptr<Ui::FlatLabel>(
box,
@ -510,6 +536,7 @@ object_ptr<Ui::BoxContent> StarRefLinkBox(
box->addRow(object_ptr<Ui::AbstractButton>::fromRaw(
MakePeerBubbleButton(box, peer).release()
))->setAttribute(Qt::WA_TransparentForMouseEvents);
#endif
struct State {
QPointer<Ui::GenericBox> weak;

View file

@ -57,6 +57,7 @@ constexpr auto kPerPage = 50;
enum class JoinType {
Joined,
Suggested,
Existing,
};
class ListController final
@ -79,12 +80,14 @@ public:
[[nodiscard]] rpl::producer<int> rowCountValue() const;
[[nodiscard]] rpl::producer<ConnectedBot> connected() const;
[[nodiscard]] rpl::producer<> addForBotRequests() const;
void process(ConnectedBot row);
private:
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(ConnectedBot bot);
void open(not_null<UserData*> bot, ConnectedBotState state);
void setupAddForBot();
const not_null<Window::SessionController*> _controller;
const not_null<PeerData*> _peer;
@ -95,6 +98,7 @@ private:
UserData *_openOnResolve = nullptr;
rpl::event_stream<ConnectedBot> _connected;
rpl::event_stream<> _addForBot;
mtpRequestId _requestId = 0;
TimeId _offsetDate = 0;
@ -171,15 +175,16 @@ void ListController::loadMoreRows() {
return;
} else if (_type == JoinType::Joined) {
using Flag = MTPpayments_GetConnectedStarRefBots::Flag;
_requestId = session().api().request(MTPpayments_GetConnectedStarRefBots(
MTP_flags(Flag()
| (_offsetDate ? Flag::f_offset_date : Flag())
| (_offsetThing.isEmpty() ? Flag() : Flag::f_offset_link)),
_peer->input,
MTP_int(_offsetDate),
MTP_string(_offsetThing),
MTP_int(kPerPage)
)).done([=](const MTPpayments_ConnectedStarRefBots &result) {
_requestId = session().api().request(
MTPpayments_GetConnectedStarRefBots(
MTP_flags(Flag()
| (_offsetDate ? Flag::f_offset_date : Flag())
| (_offsetThing.isEmpty() ? Flag() : Flag::f_offset_link)),
_peer->input,
MTP_int(_offsetDate),
MTP_string(_offsetThing),
MTP_int(kPerPage))
).done([=](const MTPpayments_ConnectedStarRefBots &result) {
const auto parsed = Parse(&session(), result);
if (parsed.empty()) {
_allLoaded = true;
@ -195,6 +200,9 @@ void ListController::loadMoreRows() {
_requestId = 0;
}).send();
} else {
if (_type == JoinType::Existing) {
setDescriptionText(tr::lng_contacts_loading(tr::now));
}
using Flag = MTPpayments_GetSuggestedStarRefBots::Flag;
_requestId = session().api().request(
MTPpayments_GetSuggestedStarRefBots(
@ -203,6 +211,9 @@ void ListController::loadMoreRows() {
MTP_string(_offsetThing),
MTP_int(kPerPage))
).done([=](const MTPpayments_SuggestedStarRefBots &result) {
setDescriptionText(QString());
setupAddForBot();
const auto &data = result.data();
if (data.vnext_offset()) {
_offsetThing = qs(*data.vnext_offset());
@ -210,20 +221,13 @@ void ListController::loadMoreRows() {
_allLoaded = true;
}
session().data().processUsers(data.vusers());
for (const auto &bot : data.vsuggested_bots().v) {
const auto &data = bot.data();
const auto botId = UserId(data.vbot_id());
const auto commission = data.vcommission_permille().v;
const auto durationMonths
= data.vduration_months().value_or_empty();
for (const auto &program : data.vsuggested_bots().v) {
const auto botId = UserId(program.data().vbot_id());
const auto user = session().data().user(botId);
delegate()->peerListAppendRow(createRow({
.bot = user,
.state = {
.program = {
.commission = ushort(commission),
.durationMonths = uchar(durationMonths),
},
.program = Data::ParseStarRefProgram(&program),
.unresolved = true,
},
}));
@ -238,6 +242,46 @@ void ListController::loadMoreRows() {
}
}
void ListController::setupAddForBot() {
const auto user = _peer->asUser();
if (_type != JoinType::Existing
|| !user
|| !user->isBot()
|| user->botInfo->starRefProgram.commission > 0) {
return;
}
auto button = object_ptr<Ui::PaddingWrap<Ui::SettingsButton>>(
nullptr,
object_ptr<Ui::SettingsButton>(
nullptr,
tr::lng_star_ref_add_bot(lt_bot, rpl::single(user->name())),
st::inviteViaLinkButton),
style::margins(0, st::membersMarginTop, 0, 0));
const auto icon = Ui::CreateChild<Info::Profile::FloatingIcon>(
button->entity(),
st::starrefAddForBotIcon,
QPoint());
button->entity()->heightValue(
) | rpl::start_with_next([=](int height) {
icon->moveToLeft(
st::starrefAddForBotIconPosition.x(),
(height - st::starrefAddForBotIcon.height()) / 2);
}, icon->lifetime());
button->entity()->setClickedCallback([=] {
_addForBot.fire({});
});
button->entity()->events(
) | rpl::filter([=](not_null<QEvent*> e) {
return (e->type() == QEvent::Enter);
}) | rpl::start_with_next([=] {
delegate()->peerListMouseLeftGeometry();
}, button->lifetime());
delegate()->peerListSetAboveWidget(std::move(button));
delegate()->peerListRefreshRows();
}
rpl::producer<int> ListController::rowCountValue() const {
return _rowCount.value();
}
@ -246,6 +290,10 @@ rpl::producer<ConnectedBot> ListController::connected() const {
return _connected.events();
}
rpl::producer<> ListController::addForBotRequests() const {
return _addForBot.events();
}
void ListController::process(ConnectedBot row) {
if (!delegate()->peerListFindRow(PeerListRowId(row.bot->id.value))) {
delegate()->peerListPrependRow(createRow(row));
@ -720,19 +768,27 @@ std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer) {
}
object_ptr<Ui::BoxContent> ProgramsListBox(
not_null<Window::SessionController*> controller,
not_null<Window::SessionController*> window,
not_null<PeerData*> peer) {
const auto weak = std::make_shared<QPointer<PeerListBox>>();
const auto initBox = [=](not_null<PeerListBox*> box) {
*weak = box;
box->addButton(tr::lng_close(), [=] {
box->closeBox();
});
};
return Box<PeerListBox>(
std::make_unique<ListController>(
controller,
peer,
JoinType::Suggested),
initBox);
auto controller = std::make_unique<ListController>(
window,
peer,
JoinType::Existing);
controller->addForBotRequests() | rpl::start_with_next([=] {
if (const auto strong = weak->data()) {
strong->closeBox();
}
}, controller->lifetime());
return Box<PeerListBox>(std::move(controller), initBox);
}
} // namespace Info::BotStarRef::Join

View file

@ -83,7 +83,7 @@ private:
[[nodiscard]] std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer);
[[nodiscard]] object_ptr<Ui::BoxContent> ProgramsListBox(
not_null<Window::SessionController*> controller,
not_null<Window::SessionController*> window,
not_null<PeerData*> peer);
} // namespace Info::BotStarRef::Join

View file

@ -441,6 +441,11 @@ starrefCenteredText: FlatLabel(defaultFlatLabel) {
starrefJoinFooter: FlatLabel(starrefCenteredText) {
textFg: windowSubTextFg;
}
starrefRevenueText: FlatLabel(starrefCenteredText) {
palette: TextPalette(defaultTextPalette) {
linkFg: creditsBg1;
}
}
starrefInfoIconPosition: point(16px, 8px);
starrefBottomButton: RoundButton(defaultActiveButton) {
@ -469,4 +474,7 @@ starrefLinkCountAdd: 6px;
starrefLinkCountIcon: icon{{ "chat/mini_subscribers", historyPeerUserpicFg }};
starrefLinkCountIconPosition: point(0px, 1px);
starrefLinkCountFont: font(10px bold);
starrefLinkCountPadding: margins(2px, 0px, 3px, 1px);
starrefLinkCountPadding: margins(2px, 0px, 3px, 1px);
starrefAddForBotIcon: icon {{ "menu/bot_add", lightButtonFg }};
starrefAddForBotIconPosition: point(23px, 2px);