mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-03-21 17:24:37 -05:00
Add sort options
This commit is contained in:
parent
50b195f398
commit
11a382794b
2
Makefile
2
Makefile
|
|
@ -38,7 +38,7 @@ INCLUDES := inc
|
|||
EXEFS_SRC := exefs_src
|
||||
APP_TITLE := JKSV
|
||||
APP_AUTHOR := JK
|
||||
APP_VERSION := 08.04.2020
|
||||
APP_VERSION := 08.27.2020
|
||||
ROMFS := romfs
|
||||
ICON := romfs/icon.jpg
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#define curData users[data::selUser].titles[data::selData]
|
||||
|
||||
#define BLD_MON 8
|
||||
#define BLD_DAY 4
|
||||
#define BLD_DAY 27
|
||||
#define BLD_YEAR 2020
|
||||
|
||||
namespace data
|
||||
|
|
@ -72,6 +72,10 @@ namespace data
|
|||
tex *getIconFav() const { return favIcon; }
|
||||
void setPlayTime(const uint32_t& _p){ playMins = _p; }
|
||||
uint32_t getPlayTime() const { return playMins; }
|
||||
void setLastTimeStamp(const uint32_t& _ts){ lastTimeStamp = _ts; }
|
||||
uint32_t getLastTimeStamp() const { return lastTimeStamp; }
|
||||
void setLaunchCount(const uint32_t& _lc) { launchCount = _lc; }
|
||||
uint32_t getLaunchCount() const { return launchCount; }
|
||||
|
||||
private:
|
||||
tex *icon, *favIcon;
|
||||
|
|
@ -79,7 +83,7 @@ namespace data
|
|||
std::string title, titleSafe, author;
|
||||
uint64_t id, saveID;
|
||||
uint16_t saveIndex;
|
||||
uint32_t playMins;
|
||||
uint32_t playMins, lastTimeStamp, launchCount;
|
||||
bool favorite = false;
|
||||
};
|
||||
|
||||
|
|
@ -136,6 +140,7 @@ namespace data
|
|||
extern int selUser, selData;
|
||||
extern SetLanguage sysLang;
|
||||
extern bool incDev, autoBack, ovrClk, holdDel, holdRest, holdOver, forceMount, accSysSave, sysSaveWrite, directFsCmd, skipUser, zip;
|
||||
extern uint8_t sortType;
|
||||
}
|
||||
|
||||
#endif // DATA_H
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@ namespace ui
|
|||
//Strings for extras menu
|
||||
extern std::string exMenuStr[11];
|
||||
//Strings for options menu
|
||||
extern std::string optMenuStr[13];
|
||||
extern std::string optMenuStr[14];
|
||||
//Strings for options explanations
|
||||
extern std::string optMenuExp[13];
|
||||
extern std::string optMenuExp[14];
|
||||
//Strings for the holding thing
|
||||
extern std::string holdingText[3];
|
||||
//Strings for sort type
|
||||
extern std::string sortString[3];
|
||||
}
|
||||
|
||||
#endif // UISTR_H
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ optMenu = 9, "Text UI Mode: "
|
|||
optMenu = 10, "Direct FS Cmd: "
|
||||
optMenu = 11, "Skip User Select: "
|
||||
optMenu = 12, "Export to ZIP: "
|
||||
optMenu = 13, "Sort: "
|
||||
|
||||
#Explanations of what options do.
|
||||
optMenuExp = 0, "Includes Device Save data in user accounts."
|
||||
|
|
@ -122,3 +123,9 @@ optMenuExp = 9, "Changes the UI to be text menu based like the original JKSM for
|
|||
optMenuExp = 10, "Directly uses the Switch's FS commands to copy files instead of stdio."
|
||||
optMenuExp = 11, "Skips the user selection screen and jumps directly to the first user account found."
|
||||
optMenuExp = 12, "Exports saves to zip files."
|
||||
optMenuExp = 13, ""Changes the way titles are sorted and listed."
|
||||
|
||||
#Sort Types
|
||||
sortType = 0, "Alphabetical"
|
||||
sortType = 1, "Time Played"
|
||||
sortType = 2, "Last Played"
|
||||
|
|
|
|||
48
src/data.cpp
48
src/data.cpp
|
|
@ -28,6 +28,7 @@ SetLanguage data::sysLang;
|
|||
//Options
|
||||
bool data::incDev = false, data::autoBack = true, data::ovrClk = false, data::holdDel = true, data::holdRest = true, data::holdOver = true;
|
||||
bool data::forceMount = true, data::accSysSave = false, data::sysSaveWrite = false, data::directFsCmd = false, data::skipUser = false, data::zip = false;
|
||||
uint8_t data::sortType = 0;
|
||||
|
||||
//For other save types
|
||||
static bool sysBCATPushed = false, cachePushed = false, tempPushed = false;
|
||||
|
|
@ -37,23 +38,39 @@ static std::vector<uint64_t> favorites;
|
|||
static std::unordered_map<uint64_t, std::string> pathDefs;
|
||||
std::unordered_map<uint64_t, std::pair<tex *, tex *>> data::icons;
|
||||
|
||||
//Sorts titles sort-of alphabetically
|
||||
//Sorts titles by sortType
|
||||
static struct
|
||||
{
|
||||
bool operator()(const data::titledata& a, const data::titledata& b)
|
||||
{
|
||||
//Favorites override EVERYTHING
|
||||
if(a.getFav() != b.getFav()) return a.getFav();
|
||||
|
||||
uint32_t tmpA, tmpB;
|
||||
for(unsigned i = 0; i < a.getTitle().length(); )
|
||||
switch(data::sortType)
|
||||
{
|
||||
ssize_t uCnt = decode_utf8(&tmpA, (const uint8_t *)&a.getTitle().data()[i]);
|
||||
decode_utf8(&tmpB, (const uint8_t *)&b.getTitle().data()[i]);
|
||||
tmpA = tolower(tmpA), tmpB = tolower(tmpB);
|
||||
if(tmpA != tmpB)
|
||||
return tmpA < tmpB;
|
||||
case 0://Alpha
|
||||
{
|
||||
uint32_t tmpA, tmpB;
|
||||
for(unsigned i = 0; i < a.getTitle().length(); )
|
||||
{
|
||||
ssize_t uCnt = decode_utf8(&tmpA, (const uint8_t *)&a.getTitle().data()[i]);
|
||||
decode_utf8(&tmpB, (const uint8_t *)&b.getTitle().data()[i]);
|
||||
tmpA = tolower(tmpA), tmpB = tolower(tmpB);
|
||||
if(tmpA != tmpB)
|
||||
return tmpA < tmpB;
|
||||
|
||||
i += uCnt;
|
||||
i += uCnt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1://Most played
|
||||
return a.getPlayTime() > b.getPlayTime();
|
||||
break;
|
||||
|
||||
case 2://Last Played
|
||||
return a.getLastTimeStamp() > b.getLastTimeStamp();
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -312,7 +329,6 @@ void data::exit()
|
|||
|
||||
saveFav();
|
||||
saveBlackList();
|
||||
saveCfg();
|
||||
util::setCPU(1020000000);
|
||||
}
|
||||
|
||||
|
|
@ -441,20 +457,26 @@ void data::user::loadPlayTimes()
|
|||
PdmPlayStatistics stats;
|
||||
for(data::titledata& _d : titles)
|
||||
{
|
||||
switch(_d.getType())//Users can hold device saves
|
||||
switch(_d.getType())
|
||||
{
|
||||
case FsSaveDataType_Account:
|
||||
pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(_d.getID(), userID, false, &stats);
|
||||
_d.setPlayTime(stats.playtimeMinutes);
|
||||
_d.setLastTimeStamp(stats.last_timestampUser);
|
||||
_d.setLaunchCount(stats.totalLaunches);
|
||||
break;
|
||||
|
||||
case FsSaveDataType_Device:
|
||||
pdmqryQueryPlayStatisticsByApplicationId(_d.getID(), false, &stats);
|
||||
_d.setPlayTime(stats.playtimeMinutes);
|
||||
_d.setLastTimeStamp(stats.last_timestampNetwork);
|
||||
_d.setLaunchCount(stats.totalLaunches);
|
||||
break;
|
||||
|
||||
default:
|
||||
_d.setPlayTime(0);
|
||||
_d.setLastTimeStamp(0);
|
||||
_d.setLaunchCount(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -528,6 +550,7 @@ void data::loadCfg()
|
|||
|
||||
uint64_t cfgIn = 0;
|
||||
fread(&cfgIn, sizeof(uint64_t), 1, cfg);
|
||||
fread(&data::sortType, 1, 1, cfg);
|
||||
fclose(cfg);
|
||||
|
||||
data::incDev = cfgIn >> 63 & 1;
|
||||
|
|
@ -567,6 +590,7 @@ void data::saveCfg()
|
|||
cfgOut |= (uint64_t)data::skipUser << 52;
|
||||
cfgOut |= (uint64_t)data::zip << 51;
|
||||
fwrite(&cfgOut, sizeof(uint64_t), 1, cfg);
|
||||
fwrite(&data::sortType, 1, 1, cfg);
|
||||
|
||||
fclose(cfg);
|
||||
}
|
||||
|
|
@ -586,6 +610,7 @@ void data::restoreDefaultConfig()
|
|||
data::directFsCmd = false;
|
||||
data::skipUser = false;
|
||||
data::zip = false;
|
||||
data::sortType = 0;
|
||||
}
|
||||
|
||||
void data::loadFav()
|
||||
|
|
@ -632,5 +657,6 @@ void data::dispStats()
|
|||
stats += "Current Title: " + data::curData.getTitle() + "\n";
|
||||
stats += "Safe Title: " + data::curData.getTitleSafe() + "\n";
|
||||
stats += "Icon count: " + std::to_string(icons.size()) + "\n";
|
||||
stats += "Sort Type: " + std::to_string(data::sortType) + "\n";
|
||||
drawText(stats.c_str(), frameBuffer, ui::shared, 2, 2, 16, clrCreateU32(0xFF00DD00));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ static std::unordered_map<std::string, unsigned> uistrdef =
|
|||
{"confirmRestore", 11}, {"confirmDelete", 12}, {"confirmCopy", 13}, {"confirmEraseNand", 14},
|
||||
{"confirmEraseFolder", 15}, {"confirmHead", 16}, {"copyHead", 17}, {"noSavesFound", 18},
|
||||
{"advMenu", 19}, {"extMenu", 20}, {"optMenu", 21}, {"optMenuExp", 22}, {"holdingText", 23},
|
||||
{"errorConnecting", 24}, {"noUpdate", 25}
|
||||
{"errorConnecting", 24}, {"noUpdate", 25}, {"sortType", 26}
|
||||
};
|
||||
|
||||
static void loadTrans()
|
||||
|
|
@ -217,6 +217,13 @@ static void loadTrans()
|
|||
ui::noUpdate = lang.getNextValueStr();
|
||||
break;
|
||||
|
||||
case 26:
|
||||
{
|
||||
int ind = lang.getNextValueInt();
|
||||
ui::sortString[ind] = lang.getNextValueStr();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ui::showMessage("*Translation File Error:*", "On Line: %s\n*%s* is not a known or valid string name.", lang.getLine(), lang.getName());
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -12,16 +12,6 @@
|
|||
static ui::menu userMenu, titleMenu, exMenu, optMenu;
|
||||
extern ui::menu folderMenu;
|
||||
|
||||
static inline void switchBool(bool& sw)
|
||||
{
|
||||
sw ? sw = false : sw = true;
|
||||
}
|
||||
|
||||
static inline std::string getBoolText(bool b)
|
||||
{
|
||||
return b ? ui::on : ui::off;
|
||||
}
|
||||
|
||||
void ui::textUserPrep()
|
||||
{
|
||||
userMenu.reset();
|
||||
|
|
@ -358,10 +348,26 @@ void ui::drawExMenu()
|
|||
exMenu.draw(ui::txtCont);
|
||||
}
|
||||
|
||||
static inline void switchBool(bool& sw)
|
||||
{
|
||||
sw ? sw = false : sw = true;
|
||||
}
|
||||
|
||||
static inline std::string getBoolText(bool b)
|
||||
{
|
||||
return b ? ui::on : ui::off;
|
||||
}
|
||||
|
||||
static inline void changeSort()
|
||||
{
|
||||
if(++data::sortType > 2)
|
||||
data::sortType = 0;
|
||||
}
|
||||
|
||||
void ui::optMenuInit()
|
||||
{
|
||||
optMenu.setParams(76, 98, 310);
|
||||
for(unsigned i = 0; i < 13; i++)
|
||||
for(unsigned i = 0; i < 14; i++)
|
||||
optMenu.addOpt(ui::optMenuStr[i]);
|
||||
}
|
||||
|
||||
|
|
@ -383,6 +389,7 @@ void ui::updateOptMenu(const uint64_t& down, const uint64_t& held)
|
|||
optMenu.editOpt(10, optMenuStr[10] + getBoolText(data::directFsCmd));
|
||||
optMenu.editOpt(11, optMenuStr[11] + getBoolText(data::skipUser));
|
||||
optMenu.editOpt(12, optMenuStr[12] + getBoolText(data::zip));
|
||||
optMenu.editOpt(13, optMenuStr[13] + ui::sortString[data::sortType]);
|
||||
|
||||
if(down & KEY_A)
|
||||
{
|
||||
|
|
@ -439,12 +446,20 @@ void ui::updateOptMenu(const uint64_t& down, const uint64_t& held)
|
|||
case 12:
|
||||
switchBool(data::zip);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
changeSort();
|
||||
data::loadUsersTitles(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(down & KEY_X)
|
||||
data::restoreDefaultConfig();
|
||||
else if(down & KEY_B)
|
||||
{
|
||||
data::saveCfg();
|
||||
ui::changeState(ui::textMode ? TXT_USR : USR_SEL);
|
||||
}
|
||||
}
|
||||
|
||||
void ui::drawOptMenu()
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ std::string ui::errorConnecting = "Error Connecting!";
|
|||
std::string ui::noUpdate = "No updates available!";
|
||||
std::string ui::advMenuStr[6] = { "Copy to ", "Delete", "Rename", "Make Dir", "Properties", "Close" };
|
||||
std::string ui::exMenuStr[11] = { "SD to SD Browser", "BIS: PRODINFOF", "BIS: SAFE", "BIS: SYSTEM", "BIS: USER", "Remove Update", "Terminate Process", "Mount System Save", "Rescan Titles", "Mount Process RomFS", "Backup JKSV Folder" };
|
||||
std::string ui::optMenuStr[13] = { "Include Dev Sv: ", "AutoBackup: ", "Overclock: ", "Hold to Delete: ", "Hold to Restore: ", "Hold to Overwrite: ", "Force Mount: ", "Account Sys. Saves: ", "Write to Sys. Saves: ", "Text UI Mode: ", "Direct FS Cmd: ", "Skip User Select: ", "Export to ZIP: " };
|
||||
std::string ui::optMenuExp[13] =
|
||||
std::string ui::optMenuStr[14] = { "Include Dev Sv: ", "AutoBackup: ", "Overclock: ", "Hold to Delete: ", "Hold to Restore: ", "Hold to Overwrite: ", "Force Mount: ", "Account Sys. Saves: ", "Write to Sys. Saves: ", "Text UI Mode: ", "Direct FS Cmd: ", "Skip User Select: ", "Export to ZIP: ", "Sort: " };
|
||||
std::string ui::optMenuExp[14] =
|
||||
{
|
||||
"Includes Device Save data in user accounts.",
|
||||
"Automatically creates a save backup before restoring a save.",
|
||||
|
|
@ -38,6 +38,8 @@ std::string ui::optMenuExp[13] =
|
|||
"Changes the UI to be text menu based like the original JKSM for 3DS.",
|
||||
"Directly uses the Switch's FS commands to copy files instead of stdio.",
|
||||
"Skips the user selection screen and jumps directly to the first user account found.",
|
||||
"Exports saves to ZIP files."
|
||||
"Exports saves to ZIP files.",
|
||||
"Changes the way titles are sorted and listed."
|
||||
};
|
||||
std::string ui::holdingText[3] = { "(Hold) ", "(Keep Holding) ", "(Almost there!) " };
|
||||
std::string ui::sortString[3] = { "Alphabetical", "Time Played", "Last Played" };
|
||||
|
|
|
|||
10
src/util.cpp
10
src/util.cpp
|
|
@ -179,6 +179,13 @@ std::string util::safeString(const std::string& s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline std::string getTimeString(const uint32_t& _h, const uint32_t& _m)
|
||||
{
|
||||
char tmp[32];
|
||||
sprintf(tmp, "%02d:%02d", _h, _m);
|
||||
return std::string(tmp);
|
||||
}
|
||||
|
||||
std::string util::getInfoString(const data::user& u, const data::titledata& d)
|
||||
{
|
||||
std::string ret = d.getTitle() + "\n";
|
||||
|
|
@ -190,7 +197,8 @@ std::string util::getInfoString(const data::user& u, const data::titledata& d)
|
|||
hours = d.getPlayTime() / 60;
|
||||
mins = d.getPlayTime() - (hours * 60);
|
||||
|
||||
ret += "Play Time: " + std::to_string(hours) + ":" + std::to_string(mins) + "\n";
|
||||
ret += "Play Time: " + getTimeString(hours, mins) + "\n";
|
||||
ret += "Total Launches: " + std::to_string(d.getLaunchCount()) + "\n";
|
||||
|
||||
switch(d.getType())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user