tdesktop/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp

274 lines
7.6 KiB
C++

/*
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/boosts/info_boosts_inner_widget.h"
#include "api/api_statistics.h"
#include "boxes/peers/edit_peer_invite_link.h"
#include "info/info_controller.h"
#include "info/statistics/info_statistics_list_controllers.h"
#include "lang/lang_keys.h"
#include "settings/settings_common.h"
#include "statistics/widgets/chart_header_widget.h"
#include "ui/boxes/boost_box.h"
#include "ui/controls/invite_link_buttons.h"
#include "ui/controls/invite_link_label.h"
#include "ui/rect.h"
#include "ui/widgets/labels.h"
#include "styles/style_info.h"
#include "styles/style_statistics.h"
#include <QtGui/QGuiApplication>
namespace Info::Boosts {
namespace {
void AddHeader(
not_null<Ui::VerticalLayout*> content,
tr::phrase<> text) {
const auto header = content->add(
object_ptr<Statistic::Header>(content),
st::statisticsLayerMargins + st::statisticsChartHeaderPadding);
header->resizeToWidth(header->width());
header->setTitle(text(tr::now));
header->setSubTitle({});
}
void FillOverview(
not_null<Ui::VerticalLayout*> content,
const Data::BoostStatus &status) {
const auto &stats = status.overview;
::Settings::AddSkip(content, st::statisticsLayerOverviewMargins.top());
AddHeader(content, tr::lng_stats_overview_title);
::Settings::AddSkip(content);
const auto diffBetweenHeaders = 0
+ st::statisticsOverviewValue.style.font->height
- st::statisticsHeaderTitleTextStyle.font->height;
const auto container = content->add(
object_ptr<Ui::RpWidget>(content),
st::statisticsLayerMargins);
const auto addPrimary = [&](float64 v) {
return Ui::CreateChild<Ui::FlatLabel>(
container,
(v >= 0)
? Lang::FormatCountToShort(v).string
: QString(),
st::statisticsOverviewValue);
};
const auto addSub = [&](
not_null<Ui::RpWidget*> primary,
float64 percentage,
tr::phrase<> text) {
const auto second = Ui::CreateChild<Ui::FlatLabel>(
container,
percentage
? u"%1%"_q.arg(std::abs(std::round(percentage * 10.) / 10.))
: QString(),
st::statisticsOverviewSecondValue);
second->setTextColorOverride(st::windowSubTextFg->c);
const auto sub = Ui::CreateChild<Ui::FlatLabel>(
container,
text(),
st::statisticsOverviewSubtext);
sub->setTextColorOverride(st::windowSubTextFg->c);
primary->geometryValue(
) | rpl::start_with_next([=](const QRect &g) {
const auto &padding = st::statisticsOverviewSecondValuePadding;
second->moveToLeft(
rect::right(g) + padding.left(),
g.y() + padding.top());
sub->moveToLeft(
g.x(),
st::statisticsChartHeaderHeight
- st::statisticsOverviewSubtext.style.font->height
+ g.y()
+ diffBetweenHeaders);
}, primary->lifetime());
};
const auto topLeftLabel = addPrimary(stats.level);
const auto topRightLabel = addPrimary(stats.premiumMemberCount);
const auto bottomLeftLabel = addPrimary(stats.boostCount);
const auto bottomRightLabel = addPrimary(
stats.nextLevelBoostCount - stats.boostCount);
addSub(
topLeftLabel,
0,
tr::lng_boosts_level);
addSub(
topRightLabel,
stats.premiumMemberPercentage,
tr::lng_boosts_premium_audience);
addSub(
bottomLeftLabel,
0,
tr::lng_boosts_existing);
addSub(
bottomRightLabel,
0,
tr::lng_boosts_next_level);
container->showChildren();
container->resize(container->width(), topLeftLabel->height() * 5);
container->sizeValue(
) | rpl::start_with_next([=](const QSize &s) {
const auto halfWidth = s.width() / 2;
{
const auto &p = st::statisticsOverviewValuePadding;
topLeftLabel->moveToLeft(p.left(), p.top());
}
topRightLabel->moveToLeft(
topLeftLabel->x() + halfWidth + st::statisticsOverviewRightSkip,
topLeftLabel->y());
bottomLeftLabel->moveToLeft(
topLeftLabel->x(),
topLeftLabel->y() + st::statisticsOverviewMidSkip);
bottomRightLabel->moveToLeft(
topRightLabel->x(),
bottomLeftLabel->y());
}, container->lifetime());
::Settings::AddSkip(content, st::statisticsLayerOverviewMargins.bottom());
}
void FillShareLink(
not_null<Ui::VerticalLayout*> content,
std::shared_ptr<Ui::Show> show,
const QString &link,
not_null<PeerData*> peer) {
const auto weak = Ui::MakeWeak(content);
const auto copyLink = crl::guard(weak, [=] {
QGuiApplication::clipboard()->setText(link);
show->showToast(tr::lng_channel_public_link_copied(tr::now));
});
const auto shareLink = crl::guard(weak, [=] {
show->showBox(ShareInviteLinkBox(peer, link));
});
const auto label = content->lifetime().make_state<Ui::InviteLinkLabel>(
content,
rpl::single(link),
nullptr);
content->add(
label->take(),
st::inviteLinkFieldPadding);
label->clicks(
) | rpl::start_with_next(copyLink, label->lifetime());
const auto copyShareWrap = content->add(
object_ptr<Ui::VerticalLayout>(content));
Ui::AddCopyShareLinkButtons(copyShareWrap, copyLink, shareLink);
copyShareWrap->widgetAt(0)->showChildren();
::Settings::AddSkip(content, st::inviteLinkFieldPadding.bottom());
}
} // namespace
InnerWidget::InnerWidget(
QWidget *parent,
not_null<Controller*> controller,
not_null<PeerData*> peer)
: VerticalLayout(parent)
, _controller(controller)
, _peer(peer)
, _show(controller->uiShow()) {
const auto api = lifetime().make_state<Api::Boosts>(peer);
const auto fakeShowed = lifetime().make_state<rpl::event_stream<>>();
_showFinished.events(
) | rpl::take(1) | rpl::start_with_next([=] {
api->request(
) | rpl::start_with_error_done([](const QString &error) {
}, [=] {
const auto status = api->boostStatus();
const auto inner = this;
Ui::FillBoostLimit(
fakeShowed->events(),
rpl::single(status.overview.isBoosted),
inner,
Ui::BoostBoxData{
.boost = Ui::BoostCounters{
.level = status.overview.level,
.boosts = status.overview.boostCount,
.thisLevelBoosts
= status.overview.currentLevelBoostCount,
.nextLevelBoosts
= status.overview.nextLevelBoostCount,
.mine = status.overview.isBoosted,
}
});
FillOverview(inner, status);
::Settings::AddSkip(inner);
::Settings::AddDivider(inner);
::Settings::AddSkip(inner);
if (status.firstSlice.total > 0) {
::Settings::AddSkip(inner);
using PeerPtr = not_null<PeerData*>;
const auto header = inner->add(
object_ptr<Statistic::Header>(inner),
st::statisticsLayerMargins);
header->resizeToWidth(header->width());
header->setTitle(tr::lng_boosts_list_title(
tr::now,
lt_count,
status.firstSlice.total));
header->setSubTitle({});
Statistics::AddBoostsList(
status.firstSlice,
inner,
[=](PeerPtr p) { controller->showPeerInfo(p); },
peer,
tr::lng_boosts_title());
::Settings::AddSkip(inner);
::Settings::AddDividerText(
inner,
tr::lng_boosts_list_subtext());
::Settings::AddSkip(inner);
}
::Settings::AddSkip(inner);
AddHeader(inner, tr::lng_boosts_link_title);
FillShareLink(inner, _show, status.link, peer);
::Settings::AddSkip(inner);
::Settings::AddDividerText(inner, tr::lng_boosts_link_subtext());
resizeToWidth(width());
crl::on_main([=]{ fakeShowed->fire({}); });
}, lifetime());
}, lifetime());
}
rpl::producer<Ui::ScrollToRequest> InnerWidget::scrollToRequests() const {
return _scrollToRequests.events();
}
auto InnerWidget::showRequests() const -> rpl::producer<ShowRequest> {
return _showRequests.events();
}
void InnerWidget::showFinished() {
_showFinished.fire({});
}
not_null<PeerData*> InnerWidget::peer() const {
return _peer;
}
} // namespace Info::Boosts