mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Added initial support of statistical charts in earn channel section.
This commit is contained in:
parent
393d9e9f1f
commit
9c52f245ac
14 changed files with 84 additions and 8 deletions
BIN
Telegram/Resources/icons/statistics/mini_currency_graph.png
Normal file
BIN
Telegram/Resources/icons/statistics/mini_currency_graph.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 388 B |
BIN
Telegram/Resources/icons/statistics/mini_currency_graph@2x.png
Normal file
BIN
Telegram/Resources/icons/statistics/mini_currency_graph@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 609 B |
BIN
Telegram/Resources/icons/statistics/mini_currency_graph@3x.png
Normal file
BIN
Telegram/Resources/icons/statistics/mini_currency_graph@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 893 B |
|
@ -4988,6 +4988,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_channel_earn_learn_coin_title" = "What is {emoji} TON?";
|
"lng_channel_earn_learn_coin_title" = "What is {emoji} TON?";
|
||||||
"lng_channel_earn_learn_coin_about" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its record scalability and ultra low commissions on transactions. {link}";
|
"lng_channel_earn_learn_coin_about" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its record scalability and ultra low commissions on transactions. {link}";
|
||||||
"lng_channel_earn_learn_close" = "Got it";
|
"lng_channel_earn_learn_close" = "Got it";
|
||||||
|
"lng_channel_earn_chart_top_hours" = "Ad impressions";
|
||||||
|
"lng_channel_earn_chart_revenue" = "Ad revenue";
|
||||||
|
|
||||||
"lng_contact_add" = "Add";
|
"lng_contact_add" = "Add";
|
||||||
"lng_contact_send_message" = "message";
|
"lng_contact_send_message" = "message";
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct StatisticalChart {
|
||||||
bool isFooterHidden = false;
|
bool isFooterHidden = false;
|
||||||
bool hasPercentages = false;
|
bool hasPercentages = false;
|
||||||
bool weekFormat = false;
|
bool weekFormat = false;
|
||||||
|
bool isCurrency = false;
|
||||||
|
|
||||||
// View data.
|
// View data.
|
||||||
int dayStringMaxWidth = 0;
|
int dayStringMaxWidth = 0;
|
||||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "info/statistics/info_statistics_inner_widget.h" // FillLoading.
|
#include "info/statistics/info_statistics_inner_widget.h" // FillLoading.
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "statistics/chart_widget.h"
|
||||||
#include "ui/controls/userpic_button.h"
|
#include "ui/controls/userpic_button.h"
|
||||||
#include "ui/effects/animation_value_f.h"
|
#include "ui/effects/animation_value_f.h"
|
||||||
#include "ui/layers/generic_box.h"
|
#include "ui/layers/generic_box.h"
|
||||||
|
@ -223,6 +224,33 @@ void InnerWidget::fill() {
|
||||||
makeContext(label));
|
makeContext(label));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
using Type = Statistic::ChartViewType;
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
if (data.topHoursGraph.chart) {
|
||||||
|
const auto widget = container->add(
|
||||||
|
object_ptr<Statistic::ChartWidget>(container),
|
||||||
|
st::statisticsLayerMargins);
|
||||||
|
|
||||||
|
widget->setChartData(data.topHoursGraph.chart, Type::Linear);
|
||||||
|
widget->setTitle(tr::lng_channel_earn_chart_top_hours());
|
||||||
|
}
|
||||||
|
if (data.revenueGraph.chart) {
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddDivider(container);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
const auto widget = container->add(
|
||||||
|
object_ptr<Statistic::ChartWidget>(container),
|
||||||
|
st::statisticsLayerMargins);
|
||||||
|
|
||||||
|
widget->setChartData(data.revenueGraph.chart, Type::StackBar);
|
||||||
|
widget->setTitle(tr::lng_channel_earn_chart_revenue());
|
||||||
|
}
|
||||||
|
Ui::AddSkip(container);
|
||||||
|
}
|
||||||
|
|
||||||
const auto arrow = Ui::Text::SingleCustomEmoji(
|
const auto arrow = Ui::Text::SingleCustomEmoji(
|
||||||
session->data().customEmojiManager().registerInternalEmoji(
|
session->data().customEmojiManager().registerInternalEmoji(
|
||||||
st::topicButtonArrow,
|
st::topicButtonArrow,
|
||||||
|
|
|
@ -28,13 +28,21 @@ constexpr auto kStep = 5.;
|
||||||
: QString::number(absoluteValue);
|
: QString::number(absoluteValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QString FormatF(float64 absoluteValue) {
|
||||||
|
constexpr auto kTooMuch = int(10'000);
|
||||||
|
return (absoluteValue >= kTooMuch)
|
||||||
|
? Lang::FormatCountToShort(absoluteValue).string
|
||||||
|
: QString::number(absoluteValue);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ChartRulersData::ChartRulersData(
|
ChartRulersData::ChartRulersData(
|
||||||
int newMaxHeight,
|
int newMaxHeight,
|
||||||
int newMinHeight,
|
int newMinHeight,
|
||||||
bool useMinHeight,
|
bool useMinHeight,
|
||||||
float64 rightRatio) {
|
float64 rightRatio,
|
||||||
|
int valueDivider) {
|
||||||
if (!useMinHeight) {
|
if (!useMinHeight) {
|
||||||
const auto v = (newMaxHeight > 100)
|
const auto v = (newMaxHeight > 100)
|
||||||
? Round(newMaxHeight)
|
? Round(newMaxHeight)
|
||||||
|
@ -92,7 +100,9 @@ ChartRulersData::ChartRulersData(
|
||||||
const auto value = int(i * step);
|
const auto value = int(i * step);
|
||||||
line.absoluteValue = newMinHeight + value;
|
line.absoluteValue = newMinHeight + value;
|
||||||
line.relativeValue = 1. - value / float64(diffAbsoluteValue);
|
line.relativeValue = 1. - value / float64(diffAbsoluteValue);
|
||||||
line.caption = Format(line.absoluteValue);
|
line.caption = valueDivider
|
||||||
|
? FormatF(line.absoluteValue / float64(valueDivider))
|
||||||
|
: Format(line.absoluteValue);
|
||||||
if (rightRatio > 0) {
|
if (rightRatio > 0) {
|
||||||
const auto v = (newMinHeight + i * step) / rightRatio;
|
const auto v = (newMinHeight + i * step) / rightRatio;
|
||||||
line.scaledLineCaption = (!skipFloatValues)
|
line.scaledLineCaption = (!skipFloatValues)
|
||||||
|
|
|
@ -15,7 +15,8 @@ public:
|
||||||
int newMaxHeight,
|
int newMaxHeight,
|
||||||
int newMinHeight,
|
int newMinHeight,
|
||||||
bool useMinHeight,
|
bool useMinHeight,
|
||||||
float64 rightRatio);
|
float64 rightRatio,
|
||||||
|
int valueDivider);
|
||||||
|
|
||||||
void computeRelative(
|
void computeRelative(
|
||||||
int newMaxHeight,
|
int newMaxHeight,
|
||||||
|
|
|
@ -172,3 +172,5 @@ boostsListGiftMiniIcon: icon{{ "boosts/mini_gift", historyPeer8UserpicBg2 }};
|
||||||
boostsListGiveawayMiniIcon: icon{{ "boosts/mini_giveaway", historyPeer4UserpicBg2 }};
|
boostsListGiveawayMiniIcon: icon{{ "boosts/mini_giveaway", historyPeer4UserpicBg2 }};
|
||||||
boostsListUnclaimedIcon: icon{{ "boosts/boost_unknown", premiumButtonFg }};
|
boostsListUnclaimedIcon: icon{{ "boosts/boost_unknown", premiumButtonFg }};
|
||||||
boostsListUnknownIcon: icon{{ "boosts/boost_unclaimed", premiumButtonFg }};
|
boostsListUnknownIcon: icon{{ "boosts/boost_unclaimed", premiumButtonFg }};
|
||||||
|
|
||||||
|
statisticsCurrencyIcon: icon {{ "statistics/mini_currency_graph", windowSubTextFg }};
|
||||||
|
|
|
@ -61,7 +61,7 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
|
||||||
line.isHiddenOnStart = ranges::contains(hiddenLines, columnId);
|
line.isHiddenOnStart = ranges::contains(hiddenLines, columnId);
|
||||||
line.y.resize(length);
|
line.y.resize(length);
|
||||||
for (auto i = 0; i < length; i++) {
|
for (auto i = 0; i < length; i++) {
|
||||||
const auto value = array.at(i + 1).toInt();
|
const auto value = array.at(i + 1).toInteger();
|
||||||
line.y[i] = value;
|
line.y[i] = value;
|
||||||
if (value > line.maxValue) {
|
if (value > line.maxValue) {
|
||||||
line.maxValue = value;
|
line.maxValue = value;
|
||||||
|
@ -132,6 +132,13 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
|
||||||
result.weekFormat = tooltipFormat.contains(u"'week'"_q);
|
result.weekFormat = tooltipFormat.contains(u"'week'"_q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const auto tickFormatIt = root.constFind(u"yTickFormatter"_q);
|
||||||
|
if (tickFormatIt != root.constEnd()) {
|
||||||
|
const auto tickFormat = tickFormatIt->toString();
|
||||||
|
result.isCurrency = tickFormat.contains(u"TON"_q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto colors = root.value(u"colors"_q).toObject();
|
const auto colors = root.value(u"colors"_q).toObject();
|
||||||
const auto names = root.value(u"names"_q).toObject();
|
const auto names = root.value(u"names"_q).toObject();
|
||||||
|
|
|
@ -23,6 +23,9 @@ void ChartRulersView::setChartData(
|
||||||
std::shared_ptr<LinesFilterController> linesFilter) {
|
std::shared_ptr<LinesFilterController> linesFilter) {
|
||||||
_rulers.clear();
|
_rulers.clear();
|
||||||
_isDouble = (type == ChartViewType::DoubleLinear);
|
_isDouble = (type == ChartViewType::DoubleLinear);
|
||||||
|
_currencyIcon = chartData.isCurrency
|
||||||
|
? &st::statisticsCurrencyIcon
|
||||||
|
: nullptr;
|
||||||
if (_isDouble && (chartData.lines.size() == 2)) {
|
if (_isDouble && (chartData.lines.size() == 2)) {
|
||||||
_linesFilter = std::move(linesFilter);
|
_linesFilter = std::move(linesFilter);
|
||||||
_leftPen = QPen(chartData.lines.front().color);
|
_leftPen = QPen(chartData.lines.front().color);
|
||||||
|
@ -69,6 +72,7 @@ void ChartRulersView::paintCaptionsToRulers(
|
||||||
for (auto &ruler : _rulers) {
|
for (auto &ruler : _rulers) {
|
||||||
const auto rulerAlpha = alpha * ruler.alpha;
|
const auto rulerAlpha = alpha * ruler.alpha;
|
||||||
p.setOpacity(rulerAlpha);
|
p.setOpacity(rulerAlpha);
|
||||||
|
const auto left = _currencyIcon ? _currencyIcon->width() : 0;
|
||||||
for (const auto &line : ruler.lines) {
|
for (const auto &line : ruler.lines) {
|
||||||
const auto y = offset + r.height() * line.relativeValue;
|
const auto y = offset + r.height() * line.relativeValue;
|
||||||
const auto hasLinesFilter = _isDouble && _linesFilter;
|
const auto hasLinesFilter = _isDouble && _linesFilter;
|
||||||
|
@ -78,8 +82,14 @@ void ChartRulersView::paintCaptionsToRulers(
|
||||||
} else {
|
} else {
|
||||||
p.setPen(st::windowSubTextFg);
|
p.setPen(st::windowSubTextFg);
|
||||||
}
|
}
|
||||||
|
if (_currencyIcon) {
|
||||||
|
const auto iconTop = y
|
||||||
|
- _currencyIcon->height()
|
||||||
|
+ st::statisticsChartRulerCaptionSkip;
|
||||||
|
_currencyIcon->paint(p, 0, iconTop, r.width());
|
||||||
|
}
|
||||||
p.drawText(
|
p.drawText(
|
||||||
0,
|
left,
|
||||||
y,
|
y,
|
||||||
(!_isDouble)
|
(!_isDouble)
|
||||||
? line.caption
|
? line.caption
|
||||||
|
@ -131,7 +141,8 @@ void ChartRulersView::add(Limits newHeight, bool animated) {
|
||||||
newHeight.max,
|
newHeight.max,
|
||||||
newHeight.min,
|
newHeight.min,
|
||||||
true,
|
true,
|
||||||
_isDouble ? _scaledLineRatio : 0.);
|
_isDouble ? _scaledLineRatio : 0.,
|
||||||
|
_currencyIcon ? 1000000000 : 0);
|
||||||
if (_isDouble) {
|
if (_isDouble) {
|
||||||
const auto &font = st::statisticsDetailsBottomCaptionStyle.font;
|
const auto &font = st::statisticsDetailsBottomCaptionStyle.font;
|
||||||
for (auto &line : newLinesData.lines) {
|
for (auto &line : newLinesData.lines) {
|
||||||
|
|
|
@ -42,6 +42,7 @@ private:
|
||||||
QPen _rightPen;
|
QPen _rightPen;
|
||||||
int _leftLineId = 0;
|
int _leftLineId = 0;
|
||||||
int _rightLineId = 0;
|
int _rightLineId = 0;
|
||||||
|
const style::icon *_currencyIcon = nullptr;
|
||||||
|
|
||||||
std::vector<ChartRulersData> _rulers;
|
std::vector<ChartRulersData> _rulers;
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,8 @@ PointDetailsWidget::PointDetailsWidget(
|
||||||
, _zoomEnabled(zoomEnabled)
|
, _zoomEnabled(zoomEnabled)
|
||||||
, _chartData(chartData)
|
, _chartData(chartData)
|
||||||
, _textStyle(st::statisticsDetailsPopupStyle)
|
, _textStyle(st::statisticsDetailsPopupStyle)
|
||||||
, _headerStyle(st::statisticsDetailsPopupHeaderStyle) {
|
, _headerStyle(st::statisticsDetailsPopupHeaderStyle)
|
||||||
|
, _valueIcon(chartData.isCurrency ? &st::statisticsCurrencyIcon : nullptr) {
|
||||||
|
|
||||||
if (zoomEnabled) {
|
if (zoomEnabled) {
|
||||||
rpl::single(rpl::empty_value()) | rpl::then(
|
rpl::single(rpl::empty_value()) | rpl::then(
|
||||||
|
@ -201,6 +202,7 @@ PointDetailsWidget::PointDetailsWidget(
|
||||||
+ rect::m::sum::h(st::statisticsDetailsPopupPadding)
|
+ rect::m::sum::h(st::statisticsDetailsPopupPadding)
|
||||||
+ st::statisticsDetailsPopupPadding.left() // Between strings.
|
+ st::statisticsDetailsPopupPadding.left() // Between strings.
|
||||||
+ maxNameTextWidth
|
+ maxNameTextWidth
|
||||||
|
+ (_valueIcon ? _valueIcon->width() : 0)
|
||||||
+ _maxPercentageWidth;
|
+ _maxPercentageWidth;
|
||||||
}();
|
}();
|
||||||
sizeValue(
|
sizeValue(
|
||||||
|
@ -278,7 +280,9 @@ void PointDetailsWidget::setXIndex(int xIndex) {
|
||||||
textLine.name.setText(_textStyle, dataLine.name);
|
textLine.name.setText(_textStyle, dataLine.name);
|
||||||
textLine.value.setText(
|
textLine.value.setText(
|
||||||
_textStyle,
|
_textStyle,
|
||||||
QString("%L1").arg(dataLine.y[xIndex]));
|
_chartData.isCurrency
|
||||||
|
? QString::number(dataLine.y[xIndex] / float64(1000000000))
|
||||||
|
: QString("%L1").arg(dataLine.y[xIndex]));
|
||||||
hasPositiveValues |= (dataLine.y[xIndex] > 0);
|
hasPositiveValues |= (dataLine.y[xIndex] > 0);
|
||||||
textLine.valueColor = QColor(dataLine.color);
|
textLine.valueColor = QColor(dataLine.color);
|
||||||
_lines.push_back(std::move(textLine));
|
_lines.push_back(std::move(textLine));
|
||||||
|
@ -381,6 +385,14 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
||||||
.outerWidth = _textRect.width(),
|
.outerWidth = _textRect.width(),
|
||||||
.availableWidth = valueWidth,
|
.availableWidth = valueWidth,
|
||||||
};
|
};
|
||||||
|
if (_valueIcon) {
|
||||||
|
_valueIcon->paint(
|
||||||
|
p,
|
||||||
|
valueContext.position.x() - _valueIcon->width(),
|
||||||
|
lineY,
|
||||||
|
valueContext.outerWidth,
|
||||||
|
line.valueColor);
|
||||||
|
}
|
||||||
const auto nameContext = Ui::Text::PaintContext{
|
const auto nameContext = Ui::Text::PaintContext{
|
||||||
.position = QPoint(
|
.position = QPoint(
|
||||||
_textRect.x() + _maxPercentageWidth,
|
_textRect.x() + _maxPercentageWidth,
|
||||||
|
|
|
@ -47,6 +47,7 @@ private:
|
||||||
const style::TextStyle &_textStyle;
|
const style::TextStyle &_textStyle;
|
||||||
const style::TextStyle &_headerStyle;
|
const style::TextStyle &_headerStyle;
|
||||||
Ui::Text::String _header;
|
Ui::Text::String _header;
|
||||||
|
const style::icon *_valueIcon = nullptr;
|
||||||
|
|
||||||
void invalidateCache();
|
void invalidateCache();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue