view src/gui/pages/statistics.cc @ 375:abd956418fe9

gui/pages/now_playing: automatically update progress when the episode is "finished"
author Paper <paper@tflc.us>
date Fri, 25 Jul 2025 11:22:55 -0400
parents ea3a74ed2ef9
children
line wrap: on
line source

#include "gui/pages/statistics.h"
#include "core/anime_db.h"
#include "core/session.h"
#include "core/strings.h"
#include "core/time.h"
#include "gui/pages/anime_list.h"
#include "gui/widgets/graph.h"
#include "gui/widgets/text.h"

#include <QString>
#include <QTextDocument>
#include <QTextStream>
#include <QTimer>
#include <QVBoxLayout>
#include <QWidget>

#include <cmath>
#include <sstream>

StatisticsPage::StatisticsPage(QWidget *parent) : QFrame(parent)
{
	setBackgroundRole(QPalette::Base);

	QVBoxLayout *layout = new QVBoxLayout(this);

	setFrameShape(QFrame::Box);
	setFrameShadow(QFrame::Sunken);

	setAutoFillBackground(true);

	const std::vector<std::pair<std::string, std::string>> al_data_template = {
	    {Strings::Translate("Anime count:"),         ""},
        {Strings::Translate("Episode count:"),       ""},
	    {Strings::Translate("Time spent watching:"), ""},
        {Strings::Translate("Time to complete:"),    ""},
	    {Strings::Translate("Average score:"),       ""},
        {Strings::Translate("Score deviation:"),     ""},
	};

	_anime_list.GetHeader().SetText(Strings::Translate("Anime List"));
	_anime_list.GetContent().SetData(al_data_template);

	layout->addWidget(&_anime_list);

	{
		QWidget *score_dist_widget = new QWidget(this);
		QVBoxLayout *score_dist_layout = new QVBoxLayout(score_dist_widget);

		TextWidgets::Header *hdr = new TextWidgets::Header(score_dist_widget);
		hdr->SetText(Strings::Translate("Score distribution"));
		score_dist_layout->addWidget(hdr);

		/* Ew */
		{
			QWidget *score_graph_parent = new QWidget(score_dist_widget);
			QVBoxLayout *score_parent_layout = new QVBoxLayout(score_graph_parent);

			score_parent_layout->addWidget(&_score_distribution_graph);

			score_parent_layout->setSpacing(0);
			score_parent_layout->setContentsMargins(12, 0, 0, 0);

			score_dist_layout->addWidget(score_graph_parent);
		}

		score_dist_layout->setContentsMargins(0, 0, 0, 0);

		layout->addWidget(score_dist_widget);
	}

	const std::vector<std::pair<std::string, std::string>> app_data_template = {
	    {Strings::Translate("Uptime:"),        ""},
	    {Strings::Translate("Requests made:"), ""},
	};

	_application.GetHeader().SetText(Strings::Translate("Minori"));
	_application.GetContent().SetData(app_data_template);

	layout->addWidget(&_application);

	layout->addStretch();

	QTimer *timer = new QTimer(this);
	connect(timer, &QTimer::timeout, this, [this] {
		if (isVisible())
			UpdateStatistics();
	});
	timer->start(1000); // update statistics every second
}

void StatisticsPage::showEvent(QShowEvent *)
{
	UpdateStatistics();
}

inline int GetTotalWithScore(const int score)
{
	int count = 0;
	for (const auto &item : Anime::db.items)
		if (item.second.IsInUserList() && item.second.GetUserScore() == score)
			count++;
	return count;
}

void StatisticsPage::UpdateStatistics()
{
	const std::vector<std::pair<std::string, std::string>> al_data = {
	    {Strings::Translate("Anime count:"), Strings::ToUtf8String(Anime::db.GetTotalAnimeAmount())},
	    {Strings::Translate("Episode count:"), Strings::ToUtf8String(Anime::db.GetTotalEpisodeAmount())},
	    {Strings::Translate("Time spent watching:"),
	     Time::GetSecondsAsAbsoluteString(Time::Units::Minutes, Anime::db.GetTotalWatchedAmount(), 60.0)},
	    {Strings::Translate("Time to complete:"),
	     Time::GetSecondsAsAbsoluteString(Time::Units::Minutes, Anime::db.GetTotalPlannedAmount(), 60.0)},
	    {Strings::Translate("Average score:"), Strings::ToUtf8String(Anime::db.GetAverageScore())},
	    {Strings::Translate("Score deviation:"), Strings::ToUtf8String(Anime::db.GetScoreDeviation())},
	};

	_anime_list.GetContent().SetData(al_data);

	_score_distribution_graph.Clear();
	for (int i = 10; i <= 100; i += 10)
		_score_distribution_graph.AddItem(i, GetTotalWithScore(i));

	/* Application */
	const std::vector<std::pair<std::string, std::string>> app_data_template = {
	    {Strings::Translate("Uptime:"),
	     Time::GetSecondsAsAbsoluteString(Time::Units::Seconds, session.uptime() / 1000)},
	    {Strings::Translate("Requests made:"), Strings::ToUtf8String(session.GetRequests())},
	};

	_application.GetContent().SetData(app_data_template);
}