display storage sizes, properly colour info text, and more (see below)

- display internal and sd card storage sizes.
- removed battery info.
- removed current time info.
- fix dumping save to sd card due to not opening the file with append.
- change all sizes to display GB instead of GiB.
- change progress bar units to 1000 rather than 1024.
- all info text, such as sizes and timestamps now use the info text colouring.
- shorten the ncm content type names.
This commit is contained in:
ITotalJustice
2025-09-21 18:54:08 +01:00
parent a772d660f3
commit 5edc3869cd
16 changed files with 139 additions and 68 deletions

View File

@@ -155,6 +155,9 @@ public:
static Result SetDefaultBackgroundMusic(fs::Fs* fs, const fs::FsPath& path); static Result SetDefaultBackgroundMusic(fs::Fs* fs, const fs::FsPath& path);
static void SetBackgroundMusicPause(bool pause); static void SetBackgroundMusicPause(bool pause);
static Result GetSdSize(s64* free, s64* total);
static Result GetEmmcSize(s64* free, s64* total);
// helper that converts 1.2.3 to a u32 used for comparisons. // helper that converts 1.2.3 to a u32 used for comparisons.
static auto GetVersionFromString(const char* str) -> u32; static auto GetVersionFromString(const char* str) -> u32;
static auto IsVersionNewer(const char* current, const char* new_version) -> u32; static auto IsVersionNewer(const char* current, const char* new_version) -> u32;

View File

@@ -13,12 +13,14 @@ enum MenuFlag {
struct PolledData { struct PolledData {
struct tm tm{}; struct tm tm{};
u32 battery_percetange{};
PsmChargerType charger_type{};
NifmInternetConnectionType type{}; NifmInternetConnectionType type{};
NifmInternetConnectionStatus status{}; NifmInternetConnectionStatus status{};
u32 strength{}; u32 strength{};
u32 ip{}; u32 ip{};
s64 sd_free{1};
s64 sd_total{1};
s64 emmc_free{1};
s64 emmc_total{1};
}; };
struct MenuBase : Widget { struct MenuBase : Widget {

View File

@@ -22,4 +22,11 @@ constexpr inline T AlignDown(T value, T align) {
return value &~ (align - 1); return value &~ (align - 1);
} }
// formats size to 1.23 MB in 1024 base.
// only uses 32 bytes so its SSO optimised, not need to cache.
std::string formatSizeStorage(u64 size);
// formats size to 1.23 MB in 1000 base (used for progress bars).
std::string formatSizeNetwork(u64 size);
} // namespace sphaira::utils } // namespace sphaira::utils

View File

@@ -1462,6 +1462,20 @@ void App::SetBackgroundMusicPause(bool pause) {
} }
} }
Result App::GetSdSize(s64* free, s64* total) {
fs::FsNativeContentStorage fs{FsContentStorageId_SdCard};
R_TRY(fs.GetFreeSpace("/", free));
R_TRY(fs.GetTotalSpace("/", total));
R_SUCCEED();
}
Result App::GetEmmcSize(s64* free, s64* total) {
fs::FsNativeContentStorage fs{FsContentStorageId_User};
R_TRY(fs.GetFreeSpace("/", free));
R_TRY(fs.GetTotalSpace("/", total));
R_SUCCEED();
}
App::App(const char* argv0) { App::App(const char* argv0) {
// boost mode is enabled in userAppInit(). // boost mode is enabled in userAppInit().
ON_SCOPE_EXIT(App::SetBoostMode(false)); ON_SCOPE_EXIT(App::SetBoostMode(false));

View File

@@ -336,7 +336,7 @@ Result DumpToFile(ui::ProgressBox* pbox, fs::Fs* fs, const fs::FsPath& root, Bas
{ {
fs::File file; fs::File file;
R_TRY(fs->OpenFile(temp_path, FsOpenMode_Write, &file)); R_TRY(fs->OpenFile(temp_path, FsOpenMode_Write|FsOpenMode_Append, &file));
auto write_source = std::make_unique<WriteFileSource>(&file); auto write_source = std::make_unique<WriteFileSource>(&file);
if (custom_transfer) { if (custom_transfer) {

View File

@@ -56,8 +56,6 @@ void userAppInit(void) {
diagAbortWithResult(rc); diagAbortWithResult(rc);
if (R_FAILED(rc = plInitialize(PlServiceType_User))) if (R_FAILED(rc = plInitialize(PlServiceType_User)))
diagAbortWithResult(rc); diagAbortWithResult(rc);
if (R_FAILED(rc = psmInitialize()))
diagAbortWithResult(rc);
if (R_FAILED(rc = nifmInitialize(NifmServiceType_User))) if (R_FAILED(rc = nifmInitialize(NifmServiceType_User)))
diagAbortWithResult(rc); diagAbortWithResult(rc);
if (R_FAILED(rc = accountInitialize(is_application ? AccountServiceType_Application : AccountServiceType_System))) if (R_FAILED(rc = accountInitialize(is_application ? AccountServiceType_Application : AccountServiceType_System)))
@@ -83,7 +81,6 @@ void userAppExit(void) {
setExit(); setExit();
accountExit(); accountExit();
nifmExit(); nifmExit();
psmExit();
plExit(); plExit();
socketExit(); socketExit();
// NOTE (DMC): prevents exfat corruption. // NOTE (DMC): prevents exfat corruption.

View File

@@ -20,6 +20,8 @@
#include "web.hpp" #include "web.hpp"
#include "minizip_helper.hpp" #include "minizip_helper.hpp"
#include "utils/utils.hpp"
#include <minIni.h> #include <minIni.h>
#include <string> #include <string>
#include <cstring> #include <cstring>
@@ -738,7 +740,7 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) {
text_start_y += text_inc_y; text_start_y += text_inc_y;
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "category: %s"_i18n.c_str(), m_entry.category.c_str()); gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "category: %s"_i18n.c_str(), m_entry.category.c_str());
text_start_y += text_inc_y; text_start_y += text_inc_y;
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "extracted: %.2f MiB"_i18n.c_str(), (double)m_entry.extracted / 1024.0); gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "extracted: %s"_i18n.c_str(), utils::formatSizeStorage(m_entry.extracted).c_str());
text_start_y += text_inc_y; text_start_y += text_inc_y;
gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "app_dls: %s"_i18n.c_str(), AppDlToStr(m_entry.app_dls).c_str()); gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "app_dls: %s"_i18n.c_str(), AppDlToStr(m_entry.app_dls).c_str());
text_start_y += text_inc_y; text_start_y += text_inc_y;

View File

@@ -10,6 +10,7 @@
#include "ui/error_box.hpp" #include "ui/error_box.hpp"
#include "ui/music_player.hpp" #include "ui/music_player.hpp"
#include "utils/utils.hpp"
#include "utils/devoptab.hpp" #include "utils/devoptab.hpp"
#include "log.hpp" #include "log.hpp"
@@ -603,10 +604,10 @@ void FsView::Draw(NVGcontext* vg, Theme* theme) {
} }
if (e.file_count != -1) { if (e.file_count != -1) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%zd files"_i18n.c_str(), e.file_count); gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), "%zd files"_i18n.c_str(), e.file_count);
} }
if (e.dir_count != -1) { if (e.dir_count != -1) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(text_id), "%zd dirs"_i18n.c_str(), e.dir_count); gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "%zd dirs"_i18n.c_str(), e.dir_count);
} }
} else if (e.IsFile() && !m_fs_entry.IsNoStatFile() && (e.file_size != -1 || !e.time_stamp.is_valid)) { } else if (e.IsFile() && !m_fs_entry.IsNoStatFile() && (e.file_size != -1 || !e.time_stamp.is_valid)) {
if (!e.time_stamp.is_valid && !e.done_stat) { if (!e.time_stamp.is_valid && !e.done_stat) {
@@ -622,14 +623,9 @@ void FsView::Draw(NVGcontext* vg, Theme* theme) {
const auto t = (time_t)(e.time_stamp.modified); const auto t = (time_t)(e.time_stamp.modified);
struct tm tm{}; struct tm tm{};
localtime_r(&t, &tm); localtime_r(&t, &tm);
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(text_id), "%02u/%02u/%u", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
if ((double)e.file_size / 1024.0 / 1024.0 <= 0.009) { gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "%02u/%02u/%u", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900);
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f KiB", (double)e.file_size / 1024.0); gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", utils::formatSizeStorage(e.file_size).c_str());
} else if ((double)e.file_size / 1024.0 / 1024.0 / 1024.0 <= 0.009) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f MiB", (double)e.file_size / 1024.0 / 1024.0);
} else {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f GiB", (double)e.file_size / 1024.0 / 1024.0 / 1024.0);
}
} }
}); });
} }

View File

@@ -10,6 +10,8 @@
#include "yati/nx/ncm.hpp" #include "yati/nx/ncm.hpp"
#include "yati/nx/es.hpp" #include "yati/nx/es.hpp"
#include "utils/utils.hpp"
#include "title_info.hpp" #include "title_info.hpp"
#include "app.hpp" #include "app.hpp"
#include "defines.hpp" #include "defines.hpp"
@@ -231,14 +233,8 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
GetNcmSizeOfMetaStatus(e); GetNcmSizeOfMetaStatus(e);
} }
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(text_id), "%s", ncm::GetReadableStorageIdStr(e.status.storageID)); gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", ncm::GetReadableStorageIdStr(e.status.storageID));
if ((double)e.size / 1024.0 / 1024.0 <= 0.009) { gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", utils::formatSizeStorage(e.size).c_str());
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f KiB", (double)e.size / 1024.0);
} else if ((double)e.size / 1024.0 / 1024.0 / 1024.0 <= 0.009) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f MiB", (double)e.size / 1024.0 / 1024.0);
} else {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f GiB", (double)e.size / 1024.0 / 1024.0 / 1024.0);
}
if (e.selected) { if (e.selected) {
gfx::drawText(vg, x + text_xoffset - 80 / 2, y + (h / 2.f) - (24.f / 2), 24.f, "\uE14B", nullptr, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_SELECTED)); gfx::drawText(vg, x + text_xoffset - 80 / 2, y + (h / 2.f) - (24.f / 2), 24.f, "\uE14B", nullptr, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_SELECTED));

View File

@@ -344,15 +344,8 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
} }
gfx::drawTextArgs(vg, x + text_xoffset, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s", ncm::GetContentTypeStr(e.content_type)); gfx::drawTextArgs(vg, x + text_xoffset, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s", ncm::GetContentTypeStr(e.content_type));
gfx::drawTextArgs(vg, x + text_xoffset + 185, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s", utils::hexIdToStr(e.content_id).str); gfx::drawTextArgs(vg, x + text_xoffset + 150, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s", utils::hexIdToStr(e.content_id).str);
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", utils::formatSizeStorage(e.size).c_str());
if ((double)e.size / 1024.0 / 1024.0 <= 0.009) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%.2f KiB", (double)e.size / 1024.0);
} else if ((double)e.size / 1024.0 / 1024.0 / 1024.0 <= 0.009) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%.2f MiB", (double)e.size / 1024.0 / 1024.0);
} else {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%.2f GiB", (double)e.size / 1024.0 / 1024.0 / 1024.0);
}
if (e.missing) { if (e.missing) {
gfx::drawText(vg, x + text_xoffset - 80 / 2, y + (h / 2.f) - (24.f / 2), 24.f, "\uE140", nullptr, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_ERROR)); gfx::drawText(vg, x + text_xoffset - 80 / 2, y + (h / 2.f) - (24.f / 2), 24.f, "\uE140", nullptr, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_ERROR));

View File

@@ -233,7 +233,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
nvgRestore(vg); nvgRestore(vg);
if (!e.tag.empty()) { if (!e.tag.empty()) {
gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "version: %s", e.tag.c_str()); gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "version: %s", e.tag.c_str());
} }
}); });
} }

View File

@@ -18,8 +18,9 @@ Vec4 Menu::DrawEntry(NVGcontext* vg, Theme* theme, bool draw_image, int layout,
const auto& [x, y, w, h] = v; const auto& [x, y, w, h] = v;
auto text_id = ThemeEntryID_TEXT; auto text_id = ThemeEntryID_TEXT;
auto info_id = ThemeEntryID_TEXT_INFO;
if (selected) { if (selected) {
text_id = ThemeEntryID_TEXT_SELECTED; text_id = info_id = ThemeEntryID_TEXT_SELECTED;
gfx::drawRectOutline(vg, theme, 4.f, v); gfx::drawRectOutline(vg, theme, 4.f, v);
} else { } else {
DrawElement(v, ThemeEntryID_GRID); DrawElement(v, ThemeEntryID_GRID);
@@ -38,8 +39,8 @@ Vec4 Menu::DrawEntry(NVGcontext* vg, Theme* theme, bool draw_image, int layout,
const auto text_clip_w = w - 30.f - text_off; const auto text_clip_w = w - 30.f - text_off;
const float font_size = 18; const float font_size = 18;
m_scroll_name.Draw(vg, selected, text_x, y + 45, text_clip_w, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), name); m_scroll_name.Draw(vg, selected, text_x, y + 45, text_clip_w, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), name);
m_scroll_author.Draw(vg, selected, text_x, y + 80, text_clip_w, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), author); m_scroll_author.Draw(vg, selected, text_x, y + 80, text_clip_w, font_size, NVG_ALIGN_LEFT, theme->GetColour(info_id), author);
m_scroll_version.Draw(vg, selected, text_x, y + 115, text_clip_w, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), version); m_scroll_version.Draw(vg, selected, text_x, y + 115, text_clip_w, font_size, NVG_ALIGN_LEFT, theme->GetColour(info_id), version);
} else { } else {
if (selected) { if (selected) {
gfx::drawAppLable(vg, theme, m_scroll_name, x, y, w, name); gfx::drawAppLable(vg, theme, m_scroll_name, x, y, w, name);

View File

@@ -20,20 +20,24 @@ auto MenuBase::GetPolledData(bool force_refresh) -> PolledData {
// doesn't have focus. // doesn't have focus.
if (force_refresh || timestamp.GetSeconds() >= 1) { if (force_refresh || timestamp.GetSeconds() >= 1) {
data.tm = {}; data.tm = {};
data.battery_percetange = {};
data.charger_type = {};
data.type = {}; data.type = {};
data.status = {}; data.status = {};
data.strength = {}; data.strength = {};
data.ip = {}; data.ip = {};
// avoid divide by zero if getting the size fails, for whatever reason.
data.sd_free = 1;
data.sd_total = 1;
data.emmc_free = 1;
data.emmc_total = 1;
const auto t = std::time(NULL); const auto t = std::time(NULL);
localtime_r(&t, &data.tm); localtime_r(&t, &data.tm);
psmGetBatteryChargePercentage(&data.battery_percetange);
psmGetChargerType(&data.charger_type);
nifmGetInternetConnectionStatus(&data.type, &data.strength, &data.status); nifmGetInternetConnectionStatus(&data.type, &data.strength, &data.status);
nifmGetCurrentIpAddress(&data.ip); nifmGetCurrentIpAddress(&data.ip);
App::GetSdSize(&data.sd_free, &data.sd_total);
App::GetEmmcSize(&data.emmc_free, &data.emmc_total);
timestamp.Update(); timestamp.Update();
} }
@@ -60,7 +64,7 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) {
const auto pdata = GetPolledData(); const auto pdata = GetPolledData();
const float start_y = 70; const float start_y = 70;
const float font_size = 22; const float font_size = 20;
const float spacing = 30; const float spacing = 30;
float start_x = 1220; float start_x = 1220;
@@ -77,21 +81,59 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) {
start_x -= spacing + (bounds[2] - bounds[0]); \ start_x -= spacing + (bounds[2] - bounds[0]); \
} }
draw(ThemeEntryID_TEXT, 90, "%u\uFE6A", pdata.battery_percetange); #define STORAGE_BAR_W 180
#define STORAGE_BAR_H 8
if (App::Get12HourTimeEnable()) { const auto rounding = 2;
draw(ThemeEntryID_TEXT, 132, "%02u:%02u %s", (pdata.tm.tm_hour == 0 || pdata.tm.tm_hour == 12) ? 12 : pdata.tm.tm_hour % 12, pdata.tm.tm_min, (pdata.tm.tm_hour < 12) ? "AM" : "PM"); const auto storage_font = 19;
} else { const auto storage_y = start_y - 30;
draw(ThemeEntryID_TEXT, 90, "%02u:%02u", pdata.tm.tm_hour, pdata.tm.tm_min); auto storage_x = start_x - STORAGE_BAR_W;
}
if (pdata.ip) { gfx::drawTextArgs(vg, storage_x, storage_y, storage_font, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "System %.1f GB"_i18n.c_str(), pdata.emmc_free / 1024.0 / 1024.0 / 1024.0);
draw(ThemeEntryID_TEXT, 0, "%u.%u.%u.%u", pdata.ip&0xFF, (pdata.ip>>8)&0xFF, (pdata.ip>>16)&0xFF, (pdata.ip>>24)&0xFF); // gfx::drawTextArgs(vg, storage_x, storage_y, storage_font, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "eMMC %.1f GB"_i18n.c_str(), pdata.emmc_free / 1024.0 / 1024.0 / 1024.0);
} else { #if 0
draw(ThemeEntryID_TEXT, 0, ("No Internet"_i18n).c_str()); Vec4 prog_bar{storage_x, storage_y + 24, STORAGE_BAR_W, STORAGE_BAR_H};
} gfx::drawRect(vg, prog_bar, theme->GetColour(ThemeEntryID_PROGRESSBAR_BACKGROUND), rounding);
gfx::drawRect(vg, prog_bar.x, prog_bar.y, ((double)pdata.emmc_free / (double)pdata.emmc_total) * prog_bar.w, prog_bar.h, theme->GetColour(ThemeEntryID_PROGRESSBAR), rounding);
#else
gfx::drawRect(vg, storage_x, storage_y + 24, STORAGE_BAR_W, STORAGE_BAR_H, theme->GetColour(ThemeEntryID_TEXT_INFO), rounding);
gfx::drawRect(vg, storage_x + 1, storage_y + 24 + 1, STORAGE_BAR_W - 2, STORAGE_BAR_H - 2, theme->GetColour(ThemeEntryID_BACKGROUND), rounding);
gfx::drawRect(vg, storage_x + 2, storage_y + 24 + 2, STORAGE_BAR_W - (((double)pdata.emmc_free / (double)pdata.emmc_total) * STORAGE_BAR_W) - 4, STORAGE_BAR_H - 4, theme->GetColour(ThemeEntryID_TEXT_INFO), rounding);
#endif
storage_x -= (STORAGE_BAR_W + spacing);
gfx::drawTextArgs(vg, storage_x, storage_y, storage_font, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "microSD %.1f GB"_i18n.c_str(), pdata.sd_free / 1024.0 / 1024.0 / 1024.0);
gfx::drawRect(vg, storage_x, storage_y + 24, STORAGE_BAR_W, STORAGE_BAR_H, theme->GetColour(ThemeEntryID_TEXT_INFO), rounding);
gfx::drawRect(vg, storage_x + 1, storage_y + 24 + 1, STORAGE_BAR_W - 2, STORAGE_BAR_H - 2, theme->GetColour(ThemeEntryID_BACKGROUND), rounding);
gfx::drawRect(vg, storage_x + 2, storage_y + 24 + 2, STORAGE_BAR_W - (((double)pdata.sd_free / (double)pdata.sd_total) * STORAGE_BAR_W) - 4, STORAGE_BAR_H - 4, theme->GetColour(ThemeEntryID_TEXT_INFO), rounding);
start_x -= (STORAGE_BAR_W + spacing) * 2;
// ran out of space, its one or the other.
if (!App::IsApplication()) { if (!App::IsApplication()) {
draw(ThemeEntryID_ERROR, 0, ("[Applet Mode]"_i18n).c_str()); draw(ThemeEntryID_ERROR, 0, ("[Applet Mode]"_i18n).c_str());
} else {
if (pdata.ip) {
char ip_buf[32];
std::snprintf(ip_buf, sizeof(ip_buf), "%u.%u.%u.%u", pdata.ip & 0xFF, (pdata.ip >> 8) & 0xFF, (pdata.ip >> 16) & 0xFF, (pdata.ip >> 24) & 0xFF);
gfx::textBounds(vg, 0, 0, bounds, ip_buf);
char type_buf[32];
if (pdata.type == NifmInternetConnectionType_WiFi) {
std::snprintf(type_buf, sizeof(type_buf), "Wi-Fi %.0f%%"_i18n.c_str(), ((float)pdata.strength / 3.F) * 100);
} else if (pdata.type == NifmInternetConnectionType_Ethernet) {
std::snprintf(type_buf, sizeof(type_buf), "Ethernet"_i18n.c_str());
} else {
std::snprintf(type_buf, sizeof(type_buf), "Unknown"_i18n.c_str());
}
const auto ip_x = start_x;
const auto ip_w = bounds[2] - bounds[0];
const auto type_x = ip_x - ip_w / 2;
gfx::drawTextArgs(vg, type_x, start_y - 25, storage_font - 1, NVG_ALIGN_CENTER | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), "%s", type_buf);
gfx::drawTextArgs(vg, ip_x, start_y, storage_font, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT), "%s", ip_buf);
} else {
draw(ThemeEntryID_TEXT, 0, ("No Internet"_i18n).c_str());
}
} }
#undef draw #undef draw

View File

@@ -7,6 +7,7 @@
#include "threaded_file_transfer.hpp" #include "threaded_file_transfer.hpp"
#include "i18n.hpp" #include "i18n.hpp"
#include "utils/utils.hpp"
#include "utils/thread.hpp" #include "utils/thread.hpp"
#include <cstring> #include <cstring>
@@ -152,16 +153,6 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void {
const auto rad = 15; const auto rad = 15;
gfx::drawSpinner(vg, theme, prog_bar.x - pad - rad, prog_bar.y + prog_bar.h / 2, rad, armTicksToNs(armGetSystemTick()) / 1e+9); gfx::drawSpinner(vg, theme, prog_bar.x - pad - rad, prog_bar.y + prog_bar.h / 2, rad, armTicksToNs(armGetSystemTick()) / 1e+9);
const double speed_mb = (double)speed / (1024.0 * 1024.0);
const double speed_kb = (double)speed / (1024.0);
char speed_str[32];
if (speed_mb >= 0.01) {
std::snprintf(speed_str, sizeof(speed_str), "%.2f MiB/s", speed_mb);
} else {
std::snprintf(speed_str, sizeof(speed_str), "%.2f KiB/s", speed_kb);
}
const auto left = size - last_offset; const auto left = size - last_offset;
const auto left_seconds = left / speed; const auto left_seconds = left / speed;
const auto hours = left_seconds / (60 * 60); const auto hours = left_seconds / (60 * 60);
@@ -177,7 +168,7 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void {
std::snprintf(time_str, sizeof(time_str), "%zu seconds remaining"_i18n.c_str(), seconds); std::snprintf(time_str, sizeof(time_str), "%zu seconds remaining"_i18n.c_str(), seconds);
} }
gfx::drawTextArgs(vg, center_x, prog_bar.y + prog_bar.h + 30, 18, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s (%s)", time_str, speed_str); gfx::drawTextArgs(vg, center_x, prog_bar.y + prog_bar.h + 30, 18, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s (%s)", time_str, utils::formatSizeNetwork(speed).c_str());
} }
gfx::drawTextArgs(vg, center_x, m_pos.y + 40, 24, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), action.c_str()); gfx::drawTextArgs(vg, center_x, m_pos.y + 40, 24, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), action.c_str());

View File

@@ -14,6 +14,25 @@ HashStr hexIdToStrInternal(auto id) {
return str; return str;
} }
std::string formatSizeInetrnal(double size, double base) {
static const char* const suffixes[] = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
size_t suffix_index = 0;
while (size >= base && suffix_index < std::size(suffixes) - 1) {
size /= base;
suffix_index++;
}
char buffer[32];
if (suffix_index == 0) {
std::snprintf(buffer, sizeof(buffer), "%.0f %s", size, suffixes[suffix_index]);
} else {
std::snprintf(buffer, sizeof(buffer), "%.2f %s", size, suffixes[suffix_index]);
}
return buffer;
}
} // namespace } // namespace
HashStr hexIdToStr(FsRightsId id) { HashStr hexIdToStr(FsRightsId id) {
@@ -28,4 +47,12 @@ HashStr hexIdToStr(NcmContentId id) {
return hexIdToStrInternal(id); return hexIdToStrInternal(id);
} }
std::string formatSizeStorage(u64 size) {
return formatSizeInetrnal(size, 1024.0);
}
std::string formatSizeNetwork(u64 size) {
return formatSizeInetrnal(size, 1000.0);
}
} // namespace sphaira::utils } // namespace sphaira::utils

View File

@@ -34,9 +34,9 @@ auto GetContentTypeStr(u8 content_type) -> const char* {
case NcmContentType_Program: return "Program"; case NcmContentType_Program: return "Program";
case NcmContentType_Data: return "Data"; case NcmContentType_Data: return "Data";
case NcmContentType_Control: return "Control"; case NcmContentType_Control: return "Control";
case NcmContentType_HtmlDocument: return "HtmlDocument"; case NcmContentType_HtmlDocument: return "Html";
case NcmContentType_LegalInformation: return "LegalInformation"; case NcmContentType_LegalInformation: return "Legal";
case NcmContentType_DeltaFragment: return "DeltaFragment"; case NcmContentType_DeltaFragment: return "Delta";
} }
return "Unknown"; return "Unknown";