diff src/gui/pages/statistics.cc @ 250:c130f47f6f48

*: many many changes e.g. the search page is actually implemented now!
author Paper <paper@paper.us.eu.org>
date Sun, 04 Feb 2024 21:17:17 -0500
parents 4d461ef7d424
children d14f8e0e40c3
line wrap: on
line diff
--- a/src/gui/pages/statistics.cc	Wed Jan 24 20:18:59 2024 -0500
+++ b/src/gui/pages/statistics.cc	Sun Feb 04 21:17:17 2024 -0500
@@ -14,6 +14,12 @@
 #include <QWidget>
 
 #include <sstream>
+#include <cmath>
+
+enum class TimeUnits {
+	SECONDS,
+	MINUTES
+};
 
 StatisticsPage::StatisticsPage(QWidget* parent) : QFrame(parent) {
 	QVBoxLayout* layout = new QVBoxLayout(this);
@@ -74,47 +80,49 @@
 	UpdateStatistics();
 }
 
-/* me abusing macros :) */
-static void add_time_segment(std::ostringstream& str, int x, const std::string_view& s, const std::string_view& p) {
-	if (x > 0)
-		str << x << ((x == 1) ? s : p);
-}
+/*  [in] enum TimeUnits unit:
+ *       which unit to stop on
+ *  [in] int amount:
+ *       amount of units to parse
+ *  [in, defaults to 1.0] double unit_in_seconds:
+ *       equivalent of one of 'amount' in seconds, e.g. minutes would be 60.0
+*/
+static std::string TimeToDateString(TimeUnits unit, int amount, double unit_in_seconds = 1.0) {
+	/* avoid calculating this twice */
+	const double years_conv = (31556952.0 / unit_in_seconds);
+	const double months_conv = (2629746.0 / unit_in_seconds);
+	const double days_conv = (86400.0 / unit_in_seconds);
+	const double hours_conv = (3600.0 / unit_in_seconds);
+	const double minutes_conv = (60.0 / unit_in_seconds);
+	const double seconds_conv = (1.0 / unit_in_seconds);
 
-std::string StatisticsPage::MinutesToDateString(const int minutes) {
-	/* ew */
-	int years = (minutes * (1 / 525949.2F));
-	int months = (minutes * (1 / 43829.1F)) - (years * 12);
-	int days = (minutes * (1 / 1440.0F)) - (years * 365.2425F) - (months * 30.436875F);
-	int hours = (minutes * (1 / 60.0F)) - (years * 8765.82F) - (months * 730.485F) - (days * 24);
-	int rest_minutes = (minutes) - (years * 525949.2F) - (months * 43829.1F) - (days * 1440) - (hours * 60);
-	std::ostringstream return_stream;
-	add_time_segment(return_stream, years, " year ", " years ");
-	add_time_segment(return_stream, months, " month ", " months ");
-	add_time_segment(return_stream, days, " day ", " days ");
-	add_time_segment(return_stream, hours, " hour ", " hours ");
-	if (rest_minutes > 0 || return_stream.str().size() == 0)
-		return_stream << rest_minutes << ((rest_minutes == 1) ? " minute" : " minutes");
-	return return_stream.str();
-}
+	const int years   = amount / years_conv;
+	const int months  = std::fmod(amount, years_conv)   / months_conv;
+	const int days    = std::fmod(amount, months_conv)  / days_conv;
+	const int hours   = std::fmod(amount, days_conv)    / hours_conv;
+	const int minutes = std::fmod(amount, hours_conv)   / minutes_conv;
+	const int seconds = std::fmod(amount, minutes_conv) / seconds_conv;
+
+	const auto add_time_segment = [](std::ostringstream& str, int amount, const std::string_view& singular, const std::string_view& plural, bool always = false) {
+		if (amount > 0 || always)
+			str << amount << ((amount == 1) ? singular : plural);
+	};
 
-std::string StatisticsPage::SecondsToDateString(const int sec) {
-	/* this is all fairly unnecessary, but works:tm: */
-	int years = sec * (1 / 31556952.0F);
-	int months = sec * (1 / 2629746.0F) - (years * 12);
-	int days = sec * (1 / 86400.0F) - (years * 365.2425F) - (months * 30.436875F);
-	int hours = sec * (1 / 3600.0F) - (years * 8765.82F) - (months * 730.485F) - (days * 24);
-	int minutes = (sec) * (1 / 60.0F) - (years * 525949.2F) - (months * 43829.1F) - (days * 1440.0F) - (hours * 60.0F);
-	int seconds =
-	    sec - (years * 31556952.0F) - (months * 2629746.0F) - (days * 86400.0F) - (hours * 3600.0F) - (minutes * 60.0F);
-	std::ostringstream return_stream;
-	add_time_segment(return_stream, years, " year ", " years ");
-	add_time_segment(return_stream, months, " month ", " months ");
-	add_time_segment(return_stream, days, " day ", " days ");
-	add_time_segment(return_stream, hours, " hour ", " hours ");
-	add_time_segment(return_stream, minutes, " minute ", " minutes ");
-	if (seconds > 0 || return_stream.str().size() == 0)
-		return_stream << seconds << ((seconds == 1) ? " second" : " seconds");
-	return return_stream.str();
+	std::ostringstream string;
+	add_time_segment(string, years, " year ", " years ");
+	add_time_segment(string, months, " month ", " months ");
+	add_time_segment(string, days, " day ", " days ");
+	add_time_segment(string, hours, " hour ", " hours ");
+
+	if (unit == TimeUnits::MINUTES) {
+		add_time_segment(string, minutes, " minute", " minutes", true);
+		return string.str();
+	} else {
+		add_time_segment(string, minutes, " minute ", " minutes ");
+	}
+
+	add_time_segment(string, seconds, " second", " seconds", true);
+	return string.str();
 }
 
 inline int GetTotalWithScore(const int score) {
@@ -131,8 +139,8 @@
 	QTextStream ts(&string);
 	ts << Anime::db.GetTotalAnimeAmount() << '\n';
 	ts << Anime::db.GetTotalEpisodeAmount() << '\n';
-	ts << MinutesToDateString(Anime::db.GetTotalWatchedAmount()).c_str() << '\n';
-	ts << MinutesToDateString(Anime::db.GetTotalPlannedAmount()).c_str() << '\n';
+	ts << Strings::ToQString(TimeToDateString(TimeUnits::MINUTES, Anime::db.GetTotalWatchedAmount(), 60.0)) << '\n';
+	ts << Strings::ToQString(TimeToDateString(TimeUnits::MINUTES, Anime::db.GetTotalPlannedAmount(), 60.0)) << '\n';
 	ts << Anime::db.GetAverageScore() << '\n';
 	ts << Anime::db.GetScoreDeviation();
 	_anime_list->GetParagraph()->SetText(string);
@@ -142,7 +150,7 @@
 		_score_distribution_graph->AddItem(i, GetTotalWithScore(i));
 
 	string = "";
-	ts << Strings::ToQString(SecondsToDateString(session.uptime() / 1000)) << '\n';
+	ts << Strings::ToQString(TimeToDateString(TimeUnits::SECONDS, session.uptime() / 1000)) << '\n';
 	ts << session.GetRequests();
 	/* Application */
 	// UiUtils::SetPlainTextEditData(application_data, QString::number(session.uptime() / 1000));