finish refactor, add docs and CI
This commit is contained in:
+25
-26
@@ -24,16 +24,17 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <nxst/domain/account.hpp>
|
||||
#include <sys/stat.h>
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <nxst/domain/account.hpp>
|
||||
|
||||
static std::map<AccountUid, User> mUsers;
|
||||
|
||||
Result Account::init(void)
|
||||
{
|
||||
Result Account::init(void) {
|
||||
Result res = accountInitialize(AccountServiceType_Application);
|
||||
if (R_FAILED(res)) return res;
|
||||
if (R_FAILED(res))
|
||||
return res;
|
||||
|
||||
AccountUid uids[8];
|
||||
s32 count = 0;
|
||||
@@ -44,13 +45,11 @@ Result Account::init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Account::exit(void)
|
||||
{
|
||||
void Account::exit(void) {
|
||||
accountExit();
|
||||
}
|
||||
|
||||
std::vector<AccountUid> Account::ids(void)
|
||||
{
|
||||
std::vector<AccountUid> Account::ids(void) {
|
||||
std::vector<AccountUid> v;
|
||||
for (auto& value : mUsers) {
|
||||
v.push_back(value.second.id);
|
||||
@@ -58,8 +57,7 @@ std::vector<AccountUid> Account::ids(void)
|
||||
return v;
|
||||
}
|
||||
|
||||
static User getUser(AccountUid id)
|
||||
{
|
||||
static User getUser(AccountUid id) {
|
||||
User user{id, ""};
|
||||
AccountProfile profile;
|
||||
AccountProfileBase profilebase;
|
||||
@@ -74,8 +72,7 @@ static User getUser(AccountUid id)
|
||||
return user;
|
||||
}
|
||||
|
||||
std::string Account::username(AccountUid id)
|
||||
{
|
||||
std::string Account::username(AccountUid id) {
|
||||
std::map<AccountUid, User>::const_iterator got = mUsers.find(id);
|
||||
if (got == mUsers.end()) {
|
||||
User user = getUser(id);
|
||||
@@ -86,21 +83,21 @@ std::string Account::username(AccountUid id)
|
||||
return got->second.name;
|
||||
}
|
||||
|
||||
std::string Account::iconPath(AccountUid id)
|
||||
{
|
||||
std::string Account::iconPath(AccountUid id) {
|
||||
char path[128];
|
||||
snprintf(path, sizeof(path), "sdmc:/switch/NXST/cache/%016lX%016lX.jpg",
|
||||
id.uid[0], id.uid[1]);
|
||||
snprintf(path, sizeof(path), "sdmc:/switch/NXST/cache/%016lX%016lX.jpg", id.uid[0], id.uid[1]);
|
||||
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0 && st.st_size > 0) return std::string(path);
|
||||
if (stat(path, &st) == 0 && st.st_size > 0)
|
||||
return std::string(path);
|
||||
|
||||
mkdir("sdmc:/switch", 0755);
|
||||
mkdir("sdmc:/switch/NXST", 0755);
|
||||
mkdir("sdmc:/switch/NXST/cache", 0755);
|
||||
|
||||
AccountProfile profile;
|
||||
if (R_FAILED(accountGetProfile(&profile, id))) return "";
|
||||
if (R_FAILED(accountGetProfile(&profile, id)))
|
||||
return "";
|
||||
|
||||
u32 imgSize = 0;
|
||||
if (R_FAILED(accountProfileGetImageSize(&profile, &imgSize)) || imgSize == 0) {
|
||||
@@ -112,26 +109,28 @@ std::string Account::iconPath(AccountUid id)
|
||||
u32 outSize = 0;
|
||||
Result r = accountProfileLoadImage(&profile, buf.data(), imgSize, &outSize);
|
||||
accountProfileClose(&profile);
|
||||
if (R_FAILED(r) || outSize == 0) return "";
|
||||
if (R_FAILED(r) || outSize == 0)
|
||||
return "";
|
||||
|
||||
FILE* f = fopen(path, "wb");
|
||||
if (!f) return "";
|
||||
if (!f)
|
||||
return "";
|
||||
fwrite(buf.data(), 1, outSize, f);
|
||||
fclose(f);
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
AccountUid Account::selectAccount(void)
|
||||
{
|
||||
AccountUid Account::selectAccount(void) {
|
||||
LibAppletArgs args;
|
||||
libappletArgsCreate(&args, 0x10000);
|
||||
u8 st_in[0xA0] = {0};
|
||||
u8 st_in[0xA0] = {0};
|
||||
u8 st_out[0x18] = {0};
|
||||
size_t repsz;
|
||||
|
||||
Result res = libappletLaunch(AppletId_LibraryAppletPlayerSelect, &args, st_in, 0xA0, st_out, 0x18, &repsz);
|
||||
Result res =
|
||||
libappletLaunch(AppletId_LibraryAppletPlayerSelect, &args, st_in, 0xA0, st_out, 0x18, &repsz);
|
||||
if (R_SUCCEEDED(res)) {
|
||||
u64 lres = *(u64*)st_out;
|
||||
u64 lres = *(u64*)st_out;
|
||||
AccountUid uid = *(AccountUid*)&st_out[8];
|
||||
if (lres == 0)
|
||||
return uid;
|
||||
|
||||
+25
-28
@@ -26,8 +26,7 @@
|
||||
|
||||
#include <nxst/domain/common.hpp>
|
||||
|
||||
std::string DateTime::timeStr(void)
|
||||
{
|
||||
std::string DateTime::timeStr(void) {
|
||||
time_t unixTime;
|
||||
struct tm timeStruct;
|
||||
time(&unixTime);
|
||||
@@ -35,35 +34,32 @@ std::string DateTime::timeStr(void)
|
||||
return StringUtils::format("%02i:%02i:%02i", timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
|
||||
}
|
||||
|
||||
std::string DateTime::dateTimeStr(void)
|
||||
{
|
||||
std::string DateTime::dateTimeStr(void) {
|
||||
time_t unixTime;
|
||||
struct tm timeStruct;
|
||||
time(&unixTime);
|
||||
localtime_r(&unixTime, &timeStruct);
|
||||
return StringUtils::format("%04i%02i%02i-%02i%02i%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour,
|
||||
timeStruct.tm_min, timeStruct.tm_sec);
|
||||
return StringUtils::format("%04i%02i%02i-%02i%02i%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1,
|
||||
timeStruct.tm_mday, timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
|
||||
}
|
||||
|
||||
std::string DateTime::logDateTime(void)
|
||||
{
|
||||
std::string DateTime::logDateTime(void) {
|
||||
time_t unixTime;
|
||||
struct tm timeStruct;
|
||||
time(&unixTime);
|
||||
localtime_r(&unixTime, &timeStruct);
|
||||
return StringUtils::format("%04i-%02i-%02i %02i:%02i:%02i", timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday,
|
||||
timeStruct.tm_hour, timeStruct.tm_min, timeStruct.tm_sec);
|
||||
return StringUtils::format("%04i-%02i-%02i %02i:%02i:%02i", timeStruct.tm_year + 1900,
|
||||
timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour,
|
||||
timeStruct.tm_min, timeStruct.tm_sec);
|
||||
}
|
||||
|
||||
std::string StringUtils::UTF16toUTF8(const std::u16string& src)
|
||||
{
|
||||
std::string StringUtils::UTF16toUTF8(const std::u16string& src) {
|
||||
static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
std::string dst = convert.to_bytes(src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
std::string StringUtils::removeForbiddenCharacters(std::string src)
|
||||
{
|
||||
std::string StringUtils::removeForbiddenCharacters(std::string src) {
|
||||
static const std::string illegalChars = ".,!\\/:?*\"<>|";
|
||||
for (size_t i = 0, sz = src.length(); i < sz; i++) {
|
||||
if (illegalChars.find(src[i]) != std::string::npos) {
|
||||
@@ -79,8 +75,7 @@ std::string StringUtils::removeForbiddenCharacters(std::string src)
|
||||
return src;
|
||||
}
|
||||
|
||||
std::string StringUtils::format(const std::string fmt_str, ...)
|
||||
{
|
||||
std::string StringUtils::format(const std::string fmt_str, ...) {
|
||||
va_list ap;
|
||||
char* fp = NULL;
|
||||
va_start(ap, fmt_str);
|
||||
@@ -90,8 +85,7 @@ std::string StringUtils::format(const std::string fmt_str, ...)
|
||||
return std::string(formatted.get());
|
||||
}
|
||||
|
||||
bool StringUtils::containsInvalidChar(const std::string& str)
|
||||
{
|
||||
bool StringUtils::containsInvalidChar(const std::string& str) {
|
||||
for (size_t i = 0, sz = str.length(); i < sz; i++) {
|
||||
if (!isascii(str[i])) {
|
||||
return true;
|
||||
@@ -100,24 +94,27 @@ bool StringUtils::containsInvalidChar(const std::string& str)
|
||||
return false;
|
||||
}
|
||||
|
||||
void StringUtils::ltrim(std::string& s)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); }));
|
||||
void StringUtils::ltrim(std::string& s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
|
||||
return !std::isspace(ch);
|
||||
}));
|
||||
}
|
||||
|
||||
void StringUtils::rtrim(std::string& s)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end());
|
||||
void StringUtils::rtrim(std::string& s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||
[](int ch) {
|
||||
return !std::isspace(ch);
|
||||
})
|
||||
.base(),
|
||||
s.end());
|
||||
}
|
||||
|
||||
void StringUtils::trim(std::string& s)
|
||||
{
|
||||
void StringUtils::trim(std::string& s) {
|
||||
ltrim(s);
|
||||
rtrim(s);
|
||||
}
|
||||
|
||||
char* getConsoleIP(void)
|
||||
{
|
||||
char* getConsoleIP(void) {
|
||||
struct in_addr in;
|
||||
in.s_addr = gethostid();
|
||||
return inet_ntoa(in);
|
||||
|
||||
+89
-112
@@ -24,40 +24,39 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <nxst/domain/title.hpp>
|
||||
#include <nxst/app/main.hpp>
|
||||
#include <nxst/domain/title.hpp>
|
||||
|
||||
static std::unordered_map<AccountUid, std::vector<Title>> titles;
|
||||
static bool s_titlesLoaded = false;
|
||||
|
||||
bool areTitlesLoaded(void)
|
||||
{
|
||||
bool areTitlesLoaded(void) {
|
||||
return s_titlesLoaded;
|
||||
}
|
||||
|
||||
void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string& name, const std::string& author)
|
||||
{
|
||||
mId = id;
|
||||
mUserId = userID;
|
||||
void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string& name,
|
||||
const std::string& author) {
|
||||
mId = id;
|
||||
mUserId = userID;
|
||||
mSaveDataType = saveDataType;
|
||||
mUserName = Account::username(userID);
|
||||
mAuthor = author;
|
||||
mName = name;
|
||||
mSafeName = StringUtils::containsInvalidChar(name) ? StringUtils::format("0x%016llX", mId) : StringUtils::removeForbiddenCharacters(name);
|
||||
mPath = "sdmc:/switch/NXST/saves/" + StringUtils::format("0x%016llX", mId) + " " + mSafeName;
|
||||
mUserName = Account::username(userID);
|
||||
mAuthor = author;
|
||||
mName = name;
|
||||
mSafeName = StringUtils::containsInvalidChar(name) ? StringUtils::format("0x%016llX", mId)
|
||||
: StringUtils::removeForbiddenCharacters(name);
|
||||
mPath = "sdmc:/switch/NXST/saves/" + StringUtils::format("0x%016llX", mId) + " " + mSafeName;
|
||||
|
||||
std::string aname = StringUtils::removeAccents(mName);
|
||||
size_t pos = aname.rfind(":");
|
||||
mDisplayName = std::make_pair(aname, "");
|
||||
size_t pos = aname.rfind(":");
|
||||
mDisplayName = std::make_pair(aname, "");
|
||||
if (pos != std::string::npos) {
|
||||
std::string name1 = aname.substr(0, pos);
|
||||
std::string name2 = aname.substr(pos + 1);
|
||||
StringUtils::trim(name1);
|
||||
StringUtils::trim(name2);
|
||||
mDisplayName.first = name1;
|
||||
mDisplayName.first = name1;
|
||||
mDisplayName.second = name2;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// check for parenthesis
|
||||
size_t pos1 = aname.rfind("(");
|
||||
size_t pos2 = aname.rfind(")");
|
||||
@@ -66,7 +65,7 @@ void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string&
|
||||
std::string name2 = aname.substr(pos1 + 1, pos2 - 1 - pos1);
|
||||
StringUtils::trim(name1);
|
||||
StringUtils::trim(name2);
|
||||
mDisplayName.first = name1;
|
||||
mDisplayName.first = name1;
|
||||
mDisplayName.second = name2;
|
||||
}
|
||||
}
|
||||
@@ -74,94 +73,77 @@ void Title::init(u8 saveDataType, u64 id, AccountUid userID, const std::string&
|
||||
refreshDirectories();
|
||||
}
|
||||
|
||||
u8 Title::saveDataType(void)
|
||||
{
|
||||
u8 Title::saveDataType(void) {
|
||||
return mSaveDataType;
|
||||
}
|
||||
|
||||
u64 Title::id(void)
|
||||
{
|
||||
u64 Title::id(void) {
|
||||
return mId;
|
||||
}
|
||||
|
||||
u64 Title::saveId(void)
|
||||
{
|
||||
u64 Title::saveId(void) {
|
||||
return mSaveId;
|
||||
}
|
||||
|
||||
void Title::saveId(u64 saveId)
|
||||
{
|
||||
void Title::saveId(u64 saveId) {
|
||||
mSaveId = saveId;
|
||||
}
|
||||
|
||||
AccountUid Title::userId(void)
|
||||
{
|
||||
AccountUid Title::userId(void) {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
std::string Title::userName(void)
|
||||
{
|
||||
std::string Title::userName(void) {
|
||||
return mUserName;
|
||||
}
|
||||
|
||||
std::string Title::author(void)
|
||||
{
|
||||
std::string Title::author(void) {
|
||||
return mAuthor;
|
||||
}
|
||||
|
||||
std::string Title::name(void)
|
||||
{
|
||||
std::string Title::name(void) {
|
||||
return mName;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> Title::displayName(void)
|
||||
{
|
||||
std::pair<std::string, std::string> Title::displayName(void) {
|
||||
return mDisplayName;
|
||||
}
|
||||
|
||||
std::string Title::path(void)
|
||||
{
|
||||
std::string Title::path(void) {
|
||||
return mPath;
|
||||
}
|
||||
|
||||
std::string Title::fullPath(size_t index)
|
||||
{
|
||||
std::string Title::fullPath(size_t index) {
|
||||
return mFullSavePaths.at(index);
|
||||
}
|
||||
|
||||
std::vector<std::string> Title::saves()
|
||||
{
|
||||
std::vector<std::string> Title::saves() {
|
||||
return mSaves;
|
||||
}
|
||||
|
||||
u64 Title::playTimeNanoseconds(void)
|
||||
{
|
||||
u64 Title::playTimeNanoseconds(void) {
|
||||
return mPlayTimeNanoseconds;
|
||||
}
|
||||
|
||||
std::string Title::playTime(void)
|
||||
{
|
||||
std::string Title::playTime(void) {
|
||||
const u64 playTimeMinutes = mPlayTimeNanoseconds / 60000000000;
|
||||
return StringUtils::format("%d", playTimeMinutes / 60) + ":" + StringUtils::format("%02d", playTimeMinutes % 60) + " hours";
|
||||
return StringUtils::format("%d", playTimeMinutes / 60) + ":" +
|
||||
StringUtils::format("%02d", playTimeMinutes % 60) + " hours";
|
||||
}
|
||||
|
||||
void Title::playTimeNanoseconds(u64 playTimeNanoseconds)
|
||||
{
|
||||
void Title::playTimeNanoseconds(u64 playTimeNanoseconds) {
|
||||
mPlayTimeNanoseconds = playTimeNanoseconds;
|
||||
}
|
||||
|
||||
u32 Title::lastPlayedTimestamp(void)
|
||||
{
|
||||
u32 Title::lastPlayedTimestamp(void) {
|
||||
return mLastPlayedTimestamp;
|
||||
}
|
||||
|
||||
void Title::lastPlayedTimestamp(u32 lastPlayedTimestamp)
|
||||
{
|
||||
void Title::lastPlayedTimestamp(u32 lastPlayedTimestamp) {
|
||||
mLastPlayedTimestamp = lastPlayedTimestamp;
|
||||
}
|
||||
|
||||
void Title::refreshDirectories(void)
|
||||
{
|
||||
void Title::refreshDirectories(void) {
|
||||
mSaves.clear();
|
||||
mFullSavePaths.clear();
|
||||
|
||||
@@ -178,15 +160,15 @@ void Title::refreshDirectories(void)
|
||||
std::sort(mFullSavePaths.rbegin(), mFullSavePaths.rend());
|
||||
mSaves.insert(mSaves.begin(), g_emptySave);
|
||||
mFullSavePaths.insert(mFullSavePaths.begin(), g_emptySave);
|
||||
}
|
||||
else {
|
||||
Logger::getInstance().log(Logger::ERROR, "Couldn't retrieve the extdata directory list for the title " + name());
|
||||
} else {
|
||||
Logger::getInstance().log(Logger::ERROR,
|
||||
"Couldn't retrieve the extdata directory list for the title " + name());
|
||||
}
|
||||
}
|
||||
|
||||
void loadTitles(void)
|
||||
{
|
||||
if (s_titlesLoaded) return;
|
||||
void loadTitles(void) {
|
||||
if (s_titlesLoaded)
|
||||
return;
|
||||
s_titlesLoaded = true;
|
||||
|
||||
titles.clear();
|
||||
@@ -194,9 +176,9 @@ void loadTitles(void)
|
||||
FsSaveDataInfoReader reader;
|
||||
FsSaveDataInfo info;
|
||||
s64 total_entries = 0;
|
||||
size_t outsize = 0;
|
||||
size_t outsize = 0;
|
||||
|
||||
NacpLanguageEntry* nle = NULL;
|
||||
NacpLanguageEntry* nle = NULL;
|
||||
NsApplicationControlData* nsacd = (NsApplicationControlData*)malloc(sizeof(NsApplicationControlData));
|
||||
if (nsacd == NULL) {
|
||||
return;
|
||||
@@ -216,43 +198,44 @@ void loadTitles(void)
|
||||
}
|
||||
|
||||
if (info.save_data_type == FsSaveDataType_Account) {
|
||||
u64 tid = info.application_id;
|
||||
u64 sid = info.save_data_id;
|
||||
u64 tid = info.application_id;
|
||||
u64 sid = info.save_data_id;
|
||||
AccountUid uid = info.uid;
|
||||
// if (mFilterIds.find(tid) == mFilterIds.end()) {
|
||||
res = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, nsacd, sizeof(NsApplicationControlData), &outsize);
|
||||
if (R_SUCCEEDED(res) && !(outsize < sizeof(nsacd->nacp))) {
|
||||
res = nacpGetLanguageEntry(&nsacd->nacp, &nle);
|
||||
if (R_SUCCEEDED(res) && nle != NULL) {
|
||||
Title title;
|
||||
title.init(info.save_data_type, tid, uid, std::string(nle->name), std::string(nle->author));
|
||||
title.saveId(sid);
|
||||
res = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, nsacd,
|
||||
sizeof(NsApplicationControlData), &outsize);
|
||||
if (R_SUCCEEDED(res) && !(outsize < sizeof(nsacd->nacp))) {
|
||||
res = nacpGetLanguageEntry(&nsacd->nacp, &nle);
|
||||
if (R_SUCCEEDED(res) && nle != NULL) {
|
||||
Title title;
|
||||
title.init(info.save_data_type, tid, uid, std::string(nle->name),
|
||||
std::string(nle->author));
|
||||
title.saveId(sid);
|
||||
|
||||
// load play statistics
|
||||
PdmPlayStatistics stats;
|
||||
res = pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(tid, uid, false, &stats);
|
||||
if (R_SUCCEEDED(res)) {
|
||||
title.playTimeNanoseconds(stats.playtime);
|
||||
title.lastPlayedTimestamp(stats.last_timestamp_user);
|
||||
}
|
||||
// load play statistics
|
||||
PdmPlayStatistics stats;
|
||||
res = pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(tid, uid, false, &stats);
|
||||
if (R_SUCCEEDED(res)) {
|
||||
title.playTimeNanoseconds(stats.playtime);
|
||||
title.lastPlayedTimestamp(stats.last_timestamp_user);
|
||||
}
|
||||
|
||||
// loadIcon(tid, nsacd, outsize - sizeof(nsacd->nacp));
|
||||
// loadIcon(tid, nsacd, outsize - sizeof(nsacd->nacp));
|
||||
|
||||
// check if the vector is already created
|
||||
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
|
||||
if (it != titles.end()) {
|
||||
// found
|
||||
it->second.push_back(title);
|
||||
}
|
||||
else {
|
||||
// not found, insert into map
|
||||
std::vector<Title> v;
|
||||
v.push_back(title);
|
||||
titles.emplace(uid, v);
|
||||
}
|
||||
// check if the vector is already created
|
||||
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
|
||||
if (it != titles.end()) {
|
||||
// found
|
||||
it->second.push_back(title);
|
||||
} else {
|
||||
// not found, insert into map
|
||||
std::vector<Title> v;
|
||||
v.push_back(title);
|
||||
titles.emplace(uid, v);
|
||||
}
|
||||
}
|
||||
nle = NULL;
|
||||
}
|
||||
nle = NULL;
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -263,45 +246,40 @@ void loadTitles(void)
|
||||
sortTitles();
|
||||
}
|
||||
|
||||
void sortTitles(void)
|
||||
{
|
||||
void sortTitles(void) {
|
||||
for (auto& vect : titles) {
|
||||
std::sort(vect.second.begin(), vect.second.end(), [](Title& l, Title& r) {
|
||||
switch (g_sortMode) {
|
||||
case SORT_LAST_PLAYED:
|
||||
return l.lastPlayedTimestamp() > r.lastPlayedTimestamp();
|
||||
case SORT_PLAY_TIME:
|
||||
return l.playTimeNanoseconds() > r.playTimeNanoseconds();
|
||||
case SORT_ALPHA:
|
||||
default:
|
||||
return l.name() < r.name();
|
||||
case SORT_LAST_PLAYED:
|
||||
return l.lastPlayedTimestamp() > r.lastPlayedTimestamp();
|
||||
case SORT_PLAY_TIME:
|
||||
return l.playTimeNanoseconds() > r.playTimeNanoseconds();
|
||||
case SORT_ALPHA:
|
||||
default:
|
||||
return l.name() < r.name();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void rotateSortMode(void)
|
||||
{
|
||||
void rotateSortMode(void) {
|
||||
g_sortMode = static_cast<sort_t>((g_sortMode + 1) % SORT_MODES_COUNT);
|
||||
sortTitles();
|
||||
}
|
||||
|
||||
void getTitle(Title& dst, AccountUid uid, size_t i)
|
||||
{
|
||||
void getTitle(Title& dst, AccountUid uid, size_t i) {
|
||||
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
|
||||
if (it != titles.end() && i < getTitleCount(uid)) {
|
||||
dst = it->second.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
size_t getTitleCount(AccountUid uid)
|
||||
{
|
||||
size_t getTitleCount(AccountUid uid) {
|
||||
std::unordered_map<AccountUid, std::vector<Title>>::iterator it = titles.find(uid);
|
||||
return it != titles.end() ? it->second.size() : 0;
|
||||
}
|
||||
|
||||
void refreshDirectories(u64 id)
|
||||
{
|
||||
void refreshDirectories(u64 id) {
|
||||
for (auto& pair : titles) {
|
||||
for (size_t i = 0; i < pair.second.size(); i++) {
|
||||
if (pair.second.at(i).id() == id) {
|
||||
@@ -311,8 +289,7 @@ void refreshDirectories(u64 id)
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> getCompleteTitleList(void)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> getCompleteTitleList(void) {
|
||||
std::unordered_map<std::string, std::string> map;
|
||||
for (const auto& pair : titles) {
|
||||
for (auto value : pair.second) {
|
||||
|
||||
+30
-36
@@ -24,21 +24,19 @@
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <nxst/app/main.hpp>
|
||||
#include <nxst/app/main_application.hpp>
|
||||
#include <nxst/domain/util.hpp>
|
||||
#include <nxst/infra/sys/logger.hpp>
|
||||
#include <nxst/app/main_application.hpp>
|
||||
#include <nxst/app/main.hpp>
|
||||
|
||||
void servicesExit(void)
|
||||
{
|
||||
void servicesExit(void) {
|
||||
Logger::getInstance().flush();
|
||||
Account::exit();
|
||||
plExit();
|
||||
romfsExit();
|
||||
}
|
||||
|
||||
Result servicesInit(void)
|
||||
{
|
||||
Result servicesInit(void) {
|
||||
io::createDirectory("sdmc:/switch");
|
||||
io::createDirectory("sdmc:/switch/NXST");
|
||||
io::createDirectory("sdmc:/switch/NXST/saves");
|
||||
@@ -71,30 +69,28 @@ Result servicesInit(void)
|
||||
|
||||
if (R_SUCCEEDED(res = hidsysInitialize())) {
|
||||
g_notificationLedAvailable = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Logger::getInstance().log(Logger::INFO, "Notification led not available. Result code 0x{:08X}.", res);
|
||||
}
|
||||
|
||||
|
||||
Logger::getInstance().log(Logger::INFO, "NXST loading completed!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::u16string StringUtils::UTF8toUTF16(const char* src)
|
||||
{
|
||||
std::u16string StringUtils::UTF8toUTF16(const char* src) {
|
||||
char16_t tmp[256] = {0};
|
||||
utf8_to_utf16((uint16_t*)tmp, (uint8_t*)src, 256);
|
||||
return std::u16string(tmp);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/14094621/change-all-accented-letters-to-normal-letters-in-c
|
||||
std::string StringUtils::removeAccents(std::string str)
|
||||
{
|
||||
std::string StringUtils::removeAccents(std::string str) {
|
||||
std::u16string src = UTF8toUTF16(str.c_str());
|
||||
const std::u16string illegal = UTF8toUTF16("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüūýþÿ");
|
||||
const std::u16string fixed = UTF8toUTF16("AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiiOnooooo/0uuuuuypy");
|
||||
const std::u16string illegal =
|
||||
UTF8toUTF16("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüūýþÿ");
|
||||
const std::u16string fixed =
|
||||
UTF8toUTF16("AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiiOnooooo/0uuuuuypy");
|
||||
|
||||
for (size_t i = 0, sz = src.length(); i < sz; i++) {
|
||||
size_t index = illegal.find(src[i]);
|
||||
@@ -106,8 +102,7 @@ std::string StringUtils::removeAccents(std::string str)
|
||||
return UTF16toUTF8(src);
|
||||
}
|
||||
|
||||
std::string StringUtils::removeNotAscii(std::string str)
|
||||
{
|
||||
std::string StringUtils::removeNotAscii(std::string str) {
|
||||
for (size_t i = 0, sz = str.length(); i < sz; i++) {
|
||||
if (!isascii(str[i])) {
|
||||
str[i] = ' ';
|
||||
@@ -116,9 +111,9 @@ std::string StringUtils::removeNotAscii(std::string str)
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string StringUtils::elide(const std::string& s, size_t maxChars)
|
||||
{
|
||||
if (s.size() <= maxChars || maxChars < 6) return s;
|
||||
std::string StringUtils::elide(const std::string& s, size_t maxChars) {
|
||||
if (s.size() <= maxChars || maxChars < 6)
|
||||
return s;
|
||||
constexpr const char* dots = "...";
|
||||
size_t budget = maxChars - 3;
|
||||
size_t head = (budget + 1) / 2;
|
||||
@@ -126,36 +121,35 @@ std::string StringUtils::elide(const std::string& s, size_t maxChars)
|
||||
return s.substr(0, head) + dots + s.substr(s.size() - tail);
|
||||
}
|
||||
|
||||
HidsysNotificationLedPattern blinkLedPattern(u8 times)
|
||||
{
|
||||
HidsysNotificationLedPattern blinkLedPattern(u8 times) {
|
||||
HidsysNotificationLedPattern pattern;
|
||||
memset(&pattern, 0, sizeof(pattern));
|
||||
|
||||
pattern.baseMiniCycleDuration = 0x1; // 12.5ms.
|
||||
pattern.totalMiniCycles = 0x2; // 2 mini cycles.
|
||||
pattern.totalFullCycles = times; // Repeat n times.
|
||||
pattern.startIntensity = 0x0; // 0%.
|
||||
pattern.baseMiniCycleDuration = 0x1; // 12.5ms.
|
||||
pattern.totalMiniCycles = 0x2; // 2 mini cycles.
|
||||
pattern.totalFullCycles = times; // Repeat n times.
|
||||
pattern.startIntensity = 0x0; // 0%.
|
||||
|
||||
pattern.miniCycles[0].ledIntensity = 0xF; // 100%.
|
||||
pattern.miniCycles[0].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
|
||||
pattern.miniCycles[0].finalStepDuration = 0x0; // Forced 12.5ms.
|
||||
pattern.miniCycles[1].ledIntensity = 0x0; // 0%.
|
||||
pattern.miniCycles[1].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
|
||||
pattern.miniCycles[1].finalStepDuration = 0x0; // Forced 12.5ms.
|
||||
pattern.miniCycles[0].ledIntensity = 0xF; // 100%.
|
||||
pattern.miniCycles[0].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
|
||||
pattern.miniCycles[0].finalStepDuration = 0x0; // Forced 12.5ms.
|
||||
pattern.miniCycles[1].ledIntensity = 0x0; // 0%.
|
||||
pattern.miniCycles[1].transitionSteps = 0xF; // 15 steps. Total 187.5ms.
|
||||
pattern.miniCycles[1].finalStepDuration = 0x0; // Forced 12.5ms.
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
void blinkLed(u8 times)
|
||||
{
|
||||
void blinkLed(u8 times) {
|
||||
if (g_notificationLedAvailable) {
|
||||
PadState pad;
|
||||
padInitializeDefault(&pad);
|
||||
s32 n;
|
||||
HidsysUniquePadId uniquePadIds[2] = {0};
|
||||
HidsysUniquePadId uniquePadIds[2] = {0};
|
||||
HidsysNotificationLedPattern pattern = blinkLedPattern(times);
|
||||
memset(uniquePadIds, 0, sizeof(uniquePadIds));
|
||||
Result res = hidsysGetUniquePadsFromNpad(padIsHandheld(&pad) ? HidNpadIdType_Handheld : HidNpadIdType_No1, uniquePadIds, 2, &n);
|
||||
Result res = hidsysGetUniquePadsFromNpad(
|
||||
padIsHandheld(&pad) ? HidNpadIdType_Handheld : HidNpadIdType_No1, uniquePadIds, 2, &n);
|
||||
if (R_SUCCEEDED(res)) {
|
||||
for (s32 i = 0; i < n; i++) {
|
||||
hidsysSetNotificationLedPattern(&pattern, uniquePadIds[i]);
|
||||
|
||||
Reference in New Issue
Block a user