From 690e01080784b956a7eb7c237ccdd35998518fc1 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sun, 12 Mar 2023 11:26:38 +0800 Subject: [PATCH 01/37] support hos16.0.0 and min changes 1. Support HOS16.0.0. 2. Fix play tiem in total time exceed 100%. 3. Add year suffix. 4. Allow run under Applet mode. 5. Make sure all account play events in list. Signed-off-by: Damien Zhao --- Application/include/nx/PlayData.hpp | 10 ++-- Application/include/ui/element/SortedList.hpp | 10 ++-- Application/include/utils/Utils.hpp | 8 +-- Application/source/Application.ExportJob.cpp | 4 +- Application/source/nx/PlayData.cpp | 34 +++++------ Application/source/ui/screen/AllActivity.cpp | 4 +- Application/source/ui/screen/Details.cpp | 18 +++--- .../source/ui/screen/RecentActivity.cpp | 2 +- Application/source/utils/NX.cpp | 59 +++++++++---------- Application/source/utils/Time.cpp | 8 +-- Application/source/utils/Utils.cpp | 18 +++--- 11 files changed, 85 insertions(+), 90 deletions(-) diff --git a/Application/include/nx/PlayData.hpp b/Application/include/nx/PlayData.hpp index 226badb..7fef963 100644 --- a/Application/include/nx/PlayData.hpp +++ b/Application/include/nx/PlayData.hpp @@ -36,7 +36,7 @@ namespace NX { // and end timestamps and playtime for convenience. Note that (end-start) != playtime // due to time when the game may not have been focussed. struct PlaySession { - u32 playtime; // Total playtime in seconds + u64 playtime; // Total playtime in seconds u64 startTimestamp; // Time of launch u64 endTimestamp; // Time of exit }; @@ -44,9 +44,9 @@ namespace NX { // PdmPlayStatistics but only the necessary things struct PlayStatistics { TitleID titleID; // TitleID of these stats - u32 firstPlayed; // Timestamp of first launch - u32 lastPlayed; // Timestamp of last play (exit) - u32 playtime; // Total playtime in seconds + u64 firstPlayed; // Timestamp of first launch + u64 lastPlayed; // Timestamp of last play (exit) + u64 playtime; // Total playtime in seconds u32 launches; // Total launches }; @@ -54,7 +54,7 @@ namespace NX { // only contains recent values struct RecentPlayStatistics { TitleID titleID; // TitleID of these statistics - u32 playtime; // Total playtime in seconds + u64 playtime; // Total playtime in seconds u32 launches; // Total launches }; diff --git a/Application/include/ui/element/SortedList.hpp b/Application/include/ui/element/SortedList.hpp index 2ed18bf..8e74d45 100644 --- a/Application/include/ui/element/SortedList.hpp +++ b/Application/include/ui/element/SortedList.hpp @@ -8,11 +8,11 @@ // Struct storing information about entry used for sorting struct SortInfo { std::string name; // Name of title - unsigned long long int titleID; // Title's ID - unsigned int firstPlayed; // Timestamp of first launch - unsigned int lastPlayed; // Timestamp of last play - unsigned int playtime; // Total playtime in seconds - unsigned int launches; // Total launches + u64 titleID; // Title's ID + u64 firstPlayed; // Timestamp of first launch + u64 lastPlayed; // Timestamp of last play + u64 playtime; // Total playtime in seconds + u32 launches; // Total launches }; namespace CustomElm { diff --git a/Application/include/utils/Utils.hpp b/Application/include/utils/Utils.hpp index c4fb28c..5ae201c 100644 --- a/Application/include/utils/Utils.hpp +++ b/Application/include/utils/Utils.hpp @@ -27,20 +27,20 @@ namespace Utils { std::string insertVersionInString(std::string, std::string); // Format the given timestamp as 'last played' string - std::string lastPlayedToString(unsigned int); + std::string lastPlayedToString(uint64_t); // Format the given number of launches into a string std::string launchesToString(unsigned int); std::string launchesToPlayedString(unsigned int); // Format the given playtime (in seconds) into hours and minutes - std::string playtimeToString(unsigned int); + std::string playtimeToString(uint64_t); // Format the given playtime (in seconds) into 'played for' string - std::string playtimeToPlayedForString(unsigned int); + std::string playtimeToPlayedForString(uint64_t); // Format the given playtime (in seconds) into 'total playtime' string - std::string playtimeToTotalPlaytimeString(unsigned int); + std::string playtimeToTotalPlaytimeString(uint64_t); // Merges two vectors into one (for sorting) // Vector to merge into, two vectors to merge diff --git a/Application/source/Application.ExportJob.cpp b/Application/source/Application.ExportJob.cpp index 9ae171f..2a932bf 100644 --- a/Application/source/Application.ExportJob.cpp +++ b/Application/source/Application.ExportJob.cpp @@ -92,8 +92,8 @@ namespace Main { // Get all summary stats NX::PlayStatistics * stats2 = this->app->playdata_->getStatisticsForUser(title->titleID(), user->ID()); bool allLaunched = (stats2->launches != 0); - tJson["summary"]["firstPlayed"] = pdmPlayTimestampToPosix(stats2->firstPlayed); - tJson["summary"]["lastPlayed"] = pdmPlayTimestampToPosix(stats2->lastPlayed); + tJson["summary"]["firstPlayed"] = stats2->firstPlayed; + tJson["summary"]["lastPlayed"] = stats2->lastPlayed; tJson["summary"]["playtime"] = stats2->playtime; tJson["summary"]["launches"] = stats2->launches; delete stats2; diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index 71e0595..1ff6bb2 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -186,23 +186,23 @@ namespace NX { PlayEvent * event; // Populate PlayEvent based on event type - switch (pEvents[i].playEventType) { + switch (pEvents[i].play_event_type) { case PdmPlayEventType_Account: // Ignore this event if type is 2 - if (pEvents[i].eventData.account.type == 2) { + if (pEvents[i].event_data.account.type == 2) { continue; } event = new PlayEvent; event->type = PlayEvent_Account; // UserID words are wrong way around (why Nintendo?) - event->userID.uid[0] = pEvents[i].eventData.account.uid[0]; - event->userID.uid[0] = (event->userID.uid[0] << 32) | pEvents[i].eventData.account.uid[1]; - event->userID.uid[1] = (event->userID.uid[1] << 32) | pEvents[i].eventData.account.uid[2]; - event->userID.uid[1] = (event->userID.uid[1] << 32) | pEvents[i].eventData.account.uid[3]; + event->userID.uid[0] = pEvents[i].event_data.account.uid[0]; + event->userID.uid[0] = (event->userID.uid[0] << 32) | pEvents[i].event_data.account.uid[1]; + event->userID.uid[1] = (event->userID.uid[1] << 32) | pEvents[i].event_data.account.uid[2]; + event->userID.uid[1] = (event->userID.uid[1] << 32) | pEvents[i].event_data.account.uid[3]; // Set account event type - switch (pEvents[i].eventData.account.type) { + switch (pEvents[i].event_data.account.type) { case 0: event->eventType = Account_Active; break; @@ -214,18 +214,18 @@ namespace NX { case PdmPlayEventType_Applet: // Ignore this event based on log policy - if (pEvents[i].eventData.applet.logPolicy != PdmPlayLogPolicy_All) { + if (pEvents[i].event_data.applet.log_policy != PdmPlayLogPolicy_All) { continue; } event = new PlayEvent; event->type = PlayEvent_Applet; // Join two halves of title ID - event->titleID = pEvents[i].eventData.applet.program_id[0]; - event->titleID = (event->titleID << 32) | pEvents[i].eventData.applet.program_id[1]; + event->titleID = pEvents[i].event_data.applet.program_id[0]; + event->titleID = (event->titleID << 32) | pEvents[i].event_data.applet.program_id[1]; // Set applet event type - switch (pEvents[i].eventData.applet.eventType) { + switch (pEvents[i].event_data.applet.event_type) { case PdmAppletEventType_Launch: event->eventType = Applet_Launch; break; @@ -251,8 +251,8 @@ namespace NX { } // Set timestamps - event->clockTimestamp = pEvents[i].timestampUser; - event->steadyTimestamp = pEvents[i].timestampSteady; + event->clockTimestamp = pEvents[i].timestamp_user; + event->steadyTimestamp = pEvents[i].timestamp_steady; // Add PlayEvent to vector ret.first.push_back(event); @@ -488,10 +488,10 @@ namespace NX { PdmPlayStatistics tmp; pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(titleID, userID, false, &tmp); PlayStatistics * stats = new PlayStatistics; - stats->firstPlayed = tmp.first_timestampUser; - stats->lastPlayed = tmp.last_timestampUser; - stats->playtime = tmp.playtimeMinutes * 60; - stats->launches = tmp.totalLaunches; + stats->firstPlayed = tmp.first_timestamp_user; + stats->lastPlayed = tmp.last_timestamp_user; + stats->playtime = tmp.playtime / 1000 / 1000 / 1000; //the unit of playtime in PdmPlayStatistics is ns + stats->launches = tmp.total_launches; return stats; } diff --git a/Application/source/ui/screen/AllActivity.cpp b/Application/source/ui/screen/AllActivity.cpp index cfd418f..d833514 100644 --- a/Application/source/ui/screen/AllActivity.cpp +++ b/Application/source/ui/screen/AllActivity.cpp @@ -121,7 +121,7 @@ namespace Screen { std::vector adjustments = this->app->config()->adjustmentValues(); std::vector t = this->app->titleVector(); std::vector hidden = this->app->config()->hiddenTitles(); - unsigned int totalSecs = 0; + uint64_t totalSecs = 0; for (size_t i = 0; i < t.size(); i++) { // Skip over hidden games if (std::find(hidden.begin(), hidden.end(), t[i]->titleID()) != hidden.end()) { @@ -165,7 +165,7 @@ namespace Screen { la->setImage(t[i]->imgPtr(), t[i]->imgSize()); la->setTitle(t[i]->name()); la->setPlaytime(Utils::playtimeToPlayedForString(ps->playtime)); - la->setLeftMuted(Utils::lastPlayedToString(pdmPlayTimestampToPosix(ps->lastPlayed))); + la->setLeftMuted(Utils::lastPlayedToString(ps->lastPlayed)); la->setRightMuted(Utils::launchesToPlayedString(ps->launches)); la->onPress([this, i](){ this->app->setActiveTitle(i); diff --git a/Application/source/ui/screen/Details.cpp b/Application/source/ui/screen/Details.cpp index 593a489..0cd961e 100644 --- a/Application/source/ui/screen/Details.cpp +++ b/Application/source/ui/screen/Details.cpp @@ -212,7 +212,7 @@ namespace Screen { // Read playtime and set graph values struct tm t = tm; - unsigned int totalSecs = 0; + uint64_t totalSecs = 0; switch (this->app->viewPeriod()) { case ViewPeriod::Day: { t.tm_min = 0; @@ -240,7 +240,7 @@ namespace Screen { e.tm_hour = 23; e.tm_min = 59; e.tm_sec = 59; - unsigned int max = 0; + uint64_t max = 0; for (size_t i = 0; i < this->graph->entries(); i++) { t.tm_mday = i + 1; e.tm_mday = i + 1; @@ -274,7 +274,7 @@ namespace Screen { e.tm_hour = 23; e.tm_min = 59; e.tm_sec = 59; - unsigned int max = 0; + uint64_t max = 0; for (size_t i = 0; i < this->graph->entries(); i++) { t.tm_mon = i; e.tm_mon = i; @@ -351,9 +351,9 @@ namespace Screen { default: break; } - unsigned int s = Utils::Time::getTimeT(this->app->time()); + uint64_t s = Utils::Time::getTimeT(this->app->time()); // Minus one second so end time is 11:59pm and not 12:00am next day - unsigned int e = Utils::Time::getTimeT(Utils::Time::increaseTm(this->app->time(), c)) - 1; + 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++) { @@ -370,7 +370,7 @@ namespace Screen { }); // Defaults for a session within the range - unsigned int playtime = stats[i].playtime; + uint64_t playtime = stats[i].playtime; struct tm sTm = Utils::Time::getTm(stats[i].startTimestamp); struct tm eTm = Utils::Time::getTm(stats[i].endTimestamp); @@ -434,7 +434,7 @@ namespace Screen { // Add percentage of total playtime std::string str; - double percent = 100 * ((double)playtime / ((ps->playtime == 0) ? playtime : ps->playtime)); + 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%"; @@ -706,12 +706,12 @@ namespace Screen { this->timeplayed->setX(this->timeplayed->x() - this->timeplayed->w()/2); this->addElement(this->timeplayed); - this->firstplayed = new Aether::Text(1070, 490, Utils::Time::timestampToString(pdmPlayTimestampToPosix(ps->firstPlayed)), 20); + this->firstplayed = new Aether::Text(1070, 490, Utils::Time::timestampToString(ps->firstPlayed), 20); this->firstplayed->setColour(this->app->theme()->accent()); this->firstplayed->setX(this->firstplayed->x() - this->firstplayed->w()/2); this->addElement(this->firstplayed); - this->lastplayed = new Aether::Text(1070, 580, Utils::Time::timestampToString(pdmPlayTimestampToPosix(ps->lastPlayed)), 20); + this->lastplayed = new Aether::Text(1070, 580, Utils::Time::timestampToString(ps->lastPlayed), 20); this->lastplayed->setColour(this->app->theme()->accent()); this->lastplayed->setX(this->lastplayed->x() - this->lastplayed->w()/2); this->addElement(this->lastplayed); diff --git a/Application/source/ui/screen/RecentActivity.cpp b/Application/source/ui/screen/RecentActivity.cpp index a09fe39..b2182ae 100644 --- a/Application/source/ui/screen/RecentActivity.cpp +++ b/Application/source/ui/screen/RecentActivity.cpp @@ -307,7 +307,7 @@ namespace Screen { unsigned int e = Utils::Time::getTimeT(Utils::Time::increaseTm(this->app->time(), c)) - 1; // Get stats - unsigned int totalSecs = 0; + 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++) { diff --git a/Application/source/utils/NX.cpp b/Application/source/utils/NX.cpp index e18cf69..c435ad3 100644 --- a/Application/source/utils/NX.cpp +++ b/Application/source/utils/NX.cpp @@ -1,7 +1,9 @@ #include "utils/NX.hpp" +#include +#include // Maximum number of titles to read using pdm -#define MAX_TITLES 2000 +#define MAX_TITLES_PER_TIME 100 // Comparison of AccountUids bool operator == (const AccountUid &a, const AccountUid &b) { @@ -148,65 +150,58 @@ namespace Utils::NX { // Get ALL played titles for ALL users // (this doesn't include installed games that haven't been played) std::vector playedIDs; - for (unsigned short i = 0; i < u.size(); i++) { - s32 playedTotal = 0; + for (auto user : u) { TitleID tmpID = 0; - PdmAccountPlayEvent *userPlayEvents = new PdmAccountPlayEvent[MAX_TITLES]; - rc = pdmqryQueryAccountPlayEvent(0, u[i]->ID(), userPlayEvents, MAX_TITLES, &playedTotal); - if (R_FAILED(rc) || playedTotal == 0) { + s32 startEntryIndex = -1; + s32 endEntryIndex = -1; + s32 playedTotal = -1; + s32 totalEntries = -1; + rc = pdmqryGetAvailableAccountPlayEventRange(user->ID(), &totalEntries, &startEntryIndex, &endEntryIndex); + if (R_FAILED(rc) || !totalEntries) + continue; + + PdmAccountPlayEvent *userPlayEvents = new PdmAccountPlayEvent[totalEntries]; + rc = pdmqryQueryAccountPlayEvent(startEntryIndex, user->ID(), userPlayEvents, totalEntries, &playedTotal); + if (R_FAILED(rc) || !playedTotal) { delete[] userPlayEvents; continue; } - // Push back ID if not already in the vector for (s32 j = 0; j < playedTotal; j++) { - bool found = false; tmpID = (static_cast(userPlayEvents[j].application_id[0]) << 32) | userPlayEvents[j].application_id[1]; - for (size_t k = 0; k < playedIDs.size(); k++) { - if (playedIDs[k] == tmpID) { - found = true; - break; - } - } - - if (!found) { + if(std::find_if(playedIDs.begin(), playedIDs.end(), [tmpID](auto id){ return id == tmpID;}) == playedIDs.end()) { playedIDs.push_back(tmpID); } } delete[] userPlayEvents; } - // Get IDs of all installed titles std::vector installedIDs; - NsApplicationRecord * records = new NsApplicationRecord[MAX_TITLES]; + // Get IDs of all installed titles s32 count = 0; s32 out = 0; while (true) { - rc = nsListApplicationRecord(records, MAX_TITLES, count, &out); - // Break if at the end or no titles - if (R_FAILED(rc) || out == 0){ + NsApplicationRecord *records = new NsApplicationRecord[MAX_TITLES_PER_TIME]; + rc = nsListApplicationRecord(records, MAX_TITLES_PER_TIME, count, &out); + if (R_FAILED(rc) || out == 0) { + delete[] records; break; } for (s32 i = 0; i < out; i++) { installedIDs.push_back((records + i)->application_id); } count += out; + delete[] records; } - delete[] records; // Create Title objects from IDs std::vector<::NX::Title *> titles; - for (size_t i = 0; i < playedIDs.size(); i++) { - // Loop over installed titles to determine if installed or not - bool installed = false; - for (size_t j = 0; j < installedIDs.size(); j++) { - if (installedIDs[j] == playedIDs[i]) { - installed = true; - break; - } + for (auto playedID : playedIDs) { + if(std::find_if(installedIDs.begin(), installedIDs.end(), [playedID](auto id){ return id == playedID;}) != installedIDs.end()) { + titles.push_back(new ::NX::Title(playedID, true)); + } else { + titles.push_back(new ::NX::Title(playedID, false)); } - - titles.push_back(new ::NX::Title(playedIDs[i], installed)); } return titles; diff --git a/Application/source/utils/Time.cpp b/Application/source/utils/Time.cpp index 1921a5f..32e74fc 100644 --- a/Application/source/utils/Time.cpp +++ b/Application/source/utils/Time.cpp @@ -141,7 +141,7 @@ namespace Utils::Time { std::string tmToDate(struct tm t, bool b) { std::string str; if (b) { - str = std::regex_replace("common.dateFormatYear"_lang, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4)); + str = std::regex_replace("common.dateFormatYear"_lang, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4) + "common.yearSuffix"_lang); } else { str = "common.dateFormat"_lang; } @@ -157,7 +157,7 @@ namespace Utils::Time { case ViewPeriod::Day: { std::string str; if (t.tm_year != getTmForCurrentTime().tm_year) { - str = std::regex_replace("common.activityFor.dayYear"_lang, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4)); + str = std::regex_replace("common.activityFor.dayYear"_lang, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4) + "common.yearSuffix"_lang); } else { str = "common.activityFor.day"_lang; } @@ -169,12 +169,12 @@ namespace Utils::Time { case ViewPeriod::Month: { std::string str = std::regex_replace("common.activityFor.month"_lang, std::regex("\\$\\[m]"), getMonthString(t.tm_mon)); - return std::regex_replace(str, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4)); + return std::regex_replace(str, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4) + "common.yearSuffix"_lang); break; } case ViewPeriod::Year: - return std::regex_replace("common.activityFor.year"_lang, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4)); + return std::regex_replace("common.activityFor.year"_lang, std::regex("\\$\\[y]"), tmToString(t, "%Y", 4) + "common.yearSuffix"_lang); break; default: diff --git a/Application/source/utils/Utils.cpp b/Application/source/utils/Utils.cpp index 4e35bcd..87a578f 100644 --- a/Application/source/utils/Utils.cpp +++ b/Application/source/utils/Utils.cpp @@ -59,10 +59,10 @@ namespace Utils { return std::regex_replace(str, std::regex("\\$\\[v]"), ver); } - std::string lastPlayedToString(unsigned int t) { + std::string lastPlayedToString(uint64_t t) { struct tm now = Utils::Time::getTmForCurrentTime(); struct tm ts = Utils::Time::getTm(t); - int diff = Utils::Time::getTimeT(now) - Utils::Time::getTimeT(ts); + int64_t diff = Utils::Time::getTimeT(now) - Utils::Time::getTimeT(ts); // In the future if (diff < 0) { @@ -105,7 +105,7 @@ namespace Utils { std::string str; // Show year if not within the same year if (now.tm_year != ts.tm_year) { - str = std::regex_replace("common.lastPlayed.dateYear"_lang, std::regex("\\$\\[y]"), Utils::Time::tmToString(ts, "%Y", 4)); + str = std::regex_replace("common.lastPlayed.dateYear"_lang, std::regex("\\$\\[y]"), Utils::Time::tmToString(ts, "%Y", 4) + "common.yearSuffix"_lang); } else { str = "common.lastPlayed.date"_lang; } @@ -130,7 +130,7 @@ namespace Utils { return "common.timesPlayed.once"_lang; } - std::string playtimeToString(unsigned int s) { + std::string playtimeToString(uint64_t s) { if (s == 0) { return "common.playtime.0sec"_lang; } else if (s == 1) { @@ -139,7 +139,7 @@ namespace Utils { return std::regex_replace("common.playtime.secs"_lang, std::regex("\\$\\[s]"), std::to_string(s)); } - unsigned int h = s/3600; + uint64_t h = s/3600; unsigned int m = (s/60)%60; s = s%60; @@ -182,12 +182,12 @@ namespace Utils { return std::regex_replace(str, std::regex("\\$\\[m]"), std::to_string(m)); } - std::string playtimeToPlayedForString(unsigned int s) { + std::string playtimeToPlayedForString(uint64_t s) { if (s < 60) { return "common.playedFor.0min"_lang; } - unsigned int h = s/3600; + uint64_t h = s/3600; unsigned int m = (s/60)%60; s = s%60; @@ -230,14 +230,14 @@ namespace Utils { return std::regex_replace(str, std::regex("\\$\\[m]"), std::to_string(m)); } - std::string playtimeToTotalPlaytimeString(unsigned int s) { + std::string playtimeToTotalPlaytimeString(uint64_t s) { if (s == 0) { return "common.totalPlaytime.0sec"_lang; } else if (s < 60) { return "common.totalPlaytime.0min"_lang; } - unsigned int h = s/3600; + uint64_t h = s/3600; unsigned int m = (s/60)%60; s = s%60; From e1e4254573015f1ad5446d10ce1951821b0abeea Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Mon, 13 Mar 2023 20:59:14 +0800 Subject: [PATCH 02/37] update NX.cpp Signed-off-by: Damien Zhao --- Application/source/utils/NX.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Application/source/utils/NX.cpp b/Application/source/utils/NX.cpp index c435ad3..6e3a365 100644 --- a/Application/source/utils/NX.cpp +++ b/Application/source/utils/NX.cpp @@ -197,11 +197,8 @@ namespace Utils::NX { // Create Title objects from IDs std::vector<::NX::Title *> titles; for (auto playedID : playedIDs) { - if(std::find_if(installedIDs.begin(), installedIDs.end(), [playedID](auto id){ return id == playedID;}) != installedIDs.end()) { - titles.push_back(new ::NX::Title(playedID, true)); - } else { - titles.push_back(new ::NX::Title(playedID, false)); - } + bool installed = std::find_if(installedIDs.begin(), installedIDs.end(), [playedID](auto id){ return id == playedID;}) != installedIDs.end(); + titles.push_back(new ::NX::Title(playedID, installed)); } return titles; From c0ac7d9d88ba245ca73aff645326d28e0c3095e0 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Tue, 14 Mar 2023 10:53:28 +0800 Subject: [PATCH 03/37] Optimize the memory usage Signed-off-by: Damien Zhao --- Application/source/nx/PlayData.cpp | 31 ++++++++++++++++---------- Application/source/utils/NX.cpp | 35 ++++++++++++++++-------------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index 1ff6bb2..4050c7f 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -8,7 +8,7 @@ #include "utils/Time.hpp" // Maximum number of entries to process in one iteration -#define MAX_PROCESS_ENTRIES 1000 +#define MAX_PROCESS_ENTRIES_PER_TIME 100 namespace NX { std::vector PlayData::getPDSessions(TitleID titleID, AccountUid userID, u64 start_ts, u64 end_ts) { @@ -165,21 +165,31 @@ namespace NX { PlayEventsAndSummaries PlayData::readPlayDataFromPdm() { PlayEventsAndSummaries ret; + Result rc; - // Position of first event to read - s32 offset = 0; + // Position of first and last event to read + s32 startEntryIndex = -1; + s32 endEntryIndex = -1; // Total events read in iteration - s32 total_read = 1; + s32 totalEntries = -1; - // Array to store read events - PdmPlayEvent * pEvents = new PdmPlayEvent[MAX_PROCESS_ENTRIES]; + rc = pdmqryGetAvailablePlayEventRange(&totalEntries, &startEntryIndex, &endEntryIndex); + if (R_FAILED(rc) || !totalEntries) + return ret; + s32 count = totalEntries; + s32 offset = startEntryIndex; // Read all events - while (total_read > 0) { - Result rc = pdmqryQueryPlayEvent(offset, pEvents, MAX_PROCESS_ENTRIES, &total_read); + while (count) { + s32 total_read = -1; + + // Array to store read events + PdmPlayEvent * pEvents = new PdmPlayEvent[MAX_PROCESS_ENTRIES_PER_TIME]; + Result rc = pdmqryQueryPlayEvent(offset, pEvents, MAX_PROCESS_ENTRIES_PER_TIME, &total_read); if (R_SUCCEEDED(rc)) { // Set next read position to next event offset += total_read; + count -= total_read; // Process read events for (s32 i = 0; i < total_read; i++) { @@ -258,11 +268,10 @@ namespace NX { ret.first.push_back(event); } } + // Free memory allocated to array + delete[] pEvents; } - // Free memory allocated to array - delete[] pEvents; - return ret; } diff --git a/Application/source/utils/NX.cpp b/Application/source/utils/NX.cpp index 6e3a365..8364ff4 100644 --- a/Application/source/utils/NX.cpp +++ b/Application/source/utils/NX.cpp @@ -154,35 +154,38 @@ namespace Utils::NX { TitleID tmpID = 0; s32 startEntryIndex = -1; s32 endEntryIndex = -1; - s32 playedTotal = -1; s32 totalEntries = -1; rc = pdmqryGetAvailableAccountPlayEventRange(user->ID(), &totalEntries, &startEntryIndex, &endEntryIndex); if (R_FAILED(rc) || !totalEntries) continue; - PdmAccountPlayEvent *userPlayEvents = new PdmAccountPlayEvent[totalEntries]; - rc = pdmqryQueryAccountPlayEvent(startEntryIndex, user->ID(), userPlayEvents, totalEntries, &playedTotal); - if (R_FAILED(rc) || !playedTotal) { - delete[] userPlayEvents; - continue; - } - - for (s32 j = 0; j < playedTotal; j++) { - tmpID = (static_cast(userPlayEvents[j].application_id[0]) << 32) | userPlayEvents[j].application_id[1]; - if(std::find_if(playedIDs.begin(), playedIDs.end(), [tmpID](auto id){ return id == tmpID;}) == playedIDs.end()) { - playedIDs.push_back(tmpID); + s32 count = totalEntries; + s32 offset = startEntryIndex; + while (count) { + s32 total_read = -1; + PdmAccountPlayEvent *userPlayEvents = new PdmAccountPlayEvent[MAX_TITLES_PER_TIME]; + rc = pdmqryQueryAccountPlayEvent(offset, user->ID(), userPlayEvents, MAX_TITLES_PER_TIME, &total_read); + if (R_SUCCEEDED(rc)) { + offset += total_read; + count -= total_read; + for (s32 j = 0; j < total_read; j++) { + tmpID = (static_cast(userPlayEvents[j].application_id[0]) << 32) | userPlayEvents[j].application_id[1]; + if(std::find_if(playedIDs.begin(), playedIDs.end(), [tmpID](auto id){ return id == tmpID;}) == playedIDs.end()) { + playedIDs.push_back(tmpID); + } + } } + delete[] userPlayEvents; } - delete[] userPlayEvents; } std::vector installedIDs; // Get IDs of all installed titles - s32 count = 0; + s32 start_offset = 0; s32 out = 0; while (true) { NsApplicationRecord *records = new NsApplicationRecord[MAX_TITLES_PER_TIME]; - rc = nsListApplicationRecord(records, MAX_TITLES_PER_TIME, count, &out); + rc = nsListApplicationRecord(records, MAX_TITLES_PER_TIME, start_offset, &out); if (R_FAILED(rc) || out == 0) { delete[] records; break; @@ -190,7 +193,7 @@ namespace Utils::NX { for (s32 i = 0; i < out; i++) { installedIDs.push_back((records + i)->application_id); } - count += out; + start_offset += out; delete[] records; } From e83259bf776606438ec83b121a70e199dc4e9d45 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Tue, 14 Mar 2023 20:16:40 +0800 Subject: [PATCH 04/37] use the correct time unit Signed-off-by: Damien Zhao --- Application/source/ui/screen/RecentActivity.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Application/source/ui/screen/RecentActivity.cpp b/Application/source/ui/screen/RecentActivity.cpp index b2182ae..50bdc6b 100644 --- a/Application/source/ui/screen/RecentActivity.cpp +++ b/Application/source/ui/screen/RecentActivity.cpp @@ -182,7 +182,7 @@ namespace Screen { // Read playtime and set graph values struct tm t = tm; - unsigned int totalSecs = 0; + uint64_t totalSecs = 0; switch (this->app->viewPeriod()) { case ViewPeriod::Day: { t.tm_min = 0; @@ -210,7 +210,7 @@ namespace Screen { e.tm_hour = 23; e.tm_min = 59; e.tm_sec = 59; - unsigned int max = 0; + uint64_t max = 0; for (size_t i = 0; i < this->graph->entries(); i++) { t.tm_mday = i + 1; e.tm_mday = i + 1; @@ -244,7 +244,7 @@ namespace Screen { e.tm_hour = 23; e.tm_min = 59; e.tm_sec = 59; - unsigned int max = 0; + uint64_t max = 0; for (size_t i = 0; i < this->graph->entries(); i++) { t.tm_mon = i; e.tm_mon = i; @@ -302,9 +302,9 @@ namespace Screen { default: break; } - unsigned int s = Utils::Time::getTimeT(this->app->time()); + uint64_t s = Utils::Time::getTimeT(this->app->time()); // Minus one second so end time is 11:59pm and not 12:00am next day - unsigned int e = Utils::Time::getTimeT(Utils::Time::increaseTm(this->app->time(), c)) - 1; + uint64_t e = Utils::Time::getTimeT(Utils::Time::increaseTm(this->app->time(), c)) - 1; // Get stats uint64_t totalSecs = 0; From 444d95abf434698d7e161888174b9397d9d6f208 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Wed, 15 Mar 2023 19:36:55 +0800 Subject: [PATCH 05/37] solve the possiable ghost record issue There are some ghost records in the export json file "id": "0000000000000000", "name": "", "summary": { "firstPlayed": 0, "lastPlayed": 0, "launches": 0, "playtime": 0 } Signed-off-by: Damien Zhao --- Application/source/utils/NX.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Application/source/utils/NX.cpp b/Application/source/utils/NX.cpp index 8364ff4..3f02043 100644 --- a/Application/source/utils/NX.cpp +++ b/Application/source/utils/NX.cpp @@ -171,7 +171,9 @@ namespace Utils::NX { for (s32 j = 0; j < total_read; j++) { tmpID = (static_cast(userPlayEvents[j].application_id[0]) << 32) | userPlayEvents[j].application_id[1]; if(std::find_if(playedIDs.begin(), playedIDs.end(), [tmpID](auto id){ return id == tmpID;}) == playedIDs.end()) { - playedIDs.push_back(tmpID); + if (tmpID != 0) { + playedIDs.push_back(tmpID); + } } } } From 67d1f87d8466179030ecb2ce9bf96fa05ae9259e Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Wed, 15 Mar 2023 21:47:13 +0800 Subject: [PATCH 06/37] fix ghost record in hidden view and fix crash when deleting importing data Signed-off-by: Damien Zhao --- Application/source/Config.cpp | 5 ++++- Application/source/ui/screen/Settings.cpp | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Application/source/Config.cpp b/Application/source/Config.cpp index c3340b5..0aa40db 100644 --- a/Application/source/Config.cpp +++ b/Application/source/Config.cpp @@ -125,7 +125,10 @@ namespace Main { std::ifstream file("/config/NX-Activity-Log/hidden.conf"); std::string line; while (file >> line) { - this->hidden.push_back(Utils::stringToU64(line)); + uint64_t hiddenTitle = Utils::stringToU64(line); + if (hiddenTitle != 0) { + this->hidden.push_back(hiddenTitle); + } } // Read in adjustment values diff --git a/Application/source/ui/screen/Settings.cpp b/Application/source/ui/screen/Settings.cpp index ef37656..452a683 100644 --- a/Application/source/ui/screen/Settings.cpp +++ b/Application/source/ui/screen/Settings.cpp @@ -132,7 +132,6 @@ namespace Screen { body->addElement(tb); this->msgbox->setBodySize(bw, tb->y() + tb->h() + 40); this->msgbox->setBody(body); - this->app->addOverlay(this->msgbox); } void Settings::setupLangOverlay() { From b21cd5144182e70fcf064e2ee957428313a19add Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Wed, 15 Mar 2023 21:55:23 +0800 Subject: [PATCH 07/37] bump version to 1.5.0 Signed-off-by: Damien Zhao --- Application/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/Makefile b/Application/Makefile index bb043ef..2d373d8 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -42,7 +42,7 @@ FORWARDER := $(ROMFS)/exefs.nsp # Application version #--------------------------------------------------------------------------------- VER_MAJOR := 1 -VER_MINOR := 4 +VER_MINOR := 5 VER_MICRO := 0 #--------------------------------------------------------------------------------- From 3971359f3d53fb6034a35853dd506547171e760b Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Wed, 15 Mar 2023 22:57:55 +0800 Subject: [PATCH 08/37] make sure the title vector has no zero id Signed-off-by: Damien Zhao --- Application/source/nx/PlayData.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index 4050c7f..be09c8d 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -344,7 +344,9 @@ namespace NX { return (title["id"] == entry.first); }); if (it == this->titles.end()) { - this->titles.push_back(std::make_pair(title["id"], title["name"])); + if (title["id"] != 0) { + this->titles.push_back(std::make_pair(title["id"], title["name"])); + } } } } From 16cba339e1a7016e77277a5a30c8d31f5aeca426 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Tue, 12 Sep 2023 12:49:58 +0800 Subject: [PATCH 09/37] uplift submodues Signed-off-by: Damien Zhao --- Application/libs/Aether | 2 +- Application/libs/json | 2 +- Application/romfs/lang | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Application/libs/Aether b/Application/libs/Aether index d268de4..29c14b5 160000 --- a/Application/libs/Aether +++ b/Application/libs/Aether @@ -1 +1 @@ -Subproject commit d268de4b445ce4c01757b0793c709166d1f3727d +Subproject commit 29c14b5abf7dba7408ab5941a14ebb2f8396b54c diff --git a/Application/libs/json b/Application/libs/json index e7b3b40..da92c0e 160000 --- a/Application/libs/json +++ b/Application/libs/json @@ -1 +1 @@ -Subproject commit e7b3b40b5a95bc74b9a7f662830a27c49ffc01b4 +Subproject commit da92c0e3e72d6a42106b5d829f5ff2d57fb16f77 diff --git a/Application/romfs/lang b/Application/romfs/lang index c8f0bff..8104e13 160000 --- a/Application/romfs/lang +++ b/Application/romfs/lang @@ -1 +1 @@ -Subproject commit c8f0bff402412cf192b7f1c8d9b836aadf0bb0d0 +Subproject commit 8104e13b9eaf51decc09e4b5e2de29f664ca7ae2 From e1adda1dd73e6a790161325d45bf7c7abfc7ed2d Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Wed, 27 Dec 2023 23:44:23 +0800 Subject: [PATCH 10/37] update for new libnx Signed-off-by: Damien Zhao --- .gitmodules | 8 ++++---- Application/libs/SimpleIniParser | 2 +- Application/libs/json | 2 +- Forwarder/source/main.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitmodules b/.gitmodules index 32b221c..37868db 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "Translations"] path = Application/romfs/lang url = https://github.com/tallbl0nde/NX-Activity-Log-Translations.git -[submodule "libs/json"] - path = Application/libs/json - url = https://github.com/nlohmann/json.git [submodule "Application/libs/SimpleIniParser"] path = Application/libs/SimpleIniParser - url = https://git.nicholemattera.com/NicholeMattera/Simple-INI-Parser + url = https://github.com/zdm65477730/SimpleIniParser.git [submodule "Application/libs/Aether"] path = Application/libs/Aether url = https://github.com/tallbl0nde/Aether +[submodule "Application/libs/json"] + path = Application/libs/json + url = https://github.com/nlohmann/json.git diff --git a/Application/libs/SimpleIniParser b/Application/libs/SimpleIniParser index c28ea18..625d49f 160000 --- a/Application/libs/SimpleIniParser +++ b/Application/libs/SimpleIniParser @@ -1 +1 @@ -Subproject commit c28ea183a6eb7f4fe546cc0accf2a887576875db +Subproject commit 625d49fb533a7648d4996a7d292ffcd51fb2a61d diff --git a/Application/libs/json b/Application/libs/json index da92c0e..a259ecc 160000 --- a/Application/libs/json +++ b/Application/libs/json @@ -1 +1 @@ -Subproject commit da92c0e3e72d6a42106b5d829f5ff2d57fb16f77 +Subproject commit a259ecc51e1951e12f757ce17db958e9881e9c6c diff --git a/Forwarder/source/main.c b/Forwarder/source/main.c index 568ec4f..39a3436 100644 --- a/Forwarder/source/main.c +++ b/Forwarder/source/main.c @@ -446,7 +446,7 @@ void loadNro(void) g_smCloseWorkaround = true; } - extern NORETURN void nroEntrypointTrampoline(u64 entries_ptr, u64 handle, u64 entrypoint); + extern NX_NORETURN void nroEntrypointTrampoline(u64 entries_ptr, u64 handle, u64 entrypoint); nroEntrypointTrampoline((u64) entries, -1, entrypoint); } From 5aa79bd7069fedccf61221e53d76c15b6d6132bd Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sat, 19 Oct 2024 01:35:53 +0800 Subject: [PATCH 11/37] updatge submoudle Signed-off-by: Damien Zhao --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 37868db..16d7891 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "Translations"] path = Application/romfs/lang - url = https://github.com/tallbl0nde/NX-Activity-Log-Translations.git + url = https://github.com/zdm65477730/NX-Activity-Log-Translations.git [submodule "Application/libs/SimpleIniParser"] path = Application/libs/SimpleIniParser url = https://github.com/zdm65477730/SimpleIniParser.git From c7523e7ed68998bde82ecf4a7a3564668881a33e Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sat, 19 Oct 2024 01:56:17 +0800 Subject: [PATCH 12/37] update lib Signed-off-by: Damien Zhao --- Application/libs/json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/libs/json b/Application/libs/json index a259ecc..6325839 160000 --- a/Application/libs/json +++ b/Application/libs/json @@ -1 +1 @@ -Subproject commit a259ecc51e1951e12f757ce17db958e9881e9c6c +Subproject commit 63258397761b3dd96dd171e5a5ad5aa915834c35 From 8ab2b18d9334e364c8e2d042ae0bed46c34175f1 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sat, 19 Oct 2024 02:16:14 +0800 Subject: [PATCH 13/37] update Makefile and system json Signed-off-by: Damien Zhao --- Application/Makefile | 2 +- Forwarder/exefs.json | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Application/Makefile b/Application/Makefile index 2d373d8..9be1fac 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -72,7 +72,7 @@ OUTPUT := $(CURDIR)/$(TARGET) #--------------------------------------------------------------------------------- DEFINES := -D__SWITCH__ -DVER_MAJOR=$(VER_MAJOR) -DVER_MINOR=$(VER_MINOR) -DVER_MICRO=$(VER_MICRO) -DVER_STRING=\"$(VER_MAJOR).$(VER_MINOR).$(VER_MICRO)\" CFLAGS := -g -Wall -O2 -ffunction-sections $(ARCH) $(DEFINES) $(INCLUDE) `freetype-config --cflags` `sdl2-config --cflags` -CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++2a +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=c++23 #---------------------------------------------------------------------------------------------------------------------- # Definition of variables which store file locations diff --git a/Forwarder/exefs.json b/Forwarder/exefs.json index 64d558b..f099ade 100644 --- a/Forwarder/exefs.json +++ b/Forwarder/exefs.json @@ -151,13 +151,6 @@ { "type": "handle_table_size", "value": 512 - }, - { - "type": "debug_flags", - "value": { - "allow_debug": true, - "force_debug": true - } } ] } From c2be0e2670d75ca1f871ed6fa11e872e2629981f Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sat, 19 Oct 2024 02:52:24 +0800 Subject: [PATCH 14/37] update Makefile for new libnx Signed-off-by: Damien Zhao --- Application/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/Makefile b/Application/Makefile index 9be1fac..08e3f5f 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -34,7 +34,7 @@ BUILD := build INCLUDES := include SOURCES := source ROMFS := romfs -LIBS := -lAether -lcurl -lnx `sdl2-config --libs` -lSDL2_ttf `freetype-config --libs` -lSDL2_gfx -lSDL2_image -lpng -ljpeg -lwebp -lSimpleIniParser +LIBS := -lAether -lcurl -lnx `sdl2-config --libs` -lSDL2_ttf `freetype-config --libs` -lSDL2_gfx -lSDL2_image -lpng -ljpeg -lwebp -lSimpleIniParser -lharfbuzz LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/libs/Aether $(CURDIR)/libs/json $(CURDIR)/libs/SimpleIniParser FORWARDER := $(ROMFS)/exefs.nsp From f34b7fecaf04a67676fb05a0e1f3b364b518236a Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Mon, 21 Oct 2024 18:27:20 +0800 Subject: [PATCH 15/37] update the update checking source Signed-off-by: Damien Zhao --- Application/source/utils/UpdateUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/source/utils/UpdateUtils.cpp b/Application/source/utils/UpdateUtils.cpp index 7e75565..699069d 100644 --- a/Application/source/utils/UpdateUtils.cpp +++ b/Application/source/utils/UpdateUtils.cpp @@ -8,7 +8,7 @@ // Flag indicating an update is available #define AVAILABLE_FILE "/config/NX-Activity-Log/update.flag" // URL to query release data -#define GITHUB_API_URL "https://api.github.com/repos/tallbl0nde/NX-Activity-Log/releases/latest" +#define GITHUB_API_URL "https://api.github.com/repos/zdm65477730/NX-Activity-Log/releases/latest" // File storing timestamp of last check #define TIMESTAMP_FILE "/config/NX-Activity-Log/update.time" // Path of downloaded .nro From 8037b75e323e9231ee7854e6b49d61e1d0a8dbe3 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sun, 3 Nov 2024 10:11:15 +0800 Subject: [PATCH 16/37] Create main.yml --- .github/workflows/main.yml | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..b90eacd --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,57 @@ +name: Release + +on: + issue_comment: + types: [ created ] + +jobs: + build_and_release: + name: Build and release + runs-on: ubuntu-latest + container: devkitpro/devkita64:latest + if: contains(github.event.comment.body, '/release-action') + + steps: + - name: Update packages + run: | + sudo -n apt-get update + sudo -n apt-get upgrade -y git build-essential + shell: bash + - name: Update latest libnx + run: | + git config --global --add safe.directory "*" + git clone --recurse-submodules https://github.com/zdm65477730/libnx.git + cd libnx + make install -j$(nproc) + shell: bash + - name: Checkout latest code + uses: actions/checkout@v4.1.1 + with: + ref: master + clean: true + fetch-depth: 0 + fetch-tags: true + submodules: recursive + - name: Setup ENV parameters + run: | + rev=$(echo "$(git rev-parse --short=9 HEAD)") + VER_FILE=Application/Makefile + VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) + echo "TAG=${VERSION}-${rev}" >> "${GITHUB_ENV}" + echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" + shell: bash + - name: Build + run: | + export DEVKITPRO=/opt/devkitpro + make -j$(nproc) + shell: bash + - name: Github Release create, update, and upload assets + uses: meeDamian/github-release@v2.0.3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ env.TAG }} + name: ${{ env.RELEASE_NAME }} + gzip: false + files: > + sdcard/switch/NX-Activity-Log/NX-Activity-Log.nro + allow_override: yes From ac9287ac768f6849b699731757994bb99dd31800 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:45:22 +0800 Subject: [PATCH 17/37] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b90eacd..39d13b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,7 +46,7 @@ jobs: make -j$(nproc) shell: bash - name: Github Release create, update, and upload assets - uses: meeDamian/github-release@v2.0.3 + uses: ivan-the-terrible/github-release@v2.0.4 with: token: ${{ secrets.GITHUB_TOKEN }} tag: ${{ env.TAG }} From 45d2c0ba3977c2b82392a7d2eb8838a5c3eb9ae3 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:57:57 +0800 Subject: [PATCH 18/37] Update main.yml --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 39d13b3..c475e6a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,6 +39,8 @@ jobs: VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) echo "TAG=${VERSION}-${rev}" >> "${GITHUB_ENV}" echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" + echo "REV=${rev}" > "${GITHUB_ENV}" + echo "RELEASE_PATH=/opt/images" >> "${GITHUB_ENV}" shell: bash - name: Build run: | From 77970ffa009822aa3ecffd7da3b00d79de36a122 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:08:32 +0800 Subject: [PATCH 19/37] Update Makefile --- Application/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/Makefile b/Application/Makefile index 08e3f5f..9ef9935 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -43,7 +43,7 @@ FORWARDER := $(ROMFS)/exefs.nsp #--------------------------------------------------------------------------------- VER_MAJOR := 1 VER_MINOR := 5 -VER_MICRO := 0 +VER_MICRO := 1 #--------------------------------------------------------------------------------- # Options for .nacp information From d38bf2d9af4b925d95a805dae2c1654179bdb236 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:11:47 +0800 Subject: [PATCH 20/37] Update main.yml --- .github/workflows/main.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c475e6a..6ceb0b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,10 +37,9 @@ jobs: rev=$(echo "$(git rev-parse --short=9 HEAD)") VER_FILE=Application/Makefile VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) - echo "TAG=${VERSION}-${rev}" >> "${GITHUB_ENV}" - echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" echo "REV=${rev}" > "${GITHUB_ENV}" - echo "RELEASE_PATH=/opt/images" >> "${GITHUB_ENV}" + echo "TAG=${VERSION}-support-new-hos" >> "${GITHUB_ENV}" + echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" shell: bash - name: Build run: | From 4af4026d60504b14915cc9bb13388099265706fc Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sat, 9 Nov 2024 16:31:04 +0800 Subject: [PATCH 21/37] pull jpn&kr lang commits Signed-off-by: Damien Zhao --- Application/romfs/lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/romfs/lang b/Application/romfs/lang index 8104e13..ff1e37e 160000 --- a/Application/romfs/lang +++ b/Application/romfs/lang @@ -1 +1 @@ -Subproject commit 8104e13b9eaf51decc09e4b5e2de29f664ca7ae2 +Subproject commit ff1e37e33136b8b83cec6a578e20d303d4ff6911 From 034c95f932231503ddbc470e1ac5ca97d6cee0e5 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:16:03 +0800 Subject: [PATCH 22/37] Update main.yml --- .github/workflows/main.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ceb0b3..78b89f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,11 +34,9 @@ jobs: submodules: recursive - name: Setup ENV parameters run: | - rev=$(echo "$(git rev-parse --short=9 HEAD)") VER_FILE=Application/Makefile VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) - echo "REV=${rev}" > "${GITHUB_ENV}" - echo "TAG=${VERSION}-support-new-hos" >> "${GITHUB_ENV}" + echo "TAG=${VERSION}-support-new-hos" > "${GITHUB_ENV}" echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" shell: bash - name: Build @@ -46,13 +44,14 @@ jobs: export DEVKITPRO=/opt/devkitpro make -j$(nproc) shell: bash - - name: Github Release create, update, and upload assets - uses: ivan-the-terrible/github-release@v2.0.4 + - name: Upload Release Asset + uses: softprops/action-gh-release@v2.0.9 with: - token: ${{ secrets.GITHUB_TOKEN }} - tag: ${{ env.TAG }} name: ${{ env.RELEASE_NAME }} - gzip: false - files: > - sdcard/switch/NX-Activity-Log/NX-Activity-Log.nro - allow_override: yes + tag_name: ${{ env.TAG }} + draft: false + prerelease: false + generate_release_notes: yes + make_latest: true + files: | + ./sdcard/switch/NX-Activity-Log/NX-Activity-Log.nro From 21541d023a539830cf3100cde407b0ecd865a6c0 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sun, 10 Nov 2024 13:33:34 +0800 Subject: [PATCH 23/37] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 78b89f3..18477f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ jobs: run: | VER_FILE=Application/Makefile VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) - echo "TAG=${VERSION}-support-new-hos" > "${GITHUB_ENV}" + echo "TAG=${VERSION}" > "${GITHUB_ENV}" echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" shell: bash - name: Build From e6bb766085117a3089a9d3c80d765bf73f3c5da9 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:10:14 +0800 Subject: [PATCH 24/37] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 18477f3..3a51266 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ jobs: run: | VER_FILE=Application/Makefile VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) - echo "TAG=${VERSION}" > "${GITHUB_ENV}" + echo "TAG=v${VERSION}" > "${GITHUB_ENV}" echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" shell: bash - name: Build From 50d5d3745167be016d3a7d963a840784f317e9d4 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sun, 10 Nov 2024 14:59:27 +0800 Subject: [PATCH 25/37] add Japanese support Signed-off-by: Damien Zhao --- Application/Makefile | 2 +- Application/include/Types.hpp | 1 + Application/romfs/lang | 2 +- Application/source/Config.cpp | 4 ++++ Application/source/Types.cpp | 4 ++++ Application/source/utils/Lang.cpp | 4 ++++ README.md | 6 +++--- 7 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Application/Makefile b/Application/Makefile index 9ef9935..ee7c8d0 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -49,7 +49,7 @@ VER_MICRO := 1 # Options for .nacp information #--------------------------------------------------------------------------------- APP_TITLE := NX Activity Log -APP_AUTHOR := tallbl0nde +APP_AUTHOR := tallbl0nde&zdm65477730 APP_VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO) ICON := icon.jpg diff --git a/Application/include/Types.hpp b/Application/include/Types.hpp index 7d8d313..0e94e58 100644 --- a/Application/include/Types.hpp +++ b/Application/include/Types.hpp @@ -19,6 +19,7 @@ enum Language { ChineseTraditional, Chinese, Korean, + Japanese, TotalLanguages // Total number of languages (only used for iterating) }; // Return string matching language diff --git a/Application/romfs/lang b/Application/romfs/lang index ff1e37e..a937a74 160000 --- a/Application/romfs/lang +++ b/Application/romfs/lang @@ -1 +1 @@ -Subproject commit ff1e37e33136b8b83cec6a578e20d303d4ff6911 +Subproject commit a937a7467c4d1c28a7407b064344d33c05479700 diff --git a/Application/source/Config.cpp b/Application/source/Config.cpp index 0aa40db..2fe5343 100644 --- a/Application/source/Config.cpp +++ b/Application/source/Config.cpp @@ -46,6 +46,8 @@ namespace Main { this->gLang_ = Chinese; } else if (option->value == "Korean") { this->gLang_ = Korean; + } else if (option->value == "Japanese") { + this->gLang_ = Japanese; } else { this->gLang_ = Default; } @@ -189,6 +191,8 @@ namespace Main { option->value = "Chinese"; } else if (this->gLang_ == Korean) { option->value = "Korean"; + } else if (this->gLang_ == Japanese) { + option->value = "Japanese"; } option = ini->findSection("general")->findFirstOption("showGraphValues"); diff --git a/Application/source/Types.cpp b/Application/source/Types.cpp index 091c6d7..72ea135 100644 --- a/Application/source/Types.cpp +++ b/Application/source/Types.cpp @@ -52,6 +52,10 @@ std::string toString(Language l) { case Language::Korean: str = "한국어"; break; + + case Language::Japanese: + str = "日本語"; + break; default: break; diff --git a/Application/source/utils/Lang.cpp b/Application/source/utils/Lang.cpp index cb70f17..6cca74b 100644 --- a/Application/source/utils/Lang.cpp +++ b/Application/source/utils/Lang.cpp @@ -80,6 +80,10 @@ namespace Utils::Lang { case Korean: path = "romfs:/lang/ko.json"; break; + + case Japanese: + path = "romfs:/lang/ja.json"; + break; default: break; diff --git a/README.md b/README.md index 3a8e32d..25f188d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **NX Activity Log** is a homebrew application for the Nintendo Switch which displays more precise information about your play activity. -[Download](https://github.com/tallbl0nde/NX-Activity-Log/releases) +[Download](https://github.com/zdm65477730/NX-Activity-Log/releases) Curious about what's next? See my to-do list on [Trello](https://trello.com/b/HaJ1THGq/nx-activity-log) @@ -62,7 +62,7 @@ _Note: The data shown in Recent Activity and Details may be slightly inaccurate If you are seeing wildly incorrect values/believe the playtime shown is incorrect within Recent Activity or the Details screen, please do the following: -1. Download and run the .nro from [here](https://github.com/tallbl0nde/PlayEventParser/releases) +1. Download and run the .nro from [here](https://github.com/zdm65477730/PlayEventParser/releases) 2. Leave it run; if it appears to be frozen leave it for up to a minute! 3. Once it is done there should be a playlog.txt at the root of your SD card. 4. Create an issue with the following: @@ -81,7 +81,7 @@ _Note: If the data shown under All Activity is incorrect there is nothing I can ## Translations -If you'd like to translate the app or fix an issue with a translation, please make a pull request to [this repo](https://github.com/tallbl0nde/NX-Activity-Log-Translations)! I'll add all the relevant code here (if need be) once I see the request :) +If you'd like to translate the app or fix an issue with a translation, please make a pull request to [this repo](https://github.com/zdm65477730/NX-Activity-Log-Translations)! I'll add all the relevant code here (if need be) once I see the request :) ## Credits From 289d7069a39159930ed95a8293b176034795523f Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sun, 10 Nov 2024 17:34:50 +0800 Subject: [PATCH 26/37] uplift Aether Signed-off-by: Damien Zhao --- .gitmodules | 6 +++--- Application/libs/Aether | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index 16d7891..bc7be9b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,9 @@ [submodule "Application/libs/SimpleIniParser"] path = Application/libs/SimpleIniParser url = https://github.com/zdm65477730/SimpleIniParser.git -[submodule "Application/libs/Aether"] - path = Application/libs/Aether - url = https://github.com/tallbl0nde/Aether [submodule "Application/libs/json"] path = Application/libs/json url = https://github.com/nlohmann/json.git +[submodule "Application/libs/Aether"] + path = Application/libs/Aether + url = https://github.com/zdm65477730/Aether diff --git a/Application/libs/Aether b/Application/libs/Aether index 29c14b5..8c816c2 160000 --- a/Application/libs/Aether +++ b/Application/libs/Aether @@ -1 +1 @@ -Subproject commit 29c14b5abf7dba7408ab5941a14ebb2f8396b54c +Subproject commit 8c816c2b8c919c448a9d18cb8c22ab18f8d2c6cd From e0a84daaf2eb27c6d5b1505e066e45c23cb36a53 Mon Sep 17 00:00:00 2001 From: zdm65477730 <68624650+zdm65477730@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:43:21 +0800 Subject: [PATCH 27/37] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a51266..4196221 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,7 +37,7 @@ jobs: VER_FILE=Application/Makefile VERSION=$(awk '/^VER_MAJOR/{print $3}' $VER_FILE).$(awk '/^VER_MINOR/{print $3}' $VER_FILE).$(awk '/^VER_MICRO/{print $3}' $VER_FILE) echo "TAG=v${VERSION}" > "${GITHUB_ENV}" - echo "RELEASE_NAME=NX-Activity-Log ${VERSION}" >> "${GITHUB_ENV}" + echo "RELEASE_NAME=NX-Activity-Log v${VERSION}" >> "${GITHUB_ENV}" shell: bash - name: Build run: | From 112974895177ba289443cc77dfceabbd0c021add Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Sun, 10 Nov 2024 18:09:46 +0800 Subject: [PATCH 28/37] uplift Aether Signed-off-by: Damien Zhao --- Application/libs/Aether | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/libs/Aether b/Application/libs/Aether index 8c816c2..29c14b5 160000 --- a/Application/libs/Aether +++ b/Application/libs/Aether @@ -1 +1 @@ -Subproject commit 8c816c2b8c919c448a9d18cb8c22ab18f8d2c6cd +Subproject commit 29c14b5abf7dba7408ab5941a14ebb2f8396b54c From d6cf467ba449bdde16adf60d974fc547f20ba576 Mon Sep 17 00:00:00 2001 From: Damien Zhao Date: Fri, 15 Nov 2024 22:16:19 +0800 Subject: [PATCH 29/37] Optimize the loading performance when dealing with a large number of data entries - Fixed APP stuck on black screen when there are a large number of game data entries - Optimized the loading performance of the game data enteries. - Add debug traces. - Bump to v1.5.2 Signed-off-by: Damien Zhao --- Application/Makefile | 2 +- Application/include/utils/Debug.hpp | 15 ++++++ Application/source/Application.cpp | 18 +++++++ Application/source/nx/PlayData.cpp | 57 +++++++++++------------ Application/source/ui/screen/Settings.cpp | 1 + Application/source/utils/Debug.cpp | 23 +++++++++ Application/source/utils/NX.cpp | 57 +++++++++-------------- Forwarder/exefs.json | 8 ++++ 8 files changed, 117 insertions(+), 64 deletions(-) create mode 100644 Application/include/utils/Debug.hpp create mode 100644 Application/source/utils/Debug.cpp diff --git a/Application/Makefile b/Application/Makefile index ee7c8d0..4232661 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -43,7 +43,7 @@ FORWARDER := $(ROMFS)/exefs.nsp #--------------------------------------------------------------------------------- VER_MAJOR := 1 VER_MINOR := 5 -VER_MICRO := 1 +VER_MICRO := 2 #--------------------------------------------------------------------------------- # Options for .nacp information diff --git a/Application/include/utils/Debug.hpp b/Application/include/utils/Debug.hpp new file mode 100644 index 0000000..2fe6009 --- /dev/null +++ b/Application/include/utils/Debug.hpp @@ -0,0 +1,15 @@ +#pragma once +#ifndef DEBUG_HPP +#define DEBUG_HPP + +#include +#include + +//#define ENABLE_DEBUG + +namespace Utils { + extern std::mutex mutex; + void write_log(const std::string& msg); +}; + +#endif diff --git a/Application/source/Application.cpp b/Application/source/Application.cpp index 1091c77..241fb63 100644 --- a/Application/source/Application.cpp +++ b/Application/source/Application.cpp @@ -5,6 +5,7 @@ #include "utils/Lang.hpp" #include "utils/UpdateUtils.hpp" #include "utils/Utils.hpp" +#include "utils/Debug.hpp" #include "ui/screen/AdjustPlaytime.hpp" #include "ui/screen/AllActivity.hpp" @@ -24,22 +25,28 @@ namespace Main { // Start all required services Utils::NX::startServices(); Utils::Curl::init(); + Utils::write_log("Services started and Crul init finished!"); // Create config object and read in values this->config_ = new Config(); this->config_->readConfig(); + Utils::write_log("Read config file finished!"); // Set language if (!Utils::Lang::setLanguage(this->config_->gLang())) { this->window->exit(); } + Utils::write_log("Set language finished!"); this->playdata_ = new NX::PlayData(); + Utils::write_log("NX::PlayData() finished!"); this->theme_ = new Theme(this->config_->gTheme()); + Utils::write_log("Theme(this->config_->gTheme()) finished!"); // Start update thread this->hasUpdate_ = false; this->updateThread = std::async(std::launch::async, &Application::checkForUpdate, this); + Utils::write_log("Start update thread finished!"); // Check if launched via user page and if so only use the chosen user NX::User * u = Utils::NX::getUserPageUser(); @@ -48,6 +55,7 @@ namespace Main { this->isUserPage_ = true; this->users.push_back(u); } + Utils::write_log("Check user page finished!"); // Set view to today and by day this->tm = Utils::Time::getTmForCurrentTime(); @@ -67,12 +75,14 @@ namespace Main { } this->tmCopy = this->tm; this->viewTypeCopy = this->viewType; + Utils::write_log("Set view to today and by day finished!"); // Populate users vector if (!this->isUserPage_) { this->users = Utils::NX::getUserObjects(); } this->userIdx = 0; + Utils::write_log("Populate users vector finished!"); // Populate titles vector this->titles = Utils::NX::getTitleObjects(this->users); @@ -81,24 +91,28 @@ namespace Main { this->titles.push_back(title); } this->titleIdx = 0; + Utils::write_log("Populate titles vector finished!"); // Create Aether instance (ignore log messages for now) this->window = new Aether::Window("NX-Activity-Log", 1280, 720, [](const std::string message, const bool important) { }); // this->window->showDebugInfo(true); + Utils::write_log("Create Aether instance finished!"); // Create overlays this->dtpicker = nullptr; this->periodpicker = new Aether::PopupList("common.view.heading"_lang); this->periodpicker->setBackLabel("common.buttonHint.back"_lang); this->periodpicker->setOKLabel("common.buttonHint.ok"_lang); + Utils::write_log("Create overlays finished!"); // Setup screens this->setDisplayTheme(); this->createReason = ScreenCreate::Normal; this->createScreens(); this->reinitScreens_ = ReinitState::False; + Utils::write_log("Setup screens finished!"); if (this->isUserPage_) { // Skip UserSelect screen if launched via user page @@ -109,6 +123,7 @@ namespace Main { this->window->setFadeOut(true); this->setScreen(ScreenID::UserSelect); } + Utils::write_log("Start screens finished!"); } void Application::checkForUpdate() { @@ -455,13 +470,16 @@ namespace Main { // Check if screens should be recreated if (this->reinitScreens_ == ReinitState::Wait) { this->reinitScreens_ = ReinitState::True; + Utils::write_log("Waiting for reinit screens..."); } else if (this->reinitScreens_ == ReinitState::True) { + Utils::write_log("Reinit screens start!"); this->reinitScreens_ = ReinitState::False; this->window->removeScreen(); this->deleteScreens(); this->setDisplayTheme(); this->createScreens(); this->setScreen(this->screen); + Utils::write_log("Reinit screens finished!"); } } } diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index be09c8d..ced5e89 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -6,9 +6,10 @@ #include "nx/PlayData.hpp" #include "utils/NX.hpp" #include "utils/Time.hpp" +#include "utils/Debug.hpp" // Maximum number of entries to process in one iteration -#define MAX_PROCESS_ENTRIES_PER_TIME 100 +#define MAX_PROCESS_ENTRIES 4096 namespace NX { std::vector PlayData::getPDSessions(TitleID titleID, AccountUid userID, u64 start_ts, u64 end_ts) { @@ -164,32 +165,24 @@ namespace NX { } PlayEventsAndSummaries PlayData::readPlayDataFromPdm() { + Utils::write_log("readPlayDataFromPdm() enter"); + PlayEventsAndSummaries ret; - Result rc; - // Position of first and last event to read - s32 startEntryIndex = -1; - s32 endEntryIndex = -1; + // Position of first event to read + s32 offset = 0; // Total events read in iteration - s32 totalEntries = -1; + s32 total_read = 1; - rc = pdmqryGetAvailablePlayEventRange(&totalEntries, &startEntryIndex, &endEntryIndex); - if (R_FAILED(rc) || !totalEntries) - return ret; + // Array to store read events + PdmPlayEvent * pEvents = new PdmPlayEvent[MAX_PROCESS_ENTRIES]; - s32 count = totalEntries; - s32 offset = startEntryIndex; // Read all events - while (count) { - s32 total_read = -1; - - // Array to store read events - PdmPlayEvent * pEvents = new PdmPlayEvent[MAX_PROCESS_ENTRIES_PER_TIME]; - Result rc = pdmqryQueryPlayEvent(offset, pEvents, MAX_PROCESS_ENTRIES_PER_TIME, &total_read); + while (total_read > 0) { + Result rc = pdmqryQueryPlayEvent(offset, pEvents, MAX_PROCESS_ENTRIES, &total_read); if (R_SUCCEEDED(rc)) { // Set next read position to next event offset += total_read; - count -= total_read; // Process read events for (s32 i = 0; i < total_read; i++) { @@ -253,7 +246,6 @@ namespace NX { break; } break; - // Do nothing for other event types default: continue; @@ -268,18 +260,23 @@ namespace NX { ret.first.push_back(event); } } - // Free memory allocated to array - delete[] pEvents; + Utils::write_log("pdmqryQueryPlayEvent() called, rc=" + std::to_string(rc) + " offset=" + std::to_string(offset) + " total_read=" + std::to_string(total_read)); } + // Free memory allocated to array + delete[] pEvents; + + Utils::write_log("readPlayDataFromPdm() exit"); return ret; } PlayEventsAndSummaries PlayData::readPlayDataFromImport() { PlayEventsAndSummaries ret; + Utils::write_log("readPlayDataFromImport() enter"); // Abort if no file if (!std::filesystem::exists("/switch/NX-Activity-Log/importedData.json")) { + Utils::write_log("readPlayDataFromImport() exit"); return ret; } @@ -308,7 +305,7 @@ namespace NX { if (event["clockTimestamp"] != nullptr && event["steadyTimestamp"] != nullptr && event["type"] != nullptr) { EventType type = static_cast(event["type"]); - PlayEvent * evt = new PlayEvent; + PlayEvent *evt = new PlayEvent; evt->type = (type == Account_Active || type == Account_Inactive ? PlayEvent_Account : PlayEvent_Applet); evt->userID = {user["id"][0], user["id"][1]}; evt->titleID = title["id"]; @@ -340,24 +337,23 @@ namespace NX { // Store data if entry added if (hasEntry) { - std::vector>::iterator it = std::find_if(this->titles.begin(), this->titles.end(), [title](std::pair entry) { - return (title["id"] == entry.first); - }); - if (it == this->titles.end()) { - if (title["id"] != 0) { - this->titles.push_back(std::make_pair(title["id"], title["name"])); - } + if (std::find_if(this->titles.begin(), this->titles.end(), [title](std::pair entry) { return (title["id"] == entry.first && title["id"] != 0); }) == this->titles.end()) { + this->titles.push_back(std::make_pair(title["id"], title["name"])); } } } + + Utils::write_log("Parse user data from importedData.json finished!"); } + Utils::write_log("readPlayDataFromImport() exit"); return ret; } std::vector PlayData::mergePlayEvents(std::vector & one, std::vector & two) { std::vector merged = one; + Utils::write_log("mergePlayEvents enter"); for (PlayEvent * event : two) { std::vector::iterator it = std::find_if(one.begin(), one.end(), [event](PlayEvent * pot) { return (event->type == pot->type && event->titleID == pot->titleID && @@ -374,6 +370,7 @@ namespace NX { one.clear(); two.clear(); + Utils::write_log("mergePlayEvents exit"); return merged; } @@ -389,8 +386,10 @@ namespace NX { PlayEventsAndSummaries pdmData = pdmThread.get(); PlayEventsAndSummaries impData = impThread.get(); + Utils::write_log("Read in all data simultaneously finished"); this->events = this->mergePlayEvents(pdmData.first, impData.first); this->summaries = impData.second; + Utils::write_log("mergePlayEvents() finished"); } std::vector PlayData::getMissingTitles(std::vector<Title *> passed) { diff --git a/Application/source/ui/screen/Settings.cpp b/Application/source/ui/screen/Settings.cpp index 452a683..ef37656 100644 --- a/Application/source/ui/screen/Settings.cpp +++ b/Application/source/ui/screen/Settings.cpp @@ -132,6 +132,7 @@ namespace Screen { body->addElement(tb); this->msgbox->setBodySize(bw, tb->y() + tb->h() + 40); this->msgbox->setBody(body); + this->app->addOverlay(this->msgbox); } void Settings::setupLangOverlay() { diff --git a/Application/source/utils/Debug.cpp b/Application/source/utils/Debug.cpp new file mode 100644 index 0000000..5f0ee22 --- /dev/null +++ b/Application/source/utils/Debug.cpp @@ -0,0 +1,23 @@ + +#include <fstream> +#include <ctime> +#include "utils/Debug.hpp" + +namespace Utils { + std::mutex mutex; + void write_log(const std::string& msg) { +#ifdef ENABLE_DEBUG + std::time_t currentTime = std::time(nullptr); + std::tm* time = std::localtime(¤tTime); + char buffer[30]; + strftime(buffer, sizeof(buffer), "[%Y-%m-%d %H:%M:%S] ", time); + std::string timestamp(buffer); + + std::lock_guard<std::mutex> lock(Utils::mutex); + std::ofstream file("/switch/NX-Activity-Log/debug.log", std::ios::app); + if (file.is_open()) { + file << timestamp + msg << std::endl; + } +#endif + } +}; diff --git a/Application/source/utils/NX.cpp b/Application/source/utils/NX.cpp index 3f02043..12cbaa5 100644 --- a/Application/source/utils/NX.cpp +++ b/Application/source/utils/NX.cpp @@ -3,7 +3,7 @@ #include <iterator> // Maximum number of titles to read using pdm -#define MAX_TITLES_PER_TIME 100 +#define MAX_TITLES 4096 // Comparison of AccountUids bool operator == (const AccountUid &a, const AccountUid &b) { @@ -146,63 +146,52 @@ namespace Utils::NX { std::vector<::NX::Title *> getTitleObjects(std::vector<::NX::User *> u) { Result rc; - // Get ALL played titles for ALL users // (this doesn't include installed games that haven't been played) std::vector<TitleID> playedIDs; for (auto user : u) { + s32 playedTotal = 0; TitleID tmpID = 0; - s32 startEntryIndex = -1; - s32 endEntryIndex = -1; - s32 totalEntries = -1; - rc = pdmqryGetAvailableAccountPlayEventRange(user->ID(), &totalEntries, &startEntryIndex, &endEntryIndex); - if (R_FAILED(rc) || !totalEntries) + PdmAccountPlayEvent *userPlayEvents = new PdmAccountPlayEvent[MAX_TITLES]; + rc = pdmqryQueryAccountPlayEvent(0, user->ID(), userPlayEvents, MAX_TITLES, &playedTotal); + if (R_FAILED(rc) || playedTotal == 0) { + delete[] userPlayEvents; continue; + } - s32 count = totalEntries; - s32 offset = startEntryIndex; - while (count) { - s32 total_read = -1; - PdmAccountPlayEvent *userPlayEvents = new PdmAccountPlayEvent[MAX_TITLES_PER_TIME]; - rc = pdmqryQueryAccountPlayEvent(offset, user->ID(), userPlayEvents, MAX_TITLES_PER_TIME, &total_read); - if (R_SUCCEEDED(rc)) { - offset += total_read; - count -= total_read; - for (s32 j = 0; j < total_read; j++) { - tmpID = (static_cast<TitleID>(userPlayEvents[j].application_id[0]) << 32) | userPlayEvents[j].application_id[1]; - if(std::find_if(playedIDs.begin(), playedIDs.end(), [tmpID](auto id){ return id == tmpID;}) == playedIDs.end()) { - if (tmpID != 0) { - playedIDs.push_back(tmpID); - } - } - } + // Push back ID if not already in the vector + for (s32 j = 0; j < playedTotal; j++) { + tmpID = (static_cast<TitleID>(userPlayEvents[j].application_id[0]) << 32) | userPlayEvents[j].application_id[1]; + if (std::find_if(playedIDs.begin(), playedIDs.end(), [tmpID](auto id){ return (id == tmpID && tmpID != 0); }) == playedIDs.end()) { + playedIDs.push_back(tmpID); } - delete[] userPlayEvents; } + delete[] userPlayEvents; } - std::vector<TitleID> installedIDs; // Get IDs of all installed titles - s32 start_offset = 0; + std::vector<TitleID> installedIDs; + NsApplicationRecord * records = new NsApplicationRecord[MAX_TITLES]; + s32 count = 0; s32 out = 0; while (true) { - NsApplicationRecord *records = new NsApplicationRecord[MAX_TITLES_PER_TIME]; - rc = nsListApplicationRecord(records, MAX_TITLES_PER_TIME, start_offset, &out); - if (R_FAILED(rc) || out == 0) { - delete[] records; + rc = nsListApplicationRecord(records, MAX_TITLES, count, &out); + // Break if at the end or no titles + if (R_FAILED(rc) || out == 0){ break; } for (s32 i = 0; i < out; i++) { installedIDs.push_back((records + i)->application_id); } - start_offset += out; - delete[] records; + count += out; } + delete[] records; // Create Title objects from IDs std::vector<::NX::Title *> titles; for (auto playedID : playedIDs) { - bool installed = std::find_if(installedIDs.begin(), installedIDs.end(), [playedID](auto id){ return id == playedID;}) != installedIDs.end(); + // Loop over installed titles to determine if installed or not + bool installed = std::find_if(installedIDs.begin(), installedIDs.end(), [playedID](auto id) { return id == playedID; }) != installedIDs.end(); titles.push_back(new ::NX::Title(playedID, installed)); } diff --git a/Forwarder/exefs.json b/Forwarder/exefs.json index f099ade..5530734 100644 --- a/Forwarder/exefs.json +++ b/Forwarder/exefs.json @@ -151,6 +151,14 @@ { "type": "handle_table_size", "value": 512 + }, + { + "type": "debug_flags", + "value": { + "allow_debug": false, + "force_debug_prod": false, + "force_debug": true + } } ] } From 78ff8d93c07db4ccdd3372ead5bb54c288616e41 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Sun, 17 Nov 2024 19:57:29 +0800 Subject: [PATCH 30/37] fix total play time in recent activity view mismatch Bump version to v1.5.3 Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/Makefile | 2 +- Application/include/nx/PlayData.hpp | 5 +- .../include/ui/screen/RecentActivity.hpp | 3 + Application/source/nx/PlayData.cpp | 6 +- .../source/ui/screen/RecentActivity.cpp | 68 +++++++++++-------- 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Application/Makefile b/Application/Makefile index 4232661..8b2bf0f 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -43,7 +43,7 @@ FORWARDER := $(ROMFS)/exefs.nsp #--------------------------------------------------------------------------------- VER_MAJOR := 1 VER_MINOR := 5 -VER_MICRO := 2 +VER_MICRO := 3 #--------------------------------------------------------------------------------- # Options for .nacp information diff --git a/Application/include/nx/PlayData.hpp b/Application/include/nx/PlayData.hpp index 7fef963..c7698cb 100644 --- a/Application/include/nx/PlayData.hpp +++ b/Application/include/nx/PlayData.hpp @@ -118,10 +118,7 @@ namespace NX { // Returns all play sessions for the given title ID and user ID std::vector<PlaySession> getPlaySessionsForUser(TitleID, AccountUid); - // Returns a RecentPlayStatistics for the given time range for all users - RecentPlayStatistics * getRecentStatisticsForUser(u64, u64, AccountUid); - - // Returns a RecentPlayStatistics for the given time range and user ID + // Returns a RecentPlayStatistics for the given time range, user ID and title ID RecentPlayStatistics * getRecentStatisticsForTitleAndUser(TitleID, u64, u64, AccountUid); // Returns a PlayStatistics for the given titleID and userID diff --git a/Application/include/ui/screen/RecentActivity.hpp b/Application/include/ui/screen/RecentActivity.hpp index 60001fd..617254a 100644 --- a/Application/include/ui/screen/RecentActivity.hpp +++ b/Application/include/ui/screen/RecentActivity.hpp @@ -15,6 +15,9 @@ namespace Screen { // Pointer to app for theme Main::Application * app; + // Returns active user's total play time in second for the given time range + uint64_t getUserTotalSecsForAllTitles(struct tm t, struct tm e); + // Updates the "recent activity" part of the screen void updateActivity(); // Updates graph if data matching current time range diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index ced5e89..c7728d8 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -22,7 +22,7 @@ namespace NX { size_t s = a; bool time_c = false; bool titleID_c = false; - if (titleID == 0 || this->events[a]->titleID == titleID) { + if (this->events[a]->titleID == titleID) { titleID_c = true; } bool userID_c = false; @@ -484,10 +484,6 @@ namespace NX { return sessions; } - RecentPlayStatistics * PlayData::getRecentStatisticsForUser(u64 start_ts, u64 end_ts, AccountUid userID) { - return this->countPlaytime(this->getPDSessions(0, userID, start_ts, end_ts), start_ts, end_ts); - } - RecentPlayStatistics * PlayData::getRecentStatisticsForTitleAndUser(TitleID titleID, u64 start_ts, u64 end_ts, AccountUid userID) { RecentPlayStatistics * s = this->countPlaytime(this->getPDSessions(titleID, userID, start_ts, end_ts), start_ts, end_ts); s->titleID = titleID; diff --git a/Application/source/ui/screen/RecentActivity.cpp b/Application/source/ui/screen/RecentActivity.cpp index 50bdc6b..d9a48be 100644 --- a/Application/source/ui/screen/RecentActivity.cpp +++ b/Application/source/ui/screen/RecentActivity.cpp @@ -66,6 +66,23 @@ namespace Screen { }); } + uint64_t RecentActivity::getUserTotalSecsForAllTitles(struct tm begin, struct tm end) { + uint64_t totalSecs = 0; + std::vector<uint64_t> hidden = this->app->config()->hiddenTitles(); + NX::RecentPlayStatistics *s = nullptr; + for (auto title : this->app->titleVector()) { + // Skip over hidden games + if (std::find(hidden.begin(), hidden.end(), title->titleID()) != hidden.end()) + continue; + s = this->app->playdata()->getRecentStatisticsForTitleAndUser(title->titleID(), Utils::Time::getTimeT(begin), Utils::Time::getTimeT(end), this->app->activeUser()->ID()); + // Only show games that have actually been played + if (s->launches > 0) + totalSecs += s->playtime; + delete s; + } + return totalSecs; + } + void RecentActivity::updateActivity() { // Check if there is any activity + update heading struct tm t = this->app->time(); @@ -93,7 +110,8 @@ namespace Screen { } this->graphHeading->setString(Utils::Time::dateToActivityForString(t, 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()); + + uint64_t totalSecs = getUserTotalSecsForAllTitles(t, e); // Remove current sessions regardless this->list->removeElementsAfter(this->topElm); @@ -102,7 +120,7 @@ namespace Screen { } // Only update list if there is activity - if (ps->playtime != 0) { + if (totalSecs != 0) { this->gameHeading->setHidden(false); this->graph->setHidden(false); this->graphSubheading->setHidden(false); @@ -121,8 +139,6 @@ namespace Screen { this->list->setCanScroll(false); this->noStats->setHidden(false); } - - delete ps; } void RecentActivity::update(uint32_t dt) { @@ -183,6 +199,8 @@ namespace Screen { // Read playtime and set graph values struct tm t = tm; uint64_t totalSecs = 0; + std::vector<uint64_t> hidden = this->app->config()->hiddenTitles(); + NX::RecentPlayStatistics *s = nullptr; switch (this->app->viewPeriod()) { case ViewPeriod::Day: { t.tm_min = 0; @@ -193,9 +211,8 @@ namespace Screen { 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; + totalSecs = getUserTotalSecsForAllTitles(t, e); + double val = totalSecs/60.0; this->graph->setValue(i, val); delete s; } @@ -214,12 +231,11 @@ namespace Screen { 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; + totalSecs = getUserTotalSecsForAllTitles(t, e); + if (totalSecs > max) { + max = totalSecs; } - double val = s->playtime/60/60.0; + double val = totalSecs/60/60.0; this->graph->setValue(i, val); delete s; } @@ -249,14 +265,12 @@ namespace Screen { 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; + totalSecs = getUserTotalSecsForAllTitles(t, e); + if (totalSecs > max) { + max = totalSecs; } - double val = s->playtime/60/60.0; + double val = totalSecs/60/60.0; this->graph->setValue(i, val); - delete s; } max /= 60.0; max /= 60.0; @@ -328,16 +342,16 @@ namespace Screen { }); // Add to list - for (size_t i = 0; i < stats.size(); i++) { + for (auto stat : stats) { // Only show games that have actually been played - if (stats[i].first->launches > 0) { - totalSecs += stats[i].first->playtime; + if (stat.first->launches > 0) { + totalSecs += stat.first->playtime; CustomElm::ListActivity * la = new CustomElm::ListActivity(); - la->setImage(this->app->titleVector()[stats[i].second]->imgPtr(), this->app->titleVector()[stats[i].second]->imgSize()); - la->setTitle(this->app->titleVector()[stats[i].second]->name()); - la->setPlaytime(Utils::playtimeToPlayedForString(stats[i].first->playtime)); - la->setLeftMuted(Utils::launchesToPlayedString(stats[i].first->launches)); - unsigned int j = stats[i].second; + 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(); @@ -351,7 +365,7 @@ namespace Screen { } // Can delete each pointer after it's accessed - delete stats[i].first; + delete stat.first; } // Update playtime string From 320c2b84e4d53d390c2ae0f6d47d72d9d9909e12 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Wed, 20 Nov 2024 23:42:14 +0800 Subject: [PATCH 31/37] fix total play time in recent activity view mismatch Revert the pervious commit and update the fix. Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/include/nx/PlayData.hpp | 3 + .../include/ui/screen/RecentActivity.hpp | 3 - Application/source/nx/PlayData.cpp | 6 +- .../source/ui/screen/RecentActivity.cpp | 100 ++++++++---------- 4 files changed, 50 insertions(+), 62 deletions(-) diff --git a/Application/include/nx/PlayData.hpp b/Application/include/nx/PlayData.hpp index c7698cb..c8edf47 100644 --- a/Application/include/nx/PlayData.hpp +++ b/Application/include/nx/PlayData.hpp @@ -118,6 +118,9 @@ namespace NX { // Returns all play sessions for the given title ID and user ID std::vector<PlaySession> getPlaySessionsForUser(TitleID, AccountUid); + // Returns a RecentPlayStatistics for the given time range and user ID for all Title IDs + RecentPlayStatistics * getRecentStatisticsForUser(u64, u64, AccountUid); + // Returns a RecentPlayStatistics for the given time range, user ID and title ID RecentPlayStatistics * getRecentStatisticsForTitleAndUser(TitleID, u64, u64, AccountUid); diff --git a/Application/include/ui/screen/RecentActivity.hpp b/Application/include/ui/screen/RecentActivity.hpp index 617254a..60001fd 100644 --- a/Application/include/ui/screen/RecentActivity.hpp +++ b/Application/include/ui/screen/RecentActivity.hpp @@ -15,9 +15,6 @@ namespace Screen { // Pointer to app for theme Main::Application * app; - // Returns active user's total play time in second for the given time range - uint64_t getUserTotalSecsForAllTitles(struct tm t, struct tm e); - // Updates the "recent activity" part of the screen void updateActivity(); // Updates graph if data matching current time range diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index c7728d8..ced5e89 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -22,7 +22,7 @@ namespace NX { size_t s = a; bool time_c = false; bool titleID_c = false; - if (this->events[a]->titleID == titleID) { + if (titleID == 0 || this->events[a]->titleID == titleID) { titleID_c = true; } bool userID_c = false; @@ -484,6 +484,10 @@ namespace NX { return sessions; } + RecentPlayStatistics * PlayData::getRecentStatisticsForUser(u64 start_ts, u64 end_ts, AccountUid userID) { + return this->countPlaytime(this->getPDSessions(0, userID, start_ts, end_ts), start_ts, end_ts); + } + RecentPlayStatistics * PlayData::getRecentStatisticsForTitleAndUser(TitleID titleID, u64 start_ts, u64 end_ts, AccountUid userID) { RecentPlayStatistics * s = this->countPlaytime(this->getPDSessions(titleID, userID, start_ts, end_ts), start_ts, end_ts); s->titleID = titleID; diff --git a/Application/source/ui/screen/RecentActivity.cpp b/Application/source/ui/screen/RecentActivity.cpp index d9a48be..ce8f589 100644 --- a/Application/source/ui/screen/RecentActivity.cpp +++ b/Application/source/ui/screen/RecentActivity.cpp @@ -66,23 +66,6 @@ namespace Screen { }); } - uint64_t RecentActivity::getUserTotalSecsForAllTitles(struct tm begin, struct tm end) { - uint64_t totalSecs = 0; - std::vector<uint64_t> hidden = this->app->config()->hiddenTitles(); - NX::RecentPlayStatistics *s = nullptr; - for (auto title : this->app->titleVector()) { - // Skip over hidden games - if (std::find(hidden.begin(), hidden.end(), title->titleID()) != hidden.end()) - continue; - s = this->app->playdata()->getRecentStatisticsForTitleAndUser(title->titleID(), Utils::Time::getTimeT(begin), Utils::Time::getTimeT(end), this->app->activeUser()->ID()); - // Only show games that have actually been played - if (s->launches > 0) - totalSecs += s->playtime; - delete s; - } - return totalSecs; - } - void RecentActivity::updateActivity() { // Check if there is any activity + update heading struct tm t = this->app->time(); @@ -110,8 +93,7 @@ namespace Screen { } this->graphHeading->setString(Utils::Time::dateToActivityForString(t, this->app->viewPeriod())); this->graphHeading->setX(this->header->x() + (this->header->w() - this->graphHeading->w())/2); - - uint64_t totalSecs = getUserTotalSecsForAllTitles(t, e); + NX::RecentPlayStatistics * ps = this->app->playdata()->getRecentStatisticsForUser(Utils::Time::getTimeT(t), Utils::Time::getTimeT(e), this->app->activeUser()->ID()); // Remove current sessions regardless this->list->removeElementsAfter(this->topElm); @@ -120,7 +102,7 @@ namespace Screen { } // Only update list if there is activity - if (totalSecs != 0) { + if (ps->playtime != 0) { this->gameHeading->setHidden(false); this->graph->setHidden(false); this->graphSubheading->setHidden(false); @@ -139,6 +121,8 @@ namespace Screen { this->list->setCanScroll(false); this->noStats->setHidden(false); } + + delete ps; } void RecentActivity::update(uint32_t dt) { @@ -199,8 +183,6 @@ namespace Screen { // Read playtime and set graph values struct tm t = tm; uint64_t totalSecs = 0; - std::vector<uint64_t> hidden = this->app->config()->hiddenTitles(); - NX::RecentPlayStatistics *s = nullptr; switch (this->app->viewPeriod()) { case ViewPeriod::Day: { t.tm_min = 0; @@ -211,8 +193,9 @@ namespace Screen { for (size_t i = 0; i < this->graph->entries(); i++) { t.tm_hour = i; e.tm_hour = i; - totalSecs = getUserTotalSecsForAllTitles(t, e); - double val = totalSecs/60.0; + 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; } @@ -231,11 +214,12 @@ namespace Screen { for (size_t i = 0; i < this->graph->entries(); i++) { t.tm_mday = i + 1; e.tm_mday = i + 1; - totalSecs = getUserTotalSecsForAllTitles(t, e); - if (totalSecs > max) { - max = totalSecs; + 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 = totalSecs/60/60.0; + double val = s->playtime/60/60.0; this->graph->setValue(i, val); delete s; } @@ -265,12 +249,14 @@ namespace Screen { t.tm_mon = i; e.tm_mon = i; e.tm_mday = Utils::Time::tmGetDaysInMonth(t); - totalSecs = getUserTotalSecsForAllTitles(t, e); - if (totalSecs > max) { - max = totalSecs; + 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 = totalSecs/60/60.0; + double val = s->playtime/60/60.0; this->graph->setValue(i, val); + delete s; } max /= 60.0; max /= 60.0; @@ -325,11 +311,6 @@ namespace Screen { std::vector<std::pair<NX::RecentPlayStatistics *, unsigned int> > stats; std::vector<uint64_t> hidden = this->app->config()->hiddenTitles(); for (size_t i = 0; i < this->app->titleVector().size(); i++) { - // Skip over hidden games - if (std::find(hidden.begin(), hidden.end(), this->app->titleVector()[i]->titleID()) != hidden.end()) { - continue; - } - std::pair<NX::RecentPlayStatistics *, unsigned int> stat; stat.first = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->titleVector()[i]->titleID(), s, e, this->app->activeUser()->ID()); stat.second = i; @@ -342,30 +323,33 @@ namespace Screen { }); // Add to list + bool isHidden = false; for (auto stat : stats) { - // Only show games that have actually been played - if (stat.first->launches > 0) { - totalSecs += stat.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); + 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; } - // Can delete each pointer after it's accessed - delete stat.first; + 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 From 765de6240ec640374e337d30bb22904a44d59946 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Fri, 22 Nov 2024 23:28:10 +0800 Subject: [PATCH 32/37] Make the recorded time more accurate Signed-off-by: Damien Zhao <zdm65477730@126.com> --- 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<NX::PlaySession> 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<NX::PlaySession> 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<std::pair<NX::RecentPlayStatistics *, unsigned int> > stats; + for (size_t i = 0; i < this->app->titleVector().size(); i++) { + std::pair<NX::RecentPlayStatistics *, unsigned int> 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<NX::RecentPlayStatistics *, unsigned int> lhs, const std::pair<NX::RecentPlayStatistics *, unsigned int> rhs) { + return lhs.first->playtime > rhs.first->playtime; + }); - // Get stats - uint64_t totalSecs = 0; - std::vector<std::pair<NX::RecentPlayStatistics *, unsigned int> > stats; - std::vector<uint64_t> hidden = this->app->config()->hiddenTitles(); - for (size_t i = 0; i < this->app->titleVector().size(); i++) { - std::pair<NX::RecentPlayStatistics *, unsigned int> 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<uint64_t> 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<NX::RecentPlayStatistics *, unsigned int> lhs, const std::pair<NX::RecentPlayStatistics *, unsigned int> 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 From 23f43badda27742a8349cf1f5cc1c3ab5e93d5e2 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Sat, 23 Nov 2024 12:58:59 +0800 Subject: [PATCH 33/37] update for use the same API for fetch user's game play data Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/include/nx/PlayData.hpp | 12 ++++++------ Application/source/Application.ExportJob.cpp | 6 +++--- Application/source/ui/screen/AdjustPlaytime.cpp | 3 ++- Application/source/ui/screen/AllActivity.cpp | 17 +++++++++++------ Application/source/ui/screen/Details.cpp | 17 ++++++++++------- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Application/include/nx/PlayData.hpp b/Application/include/nx/PlayData.hpp index c8edf47..b2102b6 100644 --- a/Application/include/nx/PlayData.hpp +++ b/Application/include/nx/PlayData.hpp @@ -24,12 +24,12 @@ namespace NX { // PlayEvents are parsed PdmPlayEvents containing only necessary information struct PlayEvent { - PlayEventType type; // Type of PlayEvent - AccountUid userID; // UserID - TitleID titleID; // TitleID - EventType eventType; // See EventType enum - u64 clockTimestamp; // Time of event - u64 steadyTimestamp; // Steady timestamp (used for calculating duration) + PlayEventType type; // Type of PlayEvent + AccountUid userID; // UserID + TitleID titleID; // TitleID + EventType eventType; // See EventType enum + u64 clockTimestamp; // Time of event + u64 steadyTimestamp; // Steady timestamp (used for calculating duration) }; // A PlaySession represents a session of play for a game. It contains the start diff --git a/Application/source/Application.ExportJob.cpp b/Application/source/Application.ExportJob.cpp index 2a932bf..a48371a 100644 --- a/Application/source/Application.ExportJob.cpp +++ b/Application/source/Application.ExportJob.cpp @@ -38,7 +38,6 @@ namespace Main { // Check if played, and if not move onto next NX::RecentPlayStatistics * stats = this->app->playdata_->getRecentStatisticsForTitleAndUser(title->titleID(), std::numeric_limits<u64>::min(), std::numeric_limits<u64>::max(), user->ID()); bool recentLaunched = (stats->launches != 0); - delete stats; // Add title metadata tJson["name"] = title->name(); @@ -94,8 +93,9 @@ namespace Main { bool allLaunched = (stats2->launches != 0); tJson["summary"]["firstPlayed"] = stats2->firstPlayed; tJson["summary"]["lastPlayed"] = stats2->lastPlayed; - tJson["summary"]["playtime"] = stats2->playtime; - tJson["summary"]["launches"] = stats2->launches; + tJson["summary"]["playtime"] = stats->playtime; + tJson["summary"]["launches"] = stats->launches; + delete stats; delete stats2; // Append title if played at least once diff --git a/Application/source/ui/screen/AdjustPlaytime.cpp b/Application/source/ui/screen/AdjustPlaytime.cpp index 3de85e9..d0f8f43 100644 --- a/Application/source/ui/screen/AdjustPlaytime.cpp +++ b/Application/source/ui/screen/AdjustPlaytime.cpp @@ -117,7 +117,8 @@ namespace Screen { } size_t idx = std::distance(this->adjustments.begin(), it); - NX::PlayStatistics * stats = this->app->playdata()->getStatisticsForUser(title->titleID(), this->app->activeUser()->ID()); + NX::RecentPlayStatistics * stats = this->app->playdata()->getRecentStatisticsForTitleAndUser(title->titleID(), std::numeric_limits<u64>::min(), std::numeric_limits<u64>::max(), this->app->activeUser()->ID()); + //NX::PlayStatistics * stats = this->app->playdata()->getStatisticsForUser(title->titleID(), this->app->activeUser()->ID()); CustomElm::ListAdjust * l = new CustomElm::ListAdjust(title->name(), Utils::playtimeToPlayedForString(stats->playtime), this->getValueString(this->adjustments[idx].value)); delete stats; diff --git a/Application/source/ui/screen/AllActivity.cpp b/Application/source/ui/screen/AllActivity.cpp index d833514..17bdb64 100644 --- a/Application/source/ui/screen/AllActivity.cpp +++ b/Application/source/ui/screen/AllActivity.cpp @@ -129,7 +129,8 @@ namespace Screen { } // Get statistics and append adjustment if needed - NX::PlayStatistics * ps = this->app->playdata()->getStatisticsForUser(t[i]->titleID(), this->app->activeUser()->ID()); + NX::RecentPlayStatistics *ps = this->app->playdata()->getRecentStatisticsForTitleAndUser(t[i]->titleID(), std::numeric_limits<u64>::min(), std::numeric_limits<u64>::max(), this->app->activeUser()->ID()); + NX::PlayStatistics *ps2 = this->app->playdata()->getStatisticsForUser(t[i]->titleID(), this->app->activeUser()->ID()); std::vector<AdjustmentValue>::iterator it = std::find_if(adjustments.begin(), adjustments.end(), [this, t, i](AdjustmentValue val) { return (val.titleID == t[i]->titleID() && val.userID == this->app->activeUser()->ID()); }); @@ -141,12 +142,13 @@ namespace Screen { totalSecs += ps->playtime; if (ps->launches == 0) { // Add in dummy data if not launched before (due to adjustment) - ps->firstPlayed = Utils::Time::posixTimestampToPdm(Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime())); - ps->lastPlayed = ps->firstPlayed; + ps2->firstPlayed = Utils::Time::posixTimestampToPdm(Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime())); + ps2->lastPlayed = ps2->firstPlayed; ps->launches = 1; if (ps->playtime == 0) { delete ps; + delete ps2; continue; } } @@ -155,8 +157,8 @@ namespace Screen { SortInfo * si = new SortInfo; si->name = t[i]->name(); si->titleID = t[i]->titleID(); - si->firstPlayed = ps->firstPlayed; - si->lastPlayed = ps->lastPlayed; + si->firstPlayed = ps2->firstPlayed; + si->lastPlayed = ps2->lastPlayed; si->playtime = ps->playtime; si->launches = ps->launches; @@ -165,7 +167,7 @@ namespace Screen { la->setImage(t[i]->imgPtr(), t[i]->imgSize()); la->setTitle(t[i]->name()); la->setPlaytime(Utils::playtimeToPlayedForString(ps->playtime)); - la->setLeftMuted(Utils::lastPlayedToString(ps->lastPlayed)); + la->setLeftMuted(Utils::lastPlayedToString(ps2->lastPlayed)); la->setRightMuted(Utils::launchesToPlayedString(ps->launches)); la->onPress([this, i](){ this->app->setActiveTitle(i); @@ -177,6 +179,9 @@ namespace Screen { la->setMutedColour(this->app->theme()->mutedText()); la->setLineColour(this->app->theme()->mutedLine()); this->list->addElement(la, si); + + delete ps; + delete ps2; } // Sort the list diff --git a/Application/source/ui/screen/Details.cpp b/Application/source/ui/screen/Details.cpp index 9b7f4b5..9bea240 100644 --- a/Application/source/ui/screen/Details.cpp +++ b/Application/source/ui/screen/Details.cpp @@ -268,7 +268,8 @@ namespace Screen { // update sessions // Get relevant play stats - NX::PlayStatistics * pss = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + //NX::PlayStatistics * pss = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + NX::RecentPlayStatistics *pss = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), std::numeric_limits<u64>::min(), std::numeric_limits<u64>::max(), this->app->activeUser()->ID()); std::vector<NX::PlaySession> stats = this->app->playdata()->getPlaySessionsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); t.tm_min = 0; @@ -378,7 +379,7 @@ namespace Screen { // Add percentage of total playtime std::string str; - double percent = 100 * ((double)playtime / ((ps->playtime == 0 || ps->playtime < playtime) ? playtime : ps->playtime)); + double percent = 100 * ((double)playtime / ((pss->playtime == 0 || pss->playtime < playtime) ? playtime : ps->playtime)); percent = Utils::roundToDecimalPlace(percent, 2); if (percent < 0.01) { str = "< 0.01%"; @@ -642,7 +643,8 @@ namespace Screen { // Get statistics and append adjustment if needed std::vector<AdjustmentValue> adjustments = this->app->config()->adjustmentValues(); - NX::PlayStatistics * ps = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + NX::PlayStatistics * pss = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + NX::RecentPlayStatistics *ps = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), std::numeric_limits<u64>::min(), std::numeric_limits<u64>::max(), this->app->activeUser()->ID()); std::vector<AdjustmentValue>::iterator it = std::find_if(adjustments.begin(), adjustments.end(), [this](AdjustmentValue val) { return (val.titleID == this->app->activeTitle()->titleID() && val.userID == this->app->activeUser()->ID()); }); @@ -652,8 +654,8 @@ namespace Screen { if (ps->launches == 0) { // Add in dummy data if not launched before (due to adjustment) - ps->firstPlayed = Utils::Time::posixTimestampToPdm(Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime())); - ps->lastPlayed = ps->firstPlayed; + pss->firstPlayed = Utils::Time::posixTimestampToPdm(Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime())); + pss->lastPlayed = pss->firstPlayed; ps->launches = 1; } @@ -672,15 +674,16 @@ namespace Screen { this->timeplayed->setX(this->timeplayed->x() - this->timeplayed->w()/2); this->addElement(this->timeplayed); - this->firstplayed = new Aether::Text(1070, 490, Utils::Time::timestampToString(ps->firstPlayed), 20); + this->firstplayed = new Aether::Text(1070, 490, Utils::Time::timestampToString(pss->firstPlayed), 20); this->firstplayed->setColour(this->app->theme()->accent()); this->firstplayed->setX(this->firstplayed->x() - this->firstplayed->w()/2); this->addElement(this->firstplayed); - this->lastplayed = new Aether::Text(1070, 580, Utils::Time::timestampToString(ps->lastPlayed), 20); + this->lastplayed = new Aether::Text(1070, 580, Utils::Time::timestampToString(pss->lastPlayed), 20); this->lastplayed->setColour(this->app->theme()->accent()); this->lastplayed->setX(this->lastplayed->x() - this->lastplayed->w()/2); this->addElement(this->lastplayed); + delete pss; delete ps; // Show update icon if needbe From 15fbf2bc766c0e657a9d6d009132a12675c96d87 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Sat, 23 Nov 2024 16:23:23 +0800 Subject: [PATCH 34/37] fix data missing in year view Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/include/utils/Debug.hpp | 4 +++- Application/source/nx/PlayData.cpp | 11 ++++++++++- Application/source/ui/screen/Details.cpp | 16 +++++++++------- .../source/ui/screen/RecentActivity.cpp | 5 +++-- Application/source/utils/Debug.cpp | 18 +++++++++++++----- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Application/include/utils/Debug.hpp b/Application/include/utils/Debug.hpp index 2fe6009..8327101 100644 --- a/Application/include/utils/Debug.hpp +++ b/Application/include/utils/Debug.hpp @@ -3,13 +3,15 @@ #define DEBUG_HPP #include <string> +#include <cstdio> #include <mutex> //#define ENABLE_DEBUG +#define MAX_LOG_LEN 512 namespace Utils { extern std::mutex mutex; - void write_log(const std::string& msg); + void write_log(const char *pszFmt, ...); }; #endif diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index ced5e89..fdfe3e0 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -260,12 +260,21 @@ namespace NX { ret.first.push_back(event); } } - Utils::write_log("pdmqryQueryPlayEvent() called, rc=" + std::to_string(rc) + " offset=" + std::to_string(offset) + " total_read=" + std::to_string(total_read)); } // Free memory allocated to array delete[] pEvents; +#ifdef ENABLE_DEBUG + for (auto event : ret.first) { + if (event->userID.uid[1] == 0 && event->userID.uid[0] == 0) { + Utils::write_log("offset=%d, event: type=%u titleID=%016llx applet_type: %u clockTimestamp=%llu steadyTimestamp=%llu", offset, event->type, event->titleID, event->eventType, event->clockTimestamp, event->steadyTimestamp); + } else { + Utils::write_log("offset=%d, event: type=%u userID=%016llx_%016llx account_type: %u clockTimestamp=%llu steadyTimestamp=%llu", offset, event->type, event->userID.uid[1], event->userID.uid[0], event->eventType, event->clockTimestamp, event->steadyTimestamp); + } + } +#endif + Utils::write_log("readPlayDataFromPdm() exit"); return ret; } diff --git a/Application/source/ui/screen/Details.cpp b/Application/source/ui/screen/Details.cpp index 9bea240..a872934 100644 --- a/Application/source/ui/screen/Details.cpp +++ b/Application/source/ui/screen/Details.cpp @@ -3,6 +3,8 @@ #include "utils/Lang.hpp" #include "ui/element/ListSession.hpp" #include "utils/Utils.hpp" +#include "utils/Time.hpp" +#include "utils/Debug.hpp" // Values for summary appearance #define SUMMARY_BOX_HEIGHT 60 @@ -268,15 +270,15 @@ namespace Screen { // update sessions // Get relevant play stats - //NX::PlayStatistics * pss = this->app->playdata()->getStatisticsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); NX::RecentPlayStatistics *pss = this->app->playdata()->getRecentStatisticsForTitleAndUser(this->app->activeTitle()->titleID(), std::numeric_limits<u64>::min(), std::numeric_limits<u64>::max(), this->app->activeUser()->ID()); std::vector<NX::PlaySession> stats = this->app->playdata()->getPlaySessionsForUser(this->app->activeTitle()->titleID(), this->app->activeUser()->ID()); + t = begin; 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; + time_t start_time = 0; + time_t end_time = 0; switch (this->app->viewPeriod()) { case ViewPeriod::Day: t.tm_hour = 0; @@ -290,7 +292,7 @@ namespace Screen { end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'M')) - 1; break; case ViewPeriod::Year: - t.tm_mon = 1; + t.tm_mon = 0; t.tm_mday = 1; t.tm_hour = 0; start_time = Utils::Time::getTimeT(t); @@ -303,7 +305,7 @@ namespace Screen { // 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) { + if (stats[i].startTimestamp > static_cast<u64>(end_time) || stats[i].endTimestamp < static_cast<u64>(start_time)) { continue; } @@ -321,13 +323,13 @@ namespace Screen { // If started before range set start as start of range bool outRange = false; - if (stats[i].startTimestamp < start_time) { + if (stats[i].startTimestamp < static_cast<u64>(start_time)) { outRange = true; sTm = Utils::Time::getTm(start_time); } // If finished after range set end as end of range - if (stats[i].endTimestamp > end_time) { + if (stats[i].endTimestamp > static_cast<u64>(end_time)) { outRange = true; eTm = Utils::Time::getTm(end_time); } diff --git a/Application/source/ui/screen/RecentActivity.cpp b/Application/source/ui/screen/RecentActivity.cpp index d43b08a..e16dca3 100644 --- a/Application/source/ui/screen/RecentActivity.cpp +++ b/Application/source/ui/screen/RecentActivity.cpp @@ -237,10 +237,11 @@ namespace Screen { this->graphSubheading->setX(this->header->x() + (this->header->w() - this->graphSubheading->w())/2); // update Titles + t = begin; 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; + time_t end_time = 0; switch (this->app->viewPeriod()) { case ViewPeriod::Day: t.tm_hour = 0; @@ -252,7 +253,7 @@ namespace Screen { end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'M')) - 1; break; case ViewPeriod::Year: - t.tm_mon = 1; + t.tm_mon = 0; t.tm_mday = 1; t.tm_hour = 0; end_time = Utils::Time::getTimeT(Utils::Time::increaseTm(t, 'Y')) - 1; diff --git a/Application/source/utils/Debug.cpp b/Application/source/utils/Debug.cpp index 5f0ee22..8ee245d 100644 --- a/Application/source/utils/Debug.cpp +++ b/Application/source/utils/Debug.cpp @@ -1,22 +1,30 @@ #include <fstream> #include <ctime> +#include <cstdarg> #include "utils/Debug.hpp" namespace Utils { std::mutex mutex; - void write_log(const std::string& msg) { + void write_log(const char *pszFmt, ...) { #ifdef ENABLE_DEBUG + if (NULL == pszFmt || 0 == pszFmt[0]) return; + std::time_t currentTime = std::time(nullptr); std::tm* time = std::localtime(¤tTime); - char buffer[30]; - strftime(buffer, sizeof(buffer), "[%Y-%m-%d %H:%M:%S] ", time); - std::string timestamp(buffer); + char timestamp[30]; + strftime(timestamp, sizeof(timestamp), "[%Y-%m-%d %H:%M:%S] ", time); + + char logstr[MAX_LOG_LEN] = { 0 }; + va_list args; + va_start(args, pszFmt); + snprintf(logstr, MAX_LOG_LEN, pszFmt, args); + va_end(args); std::lock_guard<std::mutex> lock(Utils::mutex); std::ofstream file("/switch/NX-Activity-Log/debug.log", std::ios::app); if (file.is_open()) { - file << timestamp + msg << std::endl; + file << std::string(timestamp) + std::string(logstr) << std::endl; } #endif } From 8c092660c71478a43124774ec9b310d089ba9db8 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Sun, 24 Nov 2024 00:52:06 +0800 Subject: [PATCH 35/37] some fixes 1. Fixed crash when deleting import json file. 2. Updates all lang json files. 3. Fixed first/last play data missing for imported play data. Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/romfs/lang | 2 +- Application/source/Application.ImportJob.cpp | 4 +-- Application/source/Application.cpp | 18 ----------- Application/source/nx/PlayData.cpp | 26 +++++++-------- Application/source/ui/screen/AllActivity.cpp | 2 +- Application/source/ui/screen/Details.cpp | 3 +- Application/source/ui/screen/Settings.cpp | 34 ++++---------------- 7 files changed, 22 insertions(+), 67 deletions(-) diff --git a/Application/romfs/lang b/Application/romfs/lang index a937a74..c55046b 160000 --- a/Application/romfs/lang +++ b/Application/romfs/lang @@ -1 +1 @@ -Subproject commit a937a7467c4d1c28a7407b064344d33c05479700 +Subproject commit c55046b142f5e751a7849c6fd07052457282ebda diff --git a/Application/source/Application.ImportJob.cpp b/Application/source/Application.ImportJob.cpp index 86e616e..01bd8f8 100644 --- a/Application/source/Application.ImportJob.cpp +++ b/Application/source/Application.ImportJob.cpp @@ -132,8 +132,8 @@ namespace Main { nlohmann::json s = title["summary"]; if (s["firstPlayed"] != nullptr && s["lastPlayed"] != nullptr && s["playtime"] != nullptr && s["launches"] != nullptr) { tJson["summary"] = nlohmann::json(); - tJson["summary"]["firstPlayed"] = Utils::Time::posixTimestampToPdm(s["firstPlayed"].get<uint64_t>()); - tJson["summary"]["lastPlayed"] = Utils::Time::posixTimestampToPdm(s["lastPlayed"].get<uint64_t>()); + tJson["summary"]["firstPlayed"] = s["firstPlayed"].get<uint64_t>(); + tJson["summary"]["lastPlayed"] = s["lastPlayed"].get<uint64_t>(); tJson["summary"]["playtime"] = s["playtime"]; tJson["summary"]["launches"] = s["launches"]; } diff --git a/Application/source/Application.cpp b/Application/source/Application.cpp index 241fb63..1091c77 100644 --- a/Application/source/Application.cpp +++ b/Application/source/Application.cpp @@ -5,7 +5,6 @@ #include "utils/Lang.hpp" #include "utils/UpdateUtils.hpp" #include "utils/Utils.hpp" -#include "utils/Debug.hpp" #include "ui/screen/AdjustPlaytime.hpp" #include "ui/screen/AllActivity.hpp" @@ -25,28 +24,22 @@ namespace Main { // Start all required services Utils::NX::startServices(); Utils::Curl::init(); - Utils::write_log("Services started and Crul init finished!"); // Create config object and read in values this->config_ = new Config(); this->config_->readConfig(); - Utils::write_log("Read config file finished!"); // Set language if (!Utils::Lang::setLanguage(this->config_->gLang())) { this->window->exit(); } - Utils::write_log("Set language finished!"); this->playdata_ = new NX::PlayData(); - Utils::write_log("NX::PlayData() finished!"); this->theme_ = new Theme(this->config_->gTheme()); - Utils::write_log("Theme(this->config_->gTheme()) finished!"); // Start update thread this->hasUpdate_ = false; this->updateThread = std::async(std::launch::async, &Application::checkForUpdate, this); - Utils::write_log("Start update thread finished!"); // Check if launched via user page and if so only use the chosen user NX::User * u = Utils::NX::getUserPageUser(); @@ -55,7 +48,6 @@ namespace Main { this->isUserPage_ = true; this->users.push_back(u); } - Utils::write_log("Check user page finished!"); // Set view to today and by day this->tm = Utils::Time::getTmForCurrentTime(); @@ -75,14 +67,12 @@ namespace Main { } this->tmCopy = this->tm; this->viewTypeCopy = this->viewType; - Utils::write_log("Set view to today and by day finished!"); // Populate users vector if (!this->isUserPage_) { this->users = Utils::NX::getUserObjects(); } this->userIdx = 0; - Utils::write_log("Populate users vector finished!"); // Populate titles vector this->titles = Utils::NX::getTitleObjects(this->users); @@ -91,28 +81,24 @@ namespace Main { this->titles.push_back(title); } this->titleIdx = 0; - Utils::write_log("Populate titles vector finished!"); // Create Aether instance (ignore log messages for now) this->window = new Aether::Window("NX-Activity-Log", 1280, 720, [](const std::string message, const bool important) { }); // this->window->showDebugInfo(true); - Utils::write_log("Create Aether instance finished!"); // Create overlays this->dtpicker = nullptr; this->periodpicker = new Aether::PopupList("common.view.heading"_lang); this->periodpicker->setBackLabel("common.buttonHint.back"_lang); this->periodpicker->setOKLabel("common.buttonHint.ok"_lang); - Utils::write_log("Create overlays finished!"); // Setup screens this->setDisplayTheme(); this->createReason = ScreenCreate::Normal; this->createScreens(); this->reinitScreens_ = ReinitState::False; - Utils::write_log("Setup screens finished!"); if (this->isUserPage_) { // Skip UserSelect screen if launched via user page @@ -123,7 +109,6 @@ namespace Main { this->window->setFadeOut(true); this->setScreen(ScreenID::UserSelect); } - Utils::write_log("Start screens finished!"); } void Application::checkForUpdate() { @@ -470,16 +455,13 @@ namespace Main { // Check if screens should be recreated if (this->reinitScreens_ == ReinitState::Wait) { this->reinitScreens_ = ReinitState::True; - Utils::write_log("Waiting for reinit screens..."); } else if (this->reinitScreens_ == ReinitState::True) { - Utils::write_log("Reinit screens start!"); this->reinitScreens_ = ReinitState::False; this->window->removeScreen(); this->deleteScreens(); this->setDisplayTheme(); this->createScreens(); this->setScreen(this->screen); - Utils::write_log("Reinit screens finished!"); } } } diff --git a/Application/source/nx/PlayData.cpp b/Application/source/nx/PlayData.cpp index fdfe3e0..1becee6 100644 --- a/Application/source/nx/PlayData.cpp +++ b/Application/source/nx/PlayData.cpp @@ -165,8 +165,6 @@ namespace NX { } PlayEventsAndSummaries PlayData::readPlayDataFromPdm() { - Utils::write_log("readPlayDataFromPdm() enter"); - PlayEventsAndSummaries ret; // Position of first event to read @@ -275,17 +273,14 @@ namespace NX { } #endif - Utils::write_log("readPlayDataFromPdm() exit"); return ret; } PlayEventsAndSummaries PlayData::readPlayDataFromImport() { PlayEventsAndSummaries ret; - Utils::write_log("readPlayDataFromImport() enter"); // Abort if no file if (!std::filesystem::exists("/switch/NX-Activity-Log/importedData.json")) { - Utils::write_log("readPlayDataFromImport() exit"); return ret; } @@ -351,18 +346,13 @@ namespace NX { } } } - - Utils::write_log("Parse user data from importedData.json finished!"); } - - Utils::write_log("readPlayDataFromImport() exit"); return ret; } std::vector<PlayEvent *> PlayData::mergePlayEvents(std::vector<PlayEvent *> & one, std::vector<PlayEvent *> & two) { std::vector<PlayEvent *> merged = one; - Utils::write_log("mergePlayEvents enter"); for (PlayEvent * event : two) { std::vector<PlayEvent *>::iterator it = std::find_if(one.begin(), one.end(), [event](PlayEvent * pot) { return (event->type == pot->type && event->titleID == pot->titleID && @@ -379,7 +369,6 @@ namespace NX { one.clear(); two.clear(); - Utils::write_log("mergePlayEvents exit"); return merged; } @@ -395,10 +384,8 @@ namespace NX { PlayEventsAndSummaries pdmData = pdmThread.get(); PlayEventsAndSummaries impData = impThread.get(); - Utils::write_log("Read in all data simultaneously finished"); this->events = this->mergePlayEvents(pdmData.first, impData.first); this->summaries = impData.second; - Utils::write_log("mergePlayEvents() finished"); } std::vector<Title *> PlayData::getMissingTitles(std::vector<Title *> passed) { @@ -507,8 +494,17 @@ namespace NX { PdmPlayStatistics tmp; pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(titleID, userID, false, &tmp); PlayStatistics * stats = new PlayStatistics; - stats->firstPlayed = tmp.first_timestamp_user; - stats->lastPlayed = tmp.last_timestamp_user; + if (tmp.first_timestamp_user != 0 && tmp.last_timestamp_user != 0) { + stats->firstPlayed = tmp.first_timestamp_user; + stats->lastPlayed = tmp.last_timestamp_user; + } else { + auto it = std::find_if(this->summaries.begin(), this->summaries.end(), [titleID](auto s){ return (s->titleID == titleID); }); + if (it != this->summaries.end()) { + stats->firstPlayed = (*it)->firstPlayed; + stats->lastPlayed = (*it)->lastPlayed; + } + } + stats->playtime = tmp.playtime / 1000 / 1000 / 1000; //the unit of playtime in PdmPlayStatistics is ns stats->launches = tmp.total_launches; return stats; diff --git a/Application/source/ui/screen/AllActivity.cpp b/Application/source/ui/screen/AllActivity.cpp index 17bdb64..896a167 100644 --- a/Application/source/ui/screen/AllActivity.cpp +++ b/Application/source/ui/screen/AllActivity.cpp @@ -142,7 +142,7 @@ namespace Screen { totalSecs += ps->playtime; if (ps->launches == 0) { // Add in dummy data if not launched before (due to adjustment) - ps2->firstPlayed = Utils::Time::posixTimestampToPdm(Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime())); + ps2->firstPlayed = Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime()); ps2->lastPlayed = ps2->firstPlayed; ps->launches = 1; diff --git a/Application/source/ui/screen/Details.cpp b/Application/source/ui/screen/Details.cpp index a872934..80b6996 100644 --- a/Application/source/ui/screen/Details.cpp +++ b/Application/source/ui/screen/Details.cpp @@ -4,7 +4,6 @@ #include "ui/element/ListSession.hpp" #include "utils/Utils.hpp" #include "utils/Time.hpp" -#include "utils/Debug.hpp" // Values for summary appearance #define SUMMARY_BOX_HEIGHT 60 @@ -656,7 +655,7 @@ namespace Screen { if (ps->launches == 0) { // Add in dummy data if not launched before (due to adjustment) - pss->firstPlayed = Utils::Time::posixTimestampToPdm(Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime())); + pss->firstPlayed = Utils::Time::getTimeT(Utils::Time::getTmForCurrentTime()); pss->lastPlayed = pss->firstPlayed; ps->launches = 1; } diff --git a/Application/source/ui/screen/Settings.cpp b/Application/source/ui/screen/Settings.cpp index ef37656..1f821b3 100644 --- a/Application/source/ui/screen/Settings.cpp +++ b/Application/source/ui/screen/Settings.cpp @@ -239,38 +239,14 @@ namespace Screen { } void Settings::showDeleteImportedOverlay() { - // Create msgbox - this->prepareMessageBox(); - this->msgbox->addLeftButton("common.buttonHint.cancel"_lang, [this]() { - this->msgbox->close(); - }); - this->msgbox->addRightButton("common.delete"_lang, [this](){ - // Delete file - std::filesystem::remove("/switch/NX-Activity-Log/importedData.json"); - - // Disable button + // Update delete button status + bool hasData = std::filesystem::exists("/switch/NX-Activity-Log/importedData.json"); + if (!hasData) { this->optionDeleteImport->setTextColour(this->app->theme()->mutedLine()); this->optionDeleteImport->setSelectable(false); this->optionDeleteImport->setTouchable(false); - this->list->setFocused(this->optionHide); - - this->msgbox->close(); this->setupGenericMessageOverlay("settings.importExport.deleteSuccessful"_lang); - }); - - // Add message box body - int bw, bh; - this->msgbox->getBodySize(&bw, &bh); - Aether::Element * body = new Aether::Element(0, 0, bw, bh); - Aether::TextBlock * tb = new Aether::TextBlock(50, 40, "settings.importExport.confirmDelete"_lang, 24, bw - 100); - tb->setColour(this->app->theme()->text()); - body->addElement(tb); - tb = new Aether::TextBlock(50, tb->y() + tb->h() + 20, "settings.importExport.confirmDeleteBody"_lang, 20, bw - 100); - tb->setColour(this->app->theme()->mutedText()); - body->addElement(tb); - this->msgbox->setBodySize(bw, tb->y() + tb->h() + 40); - this->msgbox->setBody(body); - this->app->addOverlay(this->msgbox); + } } void Settings::update(uint32_t dt) { @@ -519,6 +495,8 @@ namespace Screen { // DELETE IMPORTED DATA bool hasData = std::filesystem::exists("/switch/NX-Activity-Log/importedData.json"); this->optionDeleteImport = new Aether::ListButton("settings.importExport.deleteImport"_lang, [this]() { + // Delete file + std::filesystem::remove("/switch/NX-Activity-Log/importedData.json"); this->showDeleteImportedOverlay(); }); this->optionDeleteImport->setLineColour(this->app->theme()->mutedLine()); From cc843061284ae68f133352109f8318c4343f178d Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Sun, 24 Nov 2024 16:16:18 +0800 Subject: [PATCH 36/37] fixed big when creating messageboxes and updated for full translations Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/romfs/lang | 2 +- Application/source/ui/screen/Settings.cpp | 38 ++++++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Application/romfs/lang b/Application/romfs/lang index c55046b..4b80787 160000 --- a/Application/romfs/lang +++ b/Application/romfs/lang @@ -1 +1 @@ -Subproject commit c55046b142f5e751a7849c6fd07052457282ebda +Subproject commit 4b807874cd3d1ffb85513552baa873e9f18004d8 diff --git a/Application/source/ui/screen/Settings.cpp b/Application/source/ui/screen/Settings.cpp index 1f821b3..8c7a525 100644 --- a/Application/source/ui/screen/Settings.cpp +++ b/Application/source/ui/screen/Settings.cpp @@ -95,7 +95,7 @@ namespace Screen { } void Settings::prepareMessageBox() { - delete this->msgbox; + //delete this->msgbox; this->msgbox = new Aether::MessageBox(); this->msgbox->setLineColour(this->app->theme()->mutedLine()); this->msgbox->setRectangleColour(this->app->theme()->altBG()); @@ -239,14 +239,38 @@ namespace Screen { } void Settings::showDeleteImportedOverlay() { - // Update delete button status - bool hasData = std::filesystem::exists("/switch/NX-Activity-Log/importedData.json"); - if (!hasData) { + // Create msgbox + this->prepareMessageBox(); + this->msgbox->addLeftButton("common.buttonHint.cancel"_lang, [this]() { + this->msgbox->close(); + }); + // Add message box body + int bw, bh; + this->msgbox->getBodySize(&bw, &bh); + Aether::Element * body = new Aether::Element(0, 0, bw, bh); + Aether::TextBlock * tb = new Aether::TextBlock(50, 40, "settings.importExport.confirmDelete"_lang, 24, bw - 100); + tb->setColour(this->app->theme()->text()); + body->addElement(tb); + tb = new Aether::TextBlock(50, tb->y() + tb->h() + 20, "settings.importExport.confirmDeleteBody"_lang, 20, bw - 100); + tb->setColour(this->app->theme()->mutedText()); + body->addElement(tb); + this->msgbox->setBodySize(bw, tb->y() + tb->h() + 40); + this->msgbox->setBody(body); + this->msgbox->addRightButton("common.delete"_lang, [this](){ + // Delete file + std::filesystem::remove("/switch/NX-Activity-Log/importedData.json"); + + // Disable button this->optionDeleteImport->setTextColour(this->app->theme()->mutedLine()); this->optionDeleteImport->setSelectable(false); this->optionDeleteImport->setTouchable(false); + this->list->setFocused(this->optionHide); + + this->msgbox->close(); this->setupGenericMessageOverlay("settings.importExport.deleteSuccessful"_lang); - } + }); + + this->app->addOverlay(this->msgbox); } void Settings::update(uint32_t dt) { @@ -495,8 +519,6 @@ namespace Screen { // DELETE IMPORTED DATA bool hasData = std::filesystem::exists("/switch/NX-Activity-Log/importedData.json"); this->optionDeleteImport = new Aether::ListButton("settings.importExport.deleteImport"_lang, [this]() { - // Delete file - std::filesystem::remove("/switch/NX-Activity-Log/importedData.json"); this->showDeleteImportedOverlay(); }); this->optionDeleteImport->setLineColour(this->app->theme()->mutedLine()); @@ -617,4 +639,4 @@ namespace Screen { delete this->popuplist; delete this->progressbox; } -}; +}; \ No newline at end of file From 3888470b1eb109b5c4e2c778674dddcfcbbab252 Mon Sep 17 00:00:00 2001 From: Damien Zhao <zdm65477730@126.com> Date: Sun, 24 Nov 2024 16:16:59 +0800 Subject: [PATCH 37/37] bump to v1.5.4 Signed-off-by: Damien Zhao <zdm65477730@126.com> --- Application/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Application/Makefile b/Application/Makefile index 8b2bf0f..9e4f105 100644 --- a/Application/Makefile +++ b/Application/Makefile @@ -43,7 +43,7 @@ FORWARDER := $(ROMFS)/exefs.nsp #--------------------------------------------------------------------------------- VER_MAJOR := 1 VER_MINOR := 5 -VER_MICRO := 3 +VER_MICRO := 4 #--------------------------------------------------------------------------------- # Options for .nacp information