mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Initial starref programs list implementation.
This commit is contained in:
parent
1e15764bb9
commit
62d2346471
21 changed files with 1073 additions and 154 deletions
|
@ -918,8 +918,10 @@ PRIVATE
|
||||||
info/bot/earn/info_bot_earn_list.h
|
info/bot/earn/info_bot_earn_list.h
|
||||||
info/bot/earn/info_bot_earn_widget.cpp
|
info/bot/earn/info_bot_earn_widget.cpp
|
||||||
info/bot/earn/info_bot_earn_widget.h
|
info/bot/earn/info_bot_earn_widget.h
|
||||||
info/bot/starref/info_bot_starref_widget.cpp
|
info/bot/starref/info_bot_starref_join_widget.cpp
|
||||||
info/bot/starref/info_bot_starref_widget.h
|
info/bot/starref/info_bot_starref_join_widget.h
|
||||||
|
info/bot/starref/info_bot_starref_setup_widget.cpp
|
||||||
|
info/bot/starref/info_bot_starref_setup_widget.h
|
||||||
info/channel_statistics/boosts/create_giveaway_box.cpp
|
info/channel_statistics/boosts/create_giveaway_box.cpp
|
||||||
info/channel_statistics/boosts/create_giveaway_box.h
|
info/channel_statistics/boosts/create_giveaway_box.h
|
||||||
info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp
|
info/channel_statistics/boosts/giveaway/giveaway_list_controllers.cpp
|
||||||
|
|
|
@ -46,7 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "history/admin_log/history_admin_log_section.h"
|
#include "history/admin_log/history_admin_log_section.h"
|
||||||
#include "info/bot/earn/info_bot_earn_widget.h"
|
#include "info/bot/earn/info_bot_earn_widget.h"
|
||||||
#include "info/bot/starref/info_bot_starref_widget.h"
|
#include "info/bot/starref/info_bot_starref_setup_widget.h"
|
||||||
#include "info/channel_statistics/boosts/info_boosts_widget.h"
|
#include "info/channel_statistics/boosts/info_boosts_widget.h"
|
||||||
#include "info/channel_statistics/earn/earn_format.h"
|
#include "info/channel_statistics/earn/earn_format.h"
|
||||||
#include "info/channel_statistics/earn/earn_icons.h"
|
#include "info/channel_statistics/earn/earn_icons.h"
|
||||||
|
@ -1726,7 +1726,7 @@ void Controller::fillBotAffiliateProgram() {
|
||||||
? user->botInfo->starRefProgram.commission
|
? user->botInfo->starRefProgram.commission
|
||||||
: 0;
|
: 0;
|
||||||
return commission
|
return commission
|
||||||
? u"%1%"_q.arg(commission)
|
? u"%1%"_q.arg(commission / 10.)
|
||||||
: tr::lng_manage_peer_bot_star_ref_off(tr::now);
|
: tr::lng_manage_peer_bot_star_ref_off(tr::now);
|
||||||
});
|
});
|
||||||
AddButtonWithCount(
|
AddButtonWithCount(
|
||||||
|
@ -1734,7 +1734,7 @@ void Controller::fillBotAffiliateProgram() {
|
||||||
tr::lng_manage_peer_bot_star_ref(),
|
tr::lng_manage_peer_bot_star_ref(),
|
||||||
std::move(label),
|
std::move(label),
|
||||||
[controller = _navigation->parentController(), user] {
|
[controller = _navigation->parentController(), user] {
|
||||||
controller->showSection(Info::BotStarRef::Make(user));
|
controller->showSection(Info::BotStarRef::Setup::Make(user));
|
||||||
},
|
},
|
||||||
{ &st::menuIconSharing });
|
{ &st::menuIconSharing });
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,8 +555,13 @@ bool ResolveUsernameOrPhone(
|
||||||
auto resolveType = params.contains(u"profile"_q)
|
auto resolveType = params.contains(u"profile"_q)
|
||||||
? ResolveType::Profile
|
? ResolveType::Profile
|
||||||
: ResolveType::Default;
|
: ResolveType::Default;
|
||||||
|
auto starref = params.value(u"ref"_q);
|
||||||
auto startToken = params.value(u"start"_q);
|
auto startToken = params.value(u"start"_q);
|
||||||
if (!startToken.isEmpty()) {
|
const auto kTgRefPrefix = u"_tgref_"_q;
|
||||||
|
if (startToken.startsWith(kTgRefPrefix)) {
|
||||||
|
startToken = startToken.mid(kTgRefPrefix.size());
|
||||||
|
resolveType = ResolveType::StarRef;
|
||||||
|
} else if (!startToken.isEmpty()) {
|
||||||
resolveType = ResolveType::BotStart;
|
resolveType = ResolveType::BotStart;
|
||||||
} else if (params.contains(u"startgroup"_q)) {
|
} else if (params.contains(u"startgroup"_q)) {
|
||||||
resolveType = ResolveType::AddToGroup;
|
resolveType = ResolveType::AddToGroup;
|
||||||
|
@ -565,6 +570,8 @@ bool ResolveUsernameOrPhone(
|
||||||
resolveType = ResolveType::AddToChannel;
|
resolveType = ResolveType::AddToChannel;
|
||||||
} else if (params.contains(u"boost"_q)) {
|
} else if (params.contains(u"boost"_q)) {
|
||||||
resolveType = ResolveType::Boost;
|
resolveType = ResolveType::Boost;
|
||||||
|
} else if (!starref.isEmpty()) {
|
||||||
|
resolveType = ResolveType::StarRef;
|
||||||
}
|
}
|
||||||
auto post = ShowAtUnreadMsgId;
|
auto post = ShowAtUnreadMsgId;
|
||||||
auto adminRights = ChatAdminRights();
|
auto adminRights = ChatAdminRights();
|
||||||
|
|
|
@ -0,0 +1,767 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "info/bot/starref/info_bot_starref_join_widget.h"
|
||||||
|
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "base/timer_rpl.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
|
#include "boxes/peer_list_box.h"
|
||||||
|
#include "core/click_handler_types.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_user.h"
|
||||||
|
#include "info/profile/info_profile_icon.h"
|
||||||
|
#include "info/info_controller.h"
|
||||||
|
#include "info/info_memento.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "settings/settings_common.h"
|
||||||
|
#include "ui/boxes/confirm_box.h"
|
||||||
|
#include "ui/effects/premium_top_bar.h"
|
||||||
|
#include "ui/layers/generic_box.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/continuous_sliders.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "ui/wrap/fade_wrap.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "ui/ui_utility.h"
|
||||||
|
#include "ui/vertical_list.h"
|
||||||
|
#include "styles/style_info.h"
|
||||||
|
#include "styles/style_layers.h"
|
||||||
|
#include "styles/style_menu_icons.h"
|
||||||
|
#include "styles/style_premium.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
namespace Info::BotStarRef::Join {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kPerPage = 50;
|
||||||
|
|
||||||
|
enum class JoinType {
|
||||||
|
Joined,
|
||||||
|
Suggested,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ListController final : public PeerListController {
|
||||||
|
public:
|
||||||
|
ListController(
|
||||||
|
not_null<Controller*> controller,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
JoinType type);
|
||||||
|
~ListController();
|
||||||
|
|
||||||
|
Main::Session &session() const override;
|
||||||
|
void prepare() override;
|
||||||
|
void rowClicked(not_null<PeerListRow*> row) override;
|
||||||
|
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<PeerListRow*> row) override;
|
||||||
|
void loadMoreRows() override;
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<int> rowCountValue() const;
|
||||||
|
|
||||||
|
//std::unique_ptr<PeerListRow> createRestoredRow(
|
||||||
|
// not_null<PeerData*> peer) override {
|
||||||
|
// return createRow(peer);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//std::unique_ptr<PeerListState> saveState() const override;
|
||||||
|
//void restoreState(std::unique_ptr<PeerListState> state) override;
|
||||||
|
|
||||||
|
void setContentWidget(not_null<Ui::RpWidget*> widget);
|
||||||
|
[[nodiscard]] rpl::producer<int> unlockHeightValue() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct RowState {
|
||||||
|
StarRefProgram program;
|
||||||
|
QString link;
|
||||||
|
int users = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
RowState state);
|
||||||
|
void showLink(not_null<PeerData*> peer, RowState state);
|
||||||
|
|
||||||
|
struct SavedState : SavedStateBase {
|
||||||
|
};
|
||||||
|
const not_null<Controller*> _controller;
|
||||||
|
const not_null<PeerData*> _peer;
|
||||||
|
const JoinType _type = {};
|
||||||
|
|
||||||
|
base::flat_map<not_null<PeerData*>, RowState> _states;
|
||||||
|
|
||||||
|
mtpRequestId _requestId = 0;
|
||||||
|
TimeId _offsetDate = 0;
|
||||||
|
QString _offsetThing;
|
||||||
|
bool _allLoaded = false;
|
||||||
|
|
||||||
|
rpl::variable<int> _rowCount = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ListController::ListController(
|
||||||
|
not_null<Controller*> controller,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
JoinType type)
|
||||||
|
: PeerListController()
|
||||||
|
, _controller(controller)
|
||||||
|
, _peer(peer)
|
||||||
|
, _type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ListController::~ListController() {
|
||||||
|
if (_requestId) {
|
||||||
|
session().api().request(_requestId).cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Main::Session &ListController::session() const {
|
||||||
|
return _peer->session();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<PeerListRow> ListController::createRow(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
RowState state) {
|
||||||
|
_states.emplace(peer, state);
|
||||||
|
auto result = std::make_unique<PeerListRow>(peer);
|
||||||
|
const auto program = state.program;
|
||||||
|
const auto duration = !program.durationMonths
|
||||||
|
? tr::lng_star_ref_duration_forever(tr::now)
|
||||||
|
: (program.durationMonths < 12)
|
||||||
|
? tr::lng_months(tr::now, lt_count, program.durationMonths)
|
||||||
|
: tr::lng_years(tr::now, lt_count, program.durationMonths / 12);
|
||||||
|
result->setCustomStatus(u"+%1%, %2"_q.arg(
|
||||||
|
QString::number(program.commission / 10.),
|
||||||
|
duration));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListController::prepare() {
|
||||||
|
delegate()->peerListSetTitle((_type == JoinType::Joined)
|
||||||
|
? tr::lng_star_ref_list_my()
|
||||||
|
: tr::lng_star_ref_list_subtitle());
|
||||||
|
|
||||||
|
loadMoreRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListController::loadMoreRows() {
|
||||||
|
if (_requestId || _allLoaded) {
|
||||||
|
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) {
|
||||||
|
const auto &data = result.data();
|
||||||
|
session().data().processUsers(data.vusers());
|
||||||
|
const auto &list = data.vconnected_bots().v;
|
||||||
|
if (list.empty()) {
|
||||||
|
_allLoaded = true;
|
||||||
|
} else {
|
||||||
|
for (const auto &bot : list) {
|
||||||
|
const auto &data = bot.data();
|
||||||
|
const auto botId = UserId(data.vbot_id());
|
||||||
|
_offsetThing = qs(data.vurl());
|
||||||
|
_offsetDate = data.vdate().v;
|
||||||
|
const auto commission = data.vcommission_permille().v;
|
||||||
|
const auto durationMonths
|
||||||
|
= data.vduration_months().value_or_empty();
|
||||||
|
const auto user = session().data().user(botId);
|
||||||
|
if (data.is_revoked()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
delegate()->peerListAppendRow(createRow(user, {
|
||||||
|
.program = {
|
||||||
|
.commission = ushort(commission),
|
||||||
|
.durationMonths = uchar(durationMonths),
|
||||||
|
},
|
||||||
|
.link = _offsetThing,
|
||||||
|
.users = int(data.vparticipants().v),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
delegate()->peerListRefreshRows();
|
||||||
|
_rowCount = delegate()->peerListFullRowsCount();
|
||||||
|
}
|
||||||
|
_requestId = 0;
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
_requestId = 0;
|
||||||
|
}).send();
|
||||||
|
} else {
|
||||||
|
using Flag = MTPpayments_GetSuggestedStarRefBots::Flag;
|
||||||
|
_requestId = session().api().request(MTPpayments_GetSuggestedStarRefBots(
|
||||||
|
MTP_flags(Flag::f_order_by_revenue),
|
||||||
|
_peer->input,
|
||||||
|
MTP_string(_offsetThing),
|
||||||
|
MTP_int(kPerPage)
|
||||||
|
)).done([=](const MTPpayments_SuggestedStarRefBots &result) {
|
||||||
|
const auto &data = result.data();
|
||||||
|
if (data.vnext_offset()) {
|
||||||
|
_offsetThing = qs(*data.vnext_offset());
|
||||||
|
} else {
|
||||||
|
_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();
|
||||||
|
const auto user = session().data().user(botId);
|
||||||
|
delegate()->peerListAppendRow(createRow(user, {
|
||||||
|
.program = {
|
||||||
|
.commission = ushort(commission),
|
||||||
|
.durationMonths = uchar(durationMonths),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
delegate()->peerListRefreshRows();
|
||||||
|
_rowCount = delegate()->peerListFullRowsCount();
|
||||||
|
_requestId = 0;
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
_allLoaded = true;
|
||||||
|
_requestId = 0;
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> ListController::rowCountValue() const {
|
||||||
|
return _rowCount.value();
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//std::unique_ptr<PeerListState> ListController::saveState() const {
|
||||||
|
// auto result = PeerListController::saveState();
|
||||||
|
// auto my = std::make_unique<SavedState>();
|
||||||
|
// result->controllerState = std::move(my);
|
||||||
|
// return result;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void ListController::restoreState(
|
||||||
|
// std::unique_ptr<PeerListState> state) {
|
||||||
|
// auto typeErasedState = state
|
||||||
|
// ? state->controllerState.get()
|
||||||
|
// : nullptr;
|
||||||
|
// if (dynamic_cast<SavedState*>(typeErasedState)) {
|
||||||
|
// PeerListController::restoreState(std::move(state));
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
void ListController::showLink(not_null<PeerData*> peer, RowState state) {
|
||||||
|
const auto window = _controller->parentController();
|
||||||
|
window->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
|
box->setTitle(tr::lng_star_ref_link_title());
|
||||||
|
|
||||||
|
const auto program = state.program;
|
||||||
|
auto duration = !program.durationMonths
|
||||||
|
? tr::lng_star_ref_one_about_for_forever(Ui::Text::RichLangValue)
|
||||||
|
: (program.durationMonths < 12)
|
||||||
|
? tr::lng_star_ref_one_about_for_months(
|
||||||
|
lt_count,
|
||||||
|
rpl::single(program.durationMonths * 1.),
|
||||||
|
Ui::Text::RichLangValue)
|
||||||
|
: tr::lng_star_ref_one_about_for_years(
|
||||||
|
lt_count,
|
||||||
|
rpl::single((program.durationMonths / 12) * 1.),
|
||||||
|
Ui::Text::RichLangValue);
|
||||||
|
auto text = tr::lng_star_ref_link_about_channel(
|
||||||
|
lt_amount,
|
||||||
|
rpl::single(Ui::Text::Bold(QString::number(program.commission / 10.) + '%')),
|
||||||
|
lt_app,
|
||||||
|
rpl::single(Ui::Text::Bold(peer->name())),
|
||||||
|
lt_duration,
|
||||||
|
std::move(duration),
|
||||||
|
Ui::Text::WithEntities);
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(box, std::move(text), st::boxLabel));
|
||||||
|
Ui::AddSkip(box->verticalLayout());
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box,
|
||||||
|
rpl::single(state.link) | Ui::Text::ToLink(),
|
||||||
|
st::boxLabel));
|
||||||
|
Ui::AddSkip(box->verticalLayout());
|
||||||
|
if (state.users > 0) {
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box,
|
||||||
|
tr::lng_star_ref_link_copy_users(
|
||||||
|
lt_count,
|
||||||
|
rpl::single(state.users * 1.),
|
||||||
|
lt_app,
|
||||||
|
rpl::single(peer->name())),
|
||||||
|
st::boxLabel));
|
||||||
|
} else {
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box,
|
||||||
|
tr::lng_star_ref_link_copy_none(
|
||||||
|
lt_app,
|
||||||
|
rpl::single(peer->name())),
|
||||||
|
st::boxLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
box->addButton(tr::lng_star_ref_link_copy(), [=] {
|
||||||
|
QApplication::clipboard()->setText(state.link);
|
||||||
|
window->showToast(u"Link copied to clipboard."_q);
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] {
|
||||||
|
box->closeBox();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
|
const auto peer = row->peer();
|
||||||
|
const auto i = _states.find(peer);
|
||||||
|
Assert(i != end(_states));
|
||||||
|
const auto state = i->second;
|
||||||
|
const auto program = state.program;
|
||||||
|
const auto window = _controller->parentController();
|
||||||
|
if (_type == JoinType::Joined || !state.link.isEmpty()) {
|
||||||
|
showLink(row->peer(), state);
|
||||||
|
} else {
|
||||||
|
const auto join = [=](Fn<void()> close) {
|
||||||
|
session().api().request(MTPpayments_ConnectStarRefBot(
|
||||||
|
_peer->input,
|
||||||
|
peer->asUser()->inputUser
|
||||||
|
)).done([=](const MTPpayments_ConnectedStarRefBots &result) {
|
||||||
|
window->showToast(u"Connected!"_q);
|
||||||
|
close();
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
window->showToast(u"Failed: "_q + error.type());
|
||||||
|
}).send();
|
||||||
|
};
|
||||||
|
auto duration = !program.durationMonths
|
||||||
|
? tr::lng_star_ref_one_about_for_forever(Ui::Text::RichLangValue)
|
||||||
|
: (program.durationMonths < 12)
|
||||||
|
? tr::lng_star_ref_one_about_for_months(
|
||||||
|
lt_count,
|
||||||
|
rpl::single(program.durationMonths * 1.),
|
||||||
|
Ui::Text::RichLangValue)
|
||||||
|
: tr::lng_star_ref_one_about_for_years(
|
||||||
|
lt_count,
|
||||||
|
rpl::single((program.durationMonths / 12) * 1.),
|
||||||
|
Ui::Text::RichLangValue);
|
||||||
|
auto text = tr::lng_star_ref_one_about(
|
||||||
|
lt_app,
|
||||||
|
rpl::single(Ui::Text::Bold(peer->name())),
|
||||||
|
lt_amount,
|
||||||
|
rpl::single(Ui::Text::Bold(QString::number(program.commission / 10.) + '%')),
|
||||||
|
lt_duration,
|
||||||
|
std::move(duration),
|
||||||
|
Ui::Text::WithEntities);
|
||||||
|
auto added = tr::lng_star_ref_one_join_text(
|
||||||
|
lt_terms,
|
||||||
|
tr::lng_star_ref_button_link() | Ui::Text::ToLink(),
|
||||||
|
Ui::Text::WithEntities);
|
||||||
|
auto joined = rpl::combine(
|
||||||
|
std::move(text),
|
||||||
|
std::move(added)
|
||||||
|
) | rpl::map([=](TextWithEntities a, TextWithEntities b) {
|
||||||
|
return a.append("\n\n").append(b);
|
||||||
|
});
|
||||||
|
window->show(Ui::MakeConfirmBox({
|
||||||
|
.text = std::move(joined),
|
||||||
|
.confirmed = join,
|
||||||
|
.confirmText = tr::lng_star_ref_one_join(),
|
||||||
|
.title = tr::lng_star_ref_title(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::PopupMenu> ListController::rowContextMenu(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<PeerListRow*> row) {
|
||||||
|
const auto peer = row->peer();
|
||||||
|
const auto i = _states.find(peer);
|
||||||
|
Assert(i != end(_states));
|
||||||
|
const auto state = i->second;
|
||||||
|
if (state.link.isEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto result = base::make_unique_q<Ui::PopupMenu>(
|
||||||
|
parent,
|
||||||
|
st::popupMenuWithIcons);
|
||||||
|
result->addAction(tr::lng_star_ref_list_my_open(tr::now), [=] {
|
||||||
|
_controller->parentController()->showPeerHistory(peer);
|
||||||
|
}, &st::menuIconBotCommands);
|
||||||
|
result->addAction(tr::lng_star_ref_list_my_copy(tr::now), [=] {
|
||||||
|
QApplication::clipboard()->setText(state.link);
|
||||||
|
_controller->parentController()->showToast(u"Link copied to clipboard."_q);
|
||||||
|
}, &st::menuIconLinks);
|
||||||
|
result->addAction(tr::lng_star_ref_list_my_leave(tr::now), [=] {
|
||||||
|
session().api().request(MTPpayments_EditConnectedStarRefBot(
|
||||||
|
MTP_flags(MTPpayments_EditConnectedStarRefBot::Flag::f_revoked),
|
||||||
|
_peer->input,
|
||||||
|
MTP_string(state.link)
|
||||||
|
)).done([=] {
|
||||||
|
_controller->parentController()->showToast(u"Revoked!"_q);
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
_controller->parentController()->showToast(u"Failed: "_q + error.type());
|
||||||
|
}).send();
|
||||||
|
}, &st::menuIconLeaveAttention);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class InnerWidget final : public Ui::RpWidget {
|
||||||
|
public:
|
||||||
|
InnerWidget(QWidget *parent, not_null<Controller*> controller);
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||||
|
|
||||||
|
void showFinished();
|
||||||
|
void setInnerFocus();
|
||||||
|
|
||||||
|
void saveState(not_null<Memento*> memento);
|
||||||
|
void restoreState(not_null<Memento*> memento);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void prepare();
|
||||||
|
void setupInfo();
|
||||||
|
void setupMy();
|
||||||
|
void setupSuggested();
|
||||||
|
|
||||||
|
[[nodiscard]] object_ptr<Ui::RpWidget> infoRow(
|
||||||
|
rpl::producer<QString> title,
|
||||||
|
rpl::producer<QString> text,
|
||||||
|
not_null<const style::icon*> icon);
|
||||||
|
|
||||||
|
const not_null<Controller*> _controller;
|
||||||
|
const not_null<Ui::VerticalLayout*> _container;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
InnerWidget::InnerWidget(QWidget *parent, not_null<Controller*> controller)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _controller(controller)
|
||||||
|
, _container(Ui::CreateChild<Ui::VerticalLayout>(this)) {
|
||||||
|
prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::prepare() {
|
||||||
|
Ui::ResizeFitChild(this, _container);
|
||||||
|
|
||||||
|
setupInfo();
|
||||||
|
Ui::AddSkip(_container);
|
||||||
|
Ui::AddDivider(_container);
|
||||||
|
setupMy();
|
||||||
|
setupSuggested();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setupInfo() {
|
||||||
|
AddSkip(_container, st::defaultVerticalListSkip * 2);
|
||||||
|
|
||||||
|
_container->add(infoRow(
|
||||||
|
tr::lng_star_ref_reliable_title(),
|
||||||
|
tr::lng_star_ref_reliable_about(),
|
||||||
|
&st::menuIconAntispam));
|
||||||
|
|
||||||
|
_container->add(infoRow(
|
||||||
|
tr::lng_star_ref_transparent_title(),
|
||||||
|
tr::lng_star_ref_transparent_about(),
|
||||||
|
&st::menuIconShowInChat));
|
||||||
|
|
||||||
|
_container->add(infoRow(
|
||||||
|
tr::lng_star_ref_simple_title(),
|
||||||
|
tr::lng_star_ref_simple_about(),
|
||||||
|
&st::menuIconBoosts));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setupMy() {
|
||||||
|
const auto wrap = _container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
_container,
|
||||||
|
object_ptr<Ui::VerticalLayout>(_container)));
|
||||||
|
const auto inner = wrap->entity();
|
||||||
|
|
||||||
|
Ui::AddSkip(inner);
|
||||||
|
Ui::AddSubsectionTitle(inner, tr::lng_star_ref_list_my());
|
||||||
|
|
||||||
|
const auto delegate = lifetime().make_state<
|
||||||
|
PeerListContentDelegateSimple
|
||||||
|
>();
|
||||||
|
const auto controller = lifetime().make_state<ListController>(
|
||||||
|
_controller,
|
||||||
|
peer(),
|
||||||
|
JoinType::Joined);
|
||||||
|
const auto content = inner->add(
|
||||||
|
object_ptr<PeerListContent>(
|
||||||
|
_container,
|
||||||
|
controller));
|
||||||
|
delegate->setContent(content);
|
||||||
|
controller->setDelegate(delegate);
|
||||||
|
|
||||||
|
Ui::AddDivider(inner);
|
||||||
|
|
||||||
|
wrap->toggleOn(controller->rowCountValue(
|
||||||
|
) | rpl::map(rpl::mappers::_1 > 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setupSuggested() {
|
||||||
|
Ui::AddSkip(_container);
|
||||||
|
Ui::AddSubsectionTitle(_container, tr::lng_star_ref_list_subtitle());
|
||||||
|
|
||||||
|
const auto delegate = lifetime().make_state<
|
||||||
|
PeerListContentDelegateSimple
|
||||||
|
>();
|
||||||
|
auto controller = lifetime().make_state<ListController>(
|
||||||
|
_controller,
|
||||||
|
peer(),
|
||||||
|
JoinType::Suggested);
|
||||||
|
const auto content = _container->add(
|
||||||
|
object_ptr<PeerListContent>(
|
||||||
|
_container,
|
||||||
|
controller));
|
||||||
|
delegate->setContent(content);
|
||||||
|
controller->setDelegate(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ptr<Ui::RpWidget> InnerWidget::infoRow(
|
||||||
|
rpl::producer<QString> title,
|
||||||
|
rpl::producer<QString> text,
|
||||||
|
not_null<const style::icon*> icon) {
|
||||||
|
auto result = object_ptr<Ui::VerticalLayout>(_container);
|
||||||
|
const auto raw = result.data();
|
||||||
|
|
||||||
|
raw->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
raw,
|
||||||
|
std::move(title) | Ui::Text::ToBold(),
|
||||||
|
st::defaultFlatLabel),
|
||||||
|
st::settingsPremiumRowTitlePadding);
|
||||||
|
raw->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
raw,
|
||||||
|
std::move(text),
|
||||||
|
st::boxDividerLabel),
|
||||||
|
st::settingsPremiumRowAboutPadding);
|
||||||
|
object_ptr<Info::Profile::FloatingIcon>(
|
||||||
|
raw,
|
||||||
|
*icon,
|
||||||
|
st::starrefInfoIconPosition);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<PeerData*> InnerWidget::peer() const {
|
||||||
|
return _controller->key().starrefPeer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::showFinished() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::setInnerFocus() {
|
||||||
|
setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::saveState(not_null<Memento*> memento) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::restoreState(not_null<Memento*> memento) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Memento::Memento(not_null<Controller*> controller)
|
||||||
|
: ContentMemento(Tag(controller->starrefPeer(), controller->starrefType())) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Memento::Memento(not_null<PeerData*> peer)
|
||||||
|
: ContentMemento(Tag(peer, Type::Join)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Memento::~Memento() = default;
|
||||||
|
|
||||||
|
Section Memento::section() const {
|
||||||
|
return Section(Section::Type::BotStarRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ptr<ContentWidget> Memento::createWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Controller*> controller,
|
||||||
|
const QRect &geometry) {
|
||||||
|
auto result = object_ptr<Widget>(parent, controller);
|
||||||
|
result->setInternalState(geometry, this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::Widget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Controller*> controller)
|
||||||
|
: ContentWidget(parent, controller)
|
||||||
|
, _inner(setInnerWidget(object_ptr<InnerWidget>(this, controller))) {
|
||||||
|
_top = setupTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<PeerData*> Widget::peer() const {
|
||||||
|
return _inner->peer();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::showInternal(not_null<ContentMemento*> memento) {
|
||||||
|
return (memento->starrefPeer() == peer());
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QString> Widget::title() {
|
||||||
|
return tr::lng_star_ref_list_title();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setInternalState(
|
||||||
|
const QRect &geometry,
|
||||||
|
not_null<Memento*> memento) {
|
||||||
|
setGeometry(geometry);
|
||||||
|
Ui::SendPendingMoveResizeEvents(this);
|
||||||
|
restoreState(memento);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<bool> Widget::desiredShadowVisibility() const {
|
||||||
|
return rpl::single<bool>(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::showFinished() {
|
||||||
|
_inner->showFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setInnerFocus() {
|
||||||
|
_inner->setInnerFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::enableBackButton() {
|
||||||
|
_backEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
|
||||||
|
auto result = std::make_shared<Memento>(controller());
|
||||||
|
saveState(result.get());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::saveState(not_null<Memento*> memento) {
|
||||||
|
memento->setScrollTop(scrollTopSave());
|
||||||
|
_inner->saveState(memento);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::restoreState(not_null<Memento*> memento) {
|
||||||
|
_inner->restoreState(memento);
|
||||||
|
scrollTopRestore(memento->scrollTop());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::Premium::TopBarAbstract> Widget::setupTop() {
|
||||||
|
auto title = tr::lng_star_ref_list_title();
|
||||||
|
auto about = tr::lng_star_ref_list_about_channel()
|
||||||
|
| Ui::Text::ToWithEntities();
|
||||||
|
|
||||||
|
const auto controller = this->controller();
|
||||||
|
const auto weak = base::make_weak(controller->parentController());
|
||||||
|
const auto clickContextOther = [=] {
|
||||||
|
return QVariant::fromValue(ClickHandlerContext{
|
||||||
|
.sessionWindow = weak,
|
||||||
|
.botStartAutoSubmit = true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
auto result = std::make_unique<Ui::Premium::TopBar>(
|
||||||
|
this,
|
||||||
|
st::starrefCover,
|
||||||
|
Ui::Premium::TopBarDescriptor{
|
||||||
|
.clickContextOther = clickContextOther,
|
||||||
|
.logo = u"affiliate"_q,
|
||||||
|
.title = std::move(title),
|
||||||
|
.about = std::move(about),
|
||||||
|
.light = true,
|
||||||
|
});
|
||||||
|
const auto raw = result.get();
|
||||||
|
|
||||||
|
controller->wrapValue(
|
||||||
|
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
||||||
|
raw->setRoundEdges(wrap == Info::Wrap::Layer);
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
const auto baseHeight = st::starrefCoverHeight;
|
||||||
|
raw->resize(width(), baseHeight);
|
||||||
|
|
||||||
|
raw->additionalHeight(
|
||||||
|
) | rpl::start_with_next([=](int additionalHeight) {
|
||||||
|
raw->setMaximumHeight(baseHeight + additionalHeight);
|
||||||
|
raw->setMinimumHeight(baseHeight + additionalHeight);
|
||||||
|
setPaintPadding({ 0, raw->height(), 0, 0 });
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
controller->wrapValue(
|
||||||
|
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
||||||
|
const auto isLayer = (wrap == Info::Wrap::Layer);
|
||||||
|
_back = base::make_unique_q<Ui::FadeWrap<Ui::IconButton>>(
|
||||||
|
raw,
|
||||||
|
object_ptr<Ui::IconButton>(
|
||||||
|
raw,
|
||||||
|
(isLayer
|
||||||
|
? st::infoLayerTopBar.back
|
||||||
|
: st::infoTopBar.back)),
|
||||||
|
st::infoTopBarScale);
|
||||||
|
_back->setDuration(0);
|
||||||
|
_back->toggleOn(isLayer
|
||||||
|
? _backEnabled.value() | rpl::type_erased()
|
||||||
|
: rpl::single(true));
|
||||||
|
_back->entity()->addClickHandler([=] {
|
||||||
|
controller->showBackFromStack();
|
||||||
|
});
|
||||||
|
_back->toggledValue(
|
||||||
|
) | rpl::start_with_next([=](bool toggled) {
|
||||||
|
const auto &st = isLayer ? st::infoLayerTopBar : st::infoTopBar;
|
||||||
|
raw->setTextPosition(
|
||||||
|
toggled ? st.back.width : st.titlePosition.x(),
|
||||||
|
st.titlePosition.y());
|
||||||
|
}, _back->lifetime());
|
||||||
|
|
||||||
|
if (!isLayer) {
|
||||||
|
_close = nullptr;
|
||||||
|
} else {
|
||||||
|
_close = base::make_unique_q<Ui::IconButton>(
|
||||||
|
raw,
|
||||||
|
st::infoTopBarClose);
|
||||||
|
_close->addClickHandler([=] {
|
||||||
|
controller->parentController()->hideLayer();
|
||||||
|
controller->parentController()->hideSpecialLayer();
|
||||||
|
});
|
||||||
|
raw->widthValue(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_close->moveToRight(0, 0);
|
||||||
|
}, _close->lifetime());
|
||||||
|
}
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
raw->move(0, 0);
|
||||||
|
widthValue() | rpl::start_with_next([=](int width) {
|
||||||
|
raw->resizeToWidth(width);
|
||||||
|
setScrollTopSkip(raw->height());
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer) {
|
||||||
|
return std::make_shared<Info::Memento>(
|
||||||
|
std::vector<std::shared_ptr<ContentMemento>>(
|
||||||
|
1,
|
||||||
|
std::make_shared<Memento>(peer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Info::BotStarRef::Join
|
||||||
|
|
|
@ -17,11 +17,12 @@ namespace Ui {
|
||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
class FadeWrap;
|
class FadeWrap;
|
||||||
class IconButton;
|
class IconButton;
|
||||||
|
class AbstractButton;
|
||||||
|
class VerticalLayout;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Info::BotStarRef {
|
namespace Info::BotStarRef::Join {
|
||||||
|
|
||||||
struct State;
|
|
||||||
class InnerWidget;
|
class InnerWidget;
|
||||||
|
|
||||||
class Memento final : public ContentMemento {
|
class Memento final : public ContentMemento {
|
||||||
|
@ -61,22 +62,18 @@ private:
|
||||||
void restoreState(not_null<Memento*> memento);
|
void restoreState(not_null<Memento*> memento);
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<Ui::Premium::TopBarAbstract> setupTop();
|
[[nodiscard]] std::unique_ptr<Ui::Premium::TopBarAbstract> setupTop();
|
||||||
[[nodiscard]] std::unique_ptr<Ui::RpWidget> setupBottom();
|
|
||||||
|
|
||||||
std::shared_ptr<ContentMemento> doCreateMemento() override;
|
std::shared_ptr<ContentMemento> doCreateMemento() override;
|
||||||
|
|
||||||
const not_null<InnerWidget*> _inner;
|
const not_null<InnerWidget*> _inner;
|
||||||
const not_null<State*> _state;
|
|
||||||
|
|
||||||
std::unique_ptr<Ui::Premium::TopBarAbstract> _top;
|
std::unique_ptr<Ui::Premium::TopBarAbstract> _top;
|
||||||
base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _back;
|
base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _back;
|
||||||
base::unique_qptr<Ui::IconButton> _close;
|
base::unique_qptr<Ui::IconButton> _close;
|
||||||
rpl::variable<bool> _backEnabled;
|
rpl::variable<bool> _backEnabled;
|
||||||
|
|
||||||
std::unique_ptr<Ui::RpWidget> _bottom;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer);
|
[[nodiscard]] std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer);
|
||||||
|
|
||||||
} // namespace Info::BotStarRef
|
} // namespace Info::BotStarRef::Join
|
|
@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service.
|
||||||
For license and copyright information please follow this link:
|
For license and copyright information please follow this link:
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "info/bot/starref/info_bot_starref_widget.h"
|
#include "info/bot/starref/info_bot_starref_setup_widget.h"
|
||||||
|
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/timer_rpl.h"
|
#include "base/timer_rpl.h"
|
||||||
|
@ -33,11 +33,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_premium.h"
|
#include "styles/style_premium.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
|
|
||||||
namespace Info::BotStarRef {
|
namespace Info::BotStarRef::Setup {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kDurationForeverValue = 999;
|
constexpr auto kDurationForeverValue = 999;
|
||||||
constexpr auto kCommissionDefault = 20;
|
constexpr auto kCommissionDefault = 200;
|
||||||
constexpr auto kDurationDefault = 12;
|
constexpr auto kDurationDefault = 12;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -126,9 +126,6 @@ void InnerWidget::prepare() {
|
||||||
setupDuration();
|
setupDuration();
|
||||||
Ui::AddSkip(_container);
|
Ui::AddSkip(_container);
|
||||||
setupViewExisting();
|
setupViewExisting();
|
||||||
Ui::AddSkip(_container);
|
|
||||||
Ui::AddDivider(_container);
|
|
||||||
Ui::AddSkip(_container);
|
|
||||||
setupEnd();
|
setupEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,9 +152,17 @@ void InnerWidget::setupCommission() {
|
||||||
Ui::AddSkip(_container);
|
Ui::AddSkip(_container);
|
||||||
Ui::AddSubsectionTitle(_container, tr::lng_star_ref_commission_title());
|
Ui::AddSubsectionTitle(_container, tr::lng_star_ref_commission_title());
|
||||||
|
|
||||||
|
const auto commission = ValueForCommission(_state);
|
||||||
|
|
||||||
auto values = std::vector<int>();
|
auto values = std::vector<int>();
|
||||||
|
if (commission > 0 && commission < 10) {
|
||||||
|
values.push_back(commission);
|
||||||
|
}
|
||||||
for (auto i = 1; i != 91; ++i) {
|
for (auto i = 1; i != 91; ++i) {
|
||||||
values.push_back(i);
|
values.push_back(i * 10);
|
||||||
|
if (i * 10 < commission && (i == 90 || (i + 1) * 10 > commission)) {
|
||||||
|
values.push_back(commission);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const auto valuesCount = int(values.size());
|
const auto valuesCount = int(values.size());
|
||||||
|
|
||||||
|
@ -166,7 +171,7 @@ void InnerWidget::setupCommission() {
|
||||||
st::settingsScale,
|
st::settingsScale,
|
||||||
st::settingsScaleLabel,
|
st::settingsScaleLabel,
|
||||||
st::normalFont->spacew * 2,
|
st::normalFont->spacew * 2,
|
||||||
st::settingsScaleLabel.style.font->width("90%"),
|
st::settingsScaleLabel.style.font->width("89.9%"),
|
||||||
true);
|
true);
|
||||||
_container->add(
|
_container->add(
|
||||||
std::move(sliderWithLabel.widget),
|
std::move(sliderWithLabel.widget),
|
||||||
|
@ -175,10 +180,9 @@ void InnerWidget::setupCommission() {
|
||||||
const auto label = sliderWithLabel.label;
|
const auto label = sliderWithLabel.label;
|
||||||
|
|
||||||
const auto updateLabel = [=](int value) {
|
const auto updateLabel = [=](int value) {
|
||||||
const auto labelText = QString::number(value) + '%';
|
const auto labelText = QString::number(value / 10.) + '%';
|
||||||
label->setText(labelText);
|
label->setText(labelText);
|
||||||
};
|
};
|
||||||
const auto commission = ValueForCommission(_state);
|
|
||||||
const auto setCommission = [=](int value) {
|
const auto setCommission = [=](int value) {
|
||||||
_state.program.commission = value;
|
_state.program.commission = value;
|
||||||
updateLabel(value);
|
updateLabel(value);
|
||||||
|
@ -245,91 +249,17 @@ void InnerWidget::setupDuration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::setupViewExisting() {
|
void InnerWidget::setupViewExisting() {
|
||||||
const auto &stLabel = st::defaultFlatLabel;
|
const auto button = AddViewListButton(
|
||||||
const auto iconSize = st::settingsPremiumIconDouble.size();
|
_container,
|
||||||
const auto &titlePadding = st::settingsPremiumRowTitlePadding;
|
tr::lng_star_ref_existing_title(),
|
||||||
const auto &descriptionPadding = st::settingsPremiumRowAboutPadding;
|
tr::lng_star_ref_existing_about());
|
||||||
|
|
||||||
const auto content = _container;
|
|
||||||
const auto labelAscent = stLabel.style.font->ascent;
|
|
||||||
const auto button = Ui::CreateChild<Ui::SettingsButton>(
|
|
||||||
content.get(),
|
|
||||||
rpl::single(QString()));
|
|
||||||
|
|
||||||
const auto label = content->add(
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
content,
|
|
||||||
tr::lng_star_ref_existing_title() | Ui::Text::ToBold(),
|
|
||||||
stLabel),
|
|
||||||
titlePadding);
|
|
||||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
const auto description = content->add(
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
content,
|
|
||||||
tr::lng_star_ref_existing_about(),
|
|
||||||
st::boxDividerLabel),
|
|
||||||
descriptionPadding);
|
|
||||||
description->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
|
|
||||||
const auto dummy = Ui::CreateChild<Ui::AbstractButton>(content.get());
|
|
||||||
dummy->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
|
|
||||||
content->sizeValue(
|
|
||||||
) | rpl::start_with_next([=](const QSize &s) {
|
|
||||||
dummy->resize(s.width(), iconSize.height());
|
|
||||||
}, dummy->lifetime());
|
|
||||||
|
|
||||||
label->geometryValue(
|
|
||||||
) | rpl::start_with_next([=](const QRect &r) {
|
|
||||||
dummy->moveToLeft(0, r.y() + (r.height() - labelAscent));
|
|
||||||
}, dummy->lifetime());
|
|
||||||
|
|
||||||
::Settings::AddButtonIcon(dummy, st::settingsButton, {
|
|
||||||
.icon = &st::settingsPremiumIconStar,
|
|
||||||
.backgroundBrush = st::premiumIconBg3,
|
|
||||||
});
|
|
||||||
|
|
||||||
rpl::combine(
|
|
||||||
content->widthValue(),
|
|
||||||
label->heightValue(),
|
|
||||||
description->heightValue()
|
|
||||||
) | rpl::start_with_next([=,
|
|
||||||
topPadding = titlePadding,
|
|
||||||
bottomPadding = descriptionPadding](
|
|
||||||
int width,
|
|
||||||
int topHeight,
|
|
||||||
int bottomHeight) {
|
|
||||||
button->resize(
|
|
||||||
width,
|
|
||||||
topPadding.top()
|
|
||||||
+ topHeight
|
|
||||||
+ topPadding.bottom()
|
|
||||||
+ bottomPadding.top()
|
|
||||||
+ bottomHeight
|
|
||||||
+ bottomPadding.bottom());
|
|
||||||
}, button->lifetime());
|
|
||||||
label->topValue(
|
|
||||||
) | rpl::start_with_next([=, padding = titlePadding.top()](int top) {
|
|
||||||
button->moveToLeft(0, top - padding);
|
|
||||||
}, button->lifetime());
|
|
||||||
const auto arrow = Ui::CreateChild<Ui::IconButton>(
|
|
||||||
button,
|
|
||||||
st::backButton);
|
|
||||||
arrow->setIconOverride(
|
|
||||||
&st::settingsPremiumArrow,
|
|
||||||
&st::settingsPremiumArrowOver);
|
|
||||||
arrow->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
button->sizeValue(
|
|
||||||
) | rpl::start_with_next([=](const QSize &s) {
|
|
||||||
const auto &point = st::settingsPremiumArrowShift;
|
|
||||||
arrow->moveToRight(
|
|
||||||
-point.x(),
|
|
||||||
point.y() + (s.height() - arrow->height()) / 2);
|
|
||||||
}, arrow->lifetime());
|
|
||||||
|
|
||||||
button->setClickedCallback([=] {
|
button->setClickedCallback([=] {
|
||||||
_controller->showToast(u"List or smth.."_q);
|
_controller->showToast(u"List or smth.."_q);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ui::AddSkip(_container);
|
||||||
|
Ui::AddDivider(_container);
|
||||||
|
Ui::AddSkip(_container);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::setupEnd() {
|
void InnerWidget::setupEnd() {
|
||||||
|
@ -361,6 +291,8 @@ void InnerWidget::setupEnd() {
|
||||||
_controller->showToast("Remove failed!");
|
_controller->showToast("Remove failed!");
|
||||||
})).send();
|
})).send();
|
||||||
});
|
});
|
||||||
|
Ui::AddSkip(_container);
|
||||||
|
Ui::AddDivider(_container);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<Ui::RpWidget> InnerWidget::infoRow(
|
object_ptr<Ui::RpWidget> InnerWidget::infoRow(
|
||||||
|
@ -411,11 +343,11 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Memento::Memento(not_null<Controller*> controller)
|
Memento::Memento(not_null<Controller*> controller)
|
||||||
: ContentMemento(Tag(controller->starrefPeer())) {
|
: ContentMemento(Tag(controller->starrefPeer(), controller->starrefType())) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Memento::Memento(not_null<PeerData*> peer)
|
Memento::Memento(not_null<PeerData*> peer)
|
||||||
: ContentMemento(Tag(peer)) {
|
: ContentMemento(Tag(peer, Type::Setup)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Memento::~Memento() = default;
|
Memento::~Memento() = default;
|
||||||
|
@ -509,7 +441,7 @@ std::unique_ptr<Ui::Premium::TopBarAbstract> Widget::setupTop() {
|
||||||
};
|
};
|
||||||
auto result = std::make_unique<Ui::Premium::TopBar>(
|
auto result = std::make_unique<Ui::Premium::TopBar>(
|
||||||
this,
|
this,
|
||||||
st::userPremiumCover,
|
st::starrefCover,
|
||||||
Ui::Premium::TopBarDescriptor{
|
Ui::Premium::TopBarDescriptor{
|
||||||
.clickContextOther = clickContextOther,
|
.clickContextOther = clickContextOther,
|
||||||
.logo = u"affiliate"_q,
|
.logo = u"affiliate"_q,
|
||||||
|
@ -524,16 +456,15 @@ std::unique_ptr<Ui::Premium::TopBarAbstract> Widget::setupTop() {
|
||||||
raw->setRoundEdges(wrap == Info::Wrap::Layer);
|
raw->setRoundEdges(wrap == Info::Wrap::Layer);
|
||||||
}, raw->lifetime());
|
}, raw->lifetime());
|
||||||
|
|
||||||
const auto calculateMaximumHeight = [=] {
|
const auto baseHeight = st::starrefCoverHeight;
|
||||||
return st::settingsPremiumTopHeight;
|
raw->resize(width(), baseHeight);
|
||||||
};
|
|
||||||
|
|
||||||
raw->setMaximumHeight(st::settingsPremiumTopHeight);
|
raw->additionalHeight(
|
||||||
raw->setMinimumHeight(st::settingsPremiumTopHeight);
|
) | rpl::start_with_next([=](int additionalHeight) {
|
||||||
|
raw->setMaximumHeight(baseHeight + additionalHeight);
|
||||||
raw->resize(width(), raw->maximumHeight());
|
raw->setMinimumHeight(baseHeight + additionalHeight);
|
||||||
|
setPaintPadding({ 0, raw->height(), 0, 0 });
|
||||||
setPaintPadding({ 0, st::settingsPremiumTopHeight, 0, 0 });
|
}, raw->lifetime());
|
||||||
|
|
||||||
controller->wrapValue(
|
controller->wrapValue(
|
||||||
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
||||||
|
@ -566,7 +497,7 @@ std::unique_ptr<Ui::Premium::TopBarAbstract> Widget::setupTop() {
|
||||||
} else {
|
} else {
|
||||||
_close = base::make_unique_q<Ui::IconButton>(
|
_close = base::make_unique_q<Ui::IconButton>(
|
||||||
raw,
|
raw,
|
||||||
st::settingsPremiumTopBarClose);
|
st::infoTopBarClose);
|
||||||
_close->addClickHandler([=] {
|
_close->addClickHandler([=] {
|
||||||
controller->parentController()->hideLayer();
|
controller->parentController()->hideLayer();
|
||||||
controller->parentController()->hideSpecialLayer();
|
controller->parentController()->hideSpecialLayer();
|
||||||
|
@ -677,5 +608,92 @@ std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer) {
|
||||||
std::make_shared<Memento>(peer)));
|
std::make_shared<Memento>(peer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Info::BotStarRef
|
not_null<Ui::AbstractButton*> AddViewListButton(
|
||||||
|
not_null<Ui::VerticalLayout*> parent,
|
||||||
|
rpl::producer<QString> title,
|
||||||
|
rpl::producer<QString> subtitle) {
|
||||||
|
const auto &stLabel = st::defaultFlatLabel;
|
||||||
|
const auto iconSize = st::settingsPremiumIconDouble.size();
|
||||||
|
const auto &titlePadding = st::settingsPremiumRowTitlePadding;
|
||||||
|
const auto &descriptionPadding = st::settingsPremiumRowAboutPadding;
|
||||||
|
|
||||||
|
const auto button = Ui::CreateChild<Ui::SettingsButton>(
|
||||||
|
parent,
|
||||||
|
rpl::single(QString()));
|
||||||
|
|
||||||
|
const auto label = parent->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
parent,
|
||||||
|
std::move(title) | Ui::Text::ToBold(),
|
||||||
|
stLabel),
|
||||||
|
titlePadding);
|
||||||
|
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
const auto description = parent->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
parent,
|
||||||
|
std::move(subtitle),
|
||||||
|
st::boxDividerLabel),
|
||||||
|
descriptionPadding);
|
||||||
|
description->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
const auto dummy = Ui::CreateChild<Ui::AbstractButton>(parent);
|
||||||
|
dummy->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
parent->sizeValue(
|
||||||
|
) | rpl::start_with_next([=](const QSize &s) {
|
||||||
|
dummy->resize(s.width(), iconSize.height());
|
||||||
|
}, dummy->lifetime());
|
||||||
|
|
||||||
|
button->geometryValue(
|
||||||
|
) | rpl::start_with_next([=](const QRect &r) {
|
||||||
|
dummy->moveToLeft(0, r.y() + (r.height() - iconSize.height()) / 2);
|
||||||
|
}, dummy->lifetime());
|
||||||
|
|
||||||
|
::Settings::AddButtonIcon(dummy, st::settingsButton, {
|
||||||
|
.icon = &st::settingsPremiumIconStar,
|
||||||
|
.backgroundBrush = st::premiumIconBg3,
|
||||||
|
});
|
||||||
|
|
||||||
|
rpl::combine(
|
||||||
|
parent->widthValue(),
|
||||||
|
label->heightValue(),
|
||||||
|
description->heightValue()
|
||||||
|
) | rpl::start_with_next([=,
|
||||||
|
topPadding = titlePadding,
|
||||||
|
bottomPadding = descriptionPadding](
|
||||||
|
int width,
|
||||||
|
int topHeight,
|
||||||
|
int bottomHeight) {
|
||||||
|
button->resize(
|
||||||
|
width,
|
||||||
|
topPadding.top()
|
||||||
|
+ topHeight
|
||||||
|
+ topPadding.bottom()
|
||||||
|
+ bottomPadding.top()
|
||||||
|
+ bottomHeight
|
||||||
|
+ bottomPadding.bottom());
|
||||||
|
}, button->lifetime());
|
||||||
|
label->topValue(
|
||||||
|
) | rpl::start_with_next([=, padding = titlePadding.top()](int top) {
|
||||||
|
button->moveToLeft(0, top - padding);
|
||||||
|
}, button->lifetime());
|
||||||
|
const auto arrow = Ui::CreateChild<Ui::IconButton>(
|
||||||
|
button,
|
||||||
|
st::backButton);
|
||||||
|
arrow->setIconOverride(
|
||||||
|
&st::settingsPremiumArrow,
|
||||||
|
&st::settingsPremiumArrowOver);
|
||||||
|
arrow->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
button->sizeValue(
|
||||||
|
) | rpl::start_with_next([=](const QSize &s) {
|
||||||
|
const auto &point = st::settingsPremiumArrowShift;
|
||||||
|
arrow->moveToRight(
|
||||||
|
-point.x(),
|
||||||
|
point.y() + (s.height() - arrow->height()) / 2);
|
||||||
|
}, arrow->lifetime());
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Info::BotStarRef::Setup
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "info/info_content_widget.h"
|
||||||
|
|
||||||
|
namespace Ui::Premium {
|
||||||
|
class TopBarAbstract;
|
||||||
|
} // namespace Ui::Premium
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
template <typename Widget>
|
||||||
|
class FadeWrap;
|
||||||
|
class IconButton;
|
||||||
|
class AbstractButton;
|
||||||
|
class VerticalLayout;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Info::BotStarRef::Setup {
|
||||||
|
|
||||||
|
struct State;
|
||||||
|
class InnerWidget;
|
||||||
|
|
||||||
|
class Memento final : public ContentMemento {
|
||||||
|
public:
|
||||||
|
Memento(not_null<Controller*> controller);
|
||||||
|
Memento(not_null<PeerData*> peer);
|
||||||
|
~Memento();
|
||||||
|
|
||||||
|
object_ptr<ContentWidget> createWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Controller*> controller,
|
||||||
|
const QRect &geometry) override;
|
||||||
|
|
||||||
|
Section section() const override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Widget final : public ContentWidget {
|
||||||
|
public:
|
||||||
|
Widget(QWidget *parent, not_null<Controller*> controller);
|
||||||
|
|
||||||
|
bool showInternal(not_null<ContentMemento*> memento) override;
|
||||||
|
rpl::producer<QString> title() override;
|
||||||
|
rpl::producer<bool> desiredShadowVisibility() const override;
|
||||||
|
void showFinished() override;
|
||||||
|
void setInnerFocus() override;
|
||||||
|
void enableBackButton() override;
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<PeerData*> peer() const;
|
||||||
|
|
||||||
|
void setInternalState(
|
||||||
|
const QRect &geometry,
|
||||||
|
not_null<Memento*> memento);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void saveState(not_null<Memento*> memento);
|
||||||
|
void restoreState(not_null<Memento*> memento);
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::Premium::TopBarAbstract> setupTop();
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::RpWidget> setupBottom();
|
||||||
|
|
||||||
|
std::shared_ptr<ContentMemento> doCreateMemento() override;
|
||||||
|
|
||||||
|
const not_null<InnerWidget*> _inner;
|
||||||
|
const not_null<State*> _state;
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::Premium::TopBarAbstract> _top;
|
||||||
|
base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _back;
|
||||||
|
base::unique_qptr<Ui::IconButton> _close;
|
||||||
|
rpl::variable<bool> _backEnabled;
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::RpWidget> _bottom;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer);
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<Ui::AbstractButton*> AddViewListButton(
|
||||||
|
not_null<Ui::VerticalLayout*> parent,
|
||||||
|
rpl::producer<QString> title,
|
||||||
|
rpl::producer<QString> subtitle);
|
||||||
|
|
||||||
|
} // namespace Info::BotStarRef::Setup
|
|
@ -25,10 +25,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "history/view/controls/history_view_webpage_processor.h"
|
#include "history/view/controls/history_view_webpage_processor.h"
|
||||||
|
#include "info/bot/starref/info_bot_starref_join_widget.h"
|
||||||
|
#include "info/bot/starref/info_bot_starref_setup_widget.h"
|
||||||
#include "info/channel_statistics/earn/earn_format.h"
|
#include "info/channel_statistics/earn/earn_format.h"
|
||||||
#include "info/channel_statistics/earn/earn_icons.h"
|
#include "info/channel_statistics/earn/earn_icons.h"
|
||||||
#include "info/channel_statistics/earn/info_channel_earn_widget.h"
|
#include "info/channel_statistics/earn/info_channel_earn_widget.h"
|
||||||
#include "info/info_controller.h"
|
#include "info/info_controller.h"
|
||||||
|
#include "info/info_memento.h"
|
||||||
#include "info/profile/info_profile_values.h" // Info::Profile::NameValue.
|
#include "info/profile/info_profile_values.h" // Info::Profile::NameValue.
|
||||||
#include "info/statistics/info_statistics_inner_widget.h" // FillLoading.
|
#include "info/statistics/info_statistics_inner_widget.h" // FillLoading.
|
||||||
#include "info/statistics/info_statistics_list_controllers.h"
|
#include "info/statistics/info_statistics_list_controllers.h"
|
||||||
|
@ -960,6 +963,17 @@ void InnerWidget::fill() {
|
||||||
) | rpl::map(creditsToUsdMap));
|
) | rpl::map(creditsToUsdMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto button = Info::BotStarRef::Setup::AddViewListButton(
|
||||||
|
container,
|
||||||
|
tr::lng_credits_summary_earn_title(),
|
||||||
|
tr::lng_credits_summary_earn_about());
|
||||||
|
button->setClickedCallback([=] {
|
||||||
|
_controller->showSection(Info::BotStarRef::Join::Make(_peer));
|
||||||
|
});
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddDivider(container);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
|
||||||
const auto sectionIndex = container->lifetime().make_state<int>(0);
|
const auto sectionIndex = container->lifetime().make_state<int>(0);
|
||||||
const auto rebuildLists = [=](
|
const auto rebuildLists = [=](
|
||||||
const Memento::SavedState &data,
|
const Memento::SavedState &data,
|
||||||
|
|
|
@ -379,7 +379,7 @@ Key ContentMemento::key() const {
|
||||||
} else if (statisticsTag().peer) {
|
} else if (statisticsTag().peer) {
|
||||||
return statisticsTag();
|
return statisticsTag();
|
||||||
} else if (const auto starref = starrefPeer()) {
|
} else if (const auto starref = starrefPeer()) {
|
||||||
return BotStarRef::Tag(starref);
|
return BotStarRef::Tag(starref, starrefType());
|
||||||
} else if (const auto who = reactionsWhoReadIds()) {
|
} else if (const auto who = reactionsWhoReadIds()) {
|
||||||
return Key(who, _reactionsSelected, _pollReactionsContextId);
|
return Key(who, _reactionsSelected, _pollReactionsContextId);
|
||||||
} else {
|
} else {
|
||||||
|
@ -423,7 +423,8 @@ ContentMemento::ContentMemento(Statistics::Tag statistics)
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentMemento::ContentMemento(BotStarRef::Tag starref)
|
ContentMemento::ContentMemento(BotStarRef::Tag starref)
|
||||||
: _starrefPeer(starref.peer) {
|
: _starrefPeer(starref.peer)
|
||||||
|
, _starrefType(starref.type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentMemento::ContentMemento(
|
ContentMemento::ContentMemento(
|
||||||
|
|
|
@ -53,6 +53,7 @@ struct Tag;
|
||||||
} // namespace Info::Statistics
|
} // namespace Info::Statistics
|
||||||
|
|
||||||
namespace Info::BotStarRef {
|
namespace Info::BotStarRef {
|
||||||
|
enum class Type : uchar;
|
||||||
struct Tag;
|
struct Tag;
|
||||||
} // namespace Info::BotStarRef
|
} // namespace Info::BotStarRef
|
||||||
|
|
||||||
|
@ -234,6 +235,9 @@ public:
|
||||||
PeerData *starrefPeer() const {
|
PeerData *starrefPeer() const {
|
||||||
return _starrefPeer;
|
return _starrefPeer;
|
||||||
}
|
}
|
||||||
|
BotStarRef::Type starrefType() const {
|
||||||
|
return _starrefType;
|
||||||
|
}
|
||||||
PollData *poll() const {
|
PollData *poll() const {
|
||||||
return _poll;
|
return _poll;
|
||||||
}
|
}
|
||||||
|
@ -289,6 +293,7 @@ private:
|
||||||
Stories::Tab _storiesTab = {};
|
Stories::Tab _storiesTab = {};
|
||||||
Statistics::Tag _statisticsTag;
|
Statistics::Tag _statisticsTag;
|
||||||
PeerData * const _starrefPeer = nullptr;
|
PeerData * const _starrefPeer = nullptr;
|
||||||
|
BotStarRef::Type _starrefType = {};
|
||||||
PollData * const _poll = nullptr;
|
PollData * const _poll = nullptr;
|
||||||
std::shared_ptr<Api::WhoReadList> _reactionsWhoReadIds;
|
std::shared_ptr<Api::WhoReadList> _reactionsWhoReadIds;
|
||||||
Data::ReactionId _reactionsSelected;
|
Data::ReactionId _reactionsSelected;
|
||||||
|
|
|
@ -116,6 +116,13 @@ PeerData *Key::starrefPeer() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BotStarRef::Type Key::starrefType() const {
|
||||||
|
if (const auto tag = std::get_if<BotStarRef::Tag>(&_value)) {
|
||||||
|
return tag->type;
|
||||||
|
}
|
||||||
|
return BotStarRef::Type();
|
||||||
|
}
|
||||||
|
|
||||||
PollData *Key::poll() const {
|
PollData *Key::poll() const {
|
||||||
if (const auto data = std::get_if<PollKey>(&_value)) {
|
if (const auto data = std::get_if<PollKey>(&_value)) {
|
||||||
return data->poll;
|
return data->poll;
|
||||||
|
@ -330,7 +337,8 @@ bool Controller::validateMementoPeer(
|
||||||
&& memento->settingsSelf() == settingsSelf()
|
&& memento->settingsSelf() == settingsSelf()
|
||||||
&& memento->storiesPeer() == storiesPeer()
|
&& memento->storiesPeer() == storiesPeer()
|
||||||
&& memento->statisticsTag().peer == statisticsTag().peer
|
&& memento->statisticsTag().peer == statisticsTag().peer
|
||||||
&& memento->starrefPeer() == starrefPeer();
|
&& memento->starrefPeer() == starrefPeer()
|
||||||
|
&& memento->starrefType() == starrefType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::setSection(not_null<ContentMemento*> memento) {
|
void Controller::setSection(not_null<ContentMemento*> memento) {
|
||||||
|
|
|
@ -63,11 +63,16 @@ struct Tag {
|
||||||
|
|
||||||
namespace Info::BotStarRef {
|
namespace Info::BotStarRef {
|
||||||
|
|
||||||
|
enum class Type : uchar {
|
||||||
|
Setup,
|
||||||
|
Join,
|
||||||
|
};
|
||||||
struct Tag {
|
struct Tag {
|
||||||
explicit Tag(not_null<PeerData*> peer) : peer(peer) {
|
Tag(not_null<PeerData*> peer, Type type) : peer(peer), type(type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<PeerData*> peer;
|
not_null<PeerData*> peer;
|
||||||
|
Type type = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Info::BotStarRef
|
} // namespace Info::BotStarRef
|
||||||
|
@ -97,6 +102,7 @@ public:
|
||||||
Stories::Tab storiesTab() const;
|
Stories::Tab storiesTab() const;
|
||||||
Statistics::Tag statisticsTag() const;
|
Statistics::Tag statisticsTag() const;
|
||||||
PeerData *starrefPeer() const;
|
PeerData *starrefPeer() const;
|
||||||
|
BotStarRef::Type starrefType() const;
|
||||||
PollData *poll() const;
|
PollData *poll() const;
|
||||||
FullMsgId pollContextId() const;
|
FullMsgId pollContextId() const;
|
||||||
std::shared_ptr<Api::WhoReadList> reactionsWhoReadIds() const;
|
std::shared_ptr<Api::WhoReadList> reactionsWhoReadIds() const;
|
||||||
|
@ -220,6 +226,9 @@ public:
|
||||||
[[nodiscard]] PeerData *starrefPeer() const {
|
[[nodiscard]] PeerData *starrefPeer() const {
|
||||||
return key().starrefPeer();
|
return key().starrefPeer();
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] BotStarRef::Type starrefType() const {
|
||||||
|
return key().starrefType();
|
||||||
|
}
|
||||||
[[nodiscard]] PollData *poll() const;
|
[[nodiscard]] PollData *poll() const;
|
||||||
[[nodiscard]] FullMsgId pollContextId() const {
|
[[nodiscard]] FullMsgId pollContextId() const {
|
||||||
return key().pollContextId();
|
return key().pollContextId();
|
||||||
|
|
|
@ -292,6 +292,7 @@ Dialogs::RowDescriptor WrapWidget::activeChat() const {
|
||||||
|| key().isDownloads()
|
|| key().isDownloads()
|
||||||
|| key().reactionsContextId()
|
|| key().reactionsContextId()
|
||||||
|| key().poll()
|
|| key().poll()
|
||||||
|
|| key().starrefPeer()
|
||||||
|| key().statisticsTag().peer) {
|
|| key().statisticsTag().peer) {
|
||||||
return Dialogs::RowDescriptor();
|
return Dialogs::RowDescriptor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -484,8 +484,8 @@ settingsPremiumArrow: icon{{ "settings/premium/arrow", menuIconFg }};
|
||||||
settingsPremiumArrowOver: icon{{ "settings/premium/arrow", menuIconFgOver }};
|
settingsPremiumArrowOver: icon{{ "settings/premium/arrow", menuIconFgOver }};
|
||||||
|
|
||||||
settingsPremiumOptionsPadding: margins(0px, 9px, 0px, 2px);
|
settingsPremiumOptionsPadding: margins(0px, 9px, 0px, 2px);
|
||||||
settingsPremiumTopHeight: 220px;
|
settingsPremiumTopHeight: 202px;
|
||||||
settingsPremiumUserHeight: 223px;
|
settingsPremiumUserHeight: 205px;
|
||||||
settingsPremiumUserTitlePadding: margins(0px, 16px, 0px, 6px);
|
settingsPremiumUserTitlePadding: margins(0px, 16px, 0px, 6px);
|
||||||
settingsPremiumUserTitle: FlatLabel(boxTitle) {
|
settingsPremiumUserTitle: FlatLabel(boxTitle) {
|
||||||
style: TextStyle(defaultTextStyle) {
|
style: TextStyle(defaultTextStyle) {
|
||||||
|
|
|
@ -612,23 +612,10 @@ QPointer<Ui::RpWidget> Business::createPinnedToTop(
|
||||||
content->setRoundEdges(wrap == Info::Wrap::Layer);
|
content->setRoundEdges(wrap == Info::Wrap::Layer);
|
||||||
}, content->lifetime());
|
}, content->lifetime());
|
||||||
|
|
||||||
const auto calculateMaximumHeight = [=] {
|
content->setMaximumHeight(st::settingsPremiumTopHeight);
|
||||||
return st::settingsPremiumTopHeight;
|
content->setMinimumHeight(st::settingsPremiumTopHeight);
|
||||||
};
|
|
||||||
|
|
||||||
content->setMaximumHeight(calculateMaximumHeight());
|
|
||||||
content->setMinimumHeight(st::settingsPremiumTopHeight);// st::infoLayerTopBarHeight);
|
|
||||||
|
|
||||||
content->resize(content->width(), content->maximumHeight());
|
content->resize(content->width(), content->maximumHeight());
|
||||||
//content->additionalHeight(
|
|
||||||
//) | rpl::start_with_next([=](int additionalHeight) {
|
|
||||||
// const auto wasMax = (content->height() == content->maximumHeight());
|
|
||||||
// content->setMaximumHeight(calculateMaximumHeight()
|
|
||||||
// + additionalHeight);
|
|
||||||
// if (wasMax) {
|
|
||||||
// content->resize(content->width(), content->maximumHeight());
|
|
||||||
// }
|
|
||||||
//}, content->lifetime());
|
|
||||||
|
|
||||||
_wrap.value(
|
_wrap.value(
|
||||||
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
) | rpl::start_with_next([=](Info::Wrap wrap) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ creditsLowBalancePremiumCover: PremiumCover(creditsPremiumCover) {
|
||||||
starSize: size(64px, 62px);
|
starSize: size(64px, 62px);
|
||||||
starTopSkip: 30px;
|
starTopSkip: 30px;
|
||||||
}
|
}
|
||||||
creditsLowBalancePremiumCoverHeight: 180px;
|
creditsLowBalancePremiumCoverHeight: 162px;
|
||||||
creditsTopupButton: SettingsButton(settingsButton) {
|
creditsTopupButton: SettingsButton(settingsButton) {
|
||||||
style: semiboldTextStyle;
|
style: semiboldTextStyle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,12 @@ userPremiumCoverAbout: FlatLabel(boxDividerLabel) {
|
||||||
userPremiumCover: PremiumCover(defaultPremiumCover) {
|
userPremiumCover: PremiumCover(defaultPremiumCover) {
|
||||||
about: userPremiumCoverAbout;
|
about: userPremiumCoverAbout;
|
||||||
}
|
}
|
||||||
|
starrefCover: PremiumCover(userPremiumCover) {
|
||||||
|
bg: windowBgOver;
|
||||||
|
starTopSkip: 24px;
|
||||||
|
titlePadding: margins(0px, 12px, 0px, 11px);
|
||||||
|
}
|
||||||
|
starrefCoverHeight: 180px;
|
||||||
|
|
||||||
defaultPremiumBoxLabel: FlatLabel(defaultFlatLabel) {
|
defaultPremiumBoxLabel: FlatLabel(defaultFlatLabel) {
|
||||||
minWidth: 220px;
|
minWidth: 220px;
|
||||||
|
|
|
@ -140,8 +140,7 @@ TopBar::TopBar(
|
||||||
QGradientStops{{ 0, st::premiumButtonFg->c }});
|
QGradientStops{{ 0, st::premiumButtonFg->c }});
|
||||||
} else if (_logo == u"affiliate"_q) {
|
} else if (_logo == u"affiliate"_q) {
|
||||||
_dollar = ScaleTo(QImage(u":/gui/art/affiliate_logo.png"_q));
|
_dollar = ScaleTo(QImage(u":/gui/art/affiliate_logo.png"_q));
|
||||||
_ministars.setColorOverride(
|
_ministars.setColorOverride(descriptor.gradientStops);
|
||||||
QGradientStops{{ 0, st::premiumButtonFg->c }});
|
|
||||||
} else if (!_light && !TopBarAbstract::isDark()) {
|
} else if (!_light && !TopBarAbstract::isDark()) {
|
||||||
_star.load(Svg());
|
_star.load(Svg());
|
||||||
_ministars.setColorOverride(
|
_ministars.setColorOverride(
|
||||||
|
@ -184,7 +183,7 @@ void TopBar::setTextPosition(int x, int y) {
|
||||||
rpl::producer<int> TopBar::additionalHeight() const {
|
rpl::producer<int> TopBar::additionalHeight() const {
|
||||||
return _about->heightValue(
|
return _about->heightValue(
|
||||||
) | rpl::map([l = st().about.style.lineHeight](int height) {
|
) | rpl::map([l = st().about.style.lineHeight](int height) {
|
||||||
return std::max(height - l * 2, 0);
|
return std::max(height - l, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +222,6 @@ void TopBar::resizeEvent(QResizeEvent *e) {
|
||||||
void TopBar::paintEvent(QPaintEvent *e) {
|
void TopBar::paintEvent(QPaintEvent *e) {
|
||||||
auto p = QPainter(this);
|
auto p = QPainter(this);
|
||||||
|
|
||||||
p.fillRect(e->rect(), Qt::transparent);
|
|
||||||
|
|
||||||
const auto r = rect();
|
const auto r = rect();
|
||||||
|
|
||||||
if (!_light && !TopBarAbstract::isDark()) {
|
if (!_light && !TopBarAbstract::isDark()) {
|
||||||
|
|
|
@ -381,6 +381,9 @@ void SessionNavigation::showPeerByLink(const PeerByLinkInfo &info) {
|
||||||
showPeerByLinkResolved(peer, info);
|
showPeerByLinkResolved(peer, info);
|
||||||
});
|
});
|
||||||
} else if (const auto name = std::get_if<QString>(&info.usernameOrId)) {
|
} else if (const auto name = std::get_if<QString>(&info.usernameOrId)) {
|
||||||
|
const auto starref = (info.resolveType == ResolveType::StarRef)
|
||||||
|
? info.startToken
|
||||||
|
: QString();
|
||||||
resolveUsername(*name, [=](not_null<PeerData*> peer) {
|
resolveUsername(*name, [=](not_null<PeerData*> peer) {
|
||||||
if (info.startAutoSubmit) {
|
if (info.startAutoSubmit) {
|
||||||
peer->session().api().blockedPeers().unblock(
|
peer->session().api().blockedPeers().unblock(
|
||||||
|
@ -392,7 +395,7 @@ void SessionNavigation::showPeerByLink(const PeerByLinkInfo &info) {
|
||||||
} else {
|
} else {
|
||||||
showPeerByLinkResolved(peer, info);
|
showPeerByLinkResolved(peer, info);
|
||||||
}
|
}
|
||||||
});
|
}, starref);
|
||||||
} else if (const auto id = std::get_if<ChannelId>(&info.usernameOrId)) {
|
} else if (const auto id = std::get_if<ChannelId>(&info.usernameOrId)) {
|
||||||
resolveChannelById(*id, [=](not_null<ChannelData*> channel) {
|
resolveChannelById(*id, [=](not_null<ChannelData*> channel) {
|
||||||
showPeerByLinkResolved(channel, info);
|
showPeerByLinkResolved(channel, info);
|
||||||
|
@ -454,16 +457,20 @@ void SessionNavigation::resolveChatLink(
|
||||||
|
|
||||||
void SessionNavigation::resolveUsername(
|
void SessionNavigation::resolveUsername(
|
||||||
const QString &username,
|
const QString &username,
|
||||||
Fn<void(not_null<PeerData*>)> done) {
|
Fn<void(not_null<PeerData*>)> done,
|
||||||
if (const auto peer = _session->data().peerByUsername(username)) {
|
const QString &starref) {
|
||||||
done(peer);
|
if (starref.isEmpty()) {
|
||||||
return;
|
if (const auto peer = _session->data().peerByUsername(username)) {
|
||||||
|
done(peer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_api.request(base::take(_resolveRequestId)).cancel();
|
_api.request(base::take(_resolveRequestId)).cancel();
|
||||||
|
using Flag = MTPcontacts_ResolveUsername::Flag;
|
||||||
_resolveRequestId = _api.request(MTPcontacts_ResolveUsername(
|
_resolveRequestId = _api.request(MTPcontacts_ResolveUsername(
|
||||||
MTP_flags(0),
|
MTP_flags(starref.isEmpty() ? Flag() : Flag::f_referer),
|
||||||
MTP_string(username),
|
MTP_string(username),
|
||||||
MTP_string()
|
MTP_string(starref)
|
||||||
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
)).done([=](const MTPcontacts_ResolvedPeer &result) {
|
||||||
resolveDone(result, done);
|
resolveDone(result, done);
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
@ -678,6 +685,8 @@ void SessionNavigation::showPeerByLinkResolved(
|
||||||
}
|
}
|
||||||
} else if (resolveType == ResolveType::Boost && peer->isChannel()) {
|
} else if (resolveType == ResolveType::Boost && peer->isChannel()) {
|
||||||
resolveBoostState(peer->asChannel());
|
resolveBoostState(peer->asChannel());
|
||||||
|
} else if (resolveType == ResolveType::StarRef) {
|
||||||
|
showPeerHistory(peer, params);
|
||||||
} else {
|
} else {
|
||||||
// Show specific posts only in channels / supergroups.
|
// Show specific posts only in channels / supergroups.
|
||||||
const auto msgId = peer->isChannel()
|
const auto msgId = peer->isChannel()
|
||||||
|
|
|
@ -280,7 +280,8 @@ private:
|
||||||
Fn<void(not_null<PeerData*> peer, TextWithEntities draft)> done);
|
Fn<void(not_null<PeerData*> peer, TextWithEntities draft)> done);
|
||||||
void resolveUsername(
|
void resolveUsername(
|
||||||
const QString &username,
|
const QString &username,
|
||||||
Fn<void(not_null<PeerData*>)> done);
|
Fn<void(not_null<PeerData*>)> done,
|
||||||
|
const QString &starref = QString());
|
||||||
void resolveChannelById(
|
void resolveChannelById(
|
||||||
ChannelId channelId,
|
ChannelId channelId,
|
||||||
Fn<void(not_null<ChannelData*>)> done);
|
Fn<void(not_null<ChannelData*>)> done);
|
||||||
|
|
|
@ -24,6 +24,7 @@ enum class ResolveType {
|
||||||
Mention,
|
Mention,
|
||||||
Boost,
|
Boost,
|
||||||
Profile,
|
Profile,
|
||||||
|
StarRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommentId {
|
struct CommentId {
|
||||||
|
|
Loading…
Add table
Reference in a new issue