| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- 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 "statistics/statistics_data_deserialize.h"
- #include "base/debug_log.h"
- #include "data/data_channel_earn.h" // kEarnMultiplier.
- #include "data/data_statistics_chart.h"
- #include "statistics/statistics_types.h"
- #include "ui/text/format_values.h" // kCreditsCurrency.
- #include <QtCore/QJsonArray>
- #include <QtCore/QJsonDocument>
- #include <QtCore/QJsonObject>
- #include <QtCore/QJsonValue>
- namespace Statistic {
- Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
- auto error = QJsonParseError{ 0, QJsonParseError::NoError };
- const auto document = QJsonDocument::fromJson(json, &error);
- if (error.error != QJsonParseError::NoError || !document.isObject()) {
- LOG(("API Error: Bad stats graph json received."));
- return {};
- }
- const auto root = document.object();
- const auto columns = root.value(u"columns"_q).toArray();
- if (columns.empty()) {
- LOG(("API Error: Empty columns list from stats graph received."));
- return {};
- }
- const auto hiddenLinesRaw = root.value(u"hidden"_q).toArray();
- const auto hiddenLines = ranges::views::all(
- hiddenLinesRaw
- ) | ranges::views::transform([](const auto &q) {
- return q.toString();
- }) | ranges::to_vector;
- auto result = Data::StatisticalChart();
- {
- const auto tickFormatIt = root.constFind(u"yTickFormatter"_q);
- if (tickFormatIt != root.constEnd()) {
- const auto tickFormat = tickFormatIt->toString();
- if (tickFormat.contains(u"TON"_q)) {
- result.currency = Data::StatisticalCurrency::Ton;
- } else if (tickFormat.contains(Ui::kCreditsCurrency)) {
- result.currency = Data::StatisticalCurrency::Credits;
- }
- }
- }
- auto columnIdCount = 0;
- for (const auto &column : columns) {
- const auto array = column.toArray();
- if (array.empty()) {
- LOG(("API Error: Empty column from stats graph received."));
- return {};
- }
- const auto columnId = array.first().toString();
- if (columnId == u"x"_q) {
- const auto length = array.size() - 1;
- result.x.reserve(length);
- for (auto i = 0; i < length; i++) {
- result.x.push_back(array.at(i + 1).toDouble());
- }
- } else {
- auto line = Data::StatisticalChart::Line();
- const auto length = array.size() - 1;
- line.id = (++columnIdCount);
- line.idString = columnId;
- line.isHiddenOnStart = ranges::contains(hiddenLines, columnId);
- line.y.resize(length);
- for (auto i = 0; i < length; i++) {
- using Currency = Data::StatisticalCurrency;
- const auto multiplier = (result.currency == Currency::Credits)
- ? Data::kEarnMultiplier
- : 1;
- const auto value = ChartValue(
- base::SafeRound(array.at(i + 1).toDouble()))
- * multiplier;
- line.y[i] = value;
- if (value > line.maxValue) {
- line.maxValue = value;
- }
- if (value < line.minValue) {
- line.minValue = value;
- }
- }
- result.lines.push_back(std::move(line));
- }
- if (result.x.size() > 1) {
- result.timeStep = std::max(1., result.x[1] - result.x[0]);
- } else {
- constexpr auto kOneDay = 3600 * 24 * 1000;
- result.timeStep = kOneDay;
- }
- result.measure();
- }
- if (result.maxValue == result.minValue) {
- if (result.minValue) {
- result.minValue = 0;
- } else {
- result.maxValue = 1;
- }
- }
- {
- const auto subchart = root.value(u"subchart"_q).toObject();
- const auto subchartShowIt = subchart.constFind(u"show"_q);
- if (subchartShowIt != subchart.constEnd()) {
- if (subchartShowIt->isBool()) {
- result.isFooterHidden = !(subchartShowIt->toBool());
- }
- }
- const auto defaultZoomIt = subchart.constFind(u"defaultZoom"_q);
- auto min = int(0);
- auto max = int(result.x.size() - 1);
- if (defaultZoomIt != subchart.constEnd()) {
- if (const auto array = defaultZoomIt->toArray(); !array.empty()) {
- const auto minValue = array.first().toDouble();
- const auto maxValue = array.last().toDouble();
- for (auto i = 0; i < result.x.size(); i++) {
- if (result.x[i] == minValue) {
- min = i;
- }
- if (result.x[i] == maxValue) {
- max = i;
- }
- }
- }
- }
- result.defaultZoomXIndex.min = std::min(min, max);
- result.defaultZoomXIndex.max = std::max(min, max);
- }
- {
- const auto percentageShowIt = root.constFind(u"percentage"_q);
- if (percentageShowIt != root.constEnd()) {
- if (percentageShowIt->isBool()) {
- result.hasPercentages = (percentageShowIt->toBool());
- }
- }
- }
- {
- const auto tooltipFormatIt = root.constFind(u"xTooltipFormatter"_q);
- if (tooltipFormatIt != root.constEnd()) {
- const auto tooltipFormat = tooltipFormatIt->toString();
- result.weekFormat = tooltipFormat.contains(u"'week'"_q);
- }
- }
- const auto colors = root.value(u"colors"_q).toObject();
- const auto names = root.value(u"names"_q).toObject();
- for (auto &line : result.lines) {
- const auto colorIt = colors.constFind(line.idString);
- if (colorIt != colors.constEnd() && (*colorIt).isString()) {
- static const auto RegExp = QRegularExpression(u"(.*)(#.*)"_q);
- const auto match = RegExp.match(
- colorIt->toString());
- if (match.hasMatch()) {
- line.colorKey = match.captured(1);
- line.color = QColor(match.captured(2));
- }
- }
- const auto nameIt = names.constFind(line.idString);
- if (nameIt != names.constEnd() && (*nameIt).isString()) {
- line.name = nameIt->toString().replace('-', QChar(8212));
- }
- }
- return result;
- }
- } // namespace Statistic
|