mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Start multiboosts, support dynamic state.
This commit is contained in:
parent
2d67557a91
commit
a41bbd27c8
11 changed files with 300 additions and 191 deletions
|
@ -2030,6 +2030,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_premium_gift_terms_link" = "here";
|
"lng_premium_gift_terms_link" = "here";
|
||||||
|
|
||||||
"lng_boost_channel_button" = "Boost Channel";
|
"lng_boost_channel_button" = "Boost Channel";
|
||||||
|
"lng_boost_again_button" = "Boost Again";
|
||||||
"lng_boost_level#one" = "Level {count}";
|
"lng_boost_level#one" = "Level {count}";
|
||||||
"lng_boost_level#other" = "Level {count}";
|
"lng_boost_level#other" = "Level {count}";
|
||||||
"lng_boost_channel_title_first" = "Enable stories for channel";
|
"lng_boost_channel_title_first" = "Enable stories for channel";
|
||||||
|
@ -2060,6 +2061,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_boost_error_flood_text" = "You can change the channel you boost only once a day. Next time you can boost is in {left}.";
|
"lng_boost_error_flood_text" = "You can change the channel you boost only once a day. Next time you can boost is in {left}.";
|
||||||
"lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?";
|
"lng_boost_now_instead" = "You currently boost {channel}. Do you want to boost {other} instead?";
|
||||||
"lng_boost_now_replace" = "Replace";
|
"lng_boost_now_replace" = "Replace";
|
||||||
|
"lng_boost_reassign_title" = "Reassign boost";
|
||||||
|
"lng_boost_reassign_text" = "To boost {channel}, reassign a previous boost from another channel.";
|
||||||
|
"lng_boost_remove_title" = "Remove your boost from";
|
||||||
|
"lng_boost_reassign_button" = "Reassign";
|
||||||
|
"lng_boost_available_in" = "available in {duration}";
|
||||||
|
"lng_boost_available_in_toast#one" = "Wait until the boost is available or get **{count}** more boost by gifting a **Telegram Premium** subscription.";
|
||||||
|
"lng_boost_available_in_toast#other" = "Wait until the boost is available or get **{count}** more boosts by gifting a **Telegram Premium** subscription.";
|
||||||
|
|
||||||
"lng_boost_channel_title_color" = "Enable colors";
|
"lng_boost_channel_title_color" = "Enable colors";
|
||||||
"lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color.";
|
"lng_boost_channel_needs_level_color#one" = "Your channel needs to reach **Level {count}** to change channel color.";
|
||||||
|
|
|
@ -519,7 +519,9 @@ rpl::producer<rpl::no_value, QString> Boosts::request() {
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
_boostStatus.overview = Data::BoostsOverview{
|
_boostStatus.overview = Data::BoostsOverview{
|
||||||
.isBoosted = data.is_my_boost(),
|
.mine = (data.vmy_boost_slots()
|
||||||
|
? data.vmy_boost_slots()->v.size()
|
||||||
|
: 0),
|
||||||
.level = std::max(data.vlevel().v, 0),
|
.level = std::max(data.vlevel().v, 0),
|
||||||
.boostCount = std::max(
|
.boostCount = std::max(
|
||||||
data.vboosts().v,
|
data.vboosts().v,
|
||||||
|
|
|
@ -514,21 +514,17 @@ void Apply(
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto next = data.vnext_level_boosts().value_or_empty();
|
|
||||||
const auto openStatistics = [=] {
|
const auto openStatistics = [=] {
|
||||||
if (const auto controller = show->resolveWindow(
|
if (const auto controller = show->resolveWindow(
|
||||||
ChatHelpers::WindowUsage::PremiumPromo)) {
|
ChatHelpers::WindowUsage::PremiumPromo)) {
|
||||||
controller->showSection(Info::Boosts::Make(peer));
|
controller->showSection(Info::Boosts::Make(peer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
auto counters = Window::ParseBoostCounters(result);
|
||||||
|
counters.mine = 0; // Don't show current level as just-reached.
|
||||||
show->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
|
show->show(Box(Ui::AskBoostBox, Ui::AskBoostBoxData{
|
||||||
.link = qs(data.vboost_url()),
|
.link = qs(data.vboost_url()),
|
||||||
.boost = {
|
.boost = counters,
|
||||||
.level = data.vlevel().v,
|
|
||||||
.boosts = data.vboosts().v,
|
|
||||||
.thisLevelBoosts = data.vcurrent_level_boosts().v,
|
|
||||||
.nextLevelBoosts = next,
|
|
||||||
},
|
|
||||||
.requiredLevel = required,
|
.requiredLevel = required,
|
||||||
}, openStatistics, nullptr));
|
}, openStatistics, nullptr));
|
||||||
cancel();
|
cancel();
|
||||||
|
|
|
@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
struct BoostsOverview final {
|
struct BoostsOverview final {
|
||||||
bool isBoosted = false;
|
int mine = 0;
|
||||||
int level = 0;
|
int level = 0;
|
||||||
int boostCount = 0;
|
int boostCount = 0;
|
||||||
int currentLevelBoostCount = 0;
|
int currentLevelBoostCount = 0;
|
||||||
|
|
|
@ -302,17 +302,16 @@ void InnerWidget::fill() {
|
||||||
auto dividerContent = object_ptr<Ui::VerticalLayout>(inner);
|
auto dividerContent = object_ptr<Ui::VerticalLayout>(inner);
|
||||||
Ui::FillBoostLimit(
|
Ui::FillBoostLimit(
|
||||||
fakeShowed->events(),
|
fakeShowed->events(),
|
||||||
rpl::single(status.overview.isBoosted),
|
|
||||||
dividerContent.data(),
|
dividerContent.data(),
|
||||||
Ui::BoostCounters{
|
rpl::single(Ui::BoostCounters{
|
||||||
.level = status.overview.level,
|
.level = status.overview.level,
|
||||||
.boosts = status.overview.boostCount,
|
.boosts = status.overview.boostCount,
|
||||||
.thisLevelBoosts
|
.thisLevelBoosts
|
||||||
= status.overview.currentLevelBoostCount,
|
= status.overview.currentLevelBoostCount,
|
||||||
.nextLevelBoosts
|
.nextLevelBoosts
|
||||||
= status.overview.nextLevelBoostCount,
|
= status.overview.nextLevelBoostCount,
|
||||||
.mine = status.overview.isBoosted,
|
.mine = status.overview.mine,
|
||||||
},
|
}),
|
||||||
st::statisticsLimitsLinePadding);
|
st::statisticsLimitsLinePadding);
|
||||||
inner->add(object_ptr<Ui::DividerLabel>(
|
inner->add(object_ptr<Ui::DividerLabel>(
|
||||||
inner,
|
inner,
|
||||||
|
|
|
@ -20,6 +20,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscrd]] BoostCounters AdjustByReached(BoostCounters data) {
|
||||||
|
const auto exact = (data.boosts == data.thisLevelBoosts);
|
||||||
|
const auto reached = !data.nextLevelBoosts || (exact && data.mine > 0);
|
||||||
|
if (reached) {
|
||||||
|
if (data.nextLevelBoosts) {
|
||||||
|
--data.level;
|
||||||
|
}
|
||||||
|
data.boosts = data.nextLevelBoosts = std::max({
|
||||||
|
data.boosts,
|
||||||
|
data.thisLevelBoosts,
|
||||||
|
1
|
||||||
|
});
|
||||||
|
data.thisLevelBoosts = 0;
|
||||||
|
} else {
|
||||||
|
data.boosts = std::max(data.thisLevelBoosts, data.boosts);
|
||||||
|
data.nextLevelBoosts = std::max(
|
||||||
|
data.nextLevelBoosts,
|
||||||
|
data.boosts + 1);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void StartFireworks(not_null<QWidget*> parent) {
|
void StartFireworks(not_null<QWidget*> parent) {
|
||||||
const auto result = Ui::CreateChild<RpWidget>(parent.get());
|
const auto result = Ui::CreateChild<RpWidget>(parent.get());
|
||||||
|
@ -42,62 +67,65 @@ void StartFireworks(not_null<QWidget*> parent) {
|
||||||
void BoostBox(
|
void BoostBox(
|
||||||
not_null<GenericBox*> box,
|
not_null<GenericBox*> box,
|
||||||
BoostBoxData data,
|
BoostBoxData data,
|
||||||
Fn<void(Fn<void(bool)>)> boost) {
|
Fn<void(Fn<void(BoostCounters)>)> boost) {
|
||||||
box->setWidth(st::boxWideWidth);
|
box->setWidth(st::boxWideWidth);
|
||||||
box->setStyle(st::boostBox);
|
box->setStyle(st::boostBox);
|
||||||
|
|
||||||
const auto full = !data.boost.nextLevelBoosts;
|
//AssertIsDebug();
|
||||||
|
//data.boost = {
|
||||||
|
// .level = 2,
|
||||||
|
// .boosts = 3,
|
||||||
|
// .thisLevelBoosts = 2,
|
||||||
|
// .nextLevelBoosts = 5,
|
||||||
|
// .mine = 2,
|
||||||
|
//};
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
rpl::variable<bool> you = false;
|
rpl::variable<BoostCounters> data;
|
||||||
|
rpl::variable<bool> full;
|
||||||
bool submitted = false;
|
bool submitted = false;
|
||||||
};
|
};
|
||||||
const auto state = box->lifetime().make_state<State>(State{
|
const auto state = box->lifetime().make_state<State>();
|
||||||
.you = data.boost.mine,
|
state->data = std::move(data.boost);
|
||||||
});
|
|
||||||
|
|
||||||
FillBoostLimit(
|
FillBoostLimit(
|
||||||
BoxShowFinishes(box),
|
BoxShowFinishes(box),
|
||||||
state->you.value(),
|
|
||||||
box->verticalLayout(),
|
box->verticalLayout(),
|
||||||
data.boost,
|
state->data.value(),
|
||||||
st::boxRowPadding);
|
st::boxRowPadding);
|
||||||
|
|
||||||
{
|
|
||||||
const auto &d = data.boost;
|
|
||||||
if (!d.nextLevelBoosts
|
|
||||||
|| ((d.thisLevelBoosts == d.boosts) && d.mine)) {
|
|
||||||
--data.boost.level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
|
box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
|
||||||
|
|
||||||
const auto name = data.name;
|
const auto name = data.name;
|
||||||
auto title = state->you.value() | rpl::map([=](bool your) {
|
|
||||||
return your
|
auto title = state->data.value(
|
||||||
|
) | rpl::map([=](BoostCounters counters) {
|
||||||
|
return (counters.mine > 0)
|
||||||
? tr::lng_boost_channel_you_title(
|
? tr::lng_boost_channel_you_title(
|
||||||
lt_channel,
|
lt_channel,
|
||||||
rpl::single(data.name))
|
rpl::single(name))
|
||||||
: full
|
: !counters.nextLevelBoosts
|
||||||
? tr::lng_boost_channel_title_max()
|
? tr::lng_boost_channel_title_max()
|
||||||
: !data.boost.level
|
: !counters.level
|
||||||
? tr::lng_boost_channel_title_first()
|
? tr::lng_boost_channel_title_first()
|
||||||
: tr::lng_boost_channel_title_more();
|
: tr::lng_boost_channel_title_more();
|
||||||
}) | rpl::flatten_latest();
|
}) | rpl::flatten_latest();
|
||||||
auto text = state->you.value() | rpl::map([=](bool your) {
|
|
||||||
const auto bold = Ui::Text::Bold(data.name);
|
auto text = state->data.value(
|
||||||
const auto now = data.boost.boosts + (your ? 1 : 0);
|
) | rpl::map([=](BoostCounters counters) {
|
||||||
const auto left = (data.boost.nextLevelBoosts > now)
|
const auto bold = Ui::Text::Bold(name);
|
||||||
? (data.boost.nextLevelBoosts - now)
|
const auto now = counters.boosts;
|
||||||
|
const auto full = !counters.nextLevelBoosts;
|
||||||
|
const auto left = (counters.nextLevelBoosts > now)
|
||||||
|
? (counters.nextLevelBoosts - now)
|
||||||
: 0;
|
: 0;
|
||||||
auto post = tr::lng_boost_channel_post_stories(
|
auto post = tr::lng_boost_channel_post_stories(
|
||||||
lt_count,
|
lt_count,
|
||||||
rpl::single(float64(data.boost.level + 1)),
|
rpl::single(float64(counters.level + (left ? 1 : 0))),
|
||||||
Ui::Text::RichLangValue);
|
Ui::Text::RichLangValue);
|
||||||
return (your || full)
|
return (counters.mine || full)
|
||||||
? ((!full && left > 0)
|
? (left
|
||||||
? (!data.boost.level
|
? (!counters.level
|
||||||
? tr::lng_boost_channel_you_first(
|
? tr::lng_boost_channel_you_first(
|
||||||
lt_count,
|
lt_count,
|
||||||
rpl::single(float64(left)),
|
rpl::single(float64(left)),
|
||||||
|
@ -108,16 +136,16 @@ void BoostBox(
|
||||||
lt_post,
|
lt_post,
|
||||||
std::move(post),
|
std::move(post),
|
||||||
Ui::Text::RichLangValue))
|
Ui::Text::RichLangValue))
|
||||||
: (!data.boost.level
|
: (!counters.level
|
||||||
? tr::lng_boost_channel_reached_first(
|
? tr::lng_boost_channel_reached_first(
|
||||||
Ui::Text::RichLangValue)
|
Ui::Text::RichLangValue)
|
||||||
: tr::lng_boost_channel_reached_more(
|
: tr::lng_boost_channel_reached_more(
|
||||||
lt_count,
|
lt_count,
|
||||||
rpl::single(float64(data.boost.level + 1)),
|
rpl::single(float64(counters.level)),
|
||||||
lt_post,
|
lt_post,
|
||||||
std::move(post),
|
std::move(post),
|
||||||
Ui::Text::RichLangValue)))
|
Ui::Text::RichLangValue)))
|
||||||
: !data.boost.level
|
: !counters.level
|
||||||
? tr::lng_boost_channel_needs_first(
|
? tr::lng_boost_channel_needs_first(
|
||||||
lt_count,
|
lt_count,
|
||||||
rpl::single(float64(left)),
|
rpl::single(float64(left)),
|
||||||
|
@ -133,12 +161,14 @@ void BoostBox(
|
||||||
std::move(post),
|
std::move(post),
|
||||||
Ui::Text::RichLangValue);
|
Ui::Text::RichLangValue);
|
||||||
}) | rpl::flatten_latest();
|
}) | rpl::flatten_latest();
|
||||||
|
|
||||||
box->addRow(
|
box->addRow(
|
||||||
object_ptr<Ui::FlatLabel>(
|
object_ptr<Ui::FlatLabel>(
|
||||||
box,
|
box,
|
||||||
std::move(title),
|
std::move(title),
|
||||||
st::boostTitle),
|
st::boostTitle),
|
||||||
st::boxRowPadding + QMargins(0, st::boostTitleSkip, 0, 0));
|
st::boxRowPadding + QMargins(0, st::boostTitleSkip, 0, 0));
|
||||||
|
|
||||||
box->addRow(
|
box->addRow(
|
||||||
object_ptr<Ui::FlatLabel>(
|
object_ptr<Ui::FlatLabel>(
|
||||||
box,
|
box,
|
||||||
|
@ -147,28 +177,83 @@ void BoostBox(
|
||||||
(st::boxRowPadding
|
(st::boxRowPadding
|
||||||
+ QMargins(0, st::boostTextSkip, 0, st::boostBottomSkip)));
|
+ QMargins(0, st::boostTextSkip, 0, st::boostBottomSkip)));
|
||||||
|
|
||||||
auto submit = full
|
auto submit = state->data.value(
|
||||||
? (tr::lng_box_ok() | rpl::type_erased())
|
) | rpl::map([=](BoostCounters counters) {
|
||||||
: state->you.value(
|
return !counters.nextLevelBoosts
|
||||||
) | rpl::map([](bool mine) {
|
? tr::lng_box_ok()
|
||||||
return mine ? tr::lng_box_ok() : tr::lng_boost_channel_button();
|
: (counters.mine > 0)
|
||||||
}) | rpl::flatten_latest();
|
? tr::lng_boost_again_button()
|
||||||
|
: tr::lng_boost_channel_button();
|
||||||
|
}) | rpl::flatten_latest();
|
||||||
|
|
||||||
const auto button = box->addButton(rpl::duplicate(submit), [=] {
|
const auto button = box->addButton(rpl::duplicate(submit), [=] {
|
||||||
if (state->submitted) {
|
if (state->submitted) {
|
||||||
return;
|
return;
|
||||||
} else if (!full && !state->you.current()) {
|
} else if (state->data.current().nextLevelBoosts > 0) {
|
||||||
state->submitted = true;
|
state->submitted = true;
|
||||||
boost(crl::guard(box, [=](bool success) {
|
const auto was = state->data.current().mine;
|
||||||
|
|
||||||
|
//AssertIsDebug();
|
||||||
|
//state->submitted = false;
|
||||||
|
//if (state->data.current().level == 5
|
||||||
|
// && state->data.current().boosts == 11) {
|
||||||
|
// state->data = BoostCounters{
|
||||||
|
// .level = 5,
|
||||||
|
// .boosts = 14,
|
||||||
|
// .thisLevelBoosts = 9,
|
||||||
|
// .nextLevelBoosts = 15,
|
||||||
|
// .mine = 14,
|
||||||
|
// };
|
||||||
|
//} else if (state->data.current().level == 5) {
|
||||||
|
// state->data = BoostCounters{
|
||||||
|
// .level = 7,
|
||||||
|
// .boosts = 16,
|
||||||
|
// .thisLevelBoosts = 15,
|
||||||
|
// .nextLevelBoosts = 19,
|
||||||
|
// .mine = 16,
|
||||||
|
// };
|
||||||
|
//} else if (state->data.current().level == 4) {
|
||||||
|
// state->data = BoostCounters{
|
||||||
|
// .level = 5,
|
||||||
|
// .boosts = 11,
|
||||||
|
// .thisLevelBoosts = 9,
|
||||||
|
// .nextLevelBoosts = 15,
|
||||||
|
// .mine = 9,
|
||||||
|
// };
|
||||||
|
//} else if (state->data.current().level == 3) {
|
||||||
|
// state->data = BoostCounters{
|
||||||
|
// .level = 4,
|
||||||
|
// .boosts = 7,
|
||||||
|
// .thisLevelBoosts = 7,
|
||||||
|
// .nextLevelBoosts = 9,
|
||||||
|
// .mine = 5,
|
||||||
|
// };
|
||||||
|
//} else {
|
||||||
|
// state->data = BoostCounters{
|
||||||
|
// .level = 3,
|
||||||
|
// .boosts = 5,
|
||||||
|
// .thisLevelBoosts = 5,
|
||||||
|
// .nextLevelBoosts = 7,
|
||||||
|
// .mine = 3,
|
||||||
|
// };
|
||||||
|
//}
|
||||||
|
//return;
|
||||||
|
|
||||||
|
boost(crl::guard(box, [=](BoostCounters result) {
|
||||||
state->submitted = false;
|
state->submitted = false;
|
||||||
if (success) {
|
|
||||||
StartFireworks(box->parentWidget());
|
if (result.thisLevelBoosts || result.nextLevelBoosts) {
|
||||||
state->you = true;
|
if (result.mine > was) {
|
||||||
|
StartFireworks(box->parentWidget());
|
||||||
|
}
|
||||||
|
state->data = result;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
std::move(submit),
|
std::move(submit),
|
||||||
box->widthValue()
|
box->widthValue()
|
||||||
|
@ -270,18 +355,14 @@ void AskBoostBox(
|
||||||
box->setStyle(st::boostBox);
|
box->setStyle(st::boostBox);
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
rpl::variable<bool> you = false;
|
|
||||||
bool submitted = false;
|
bool submitted = false;
|
||||||
};
|
};
|
||||||
const auto state = box->lifetime().make_state<State>(State{
|
const auto state = box->lifetime().make_state<State>();
|
||||||
.you = data.boost.mine,
|
|
||||||
});
|
|
||||||
|
|
||||||
FillBoostLimit(
|
FillBoostLimit(
|
||||||
BoxShowFinishes(box),
|
BoxShowFinishes(box),
|
||||||
state->you.value(),
|
|
||||||
box->verticalLayout(),
|
box->verticalLayout(),
|
||||||
data.boost,
|
rpl::single(data.boost),
|
||||||
st::boxRowPadding);
|
st::boxRowPadding);
|
||||||
|
|
||||||
box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
|
box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
|
||||||
|
@ -338,56 +419,22 @@ void AskBoostBox(
|
||||||
|
|
||||||
void FillBoostLimit(
|
void FillBoostLimit(
|
||||||
rpl::producer<> showFinished,
|
rpl::producer<> showFinished,
|
||||||
rpl::producer<bool> you,
|
|
||||||
not_null<VerticalLayout*> container,
|
not_null<VerticalLayout*> container,
|
||||||
BoostCounters data,
|
rpl::producer<BoostCounters> data,
|
||||||
style::margins limitLinePadding) {
|
style::margins limitLinePadding) {
|
||||||
const auto full = !data.nextLevelBoosts;
|
|
||||||
|
|
||||||
if (data.mine && data.boosts > 0) {
|
|
||||||
--data.boosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (full) {
|
|
||||||
data.nextLevelBoosts = data.boosts
|
|
||||||
+ (data.mine ? 1 : 0);
|
|
||||||
data.thisLevelBoosts = 0;
|
|
||||||
if (data.level > 0) {
|
|
||||||
--data.level;
|
|
||||||
}
|
|
||||||
} else if (data.mine
|
|
||||||
&& data.level > 0
|
|
||||||
&& data.boosts < data.thisLevelBoosts) {
|
|
||||||
--data.level;
|
|
||||||
data.nextLevelBoosts = data.thisLevelBoosts;
|
|
||||||
data.thisLevelBoosts = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto addSkip = [&](int skip) {
|
const auto addSkip = [&](int skip) {
|
||||||
container->add(object_ptr<Ui::FixedHeightWidget>(container, skip));
|
container->add(object_ptr<Ui::FixedHeightWidget>(container, skip));
|
||||||
};
|
};
|
||||||
|
|
||||||
addSkip(st::boostSkipTop);
|
addSkip(st::boostSkipTop);
|
||||||
|
|
||||||
const auto levelWidth = [&](int add) {
|
const auto ratio = [=](BoostCounters counters) {
|
||||||
return st::normalFont->width(
|
const auto min = counters.thisLevelBoosts;
|
||||||
tr::lng_boost_level(tr::now, lt_count, data.level + add));
|
const auto max = counters.nextLevelBoosts;
|
||||||
};
|
|
||||||
const auto paddings = 2 * st::premiumLineTextSkip;
|
Assert(counters.boosts >= min && counters.boosts <= max);
|
||||||
const auto labelLeftWidth = paddings + levelWidth(0);
|
|
||||||
const auto labelRightWidth = paddings + levelWidth(1);
|
|
||||||
const auto ratio = [=](int boosts) {
|
|
||||||
const auto min = std::min(
|
|
||||||
data.boosts,
|
|
||||||
data.thisLevelBoosts);
|
|
||||||
const auto max = std::max({
|
|
||||||
data.boosts,
|
|
||||||
data.nextLevelBoosts,
|
|
||||||
1,
|
|
||||||
});
|
|
||||||
Assert(boosts >= min && boosts <= max);
|
|
||||||
const auto count = (max - min);
|
const auto count = (max - min);
|
||||||
const auto index = (boosts - min);
|
const auto index = (counters.boosts - min);
|
||||||
if (!index) {
|
if (!index) {
|
||||||
return 0.;
|
return 0.;
|
||||||
} else if (index == count) {
|
} else if (index == count) {
|
||||||
|
@ -399,26 +446,33 @@ void FillBoostLimit(
|
||||||
- st::boxPadding.left()
|
- st::boxPadding.left()
|
||||||
- st::boxPadding.right();
|
- st::boxPadding.right();
|
||||||
const auto average = available / float64(count);
|
const auto average = available / float64(count);
|
||||||
|
const auto levelWidth = [&](int add) {
|
||||||
|
return st::normalFont->width(
|
||||||
|
tr::lng_boost_level(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
counters.level + add));
|
||||||
|
};
|
||||||
|
const auto paddings = 2 * st::premiumLineTextSkip;
|
||||||
|
const auto labelLeftWidth = paddings + levelWidth(0);
|
||||||
|
const auto labelRightWidth = paddings + levelWidth(1);
|
||||||
const auto first = std::max(average, labelLeftWidth * 1.);
|
const auto first = std::max(average, labelLeftWidth * 1.);
|
||||||
const auto last = std::max(average, labelRightWidth * 1.);
|
const auto last = std::max(average, labelRightWidth * 1.);
|
||||||
const auto other = (available - first - last) / (count - 2);
|
const auto other = (available - first - last) / (count - 2);
|
||||||
return (first + (index - 1) * other) / available;
|
return (first + (index - 1) * other) / available;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto min = std::min(data.boosts, data.thisLevelBoosts);
|
auto adjustedData = rpl::duplicate(data) | rpl::map(AdjustByReached);
|
||||||
const auto now = data.boosts;
|
|
||||||
const auto max = (data.nextLevelBoosts > min)
|
auto bubbleRowState = rpl::duplicate(
|
||||||
? (data.nextLevelBoosts)
|
adjustedData
|
||||||
: (data.boosts > 0)
|
) | rpl::combine_previous(
|
||||||
? data.boosts
|
BoostCounters()
|
||||||
: 1;
|
) | rpl::map([=](BoostCounters previous, BoostCounters counters) {
|
||||||
auto bubbleRowState = (
|
|
||||||
std::move(you)
|
|
||||||
) | rpl::map([=](bool mine) {
|
|
||||||
const auto index = mine ? (now + 1) : now;
|
|
||||||
return Premium::BubbleRowState{
|
return Premium::BubbleRowState{
|
||||||
.counter = index,
|
.counter = counters.boosts,
|
||||||
.ratio = ratio(index),
|
.ratio = ratio(counters),
|
||||||
|
.animateFromZero = (counters.level != previous.level),
|
||||||
.dynamic = true,
|
.dynamic = true,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -427,7 +481,6 @@ void FillBoostLimit(
|
||||||
st::boostBubble,
|
st::boostBubble,
|
||||||
std::move(showFinished),
|
std::move(showFinished),
|
||||||
rpl::duplicate(bubbleRowState),
|
rpl::duplicate(bubbleRowState),
|
||||||
max,
|
|
||||||
true,
|
true,
|
||||||
nullptr,
|
nullptr,
|
||||||
&st::premiumIconBoost,
|
&st::premiumIconBoost,
|
||||||
|
@ -437,20 +490,33 @@ void FillBoostLimit(
|
||||||
const auto level = [](int level) {
|
const auto level = [](int level) {
|
||||||
return tr::lng_boost_level(tr::now, lt_count, level);
|
return tr::lng_boost_level(tr::now, lt_count, level);
|
||||||
};
|
};
|
||||||
auto ratioValue = std::move(
|
auto limitState = std::move(
|
||||||
bubbleRowState
|
bubbleRowState
|
||||||
) | rpl::map([](const Premium::BubbleRowState &state) {
|
) | rpl::map([](const Premium::BubbleRowState &state) {
|
||||||
return state.ratio;
|
return Premium::LimitRowState{
|
||||||
|
.ratio = state.ratio,
|
||||||
|
.animateFromZero = state.animateFromZero,
|
||||||
|
.dynamic = state.dynamic
|
||||||
|
};
|
||||||
|
});
|
||||||
|
auto left = rpl::duplicate(
|
||||||
|
adjustedData
|
||||||
|
) | rpl::map([=](BoostCounters counters) {
|
||||||
|
return level(counters.level);
|
||||||
|
});
|
||||||
|
auto right = rpl::duplicate(
|
||||||
|
adjustedData
|
||||||
|
) | rpl::map([=](BoostCounters counters) {
|
||||||
|
return level(counters.level + 1);
|
||||||
});
|
});
|
||||||
Premium::AddLimitRow(
|
Premium::AddLimitRow(
|
||||||
container,
|
container,
|
||||||
st::boostLimits,
|
st::boostLimits,
|
||||||
Premium::LimitRowLabels{
|
Premium::LimitRowLabels{
|
||||||
.leftLabel = level(data.level),
|
.leftLabel = std::move(left),
|
||||||
.rightLabel = level(data.level + 1),
|
.rightLabel = std::move(right),
|
||||||
.dynamic = true,
|
|
||||||
},
|
},
|
||||||
std::move(ratioValue),
|
std::move(limitState),
|
||||||
limitLinePadding);
|
limitLinePadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,11 @@ struct BoostCounters {
|
||||||
int boosts = 0;
|
int boosts = 0;
|
||||||
int thisLevelBoosts = 0;
|
int thisLevelBoosts = 0;
|
||||||
int nextLevelBoosts = 0; // Zero means no next level is available.
|
int nextLevelBoosts = 0; // Zero means no next level is available.
|
||||||
bool mine = false;
|
int mine = 0;
|
||||||
|
|
||||||
|
friend inline constexpr bool operator==(
|
||||||
|
BoostCounters,
|
||||||
|
BoostCounters) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BoostBoxData {
|
struct BoostBoxData {
|
||||||
|
@ -34,7 +38,7 @@ struct BoostBoxData {
|
||||||
void BoostBox(
|
void BoostBox(
|
||||||
not_null<GenericBox*> box,
|
not_null<GenericBox*> box,
|
||||||
BoostBoxData data,
|
BoostBoxData data,
|
||||||
Fn<void(Fn<void(bool)>)> boost);
|
Fn<void(Fn<void(BoostCounters)>)> boost);
|
||||||
|
|
||||||
struct AskBoostBoxData {
|
struct AskBoostBoxData {
|
||||||
QString link;
|
QString link;
|
||||||
|
@ -57,9 +61,8 @@ void AskBoostBox(
|
||||||
|
|
||||||
void FillBoostLimit(
|
void FillBoostLimit(
|
||||||
rpl::producer<> showFinished,
|
rpl::producer<> showFinished,
|
||||||
rpl::producer<bool> you,
|
|
||||||
not_null<VerticalLayout*> container,
|
not_null<VerticalLayout*> container,
|
||||||
BoostCounters data,
|
rpl::producer<BoostCounters> data,
|
||||||
style::margins limitLinePadding);
|
style::margins limitLinePadding);
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -195,7 +195,7 @@ public:
|
||||||
[[nodiscard]] int height() const;
|
[[nodiscard]] int height() const;
|
||||||
[[nodiscard]] int width() const;
|
[[nodiscard]] int width() const;
|
||||||
[[nodiscard]] int bubbleRadius() const;
|
[[nodiscard]] int bubbleRadius() const;
|
||||||
[[nodiscard]] int countMaxWidth(int maxCounter) const;
|
[[nodiscard]] int countMaxWidth(int maxPossibleCounter) const;
|
||||||
|
|
||||||
void setCounter(int value);
|
void setCounter(int value);
|
||||||
void setTailEdge(EdgeProgress edge);
|
void setTailEdge(EdgeProgress edge);
|
||||||
|
@ -271,12 +271,12 @@ int Bubble::width() const {
|
||||||
return filledWidth() + _numberAnimation.countWidth();
|
return filledWidth() + _numberAnimation.countWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Bubble::countMaxWidth(int maxCounter) const {
|
int Bubble::countMaxWidth(int maxPossibleCounter) const {
|
||||||
auto numbers = Ui::NumbersAnimation(_st.font, [] {});
|
auto numbers = Ui::NumbersAnimation(_st.font, [] {});
|
||||||
numbers.setDisabledMonospace(true);
|
numbers.setDisabledMonospace(true);
|
||||||
numbers.setDuration(0);
|
numbers.setDuration(0);
|
||||||
numbers.setText(_textFactory(0), 0);
|
numbers.setText(_textFactory(0), 0);
|
||||||
numbers.setText(_textFactory(maxCounter), maxCounter);
|
numbers.setText(_textFactory(maxPossibleCounter), maxPossibleCounter);
|
||||||
numbers.finishAnimating();
|
numbers.finishAnimating();
|
||||||
return filledWidth() + numbers.maxWidth();
|
return filledWidth() + numbers.maxWidth();
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,6 @@ public:
|
||||||
const style::PremiumBubble &st,
|
const style::PremiumBubble &st,
|
||||||
TextFactory textFactory,
|
TextFactory textFactory,
|
||||||
rpl::producer<BubbleRowState> state,
|
rpl::producer<BubbleRowState> state,
|
||||||
int maxCounter,
|
|
||||||
bool premiumPossible,
|
bool premiumPossible,
|
||||||
rpl::producer<> showFinishes,
|
rpl::producer<> showFinishes,
|
||||||
const style::icon *icon,
|
const style::icon *icon,
|
||||||
|
@ -414,9 +413,8 @@ private:
|
||||||
BubbleRowState _animatingFrom;
|
BubbleRowState _animatingFrom;
|
||||||
float64 _animatingFromResultRatio = 0.;
|
float64 _animatingFromResultRatio = 0.;
|
||||||
rpl::variable<BubbleRowState> _state;
|
rpl::variable<BubbleRowState> _state;
|
||||||
const int _maxCounter;
|
|
||||||
Bubble _bubble;
|
Bubble _bubble;
|
||||||
const int _maxBubbleWidth;
|
int _maxBubbleWidth = 0;
|
||||||
const bool _premiumPossible;
|
const bool _premiumPossible;
|
||||||
const style::margins _outerPadding;
|
const style::margins _outerPadding;
|
||||||
|
|
||||||
|
@ -439,7 +437,6 @@ BubbleWidget::BubbleWidget(
|
||||||
const style::PremiumBubble &st,
|
const style::PremiumBubble &st,
|
||||||
TextFactory textFactory,
|
TextFactory textFactory,
|
||||||
rpl::producer<BubbleRowState> state,
|
rpl::producer<BubbleRowState> state,
|
||||||
int maxCounter,
|
|
||||||
bool premiumPossible,
|
bool premiumPossible,
|
||||||
rpl::producer<> showFinishes,
|
rpl::producer<> showFinishes,
|
||||||
const style::icon *icon,
|
const style::icon *icon,
|
||||||
|
@ -447,14 +444,12 @@ BubbleWidget::BubbleWidget(
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _st(st)
|
, _st(st)
|
||||||
, _state(std::move(state))
|
, _state(std::move(state))
|
||||||
, _maxCounter(maxCounter)
|
|
||||||
, _bubble(
|
, _bubble(
|
||||||
_st,
|
_st,
|
||||||
[=] { update(); },
|
[=] { update(); },
|
||||||
std::move(textFactory),
|
std::move(textFactory),
|
||||||
icon,
|
icon,
|
||||||
premiumPossible)
|
premiumPossible)
|
||||||
, _maxBubbleWidth(_bubble.countMaxWidth(_maxCounter))
|
|
||||||
, _premiumPossible(premiumPossible)
|
, _premiumPossible(premiumPossible)
|
||||||
, _outerPadding(outerPadding)
|
, _outerPadding(outerPadding)
|
||||||
, _deflection(kDeflection)
|
, _deflection(kDeflection)
|
||||||
|
@ -485,6 +480,7 @@ BubbleWidget::BubbleWidget(
|
||||||
}
|
}
|
||||||
|
|
||||||
void BubbleWidget::animateTo(BubbleRowState state) {
|
void BubbleWidget::animateTo(BubbleRowState state) {
|
||||||
|
_maxBubbleWidth = _bubble.countMaxWidth(state.counter);
|
||||||
const auto parent = parentWidget();
|
const auto parent = parentWidget();
|
||||||
const auto computeLeft = [=](float64 pointRatio, float64 animProgress) {
|
const auto computeLeft = [=](float64 pointRatio, float64 animProgress) {
|
||||||
const auto halfWidth = (_maxBubbleWidth / 2);
|
const auto halfWidth = (_maxBubbleWidth / 2);
|
||||||
|
@ -541,6 +537,11 @@ void BubbleWidget::animateTo(BubbleRowState state) {
|
||||||
const auto duration = kSlideDuration
|
const auto duration = kSlideDuration
|
||||||
* (_ignoreDeflection ? kStepBeforeDeflection : 1.)
|
* (_ignoreDeflection ? kStepBeforeDeflection : 1.)
|
||||||
* ((_state.current().ratio < 0.001) ? 0.5 : 1.);
|
* ((_state.current().ratio < 0.001) ? 0.5 : 1.);
|
||||||
|
if (state.animateFromZero) {
|
||||||
|
_animatingFrom.ratio = 0.;
|
||||||
|
_animatingFrom.counter = 0;
|
||||||
|
_animatingFromResultRatio = 0.;
|
||||||
|
}
|
||||||
_appearanceAnimation.start([=](float64 value) {
|
_appearanceAnimation.start([=](float64 value) {
|
||||||
if (!_appearanceAnimation.animating()) {
|
if (!_appearanceAnimation.animating()) {
|
||||||
_animatingFrom = state;
|
_animatingFrom = state;
|
||||||
|
@ -658,7 +659,7 @@ public:
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
const style::PremiumLimits &st,
|
const style::PremiumLimits &st,
|
||||||
LimitRowLabels labels,
|
LimitRowLabels labels,
|
||||||
rpl::producer<float64> ratio);
|
rpl::producer<LimitRowState> state);
|
||||||
|
|
||||||
void setColorOverride(QBrush brush);
|
void setColorOverride(QBrush brush);
|
||||||
|
|
||||||
|
@ -675,6 +676,7 @@ private:
|
||||||
|
|
||||||
float64 _ratio = 0.;
|
float64 _ratio = 0.;
|
||||||
Ui::Animations::Simple _animation;
|
Ui::Animations::Simple _animation;
|
||||||
|
rpl::event_stream<> _recaches;
|
||||||
Ui::Text::String _leftLabel;
|
Ui::Text::String _leftLabel;
|
||||||
Ui::Text::String _leftText;
|
Ui::Text::String _leftText;
|
||||||
Ui::Text::String _rightLabel;
|
Ui::Text::String _rightLabel;
|
||||||
|
@ -707,44 +709,56 @@ Line::Line(
|
||||||
QString min,
|
QString min,
|
||||||
float64 ratio)
|
float64 ratio)
|
||||||
: Line(parent, st, LimitRowLabels{
|
: Line(parent, st, LimitRowLabels{
|
||||||
.leftLabel = tr::lng_premium_free(tr::now),
|
.leftLabel = tr::lng_premium_free(),
|
||||||
.leftCount = min,
|
.leftCount = rpl::single(min),
|
||||||
.rightLabel = tr::lng_premium(tr::now),
|
.rightLabel = tr::lng_premium(),
|
||||||
.rightCount = max,
|
.rightCount = rpl::single(max),
|
||||||
}, rpl::single(ratio)) {
|
}, rpl::single(LimitRowState{ ratio })) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Line::Line(
|
Line::Line(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
const style::PremiumLimits &st,
|
const style::PremiumLimits &st,
|
||||||
LimitRowLabels labels,
|
LimitRowLabels labels,
|
||||||
rpl::producer<float64> ratio)
|
rpl::producer<LimitRowState> state)
|
||||||
: Ui::RpWidget(parent)
|
: Ui::RpWidget(parent)
|
||||||
, _st(st)
|
, _st(st) {
|
||||||
, _leftLabel(st::semiboldTextStyle, labels.leftLabel)
|
|
||||||
, _leftText(st::semiboldTextStyle, labels.leftCount)
|
|
||||||
, _rightLabel(st::semiboldTextStyle, labels.rightLabel)
|
|
||||||
, _rightText(st::semiboldTextStyle, labels.rightCount)
|
|
||||||
, _dynamic(labels.dynamic) {
|
|
||||||
resize(width(), st::requestsAcceptButton.height);
|
resize(width(), st::requestsAcceptButton.height);
|
||||||
|
|
||||||
std::move(ratio) | rpl::start_with_next([=](float64 ratio) {
|
const auto set = [&](
|
||||||
|
Ui::Text::String &label,
|
||||||
|
rpl::producer<QString> &text) {
|
||||||
|
std::move(text) | rpl::start_with_next([=, &label](QString text) {
|
||||||
|
label = { st::semiboldTextStyle, text };
|
||||||
|
_recaches.fire({});
|
||||||
|
}, lifetime());
|
||||||
|
};
|
||||||
|
set(_leftLabel, labels.leftLabel);
|
||||||
|
set(_leftText, labels.leftCount);
|
||||||
|
set(_rightLabel, labels.rightLabel);
|
||||||
|
set(_rightText, labels.rightCount);
|
||||||
|
|
||||||
|
std::move(state) | rpl::start_with_next([=](LimitRowState state) {
|
||||||
|
_dynamic = state.dynamic;
|
||||||
if (width() > 0) {
|
if (width() > 0) {
|
||||||
const auto from = _animation.value(_ratio);
|
const auto from = state.animateFromZero
|
||||||
|
? 0.
|
||||||
|
: _animation.value(_ratio);
|
||||||
const auto duration = kSlideDuration * kStepBeforeDeflection;
|
const auto duration = kSlideDuration * kStepBeforeDeflection;
|
||||||
_animation.start([=] {
|
_animation.start([=] {
|
||||||
update();
|
update();
|
||||||
}, from, ratio, duration, anim::easeOutCirc);
|
}, from, state.ratio, duration, anim::easeOutCirc);
|
||||||
}
|
}
|
||||||
_ratio = ratio;
|
_ratio = state.ratio;
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
sizeValue(),
|
sizeValue(),
|
||||||
parent->widthValue()
|
parent->widthValue(),
|
||||||
) | rpl::filter([](const QSize &size, int parentWidth) {
|
_recaches.events_starting_with({})
|
||||||
|
) | rpl::filter([](const QSize &size, int parentWidth, auto) {
|
||||||
return !size.isEmpty() && parentWidth;
|
return !size.isEmpty() && parentWidth;
|
||||||
}) | rpl::start_with_next([=](const QSize &size, int) {
|
}) | rpl::start_with_next([=](const QSize &size, auto, auto) {
|
||||||
recache(size);
|
recache(size);
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
@ -906,7 +920,6 @@ void AddBubbleRow(
|
||||||
.counter = current,
|
.counter = current,
|
||||||
.ratio = (current - min) / float64(max - min),
|
.ratio = (current - min) / float64(max - min),
|
||||||
}),
|
}),
|
||||||
max,
|
|
||||||
premiumPossible,
|
premiumPossible,
|
||||||
ProcessTextFactory(phrase),
|
ProcessTextFactory(phrase),
|
||||||
icon,
|
icon,
|
||||||
|
@ -918,7 +931,6 @@ void AddBubbleRow(
|
||||||
const style::PremiumBubble &st,
|
const style::PremiumBubble &st,
|
||||||
rpl::producer<> showFinishes,
|
rpl::producer<> showFinishes,
|
||||||
rpl::producer<BubbleRowState> state,
|
rpl::producer<BubbleRowState> state,
|
||||||
int max,
|
|
||||||
bool premiumPossible,
|
bool premiumPossible,
|
||||||
Fn<QString(int)> text,
|
Fn<QString(int)> text,
|
||||||
const style::icon *icon,
|
const style::icon *icon,
|
||||||
|
@ -930,7 +942,6 @@ void AddBubbleRow(
|
||||||
st,
|
st,
|
||||||
text ? std::move(text) : ProcessTextFactory(std::nullopt),
|
text ? std::move(text) : ProcessTextFactory(std::nullopt),
|
||||||
std::move(state),
|
std::move(state),
|
||||||
max,
|
|
||||||
premiumPossible,
|
premiumPossible,
|
||||||
std::move(showFinishes),
|
std::move(showFinishes),
|
||||||
icon,
|
icon,
|
||||||
|
@ -975,10 +986,10 @@ void AddLimitRow(
|
||||||
not_null<Ui::VerticalLayout*> parent,
|
not_null<Ui::VerticalLayout*> parent,
|
||||||
const style::PremiumLimits &st,
|
const style::PremiumLimits &st,
|
||||||
LimitRowLabels labels,
|
LimitRowLabels labels,
|
||||||
rpl::producer<float64> ratio,
|
rpl::producer<LimitRowState> state,
|
||||||
const style::margins &padding) {
|
const style::margins &padding) {
|
||||||
parent->add(
|
parent->add(
|
||||||
object_ptr<Line>(parent, st, std::move(labels), std::move(ratio)),
|
object_ptr<Line>(parent, st, std::move(labels), std::move(state)),
|
||||||
padding);
|
padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ void AddBubbleRow(
|
||||||
struct BubbleRowState {
|
struct BubbleRowState {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
float64 ratio = 0.;
|
float64 ratio = 0.;
|
||||||
|
bool animateFromZero = false;
|
||||||
bool dynamic = false;
|
bool dynamic = false;
|
||||||
};
|
};
|
||||||
void AddBubbleRow(
|
void AddBubbleRow(
|
||||||
|
@ -62,7 +63,6 @@ void AddBubbleRow(
|
||||||
const style::PremiumBubble &st,
|
const style::PremiumBubble &st,
|
||||||
rpl::producer<> showFinishes,
|
rpl::producer<> showFinishes,
|
||||||
rpl::producer<BubbleRowState> state,
|
rpl::producer<BubbleRowState> state,
|
||||||
int max,
|
|
||||||
bool premiumPossible,
|
bool premiumPossible,
|
||||||
Fn<QString(int)> text,
|
Fn<QString(int)> text,
|
||||||
const style::icon *icon,
|
const style::icon *icon,
|
||||||
|
@ -84,17 +84,23 @@ void AddLimitRow(
|
||||||
float64 ratio = kLimitRowRatio);
|
float64 ratio = kLimitRowRatio);
|
||||||
|
|
||||||
struct LimitRowLabels {
|
struct LimitRowLabels {
|
||||||
QString leftLabel;
|
rpl::producer<QString> leftLabel;
|
||||||
QString leftCount;
|
rpl::producer<QString> leftCount;
|
||||||
QString rightLabel;
|
rpl::producer<QString> rightLabel;
|
||||||
QString rightCount;
|
rpl::producer<QString> rightCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LimitRowState {
|
||||||
|
float64 ratio = 0.;
|
||||||
|
bool animateFromZero = false;
|
||||||
bool dynamic = false;
|
bool dynamic = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddLimitRow(
|
void AddLimitRow(
|
||||||
not_null<Ui::VerticalLayout*> parent,
|
not_null<Ui::VerticalLayout*> parent,
|
||||||
const style::PremiumLimits &st,
|
const style::PremiumLimits &st,
|
||||||
LimitRowLabels labels,
|
LimitRowLabels labels,
|
||||||
rpl::producer<float64> ratio,
|
rpl::producer<LimitRowState> state,
|
||||||
const style::margins &padding);
|
const style::margins &padding);
|
||||||
|
|
||||||
struct AccountsRowArgs final {
|
struct AccountsRowArgs final {
|
||||||
|
|
|
@ -267,6 +267,19 @@ Fn<bool()> PausedIn(
|
||||||
return [=] { return IsPaused(controller, level); };
|
return [=] { return IsPaused(controller, level); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ui::BoostCounters ParseBoostCounters(
|
||||||
|
const MTPpremium_BoostsStatus &status) {
|
||||||
|
const auto &data = status.data();
|
||||||
|
const auto slots = data.vmy_boost_slots();
|
||||||
|
return {
|
||||||
|
.level = data.vlevel().v,
|
||||||
|
.boosts = data.vboosts().v,
|
||||||
|
.thisLevelBoosts = data.vcurrent_level_boosts().v,
|
||||||
|
.nextLevelBoosts = data.vnext_level_boosts().value_or_empty(),
|
||||||
|
.mine = slots ? slots->v.size() : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const PeerThemeOverride &a, const PeerThemeOverride &b) {
|
bool operator==(const PeerThemeOverride &a, const PeerThemeOverride &b) {
|
||||||
return (a.peer == b.peer) && (a.theme == b.theme);
|
return (a.peer == b.peer) && (a.theme == b.theme);
|
||||||
}
|
}
|
||||||
|
@ -629,20 +642,12 @@ void SessionNavigation::resolveBoostState(not_null<ChannelData*> channel) {
|
||||||
channel->input
|
channel->input
|
||||||
)).done([=](const MTPpremium_BoostsStatus &result) {
|
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||||
_boostStateResolving = nullptr;
|
_boostStateResolving = nullptr;
|
||||||
const auto &data = result.data();
|
const auto submit = [=](Fn<void(Ui::BoostCounters)> done) {
|
||||||
const auto submit = [=](Fn<void(bool)> done) {
|
|
||||||
applyBoost(channel, done);
|
applyBoost(channel, done);
|
||||||
};
|
};
|
||||||
const auto next = data.vnext_level_boosts().value_or_empty();
|
|
||||||
uiShow()->show(Box(Ui::BoostBox, Ui::BoostBoxData{
|
uiShow()->show(Box(Ui::BoostBox, Ui::BoostBoxData{
|
||||||
.name = channel->name(),
|
.name = channel->name(),
|
||||||
.boost = {
|
.boost = ParseBoostCounters(result),
|
||||||
.level = data.vlevel().v,
|
|
||||||
.boosts = data.vboosts().v,
|
|
||||||
.thisLevelBoosts = data.vcurrent_level_boosts().v,
|
|
||||||
.nextLevelBoosts = next,
|
|
||||||
.mine = data.is_my_boost(),
|
|
||||||
},
|
|
||||||
}, submit));
|
}, submit));
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
_boostStateResolving = nullptr;
|
_boostStateResolving = nullptr;
|
||||||
|
@ -652,7 +657,7 @@ void SessionNavigation::resolveBoostState(not_null<ChannelData*> channel) {
|
||||||
|
|
||||||
void SessionNavigation::applyBoost(
|
void SessionNavigation::applyBoost(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
Fn<void(bool)> done) {
|
Fn<void(Ui::BoostCounters)> done) {
|
||||||
_api.request(MTPpremium_GetMyBoosts(
|
_api.request(MTPpremium_GetMyBoosts(
|
||||||
)).done([=](const MTPpremium_MyBoosts &result) {
|
)).done([=](const MTPpremium_MyBoosts &result) {
|
||||||
const auto &data = result.data();
|
const auto &data = result.data();
|
||||||
|
@ -682,7 +687,7 @@ void SessionNavigation::applyBoost(
|
||||||
.inform = true,
|
.inform = true,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
done(false);
|
done({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto slot = int();
|
auto slot = int();
|
||||||
|
@ -725,7 +730,7 @@ void SessionNavigation::applyBoost(
|
||||||
.title = tr::lng_boost_error_flood_title(),
|
.title = tr::lng_boost_error_flood_title(),
|
||||||
.inform = true,
|
.inform = true,
|
||||||
}));
|
}));
|
||||||
done(false);
|
done({});
|
||||||
} else {
|
} else {
|
||||||
const auto peer = _session->data().peer(different);
|
const auto peer = _session->data().peer(different);
|
||||||
replaceBoostConfirm(peer, channel, slot, done);
|
replaceBoostConfirm(peer, channel, slot, done);
|
||||||
|
@ -737,12 +742,12 @@ void SessionNavigation::applyBoost(
|
||||||
.title = tr::lng_boost_error_already_title(),
|
.title = tr::lng_boost_error_already_title(),
|
||||||
.inform = true,
|
.inform = true,
|
||||||
}));
|
}));
|
||||||
done(false);
|
done({});
|
||||||
}
|
}
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
const auto type = error.type();
|
const auto type = error.type();
|
||||||
showToast(u"Error: "_q + type);
|
showToast(u"Error: "_q + type);
|
||||||
done(false);
|
done({});
|
||||||
}).handleFloodErrors().send();
|
}).handleFloodErrors().send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,7 +755,7 @@ void SessionNavigation::replaceBoostConfirm(
|
||||||
not_null<PeerData*> from,
|
not_null<PeerData*> from,
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
int slot,
|
int slot,
|
||||||
Fn<void(bool)> done) {
|
Fn<void(Ui::BoostCounters)> done) {
|
||||||
const auto forwarded = std::make_shared<bool>(false);
|
const auto forwarded = std::make_shared<bool>(false);
|
||||||
const auto confirmed = [=](Fn<void()> close) {
|
const auto confirmed = [=](Fn<void()> close) {
|
||||||
*forwarded = true;
|
*forwarded = true;
|
||||||
|
@ -777,23 +782,30 @@ void SessionNavigation::replaceBoostConfirm(
|
||||||
box->boxClosing() | rpl::filter([=] {
|
box->boxClosing() | rpl::filter([=] {
|
||||||
return !*forwarded;
|
return !*forwarded;
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
done(false);
|
done({});
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionNavigation::applyBoostChecked(
|
void SessionNavigation::applyBoostChecked(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
int slot,
|
int slot,
|
||||||
Fn<void(bool)> done) {
|
Fn<void(Ui::BoostCounters)> done) {
|
||||||
_api.request(MTPpremium_ApplyBoost(
|
_api.request(MTPpremium_ApplyBoost(
|
||||||
MTP_flags(MTPpremium_ApplyBoost::Flag::f_slots),
|
MTP_flags(MTPpremium_ApplyBoost::Flag::f_slots),
|
||||||
MTP_vector<MTPint>({ MTP_int(slot) }),
|
MTP_vector<MTPint>({ MTP_int(slot) }),
|
||||||
channel->input
|
channel->input
|
||||||
)).done([=](const MTPpremium_MyBoosts &result) {
|
)).done([=](const MTPpremium_MyBoosts &result) {
|
||||||
done(true);
|
_api.request(MTPpremium_GetBoostsStatus(
|
||||||
|
channel->input
|
||||||
|
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||||
|
done(ParseBoostCounters(result));
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
showToast(u"Error: "_q + error.type());
|
||||||
|
done({});
|
||||||
|
}).send();
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
showToast(u"Error: "_q + error.type());
|
showToast(u"Error: "_q + error.type());
|
||||||
done(false);
|
done({});
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ struct ChatPaintContext;
|
||||||
struct ChatThemeBackground;
|
struct ChatThemeBackground;
|
||||||
struct ChatThemeBackgroundData;
|
struct ChatThemeBackgroundData;
|
||||||
class MessageSendingAnimationController;
|
class MessageSendingAnimationController;
|
||||||
|
struct BoostCounters;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
@ -314,16 +315,18 @@ private:
|
||||||
const PeerByLinkInfo &info);
|
const PeerByLinkInfo &info);
|
||||||
|
|
||||||
void resolveBoostState(not_null<ChannelData*> channel);
|
void resolveBoostState(not_null<ChannelData*> channel);
|
||||||
void applyBoost(not_null<ChannelData*> channel, Fn<void(bool)> done);
|
void applyBoost(
|
||||||
|
not_null<ChannelData*> channel,
|
||||||
|
Fn<void(Ui::BoostCounters)> done);
|
||||||
void replaceBoostConfirm(
|
void replaceBoostConfirm(
|
||||||
not_null<PeerData*> from,
|
not_null<PeerData*> from,
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
int slot,
|
int slot,
|
||||||
Fn<void(bool)> done);
|
Fn<void(Ui::BoostCounters)> done);
|
||||||
void applyBoostChecked(
|
void applyBoostChecked(
|
||||||
not_null<ChannelData*> channel,
|
not_null<ChannelData*> channel,
|
||||||
int slot,
|
int slot,
|
||||||
Fn<void(bool)> done);
|
Fn<void(Ui::BoostCounters)> done);
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
|
|
||||||
|
@ -752,4 +755,7 @@ void ActivateWindow(not_null<SessionController*> controller);
|
||||||
not_null<SessionController*> controller,
|
not_null<SessionController*> controller,
|
||||||
GifPauseReason level);
|
GifPauseReason level);
|
||||||
|
|
||||||
|
[[nodiscard]] Ui::BoostCounters ParseBoostCounters(
|
||||||
|
const MTPpremium_BoostsStatus &status);
|
||||||
|
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
Loading…
Add table
Reference in a new issue