mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Moved out special widget for credits input to single place.
This commit is contained in:
parent
93aebc747d
commit
37181f9d0a
3 changed files with 304 additions and 272 deletions
|
@ -8,9 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "info/bot/earn/info_earn_inner_widget.h"
|
#include "info/bot/earn/info_earn_inner_widget.h"
|
||||||
|
|
||||||
#include "api/api_credits.h"
|
#include "api/api_credits.h"
|
||||||
#include "api/api_earn.h"
|
|
||||||
#include "api/api_filter_updates.h"
|
#include "api/api_filter_updates.h"
|
||||||
#include "base/timer_rpl.h"
|
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "core/ui_integration.h"
|
#include "core/ui_integration.h"
|
||||||
#include "data/data_channel_earn.h"
|
#include "data/data_channel_earn.h"
|
||||||
|
@ -24,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "info/statistics/info_statistics_list_controllers.h"
|
#include "info/statistics/info_statistics_list_controllers.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_account.h"
|
#include "main/main_account.h"
|
||||||
#include "main/main_app_config.h"
|
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "settings/settings_credits_graphics.h"
|
#include "settings/settings_credits_graphics.h"
|
||||||
#include "statistics/chart_widget.h"
|
#include "statistics/chart_widget.h"
|
||||||
|
@ -32,7 +29,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/credits_graphics.h"
|
#include "ui/effects/credits_graphics.h"
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "ui/text/text_utilities.h"
|
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -42,20 +38,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_channel_earn.h"
|
#include "styles/style_channel_earn.h"
|
||||||
#include "styles/style_chat.h"
|
|
||||||
#include "styles/style_credits.h"
|
#include "styles/style_credits.h"
|
||||||
#include "styles/style_layers.h"
|
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
#include "styles/style_statistics.h"
|
#include "styles/style_statistics.h"
|
||||||
|
|
||||||
namespace Info::BotEarn {
|
namespace Info::BotEarn {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[nodiscard]] int WithdrawalMin(not_null<Main::Session*> session) {
|
|
||||||
const auto key = u"stars_revenue_withdrawal_min"_q;
|
|
||||||
return session->appConfig().get<int>(key, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddHeader(
|
void AddHeader(
|
||||||
not_null<Ui::VerticalLayout*> content,
|
not_null<Ui::VerticalLayout*> content,
|
||||||
tr::phrase<> text) {
|
tr::phrase<> text) {
|
||||||
|
@ -234,53 +223,6 @@ void InnerWidget::fill() {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
AddHeader(container, tr::lng_bot_earn_balance_title);
|
AddHeader(container, tr::lng_bot_earn_balance_title);
|
||||||
Ui::AddSkip(container);
|
|
||||||
|
|
||||||
const auto labels = container->add(
|
|
||||||
object_ptr<Ui::CenterWrap<Ui::RpWidget>>(
|
|
||||||
container,
|
|
||||||
object_ptr<Ui::RpWidget>(container)))->entity();
|
|
||||||
|
|
||||||
const auto majorLabel = Ui::CreateChild<Ui::FlatLabel>(
|
|
||||||
labels,
|
|
||||||
rpl::duplicate(availableBalanceValue) | rpl::map(valueToString),
|
|
||||||
st::channelEarnBalanceMajorLabel);
|
|
||||||
const auto icon = Ui::CreateSingleStarWidget(
|
|
||||||
labels,
|
|
||||||
majorLabel->height());
|
|
||||||
majorLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
majorLabel->sizeValue(
|
|
||||||
) | rpl::start_with_next([=](const QSize &majorSize) {
|
|
||||||
const auto skip = st::channelEarnBalanceMinorLabelSkip;
|
|
||||||
labels->resize(
|
|
||||||
majorSize.width() + icon->width() + skip,
|
|
||||||
majorSize.height());
|
|
||||||
majorLabel->moveToLeft(icon->width() + skip, 0);
|
|
||||||
}, labels->lifetime());
|
|
||||||
Ui::ToggleChildrenVisibility(labels, true);
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
container->add(
|
|
||||||
object_ptr<Ui::CenterWrap<>>(
|
|
||||||
container,
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
container,
|
|
||||||
rpl::duplicate(
|
|
||||||
availableBalanceValue
|
|
||||||
) | rpl::map([=](uint64 v) {
|
|
||||||
return v ? ToUsd(v, multiplier) : QString();
|
|
||||||
}),
|
|
||||||
st::channelEarnOverviewSubMinorLabel)));
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
|
|
||||||
const auto input = Ui::AddInputFieldForCredits(
|
|
||||||
container,
|
|
||||||
rpl::duplicate(availableBalanceValue));
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
|
|
||||||
auto dateValue = rpl::single(
|
auto dateValue = rpl::single(
|
||||||
data.nextWithdrawalAt
|
data.nextWithdrawalAt
|
||||||
) | rpl::then(
|
) | rpl::then(
|
||||||
|
@ -288,220 +230,18 @@ void InnerWidget::fill() {
|
||||||
return _state.nextWithdrawalAt;
|
return _state.nextWithdrawalAt;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
auto lockedValue = rpl::duplicate(
|
::Settings::AddWithdrawalWidget(
|
||||||
dateValue
|
|
||||||
) | rpl::map([=](const QDateTime &dt) {
|
|
||||||
return !dt.isNull() || (!_state.isWithdrawalEnabled);
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto &stButton = st::defaultActiveButton;
|
|
||||||
const auto button = container->add(
|
|
||||||
object_ptr<Ui::RoundButton>(
|
|
||||||
container,
|
|
||||||
rpl::never<QString>(),
|
|
||||||
stButton),
|
|
||||||
st::boxRowPadding);
|
|
||||||
|
|
||||||
rpl::duplicate(
|
|
||||||
lockedValue
|
|
||||||
) | rpl::start_with_next([=](bool v) {
|
|
||||||
button->setAttribute(Qt::WA_TransparentForMouseEvents, v);
|
|
||||||
}, button->lifetime());
|
|
||||||
|
|
||||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
|
||||||
button,
|
|
||||||
tr::lng_channel_earn_balance_button(tr::now),
|
|
||||||
st::channelEarnSemiboldLabel);
|
|
||||||
const auto processInputChange = [&] {
|
|
||||||
const auto buttonEmoji = Ui::Text::SingleCustomEmoji(
|
|
||||||
session->data().customEmojiManager().registerInternalEmoji(
|
|
||||||
st::settingsPremiumIconStar,
|
|
||||||
{ 0, -st::moderateBoxExpandInnerSkip, 0, 0 },
|
|
||||||
true));
|
|
||||||
const auto context = Core::MarkedTextContext{
|
|
||||||
.session = session,
|
|
||||||
.customEmojiRepaint = [=] { label->update(); },
|
|
||||||
};
|
|
||||||
const auto process = [=] {
|
|
||||||
const auto amount = input->getLastText().toDouble();
|
|
||||||
if (amount >= _state.availableBalance) {
|
|
||||||
label->setText(
|
|
||||||
tr::lng_bot_earn_balance_button_all(tr::now));
|
|
||||||
} else {
|
|
||||||
label->setMarkedText(
|
|
||||||
tr::lng_bot_earn_balance_button(
|
|
||||||
tr::now,
|
|
||||||
lt_count,
|
|
||||||
amount,
|
|
||||||
lt_emoji,
|
|
||||||
buttonEmoji,
|
|
||||||
Ui::Text::RichLangValue),
|
|
||||||
context);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
QObject::connect(input, &Ui::MaskedInputField::changed, process);
|
|
||||||
process();
|
|
||||||
return process;
|
|
||||||
}();
|
|
||||||
label->setTextColorOverride(stButton.textFg->c);
|
|
||||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
rpl::combine(
|
|
||||||
rpl::duplicate(lockedValue),
|
|
||||||
button->sizeValue(),
|
|
||||||
label->sizeValue()
|
|
||||||
) | rpl::start_with_next([=](bool v, const QSize &b, const QSize &l) {
|
|
||||||
label->moveToLeft(
|
|
||||||
(b.width() - l.width()) / 2,
|
|
||||||
(v ? -10 : 1) * (b.height() - l.height()) / 2);
|
|
||||||
}, label->lifetime());
|
|
||||||
|
|
||||||
const auto lockedColor = anim::with_alpha(stButton.textFg->c, .5);
|
|
||||||
const auto lockedLabelTop = Ui::CreateChild<Ui::FlatLabel>(
|
|
||||||
button,
|
|
||||||
tr::lng_bot_earn_balance_button_locked(),
|
|
||||||
st::botEarnLockedButtonLabel);
|
|
||||||
lockedLabelTop->setTextColorOverride(lockedColor);
|
|
||||||
lockedLabelTop->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
const auto lockedLabelBottom = Ui::CreateChild<Ui::FlatLabel>(
|
|
||||||
button,
|
|
||||||
QString(),
|
|
||||||
st::botEarnLockedButtonLabel);
|
|
||||||
lockedLabelBottom->setTextColorOverride(lockedColor);
|
|
||||||
lockedLabelBottom->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
rpl::combine(
|
|
||||||
rpl::duplicate(lockedValue),
|
|
||||||
button->sizeValue(),
|
|
||||||
lockedLabelTop->sizeValue(),
|
|
||||||
lockedLabelBottom->sizeValue()
|
|
||||||
) | rpl::start_with_next([=](
|
|
||||||
bool locked,
|
|
||||||
const QSize &b,
|
|
||||||
const QSize &top,
|
|
||||||
const QSize &bottom) {
|
|
||||||
const auto factor = locked ? 1 : -10;
|
|
||||||
const auto sumHeight = top.height() + bottom.height();
|
|
||||||
lockedLabelTop->moveToLeft(
|
|
||||||
(b.width() - top.width()) / 2,
|
|
||||||
factor * (b.height() - sumHeight) / 2);
|
|
||||||
lockedLabelBottom->moveToLeft(
|
|
||||||
(b.width() - bottom.width()) / 2,
|
|
||||||
factor * ((b.height() - sumHeight) / 2 + top.height()));
|
|
||||||
}, lockedLabelTop->lifetime());
|
|
||||||
|
|
||||||
const auto dateUpdateLifetime
|
|
||||||
= lockedLabelBottom->lifetime().make_state<rpl::lifetime>();
|
|
||||||
std::move(
|
|
||||||
dateValue
|
|
||||||
) | rpl::start_with_next([=](const QDateTime &dt) {
|
|
||||||
dateUpdateLifetime->destroy();
|
|
||||||
if (dt.isNull()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
constexpr auto kDateUpdateInterval = crl::time(250);
|
|
||||||
const auto was = base::unixtime::serialize(dt);
|
|
||||||
|
|
||||||
const auto context = Core::MarkedTextContext{
|
|
||||||
.session = session,
|
|
||||||
.customEmojiRepaint = [=] { lockedLabelBottom->update(); },
|
|
||||||
};
|
|
||||||
const auto emoji = Ui::Text::SingleCustomEmoji(
|
|
||||||
session->data().customEmojiManager().registerInternalEmoji(
|
|
||||||
st::chatSimilarLockedIcon,
|
|
||||||
st::botEarnButtonLockMargins,
|
|
||||||
true));
|
|
||||||
|
|
||||||
rpl::single(
|
|
||||||
rpl::empty
|
|
||||||
) | rpl::then(
|
|
||||||
base::timer_each(kDateUpdateInterval)
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
const auto secondsDifference = std::max(
|
|
||||||
was - base::unixtime::now() - 1,
|
|
||||||
0);
|
|
||||||
const auto hours = secondsDifference / 3600;
|
|
||||||
const auto minutes = (secondsDifference % 3600) / 60;
|
|
||||||
const auto seconds = secondsDifference % 60;
|
|
||||||
constexpr auto kZero = QChar('0');
|
|
||||||
const auto formatted = (hours > 0)
|
|
||||||
? (u"%1:%2:%3"_q)
|
|
||||||
.arg(hours, 2, 10, kZero)
|
|
||||||
.arg(minutes, 2, 10, kZero)
|
|
||||||
.arg(seconds, 2, 10, kZero)
|
|
||||||
: (u"%1:%2"_q)
|
|
||||||
.arg(minutes, 2, 10, kZero)
|
|
||||||
.arg(seconds, 2, 10, kZero);
|
|
||||||
lockedLabelBottom->setMarkedText(
|
|
||||||
base::duplicate(emoji).append(formatted),
|
|
||||||
context);
|
|
||||||
}, *dateUpdateLifetime);
|
|
||||||
}, lockedLabelBottom->lifetime());
|
|
||||||
|
|
||||||
Api::HandleWithdrawalButton(
|
|
||||||
Api::RewardReceiver{
|
|
||||||
.creditsReceiver = _peer,
|
|
||||||
.creditsAmount = [=, show = _controller->uiShow()] {
|
|
||||||
const auto amount = input->getLastText().toULongLong();
|
|
||||||
const auto min = float64(WithdrawalMin(session));
|
|
||||||
if (amount < min) {
|
|
||||||
auto text = tr::lng_bot_earn_credits_out_minimal(
|
|
||||||
tr::now,
|
|
||||||
lt_link,
|
|
||||||
Ui::Text::Link(
|
|
||||||
tr::lng_bot_earn_credits_out_minimal_link(
|
|
||||||
tr::now,
|
|
||||||
lt_count,
|
|
||||||
min),
|
|
||||||
u"internal:"_q),
|
|
||||||
Ui::Text::RichLangValue);
|
|
||||||
show->showToast(Ui::Toast::Config{
|
|
||||||
.text = std::move(text),
|
|
||||||
.filter = [=](const auto ...) {
|
|
||||||
input->setText(QString::number(min));
|
|
||||||
processInputChange();
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return 0ULL;
|
|
||||||
}
|
|
||||||
return amount;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
button,
|
|
||||||
_controller->uiShow());
|
|
||||||
Ui::ToggleChildrenVisibility(button, true);
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
|
|
||||||
const auto arrow = Ui::Text::SingleCustomEmoji(
|
|
||||||
session->data().customEmojiManager().registerInternalEmoji(
|
|
||||||
st::topicButtonArrow,
|
|
||||||
st::channelEarnLearnArrowMargins,
|
|
||||||
false));
|
|
||||||
auto about = Ui::CreateLabelWithCustomEmoji(
|
|
||||||
container,
|
container,
|
||||||
tr::lng_bot_earn_learn_credits_out_about(
|
_controller->parentController(),
|
||||||
lt_link,
|
_peer,
|
||||||
tr::lng_channel_earn_about_link(
|
rpl::duplicate(availableBalanceValue),
|
||||||
lt_emoji,
|
rpl::duplicate(dateValue),
|
||||||
rpl::single(arrow),
|
std::move(dateValue) | rpl::map([=](const QDateTime &dt) {
|
||||||
Ui::Text::RichLangValue
|
return !dt.isNull() || (!_state.isWithdrawalEnabled);
|
||||||
) | rpl::map([](TextWithEntities text) {
|
}),
|
||||||
return Ui::Text::Link(
|
rpl::duplicate(availableBalanceValue) | rpl::map([=](uint64 v) {
|
||||||
std::move(text),
|
return v ? ToUsd(v, multiplier) : QString();
|
||||||
tr::lng_bot_earn_balance_about_url(tr::now));
|
}));
|
||||||
}),
|
|
||||||
Ui::Text::RichLangValue),
|
|
||||||
{ .session = session },
|
|
||||||
st::boxDividerLabel);
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
container->add(object_ptr<Ui::DividerLabel>(
|
|
||||||
container,
|
|
||||||
std::move(about),
|
|
||||||
st::defaultBoxDividerLabelPadding,
|
|
||||||
RectPart::Top | RectPart::Bottom));
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fillHistory();
|
fillHistory();
|
||||||
|
|
|
@ -8,20 +8,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "settings/settings_credits_graphics.h"
|
#include "settings/settings_credits_graphics.h"
|
||||||
|
|
||||||
#include "api/api_credits.h"
|
#include "api/api_credits.h"
|
||||||
|
#include "api/api_earn.h"
|
||||||
|
#include "base/timer_rpl.h"
|
||||||
|
#include "base/unixtime.h"
|
||||||
#include "boxes/gift_premium_box.h"
|
#include "boxes/gift_premium_box.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
|
#include "core/ui_integration.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_photo_media.h"
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
|
#include "info/settings/info_settings_widget.h" // SectionCustomTopBarData.
|
||||||
#include "info/statistics/info_statistics_list_controllers.h"
|
#include "info/statistics/info_statistics_list_controllers.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_app_config.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "payments/payments_checkout_process.h"
|
#include "payments/payments_checkout_process.h"
|
||||||
#include "payments/payments_form.h"
|
#include "payments/payments_form.h"
|
||||||
#include "settings/settings_common_session.h"
|
#include "settings/settings_common_session.h"
|
||||||
#include "settings/settings_credits_graphics.h"
|
|
||||||
#include "statistics/widgets/chart_header_widget.h"
|
#include "statistics/widgets/chart_header_widget.h"
|
||||||
#include "ui/controls/userpic_button.h"
|
#include "ui/controls/userpic_button.h"
|
||||||
#include "ui/effects/credits_graphics.h"
|
#include "ui/effects/credits_graphics.h"
|
||||||
|
@ -33,9 +38,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "ui/text/format_values.h"
|
#include "ui/text/format_values.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/discrete_sliders.h"
|
#include "ui/widgets/discrete_sliders.h"
|
||||||
|
#include "ui/widgets/fields/number_input.h"
|
||||||
|
#include "ui/widgets/label_with_custom_emoji.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "ui/wrap/fade_wrap.h"
|
#include "ui/wrap/fade_wrap.h"
|
||||||
|
@ -43,6 +51,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
#include "styles/style_channel_earn.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_credits.h"
|
#include "styles/style_credits.h"
|
||||||
#include "styles/style_giveaway.h"
|
#include "styles/style_giveaway.h"
|
||||||
#include "styles/style_info.h"
|
#include "styles/style_info.h"
|
||||||
|
@ -68,6 +78,11 @@ namespace {
|
||||||
return XXH64(string.data(), string.size() * sizeof(ushort), 0);
|
return XXH64(string.data(), string.size() * sizeof(ushort), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int WithdrawalMin(not_null<Main::Session*> session) {
|
||||||
|
const auto key = u"stars_revenue_withdrawal_min"_q;
|
||||||
|
return session->appConfig().get<int>(key, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
class Balance final
|
class Balance final
|
||||||
: public Ui::RpWidget
|
: public Ui::RpWidget
|
||||||
, public Ui::AbstractTooltipShower {
|
, public Ui::AbstractTooltipShower {
|
||||||
|
@ -643,4 +658,272 @@ void SmallBalanceBox(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddWithdrawalWidget(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
rpl::producer<uint64> availableBalanceValue,
|
||||||
|
rpl::producer<QDateTime> dateValue,
|
||||||
|
rpl::producer<bool> lockedValue,
|
||||||
|
rpl::producer<QString> usdValue) {
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
|
||||||
|
const auto labels = container->add(
|
||||||
|
object_ptr<Ui::CenterWrap<Ui::RpWidget>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::RpWidget>(container)))->entity();
|
||||||
|
|
||||||
|
const auto majorLabel = Ui::CreateChild<Ui::FlatLabel>(
|
||||||
|
labels,
|
||||||
|
rpl::duplicate(availableBalanceValue) | rpl::map([](uint64 v) {
|
||||||
|
return Lang::FormatCountDecimal(v);
|
||||||
|
}),
|
||||||
|
st::channelEarnBalanceMajorLabel);
|
||||||
|
const auto icon = Ui::CreateSingleStarWidget(
|
||||||
|
labels,
|
||||||
|
majorLabel->height());
|
||||||
|
majorLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
majorLabel->sizeValue(
|
||||||
|
) | rpl::start_with_next([=](const QSize &majorSize) {
|
||||||
|
const auto skip = st::channelEarnBalanceMinorLabelSkip;
|
||||||
|
labels->resize(
|
||||||
|
majorSize.width() + icon->width() + skip,
|
||||||
|
majorSize.height());
|
||||||
|
majorLabel->moveToLeft(icon->width() + skip, 0);
|
||||||
|
}, labels->lifetime());
|
||||||
|
Ui::ToggleChildrenVisibility(labels, true);
|
||||||
|
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
container->add(
|
||||||
|
object_ptr<Ui::CenterWrap<>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
container,
|
||||||
|
std::move(usdValue),
|
||||||
|
st::channelEarnOverviewSubMinorLabel)));
|
||||||
|
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
|
||||||
|
const auto input = Ui::AddInputFieldForCredits(
|
||||||
|
container,
|
||||||
|
rpl::duplicate(availableBalanceValue));
|
||||||
|
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
|
||||||
|
const auto &stButton = st::defaultActiveButton;
|
||||||
|
const auto button = container->add(
|
||||||
|
object_ptr<Ui::RoundButton>(
|
||||||
|
container,
|
||||||
|
rpl::never<QString>(),
|
||||||
|
stButton),
|
||||||
|
st::boxRowPadding);
|
||||||
|
|
||||||
|
rpl::duplicate(
|
||||||
|
lockedValue
|
||||||
|
) | rpl::start_with_next([=](bool v) {
|
||||||
|
button->setAttribute(Qt::WA_TransparentForMouseEvents, v);
|
||||||
|
}, button->lifetime());
|
||||||
|
|
||||||
|
const auto session = &controller->session();
|
||||||
|
|
||||||
|
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||||
|
button,
|
||||||
|
tr::lng_channel_earn_balance_button(tr::now),
|
||||||
|
st::channelEarnSemiboldLabel);
|
||||||
|
const auto processInputChange = [&] {
|
||||||
|
const auto buttonEmoji = Ui::Text::SingleCustomEmoji(
|
||||||
|
session->data().customEmojiManager().registerInternalEmoji(
|
||||||
|
st::settingsPremiumIconStar,
|
||||||
|
{ 0, -st::moderateBoxExpandInnerSkip, 0, 0 },
|
||||||
|
true));
|
||||||
|
const auto context = Core::MarkedTextContext{
|
||||||
|
.session = session,
|
||||||
|
.customEmojiRepaint = [=] { label->update(); },
|
||||||
|
};
|
||||||
|
using Balance = rpl::variable<uint64>;
|
||||||
|
const auto currentBalance = input->lifetime().make_state<Balance>(
|
||||||
|
rpl::duplicate(availableBalanceValue));
|
||||||
|
const auto process = [=] {
|
||||||
|
const auto amount = input->getLastText().toDouble();
|
||||||
|
if (amount >= currentBalance->current()) {
|
||||||
|
label->setText(
|
||||||
|
tr::lng_bot_earn_balance_button_all(tr::now));
|
||||||
|
} else {
|
||||||
|
label->setMarkedText(
|
||||||
|
tr::lng_bot_earn_balance_button(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
amount,
|
||||||
|
lt_emoji,
|
||||||
|
buttonEmoji,
|
||||||
|
Ui::Text::RichLangValue),
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
QObject::connect(input, &Ui::MaskedInputField::changed, process);
|
||||||
|
process();
|
||||||
|
return process;
|
||||||
|
}();
|
||||||
|
label->setTextColorOverride(stButton.textFg->c);
|
||||||
|
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
rpl::combine(
|
||||||
|
rpl::duplicate(lockedValue),
|
||||||
|
button->sizeValue(),
|
||||||
|
label->sizeValue()
|
||||||
|
) | rpl::start_with_next([=](bool v, const QSize &b, const QSize &l) {
|
||||||
|
label->moveToLeft(
|
||||||
|
(b.width() - l.width()) / 2,
|
||||||
|
(v ? -10 : 1) * (b.height() - l.height()) / 2);
|
||||||
|
}, label->lifetime());
|
||||||
|
|
||||||
|
const auto lockedColor = anim::with_alpha(stButton.textFg->c, .5);
|
||||||
|
const auto lockedLabelTop = Ui::CreateChild<Ui::FlatLabel>(
|
||||||
|
button,
|
||||||
|
tr::lng_bot_earn_balance_button_locked(),
|
||||||
|
st::botEarnLockedButtonLabel);
|
||||||
|
lockedLabelTop->setTextColorOverride(lockedColor);
|
||||||
|
lockedLabelTop->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
const auto lockedLabelBottom = Ui::CreateChild<Ui::FlatLabel>(
|
||||||
|
button,
|
||||||
|
QString(),
|
||||||
|
st::botEarnLockedButtonLabel);
|
||||||
|
lockedLabelBottom->setTextColorOverride(lockedColor);
|
||||||
|
lockedLabelBottom->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
rpl::combine(
|
||||||
|
rpl::duplicate(lockedValue),
|
||||||
|
button->sizeValue(),
|
||||||
|
lockedLabelTop->sizeValue(),
|
||||||
|
lockedLabelBottom->sizeValue()
|
||||||
|
) | rpl::start_with_next([=](
|
||||||
|
bool locked,
|
||||||
|
const QSize &b,
|
||||||
|
const QSize &top,
|
||||||
|
const QSize &bottom) {
|
||||||
|
const auto factor = locked ? 1 : -10;
|
||||||
|
const auto sumHeight = top.height() + bottom.height();
|
||||||
|
lockedLabelTop->moveToLeft(
|
||||||
|
(b.width() - top.width()) / 2,
|
||||||
|
factor * (b.height() - sumHeight) / 2);
|
||||||
|
lockedLabelBottom->moveToLeft(
|
||||||
|
(b.width() - bottom.width()) / 2,
|
||||||
|
factor * ((b.height() - sumHeight) / 2 + top.height()));
|
||||||
|
}, lockedLabelTop->lifetime());
|
||||||
|
|
||||||
|
const auto dateUpdateLifetime
|
||||||
|
= lockedLabelBottom->lifetime().make_state<rpl::lifetime>();
|
||||||
|
std::move(
|
||||||
|
dateValue
|
||||||
|
) | rpl::start_with_next([=](const QDateTime &dt) {
|
||||||
|
dateUpdateLifetime->destroy();
|
||||||
|
if (dt.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
constexpr auto kDateUpdateInterval = crl::time(250);
|
||||||
|
const auto was = base::unixtime::serialize(dt);
|
||||||
|
|
||||||
|
const auto context = Core::MarkedTextContext{
|
||||||
|
.session = session,
|
||||||
|
.customEmojiRepaint = [=] { lockedLabelBottom->update(); },
|
||||||
|
};
|
||||||
|
const auto emoji = Ui::Text::SingleCustomEmoji(
|
||||||
|
session->data().customEmojiManager().registerInternalEmoji(
|
||||||
|
st::chatSimilarLockedIcon,
|
||||||
|
st::botEarnButtonLockMargins,
|
||||||
|
true));
|
||||||
|
|
||||||
|
rpl::single(
|
||||||
|
rpl::empty
|
||||||
|
) | rpl::then(
|
||||||
|
base::timer_each(kDateUpdateInterval)
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
const auto secondsDifference = std::max(
|
||||||
|
was - base::unixtime::now() - 1,
|
||||||
|
0);
|
||||||
|
const auto hours = secondsDifference / 3600;
|
||||||
|
const auto minutes = (secondsDifference % 3600) / 60;
|
||||||
|
const auto seconds = secondsDifference % 60;
|
||||||
|
constexpr auto kZero = QChar('0');
|
||||||
|
const auto formatted = (hours > 0)
|
||||||
|
? (u"%1:%2:%3"_q)
|
||||||
|
.arg(hours, 2, 10, kZero)
|
||||||
|
.arg(minutes, 2, 10, kZero)
|
||||||
|
.arg(seconds, 2, 10, kZero)
|
||||||
|
: (u"%1:%2"_q)
|
||||||
|
.arg(minutes, 2, 10, kZero)
|
||||||
|
.arg(seconds, 2, 10, kZero);
|
||||||
|
lockedLabelBottom->setMarkedText(
|
||||||
|
base::duplicate(emoji).append(formatted),
|
||||||
|
context);
|
||||||
|
}, *dateUpdateLifetime);
|
||||||
|
}, lockedLabelBottom->lifetime());
|
||||||
|
|
||||||
|
Api::HandleWithdrawalButton(
|
||||||
|
Api::RewardReceiver{
|
||||||
|
.creditsReceiver = peer,
|
||||||
|
.creditsAmount = [=, show = controller->uiShow()] {
|
||||||
|
const auto amount = input->getLastText().toULongLong();
|
||||||
|
const auto min = float64(WithdrawalMin(session));
|
||||||
|
if (amount < min) {
|
||||||
|
auto text = tr::lng_bot_earn_credits_out_minimal(
|
||||||
|
tr::now,
|
||||||
|
lt_link,
|
||||||
|
Ui::Text::Link(
|
||||||
|
tr::lng_bot_earn_credits_out_minimal_link(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
min),
|
||||||
|
u"internal:"_q),
|
||||||
|
Ui::Text::RichLangValue);
|
||||||
|
show->showToast(Ui::Toast::Config{
|
||||||
|
.text = std::move(text),
|
||||||
|
.filter = [=](const auto ...) {
|
||||||
|
input->setText(QString::number(min));
|
||||||
|
processInputChange();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
return amount;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
button,
|
||||||
|
controller->uiShow());
|
||||||
|
Ui::ToggleChildrenVisibility(button, true);
|
||||||
|
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
|
||||||
|
const auto arrow = Ui::Text::SingleCustomEmoji(
|
||||||
|
session->data().customEmojiManager().registerInternalEmoji(
|
||||||
|
st::topicButtonArrow,
|
||||||
|
st::channelEarnLearnArrowMargins,
|
||||||
|
false));
|
||||||
|
auto about = Ui::CreateLabelWithCustomEmoji(
|
||||||
|
container,
|
||||||
|
tr::lng_bot_earn_learn_credits_out_about(
|
||||||
|
lt_link,
|
||||||
|
tr::lng_channel_earn_about_link(
|
||||||
|
lt_emoji,
|
||||||
|
rpl::single(arrow),
|
||||||
|
Ui::Text::RichLangValue
|
||||||
|
) | rpl::map([](TextWithEntities text) {
|
||||||
|
return Ui::Text::Link(
|
||||||
|
std::move(text),
|
||||||
|
tr::lng_bot_earn_balance_about_url(tr::now));
|
||||||
|
}),
|
||||||
|
Ui::Text::RichLangValue),
|
||||||
|
{ .session = session },
|
||||||
|
st::boxDividerLabel);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
container->add(object_ptr<Ui::DividerLabel>(
|
||||||
|
container,
|
||||||
|
std::move(about),
|
||||||
|
st::defaultBoxDividerLabelPadding,
|
||||||
|
RectPart::Top | RectPart::Bottom));
|
||||||
|
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Settings
|
} // namespace Settings
|
||||||
|
|
|
@ -39,6 +39,15 @@ void FillCreditOptions(
|
||||||
rpl::producer<uint64> balanceValue,
|
rpl::producer<uint64> balanceValue,
|
||||||
bool rightAlign);
|
bool rightAlign);
|
||||||
|
|
||||||
|
void AddWithdrawalWidget(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
rpl::producer<uint64> availableBalanceValue,
|
||||||
|
rpl::producer<QDateTime> dateValue,
|
||||||
|
rpl::producer<bool> lockedValue,
|
||||||
|
rpl::producer<QString> usdValue);
|
||||||
|
|
||||||
void ReceiptCreditsBox(
|
void ReceiptCreditsBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
|
Loading…
Add table
Reference in a new issue