From 765de6240ec640374e337d30bb22904a44d59946 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Fri, 22 Nov 2024 23:28:10 +0800 Subject: [PATCH] Make the recorded time more accurate Signed-off-by: Damien Zhao --- Application/include/ui/screen/Details.hpp | 4 - .../include/ui/screen/RecentActivity.hpp | 4 - Application/source/ui/screen/Details.cpp | 564 ++++++++---------- .../source/ui/screen/RecentActivity.cpp | 445 +++++++------- 4 files changed, 474 insertions(+), 543 deletions(-) diff --git a/Application/include/ui/screen/Details.hpp b/Application/include/ui/screen/Details.hpp index d0dc40c..8e9170c 100644 --- a/Application/include/ui/screen/Details.hpp +++ b/Application/include/ui/screen/Details.hpp @@ -18,10 +18,6 @@ namespace Screen { // Used to udpate prev. screen bool popped; - // Updates graph if data matching current time range - void updateGraph(); - // Updates the list of play sessions matching current time range - void updateSessions(); // Element which marks top of sessions Aether::Element * topElm; diff --git a/Application/include/ui/screen/RecentActivity.hpp b/Application/include/ui/screen/RecentActivity.hpp index 60001fd..3a98af4 100644 --- a/Application/include/ui/screen/RecentActivity.hpp +++ b/Application/include/ui/screen/RecentActivity.hpp @@ -17,10 +17,6 @@ namespace Screen { // Updates the "recent activity" part of the screen void updateActivity(); - // Updates graph if data matching current time range - void updateGraph(); - // Updates the list of games played underneath - void updateTitles(); // Element which marks top of sessions Aether::Element * topElm; diff --git a/Application/source/ui/screen/Details.cpp b/Application/source/ui/screen/Details.cpp index 0cd961e..9b7f4b5 100644 --- a/Application/source/ui/screen/Details.cpp +++ b/Application/source/ui/screen/Details.cpp @@ -96,32 +96,36 @@ namespace Screen { void Details::updateActivity() { // Check if there is any activity + update heading - struct tm t = this->app->time(); - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_min = 59; - e.tm_sec = 59; + struct tm begin = this->app->time(); + struct tm t = begin; + uint64_t totalSecs = 0; + + struct tm tm = begin; + tm.tm_min = 0; + tm.tm_sec = 0; + struct tm em = tm; + em.tm_min = 59; + em.tm_sec = 59; switch (this->app->viewPeriod()) { case ViewPeriod::Day: - e.tm_hour = 23; + em.tm_hour = 23; break; case ViewPeriod::Month: - e.tm_mday = Utils::Time::tmGetDaysInMonth(t); + em.tm_mday = Utils::Time::tmGetDaysInMonth(tm); break; case ViewPeriod::Year: - e.tm_mon = 11; - e.tm_mday = Utils::Time::tmGetDaysInMonth(t); + em.tm_mon = 11; + em.tm_mday = Utils::Time::tmGetDaysInMonth(tm); break; default: break; } - this->graphHeading->setString(Utils::Time::dateToActivityForString(t, this->app->viewPeriod())); + this->graphHeading->setString(Utils::Time::dateToActivityForString(tm, this->app->viewPeriod())); this->graphHeading->setX(this->header->x() + (this->header->w() - this->graphHeading->w())/2); - NX::RecentPlayStatistics * ps = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + NX::RecentPlayStatistics * ps = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(tm), Utils::Time::getTimeT(em), this->app->activeUser()->ID()); // Remove current sessions regardless this->list->removeElementsAfter(this->topElm); @@ -136,323 +140,285 @@ namespace Screen { this->list->setCanScroll(true); this->playHeading->setHidden(false); this->noStats->setHidden(true); - this->updateGraph(); - this->updateSessions(); - } else { - this->graph->setHidden(true); - this->graphSubheading->setHidden(true); - this->graphTotal->setHidden(true); - this->list->setShowScrollBar(false); - this->list->setCanScroll(false); - this->playHeading->setHidden(true); - this->noStats->setHidden(false); - } - delete ps; - } - - void Details::update(uint32_t dt) { - // Don't check!! - if (!this->popped) { - if (this->app->timeChanged()) { - this->updateActivity(); + // update Graph + // Setup graph columns + labels + for (unsigned int i = 0; i < this->graph->entries(); i++) { + this->graph->setLabel(i, ""); } - } - - Screen::update(dt); - } - void Details::updateGraph() { - // Setup graph columns + labels - for (unsigned int i = 0; i < this->graph->entries(); i++) { - this->graph->setLabel(i, ""); - } - struct tm tm = this->app->time(); - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: - this->graph->setFontSize(14); - this->graph->setMaximumValue(60); - this->graph->setYSteps(6); - this->graph->setValuePrecision(0); - this->graph->setNumberOfEntries(24); - if (this->app->config()->gIs24H()) { - for (int i = 0; i < 24; i += 2) { - this->graph->setLabel(i, std::to_string(i)); + t.tm_min = 0; + t.tm_sec = 0; + struct tm e = t; + e.tm_min = 59; + e.tm_sec = 59; + // Read playtime and set graph values + switch (this->app->viewPeriod()) { + case ViewPeriod::Day: { + this->graph->setFontSize(14); + this->graph->setMaximumValue(60); + this->graph->setYSteps(6); + this->graph->setValuePrecision(0); + this->graph->setNumberOfEntries(24); + if (this->app->config()->gIs24H()) { + for (int i = 0; i < 24; i += 2) { + this->graph->setLabel(i, std::to_string(i)); + } + } else { + for (int i = 0; i < 24; i += 3) { + this->graph->setLabel(i, Utils::format12H(i)); + } } - } else { - for (int i = 0; i < 24; i += 3) { - this->graph->setLabel(i, Utils::format12H(i)); + for (size_t i = 0; i < this->graph->entries(); i++) { + t.tm_hour = i; + e.tm_hour = i; + NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + totalSecs += s->playtime; + double val = s->playtime/60.0; + this->graph->setValue(i, val); + delete s; } + this->graphSubheading->setString("common.playtimeMinutes"_lang); + break; } - break; - - case ViewPeriod::Month: { - unsigned int c = Utils::Time::tmGetDaysInMonth(tm); - this->graph->setFontSize(13); - this->graph->setValuePrecision(1); - this->graph->setNumberOfEntries(c); - for (unsigned int i = 0; i < c; i+=3) { - this->graph->setLabel(i, std::to_string(i + 1) + Utils::Time::getDateSuffix(i + 1)); - } - break; - } - - case ViewPeriod::Year: - this->graph->setFontSize(16); - this->graph->setValuePrecision(1); - this->graph->setNumberOfEntries(12); - for (int i = 0; i < 12; i++) { - this->graph->setLabel(i, Utils::Time::getShortMonthString(i)); - } - break; - - default: - break; - } - - // Read playtime and set graph values - struct tm t = tm; - uint64_t totalSecs = 0; - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: { - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_min = 59; - e.tm_sec = 59; - for (size_t i = 0; i < this->graph->entries(); i++) { - t.tm_hour = i; - e.tm_hour = i; - NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); - totalSecs += s->playtime; - double val = s->playtime/60.0; - this->graph->setValue(i, val); - delete s; - } - break; - } - - case ViewPeriod::Month: { - t.tm_hour = 0; - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_hour = 23; - e.tm_min = 59; - e.tm_sec = 59; - uint64_t max = 0; - for (size_t i = 0; i < this->graph->entries(); i++) { - t.tm_mday = i + 1; - e.tm_mday = i + 1; - NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); - totalSecs += s->playtime; - if (s->playtime > max) { - max = s->playtime; + case ViewPeriod::Month: { + unsigned int c = Utils::Time::tmGetDaysInMonth(tm); + this->graph->setFontSize(13); + this->graph->setValuePrecision(1); + this->graph->setNumberOfEntries(c); + for (unsigned int i = 0; i < c; i+=3) { + this->graph->setLabel(i, std::to_string(i + 1) + Utils::Time::getDateSuffix(i + 1)); } - double val = s->playtime/60/60.0; - this->graph->setValue(i, val); - delete s; - } - max /= 60.0; - max /= 60.0; - if (max <= 2) { - this->graph->setMaximumValue(max + 2 - max%2); - this->graph->setYSteps(2); - } else { - this->graph->setMaximumValue(max + 5 - max%5); - this->graph->setYSteps(5); - } - break; - } - - case ViewPeriod::Year: { - t.tm_mday = 1; - t.tm_hour = 0; - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_hour = 23; - e.tm_min = 59; - e.tm_sec = 59; - uint64_t max = 0; - for (size_t i = 0; i < this->graph->entries(); i++) { - t.tm_mon = i; - e.tm_mon = i; - e.tm_mday = Utils::Time::tmGetDaysInMonth(t); - NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); - totalSecs += s->playtime; - if (s->playtime > max) { - max = s->playtime; + t.tm_hour = 0; + e = t; + e.tm_hour = 23; + uint64_t max = 0; + for (size_t i = 0; i < this->graph->entries(); i++) { + t.tm_mday = i + 1; + e.tm_mday = i + 1; + NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + totalSecs += s->playtime; + if (s->playtime > max) { + max = s->playtime; + } + double val = s->playtime/60/60.0; + this->graph->setValue(i, val); + delete s; } - double val = s->playtime/60/60.0; - this->graph->setValue(i, val); - delete s; + max /= 60.0; + max /= 60.0; + if (max <= 2) { + this->graph->setMaximumValue(max + 2 - max%2); + this->graph->setYSteps(2); + } else { + this->graph->setMaximumValue(max + 5 - max%5); + this->graph->setYSteps(5); + } + this->graphSubheading->setString("common.playtimeHours"_lang); + break; } - max /= 60.0; - max /= 60.0; - if (max <= 2) { - this->graph->setMaximumValue(max + 2 - max%2); - this->graph->setYSteps(2); - } else { - this->graph->setMaximumValue(max + 5 - max%5); - this->graph->setYSteps(5); + case ViewPeriod::Year: { + this->graph->setFontSize(16); + this->graph->setValuePrecision(1); + this->graph->setNumberOfEntries(12); + for (int i = 0; i < 12; i++) { + this->graph->setLabel(i, Utils::Time::getShortMonthString(i)); + } + t.tm_mday = 1; + t.tm_hour = 0; + e = t; + e.tm_hour = 23; + uint64_t max = 0; + for (size_t i = 0; i < this->graph->entries(); i++) { + t.tm_mon = i; + e.tm_mon = i; + e.tm_mday = Utils::Time::tmGetDaysInMonth(t); + NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + totalSecs += s->playtime; + if (s->playtime > max) { + max = s->playtime; + } + double val = s->playtime/60/60.0; + this->graph->setValue(i, val); + delete s; + } + max /= 60.0; + max /= 60.0; + if (max <= 2) { + this->graph->setMaximumValue(max + 2 - max%2); + this->graph->setYSteps(2); + } else { + this->graph->setMaximumValue(max + 5 - max%5); + this->graph->setYSteps(5); + } + this->graphSubheading->setString("common.playtimeHours"_lang); + break; } - break; + default: + break; } - default: - break; - } - - // Set headings etc... - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: - this->graphSubheading->setString("common.playtimeMinutes"_lang); - break; - - case ViewPeriod::Month: - case ViewPeriod::Year: - this->graphSubheading->setString("common.playtimeHours"_lang); - break; - - default: - break; - } - - this->graphSubheading->setX(this->header->x() + (this->header->w() - this->graphSubheading->w())/2); - this->graphTotalSub->setString(Utils::playtimeToString(totalSecs)); - int w = this->graphTotalHead->w() + this->graphTotalSub->w(); - this->graphTotalHead->setX(this->graphTotal->x()); - this->graphTotalSub->setX(this->graphTotalHead->x() + this->graphTotalHead->w()); - this->graphTotalHead->setX(this->graphTotalHead->x() + (this->graphTotal->w() - w)/2); - this->graphTotalSub->setX(this->graphTotalSub->x() + (this->graphTotal->w() - w)/2); - } - - void Details::updateSessions() { - // Get relevant play stats - NX::PlayStatistics * ps = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); - std::vector stats = this->app->playdata()->getPlaySessionsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); - - // Get start and end timestamps for date - char c = ' '; - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: - c = 'D'; - break; - - case ViewPeriod::Month: - c = 'M'; - break; - - case ViewPeriod::Year: - c = 'Y'; - break; - - default: - break; - } - uint64_t s = Utils::Time::getTimeT(this->app->time()); - // Minus one second so end time is 11:59pm and not 12:00am next day - uint64_t e = Utils::Time::getTimeT(Utils::Time::increaseTm(this->app->time(), c)) - 1; - - // Add sessions to list - for (size_t i = 0; i < stats.size(); i++) { - // Only add session if start or end is within the current time period - if (stats[i].startTimestamp > e || stats[i].endTimestamp < s) { - continue; + this->graphSubheading->setX(this->header->x() + (this->header->w() - this->graphSubheading->w())/2); + this->graphTotalSub->setString(Utils::playtimeToString(totalSecs)); + int w = this->graphTotalHead->w() + this->graphTotalSub->w(); + this->graphTotalHead->setX(this->graphTotal->x()); + this->graphTotalSub->setX(this->graphTotalHead->x() + this->graphTotalHead->w()); + this->graphTotalHead->setX(this->graphTotalHead->x() + (this->graphTotal->w() - w)/2); + this->graphTotalSub->setX(this->graphTotalSub->x() + (this->graphTotal->w() - w)/2); + + // update sessions + // Get relevant play stats + NX::PlayStatistics * pss = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + std::vector stats = this->app->playdata()->getPlaySessionsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + + t.tm_min = 0; + t.tm_sec = 0; + // Minus one second so end time is 11:59pm and not 12:00am next day + unsigned int start_time; + unsigned int end_time; + switch (this->app->viewPeriod()) { + case ViewPeriod::Day: + t.tm_hour = 0; + start_time = Utils::Time::getTimeT(t); + end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'D')) - 1; + break; + case ViewPeriod::Month: + t.tm_mday = 1; + t.tm_hour = 0; + start_time = Utils::Time::getTimeT(t); + end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'M')) - 1; + break; + case ViewPeriod::Year: + t.tm_mon = 1; + t.tm_mday = 1; + t.tm_hour = 0; + start_time = Utils::Time::getTimeT(t); + end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'Y')) - 1; + break; + default: + break; } - // Create element - CustomElm::ListSession * ls = new CustomElm::ListSession(); - NX::PlaySession ses = stats[i]; - ls->onPress([this, ses](){ - this->setupSessionBreakdown(ses); - }); - - // Defaults for a session within the range - uint64_t playtime = stats[i].playtime; - struct tm sTm = Utils::Time::getTm(stats[i].startTimestamp); - struct tm eTm = Utils::Time::getTm(stats[i].endTimestamp); - - // If started before range set start as start of range - bool outRange = false; - if (stats[i].startTimestamp < s) { - outRange = true; - sTm = Utils::Time::getTm(s); - } + // Add sessions to list + for (size_t i = 0; i < stats.size(); i++) { + // Only add session if start or end is within the current time period + if (stats[i].startTimestamp > end_time || stats[i].endTimestamp < start_time) { + continue; + } - // If finished after range set end as end of range - if (stats[i].endTimestamp > e) { - outRange = true; - eTm = Utils::Time::getTm(e); - } + // Create element + CustomElm::ListSession * ls = new CustomElm::ListSession(); + NX::PlaySession ses = stats[i]; + ls->onPress([this, ses](){ + this->setupSessionBreakdown(ses); + }); + + // Defaults for a session within the range + uint64_t playtime = stats[i].playtime; + struct tm sTm = Utils::Time::getTm(stats[i].startTimestamp); + struct tm eTm = Utils::Time::getTm(stats[i].endTimestamp); + + // If started before range set start as start of range + bool outRange = false; + if (stats[i].startTimestamp < start_time) { + outRange = true; + sTm = Utils::Time::getTm(start_time); + } - // Get playtime if range is altered - if (outRange) { - NX::RecentPlayStatistics * rps = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(sTm), Utils::Time::getTimeT(eTm), this->app->activeUser()->ID()); - playtime = rps->playtime; - delete rps; - } + // If finished after range set end as end of range + if (stats[i].endTimestamp > end_time) { + outRange = true; + eTm = Utils::Time::getTm(end_time); + } - // Set timestamp string - std::string first = ""; - std::string last = ""; - struct tm nTm = Utils::Time::getTmForCurrentTime(); - switch (this->app->viewPeriod()) { - case ViewPeriod::Year: - case ViewPeriod::Month: - first = Utils::Time::tmToDate(sTm, sTm.tm_year != nTm.tm_year) + " "; - // Show date on end timestamp if not the same - if (sTm.tm_mday != eTm.tm_mday) { - last = Utils::Time::tmToDate(eTm, eTm.tm_year != nTm.tm_year) + " "; - } + // Get playtime if range is altered + if (outRange) { + NX::RecentPlayStatistics * rps = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), Utils::Time::getTimeT(sTm), Utils::Time::getTimeT(eTm), this->app->activeUser()->ID()); + playtime = rps->playtime; + delete rps; + } - case ViewPeriod::Day: - if (this->app->config()->gIs24H()) { - first += Utils::Time::tmToString(sTm, "%R", 5); - last += Utils::Time::tmToString(eTm, "%R", 5); - } else { - std::string tmp = Utils::Time::tmToString(sTm, "%I:%M", 5); - if (tmp[0] == '0') { - tmp.erase(0, 1); + // Set timestamp string + std::string first = ""; + std::string last = ""; + struct tm nTm = Utils::Time::getTmForCurrentTime(); + switch (this->app->viewPeriod()) { + case ViewPeriod::Year: + case ViewPeriod::Month: + first = Utils::Time::tmToDate(sTm, sTm.tm_year != nTm.tm_year) + " "; + // Show date on end timestamp if not the same + if (sTm.tm_mday != eTm.tm_mday) { + last = Utils::Time::tmToDate(eTm, eTm.tm_year != nTm.tm_year) + " "; } - first += tmp + Utils::Time::getAMPM(sTm.tm_hour); - tmp = Utils::Time::tmToString(eTm, "%I:%M", 5); - if (tmp[0] == '0') { - tmp.erase(0, 1); + case ViewPeriod::Day: + if (this->app->config()->gIs24H()) { + first += Utils::Time::tmToString(sTm, "%R", 5); + last += Utils::Time::tmToString(eTm, "%R", 5); + } else { + std::string tmp = Utils::Time::tmToString(sTm, "%I:%M", 5); + if (tmp[0] == '0') { + tmp.erase(0, 1); + } + first += tmp + Utils::Time::getAMPM(sTm.tm_hour); + + tmp = Utils::Time::tmToString(eTm, "%I:%M", 5); + if (tmp[0] == '0') { + tmp.erase(0, 1); + } + last += tmp + Utils::Time::getAMPM(eTm.tm_hour); } - last += tmp + Utils::Time::getAMPM(eTm.tm_hour); - } - break; + break; - default: - break; - } - ls->setTimeString(first + " - " + last + (outRange ? "*" : "")); - ls->setPlaytimeString(Utils::playtimeToString(playtime)); + default: + break; + } + ls->setTimeString(first + " - " + last + (outRange ? "*" : "")); + ls->setPlaytimeString(Utils::playtimeToString(playtime)); + + // Add percentage of total playtime + std::string str; + double percent = 100 * ((double)playtime / ((ps->playtime == 0 || ps->playtime < playtime) ? playtime : ps->playtime)); + percent = Utils::roundToDecimalPlace(percent, 2); + if (percent < 0.01) { + str = "< 0.01%"; + } else { + str = Utils::truncateToDecimalPlace(std::to_string(percent), 2) + "%"; + } + ls->setPercentageString(str); - // Add percentage of total playtime - std::string str; - double percent = 100 * ((double)playtime / ((ps->playtime == 0 || ps->playtime < playtime) ? playtime : ps->playtime)); - percent = Utils::roundToDecimalPlace(percent, 2); - if (percent < 0.01) { - str = "< 0.01%"; - } else { - str = Utils::truncateToDecimalPlace(std::to_string(percent), 2) + "%"; + ls->setLineColour(this->app->theme()->mutedLine()); + ls->setPercentageColour(this->app->theme()->mutedText()); + ls->setPlaytimeColour(this->app->theme()->accent()); + ls->setTimeColour(this->app->theme()->text()); + this->list->addElement(ls); } - ls->setPercentageString(str); - ls->setLineColour(this->app->theme()->mutedLine()); - ls->setPercentageColour(this->app->theme()->mutedText()); - ls->setPlaytimeColour(this->app->theme()->accent()); - ls->setTimeColour(this->app->theme()->text()); - this->list->addElement(ls); + delete pss; + } else { + this->graph->setHidden(true); + this->graphSubheading->setHidden(true); + this->graphTotal->setHidden(true); + this->list->setShowScrollBar(false); + this->list->setCanScroll(false); + this->playHeading->setHidden(true); + this->noStats->setHidden(false); } delete ps; } + void Details::update(uint32_t dt) { + // Don't check!! + if (!this->popped) { + if (this->app->timeChanged()) { + this->updateActivity(); + } + } + + Screen::update(dt); + } + void Details::setupSessionHelp() { this->msgbox->emptyBody(); diff --git a/Application/source/ui/screen/RecentActivity.cpp b/Application/source/ui/screen/RecentActivity.cpp index ce8f589..d43b08a 100644 --- a/Application/source/ui/screen/RecentActivity.cpp +++ b/Application/source/ui/screen/RecentActivity.cpp @@ -68,32 +68,36 @@ namespace Screen { void RecentActivity::updateActivity() { // Check if there is any activity + update heading - struct tm t = this->app->time(); - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_min = 59; - e.tm_sec = 59; + struct tm begin = this->app->time(); + struct tm t = begin; + uint64_t totalSecs = 0; + + struct tm tm = begin; + tm.tm_min = 0; + tm.tm_sec = 0; + struct tm em = tm; + em.tm_min = 59; + em.tm_sec = 59; switch (this->app->viewPeriod()) { case ViewPeriod::Day: - e.tm_hour = 23; + em.tm_hour = 23; break; case ViewPeriod::Month: - e.tm_mday = Utils::Time::tmGetDaysInMonth(t); + em.tm_mday = Utils::Time::tmGetDaysInMonth(tm); break; case ViewPeriod::Year: - e.tm_mon = 11; - e.tm_mday = Utils::Time::tmGetDaysInMonth(t); + em.tm_mon = 11; + em.tm_mday = Utils::Time::tmGetDaysInMonth(tm); break; default: break; } - this->graphHeading->setString(Utils::Time::dateToActivityForString(t, this->app->viewPeriod())); + this->graphHeading->setString(Utils::Time::dateToActivityForString(tm, this->app->viewPeriod())); this->graphHeading->setX(this->header->x() + (this->header->w() - this->graphHeading->w())/2); - NX::RecentPlayStatistics * ps = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + NX::RecentPlayStatistics *ps = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(tm), Utils::Time::getTimeT(em), this->app->activeUser()->ID()); // Remove current sessions regardless this->list->removeElementsAfter(this->topElm); @@ -109,254 +113,223 @@ namespace Screen { this->list->setShowScrollBar(true); this->list->setCanScroll(true); this->noStats->setHidden(true); - this->updateGraph(); - this->updateTitles(); - } else { - this->gameHeading->setHidden(true); - this->graph->setHidden(true); - this->graphSubheading->setHidden(true); - this->hours->setString("common.totalPlaytime.0min"_lang); - this->hours->setX(1215 - this->hours->w()); - this->list->setShowScrollBar(false); - this->list->setCanScroll(false); - this->noStats->setHidden(false); - } - delete ps; - } - - void RecentActivity::update(uint32_t dt) { - if (this->app->timeChanged()) { - this->updateActivity(); - } - Screen::update(dt); - } - - void RecentActivity::updateGraph() { - // Setup graph columns + labels - for (unsigned int i = 0; i < this->graph->entries(); i++) { - this->graph->setLabel(i, ""); - } - struct tm tm = this->app->time(); - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: - this->graph->setFontSize(14); - this->graph->setMaximumValue(60); - this->graph->setYSteps(6); - this->graph->setValuePrecision(0); - this->graph->setNumberOfEntries(24); - if (this->app->config()->gIs24H()) { - for (int i = 0; i < 24; i += 2) { - this->graph->setLabel(i, std::to_string(i)); + // update Graph + // Setup graph columns + labels + for (unsigned int i = 0; i < this->graph->entries(); i++) + this->graph->setLabel(i, ""); + + t.tm_min = 0; + t.tm_sec = 0; + struct tm e = t; + e.tm_min = 59; + e.tm_sec = 59; + // Read playtime and set graph values + switch (this->app->viewPeriod()) { + case ViewPeriod::Day: { + this->graph->setFontSize(14); + this->graph->setMaximumValue(60); + this->graph->setYSteps(6); + this->graph->setValuePrecision(0); + this->graph->setNumberOfEntries(24); + if (this->app->config()->gIs24H()) { + for (int i = 0; i < 24; i += 2) { + this->graph->setLabel(i, std::to_string(i)); + } + } else { + for (int i = 0; i < 24; i += 3) { + this->graph->setLabel(i, Utils::format12H(i)); + } } - } else { - for (int i = 0; i < 24; i += 3) { - this->graph->setLabel(i, Utils::format12H(i)); + for (size_t i = 0; i < this->graph->entries(); i++) { + t.tm_hour = i; + e.tm_hour = i; + NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + totalSecs += s->playtime; + double val = s->playtime/60.0; + this->graph->setValue(i, val); + delete s; } - } - break; + break; - case ViewPeriod::Month: { - unsigned int c = Utils::Time::tmGetDaysInMonth(tm); - this->graph->setFontSize(13); - this->graph->setValuePrecision(1); - this->graph->setNumberOfEntries(c); - for (unsigned int i = 0; i < c; i+=3) { - this->graph->setLabel(i, std::to_string(i + 1) + Utils::Time::getDateSuffix(i + 1)); - } - break; - } - - case ViewPeriod::Year: - this->graph->setFontSize(16); - this->graph->setValuePrecision(1); - this->graph->setNumberOfEntries(12); - for (int i = 0; i < 12; i++) { - this->graph->setLabel(i, Utils::Time::getShortMonthString(i)); } - break; - - default: - break; - } - - // Read playtime and set graph values - struct tm t = tm; - uint64_t totalSecs = 0; - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: { - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_min = 59; - e.tm_sec = 59; - for (size_t i = 0; i < this->graph->entries(); i++) { - t.tm_hour = i; - e.tm_hour = i; - NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); - totalSecs += s->playtime; - double val = s->playtime/60.0; - this->graph->setValue(i, val); - delete s; - } - break; - } - - case ViewPeriod::Month: { - t.tm_hour = 0; - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_hour = 23; - e.tm_min = 59; - e.tm_sec = 59; - uint64_t max = 0; - for (size_t i = 0; i < this->graph->entries(); i++) { - t.tm_mday = i + 1; - e.tm_mday = i + 1; - NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); - totalSecs += s->playtime; - if (s->playtime > max) { - max = s->playtime; + case ViewPeriod::Month: { + unsigned int n = Utils::Time::tmGetDaysInMonth(t); + this->graph->setFontSize(13); + this->graph->setValuePrecision(1); + this->graph->setNumberOfEntries(n); + for (unsigned int i = 0; i < n; i+=3) { + this->graph->setLabel(i, std::to_string(i + 1) + Utils::Time::getDateSuffix(i + 1)); } - double val = s->playtime/60/60.0; - this->graph->setValue(i, val); - delete s; - } - max /= 60.0; - max /= 60.0; - if (max <= 2) { - this->graph->setMaximumValue(max + 2 - max%2); - this->graph->setYSteps(2); - } else { - this->graph->setMaximumValue(max + 5 - max%5); - this->graph->setYSteps(5); - } - break; - } - - case ViewPeriod::Year: { - t.tm_mday = 1; - t.tm_hour = 0; - t.tm_min = 0; - t.tm_sec = 0; - struct tm e = t; - e.tm_hour = 23; - e.tm_min = 59; - e.tm_sec = 59; - uint64_t max = 0; - for (size_t i = 0; i < this->graph->entries(); i++) { - t.tm_mon = i; - e.tm_mon = i; - e.tm_mday = Utils::Time::tmGetDaysInMonth(t); - NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); - totalSecs += s->playtime; - if (s->playtime > max) { - max = s->playtime; + t.tm_hour = 0; + e = t; + e.tm_hour = 23; + uint64_t max = 0; + for (size_t i = 0; i < this->graph->entries(); i++) { + t.tm_mday = i + 1; + e.tm_mday = i + 1; + NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + totalSecs += s->playtime; + if (s->playtime > max) { + max = s->playtime; + } + double val = s->playtime/60/60.0; + this->graph->setValue(i, val); + delete s; + } + max /= 60.0; + max /= 60.0; + if (max <= 2) { + this->graph->setMaximumValue(max + 2 - max%2); + this->graph->setYSteps(2); + } else { + this->graph->setMaximumValue(max + 5 - max%5); + this->graph->setYSteps(5); } - double val = s->playtime/60/60.0; - this->graph->setValue(i, val); - delete s; + break; } - max /= 60.0; - max /= 60.0; - if (max <= 2) { - this->graph->setMaximumValue(max + 2 - max%2); - this->graph->setYSteps(2); - } else { - this->graph->setMaximumValue(max + 5 - max%5); - this->graph->setYSteps(5); + case ViewPeriod::Year: { + this->graph->setFontSize(16); + this->graph->setValuePrecision(1); + this->graph->setNumberOfEntries(12); + for (int i = 0; i < 12; i++) { + this->graph->setLabel(i, Utils::Time::getShortMonthString(i)); + } + t.tm_mday = 1; + t.tm_hour = 0; + e = t; + e.tm_hour = 23; + uint64_t max = 0; + for (size_t i = 0; i < this->graph->entries(); i++) { + t.tm_mon = i; + e.tm_mon = i; + e.tm_mday = Utils::Time::tmGetDaysInMonth(t); + NX::RecentPlayStatistics * s = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); + totalSecs += s->playtime; + if (s->playtime > max) { + max = s->playtime; + } + double val = s->playtime/60/60.0; + this->graph->setValue(i, val); + delete s; + } + max /= 60.0; + max /= 60.0; + if (max <= 2) { + this->graph->setMaximumValue(max + 2 - max%2); + this->graph->setYSteps(2); + } else { + this->graph->setMaximumValue(max + 5 - max%5); + this->graph->setYSteps(5); + } + break; } - break; + default: + break; } - default: - break; - } - - // Set headings - if (this->app->viewPeriod() == ViewPeriod::Day) { - this->graphSubheading->setString("common.playtimeMinutes"_lang); - } else { - this->graphSubheading->setString("common.playtimeHours"_lang); - } - this->graphSubheading->setX(this->header->x() + (this->header->w() - this->graphSubheading->w())/2); - } - - void RecentActivity::updateTitles() { - // Get start and end timestamps for date - char c = ' '; - switch (this->app->viewPeriod()) { - case ViewPeriod::Day: - c = 'D'; - break; - - case ViewPeriod::Month: - c = 'M'; - break; + // Set graph headings + if (this->app->viewPeriod() == ViewPeriod::Day) { + this->graphSubheading->setString("common.playtimeMinutes"_lang); + } else { + this->graphSubheading->setString("common.playtimeHours"_lang); + } + this->graphSubheading->setX(this->header->x() + (this->header->w() - this->graphSubheading->w())/2); + + // update Titles + t.tm_min = 0; + t.tm_sec = 0; + // Minus one second so end time is 11:59pm and not 12:00am next day + unsigned int end_time; + switch (this->app->viewPeriod()) { + case ViewPeriod::Day: + t.tm_hour = 0; + end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'D')) - 1; + break; + case ViewPeriod::Month: + t.tm_mday = 1; + t.tm_hour = 0; + end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'M')) - 1; + break; + case ViewPeriod::Year: + t.tm_mon = 1; + t.tm_mday = 1; + t.tm_hour = 0; + end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'Y')) - 1; + break; + default: + break; + } - case ViewPeriod::Year: - c = 'Y'; - break; + // Get stats + std::vector > stats; + for (size_t i = 0; i < this->app->titleVector().size(); i++) { + std::pair stat; + stat.first = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->titleVector()[i]->titleID(), Utils::Time::getTimeT(begin), end_time, this->app->activeUser()->ID()); + stat.second = i; + stats.push_back(stat); + } - default: - break; - } - uint64_t s = Utils::Time::getTimeT(this->app->time()); - // Minus one second so end time is 11:59pm and not 12:00am next day - uint64_t e = Utils::Time::getTimeT(Utils::Time::increaseTm(this->app->time(), c)) - 1; + // Sort to have most played first + std::sort(stats.begin(), stats.end(), [](const std::pair lhs, const std::pair rhs) { + return lhs.first->playtime > rhs.first->playtime; + }); - // Get stats - uint64_t totalSecs = 0; - std::vector > stats; - std::vector hidden = this->app->config()->hiddenTitles(); - for (size_t i = 0; i < this->app->titleVector().size(); i++) { - std::pair stat; - stat.first = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->titleVector()[i]->titleID(), s, e, this->app->activeUser()->ID()); - stat.second = i; - stats.push_back(stat); - } + // Add to list + bool isHidden = false; + std::vector hidden = this->app->config()->hiddenTitles(); + for (auto stat : stats) { + isHidden = std::find(hidden.begin(), hidden.end(), this->app->titleVector()[stat.second]->titleID()) != hidden.end(); + // Only show games that have actually been played and skip over hidden games + if (stat.first->launches == 0 || isHidden) { + delete stat.first; + continue; + } - // Sort to have most played first - std::sort(stats.begin(), stats.end(), [](const std::pair lhs, const std::pair rhs) { - return lhs.first->playtime > rhs.first->playtime; - }); + CustomElm::ListActivity * la = new CustomElm::ListActivity(); + la->setImage(this->app->titleVector()[stat.second]->imgPtr(), this->app->titleVector()[stat.second]->imgSize()); + la->setTitle(this->app->titleVector()[stat.second]->name()); + la->setPlaytime(Utils::playtimeToPlayedForString(stat.first->playtime)); + la->setLeftMuted(Utils::launchesToPlayedString(stat.first->launches)); + unsigned int j = stat.second; + la->onPress([this, j](){ + this->app->setActiveTitle(j); + this->app->pushScreen(); + this->app->setScreen(ScreenID::Details); + }); + la->setTitleColour(this->app->theme()->text()); + la->setPlaytimeColour(this->app->theme()->accent()); + la->setMutedColour(this->app->theme()->mutedText()); + la->setLineColour(this->app->theme()->mutedLine()); + this->list->addElement(la); - // Add to list - bool isHidden = false; - for (auto stat : stats) { - totalSecs += stat.first->playtime; - isHidden = std::find(hidden.begin(), hidden.end(), this->app->titleVector()[stat.second]->titleID()) != hidden.end(); - // Only show games that have actually been played and skip over hidden games - if (stat.first->launches == 0 || isHidden) { // Can delete each pointer after it's accessed delete stat.first; - continue; } - CustomElm::ListActivity * la = new CustomElm::ListActivity(); - la->setImage(this->app->titleVector()[stat.second]->imgPtr(), this->app->titleVector()[stat.second]->imgSize()); - la->setTitle(this->app->titleVector()[stat.second]->name()); - la->setPlaytime(Utils::playtimeToPlayedForString(stat.first->playtime)); - la->setLeftMuted(Utils::launchesToPlayedString(stat.first->launches)); - unsigned int j = stat.second; - la->onPress([this, j](){ - this->app->setActiveTitle(j); - this->app->pushScreen(); - this->app->setScreen(ScreenID::Details); - }); - la->setTitleColour(this->app->theme()->text()); - la->setPlaytimeColour(this->app->theme()->accent()); - la->setMutedColour(this->app->theme()->mutedText()); - la->setLineColour(this->app->theme()->mutedLine()); - this->list->addElement(la); + // Update playtime string + this->hours->setString(Utils::playtimeToTotalPlaytimeString(totalSecs)); + this->hours->setX(1215 - this->hours->w()); + } else { + this->gameHeading->setHidden(true); + this->graph->setHidden(true); + this->graphSubheading->setHidden(true); + this->hours->setString("common.totalPlaytime.0min"_lang); + this->hours->setX(1215 - this->hours->w()); + this->list->setShowScrollBar(false); + this->list->setCanScroll(false); + this->noStats->setHidden(false); } - // Update playtime string - this->hours->setString(Utils::playtimeToTotalPlaytimeString(totalSecs)); - this->hours->setX(1215 - this->hours->w()); + delete ps; } + void RecentActivity::update(uint32_t dt) { + if (this->app->timeChanged()) { + this->updateActivity(); + } + Screen::update(dt); + } void RecentActivity::onLoad() { // Create heading using user's name