diff --git a/source/core/core.h b/source/core/core.h new file mode 100644 index 0000000..043c13b --- /dev/null +++ b/source/core/core.h @@ -0,0 +1,14 @@ +#pragma once + +#include "data/data.h" +#include "task/task.h" +#include "ui/ui.h" + +#include "clipboard.h" +#include "error.h" +#include "fs.h" +#include "http.h" +#include "linkedlist.h" +#include "screen.h" +#include "spi.h" +#include "stringutil.h" \ No newline at end of file diff --git a/source/core/data/data.h b/source/core/data/data.h new file mode 100644 index 0000000..2561d3b --- /dev/null +++ b/source/core/data/data.h @@ -0,0 +1,7 @@ +#pragma once + +#include "bnr.h" +#include "cia.h" +#include "smdh.h" +#include "ticket.h" +#include "tmd.h" \ No newline at end of file diff --git a/source/core/screen.h b/source/core/screen.h index 2d8078c..2e06d99 100644 --- a/source/core/screen.h +++ b/source/core/screen.h @@ -11,6 +11,8 @@ typedef struct __sFILE FILE; #define MAX_TEXTURES 1024 #define MAX_COLORS 32 +#define COLOR_TEXT 0 + void screen_init(); void screen_exit(); void screen_set_base_alpha(u8 alpha); diff --git a/source/ui/section/task/dataop.c b/source/core/task/dataop.c similarity index 98% rename from source/ui/section/task/dataop.c rename to source/core/task/dataop.c index 33dfbe3..8b5f6e2 100644 --- a/source/ui/section/task/dataop.c +++ b/source/core/task/dataop.c @@ -5,15 +5,8 @@ #include #include -#include "uitask.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/http.h" -#include "../../../core/screen.h" -#include "../../../core/task/task.h" +#include "dataop.h" +#include "../core.h" static Result task_data_op_check_running(data_op_data* data, u32 index, u32* srcHandle, u32* dstHandle) { Result res = 0; diff --git a/source/core/task/dataop.h b/source/core/task/dataop.h new file mode 100644 index 0000000..afcf48d --- /dev/null +++ b/source/core/task/dataop.h @@ -0,0 +1,77 @@ +#pragma once + +typedef struct json_t json_t; + +typedef struct ui_view_s ui_view; + +#define DOWNLOAD_URL_MAX 1024 + +typedef enum data_op_e { + DATAOP_COPY, + DATAOP_DOWNLOAD, + DATAOP_DELETE +} data_op; + +typedef struct data_op_data_s { + void* data; + + data_op op; + + u32 processed; + u32 total; + + // Copy + bool copyEmpty; + + Result (*isSrcDirectory)(void* data, u32 index, bool* isDirectory); + Result (*makeDstDirectory)(void* data, u32 index); + + Result (*openSrc)(void* data, u32 index, u32* handle); + Result (*closeSrc)(void* data, u32 index, bool succeeded, u32 handle); + + Result (*getSrcSize)(void* data, u32 handle, u64* size); + Result (*readSrc)(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size); + + // Download + char (*downloadUrls)[DOWNLOAD_URL_MAX]; + + // Copy/Download + u64 currProcessed; + u64 currTotal; + + u32 bytesPerSecond; + u32 estimatedRemainingSeconds; + + u32 bufferSize; + + Result (*openDst)(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle); + Result (*closeDst)(void* data, u32 index, bool succeeded, u32 handle); + + Result (*writeDst)(void* data, u32 handle, u32* bytesWritten, void* buffer, u64 offset, u32 size); + + Result (*suspendTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle); + Result (*restoreTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle); + + // Delete + Result (*delete)(void* data, u32 index); + + // Suspend + Result (*suspend)(void* data, u32 index); + Result (*restore)(void* data, u32 index); + + // Errors + bool (*error)(void* data, u32 index, Result res, ui_view** errorView); + + // General + volatile bool finished; + Result result; + Handle cancelEvent; + + // Internal + volatile bool retryResponse; +} data_op_data; + +Result task_download_sync(const char* url, u32* downloadedSize, void* buf, size_t size); +Result task_download_json_sync(const char* url, json_t** json, size_t maxSize); +Result task_download_seed_sync(u64 titleId); +Result task_data_op(data_op_data* data); \ No newline at end of file diff --git a/source/core/task/task.h b/source/core/task/task.h index 301ff07..a0ed750 100644 --- a/source/core/task/task.h +++ b/source/core/task/task.h @@ -4,4 +4,7 @@ void task_init(); void task_exit(); bool task_is_quit_all(); Handle task_get_pause_event(); -Handle task_get_suspend_event(); \ No newline at end of file +Handle task_get_suspend_event(); + +#include "capturecam.h" +#include "dataop.h" \ No newline at end of file diff --git a/source/ui/error.c b/source/core/ui/error.c similarity index 99% rename from source/ui/error.c rename to source/core/ui/error.c index a602367..edea50e 100644 --- a/source/ui/error.c +++ b/source/core/ui/error.c @@ -8,9 +8,9 @@ #include "error.h" #include "prompt.h" -#include "resources.h" -#include "../core/error.h" -#include "../core/screen.h" +#include "../error.h" +#include "../screen.h" +#include "../../fbi/resources.h" static const char* level_to_string(Result res) { switch(R_LEVEL(res)) { diff --git a/source/ui/error.h b/source/core/ui/error.h similarity index 100% rename from source/ui/error.h rename to source/core/ui/error.h diff --git a/source/ui/info.c b/source/core/ui/info.c similarity index 98% rename from source/ui/info.c rename to source/core/ui/info.c index 6d7b16b..48b350f 100644 --- a/source/ui/info.c +++ b/source/core/ui/info.c @@ -5,9 +5,9 @@ #include "error.h" #include "info.h" -#include "resources.h" #include "ui.h" -#include "../core/screen.h" +#include "../screen.h" +#include "../../fbi/resources.h" typedef struct { bool bar; diff --git a/source/ui/info.h b/source/core/ui/info.h similarity index 100% rename from source/ui/info.h rename to source/core/ui/info.h diff --git a/source/ui/kbd.c b/source/core/ui/kbd.c similarity index 100% rename from source/ui/kbd.c rename to source/core/ui/kbd.c diff --git a/source/ui/kbd.h b/source/core/ui/kbd.h similarity index 100% rename from source/ui/kbd.h rename to source/core/ui/kbd.h diff --git a/source/ui/list.c b/source/core/ui/list.c similarity index 99% rename from source/ui/list.c rename to source/core/ui/list.c index 8aee4db..d98c62d 100644 --- a/source/ui/list.c +++ b/source/core/ui/list.c @@ -4,10 +4,10 @@ #include "error.h" #include "list.h" -#include "resources.h" #include "ui.h" -#include "../core/screen.h" -#include "../core/linkedlist.h" +#include "../screen.h" +#include "../linkedlist.h" +#include "../../fbi/resources.h" typedef struct { void* data; diff --git a/source/ui/list.h b/source/core/ui/list.h similarity index 100% rename from source/ui/list.h rename to source/core/ui/list.h diff --git a/source/ui/prompt.c b/source/core/ui/prompt.c similarity index 99% rename from source/ui/prompt.c rename to source/core/ui/prompt.c index 24bb192..584a353 100644 --- a/source/ui/prompt.c +++ b/source/core/ui/prompt.c @@ -6,9 +6,9 @@ #include "error.h" #include "prompt.h" -#include "resources.h" #include "ui.h" -#include "../core/screen.h" +#include "../screen.h" +#include "../../fbi/resources.h" typedef struct { const char* text; diff --git a/source/ui/prompt.h b/source/core/ui/prompt.h similarity index 100% rename from source/ui/prompt.h rename to source/core/ui/prompt.h diff --git a/source/ui/ui.c b/source/core/ui/ui.c similarity index 50% rename from source/ui/ui.c rename to source/core/ui/ui.c index 902b346..18a57a5 100644 --- a/source/ui/ui.c +++ b/source/core/ui/ui.c @@ -1,745 +1,406 @@ -#include -#include -#include - -#include <3ds.h> -#include - -#include "resources.h" -#include "ui.h" -#include "section/task/uitask.h" -#include "../core/error.h" -#include "../core/screen.h" -#include "../core/data/smdh.h" - -#define MAX_UI_VIEWS 16 - -static ui_view* ui_stack[MAX_UI_VIEWS]; -static int ui_stack_top = -1; - -static Handle ui_stack_mutex = 0; - -static u64 ui_free_space_last_update = 0; -static char ui_free_space_buffer[128]; - -static u64 ui_fade_begin_time = 0; -static u8 ui_fade_alpha = 0; - -void ui_init() { - if(ui_stack_mutex == 0) { - svcCreateMutex(&ui_stack_mutex, false); - } - - resources_load(); - - ui_fade_begin_time = osGetTime(); -} - -void ui_exit() { - if(ui_stack_mutex != 0) { - svcCloseHandle(ui_stack_mutex); - ui_stack_mutex = 0; - } -} - -ui_view* ui_create() { - ui_view* view = (ui_view*) calloc(1, sizeof(ui_view)); - if(view == NULL) { - error_panic("Failed to allocate UI view."); - return NULL; - } - - Result res = 0; - if(R_FAILED(res = svcCreateEvent(&view->active, RESET_STICKY))) { - error_panic("Failed to create view active event: 0x%08lX", res); - - free(view); - return NULL; - } - - return view; -} - -void ui_destroy(ui_view* view) { - if(view != NULL) { - svcCloseHandle(view->active); - free(view); - } -} - -ui_view* ui_top() { - svcWaitSynchronization(ui_stack_mutex, U64_MAX); - - ui_view* ui = NULL; - if(ui_stack_top >= 0) { - ui = ui_stack[ui_stack_top]; - } - - svcReleaseMutex(ui_stack_mutex); - - return ui; -} - -bool ui_push(ui_view* view) { - if(view == NULL) { - return false; - } - - svcWaitSynchronization(ui_stack_mutex, U64_MAX); - - bool space = ui_stack_top < MAX_UI_VIEWS - 1; - if(space) { - ui_stack[++ui_stack_top] = view; - - svcClearEvent(view->active); - } - - svcReleaseMutex(ui_stack_mutex); - - return space; -} - -void ui_pop() { - svcWaitSynchronization(ui_stack_mutex, U64_MAX); - - if(ui_stack_top >= 0) { - svcSignalEvent(ui_stack[ui_stack_top]->active); - - ui_stack[ui_stack_top--] = NULL; - } - - svcReleaseMutex(ui_stack_mutex); -} - -static void ui_draw_top(ui_view* ui) { - screen_select(GFX_TOP); - - u32 topScreenBgWidth = 0; - u32 topScreenBgHeight = 0; - screen_get_texture_size(&topScreenBgWidth, &topScreenBgHeight, TEXTURE_TOP_SCREEN_BG); - - u32 topScreenTopBarWidth = 0; - u32 topScreenTopBarHeight = 0; - screen_get_texture_size(&topScreenTopBarWidth, &topScreenTopBarHeight, TEXTURE_TOP_SCREEN_TOP_BAR); - - u32 topScreenTopBarShadowWidth = 0; - u32 topScreenTopBarShadowHeight = 0; - screen_get_texture_size(&topScreenTopBarShadowWidth, &topScreenTopBarShadowHeight, TEXTURE_TOP_SCREEN_TOP_BAR_SHADOW); - - u32 topScreenBottomBarWidth = 0; - u32 topScreenBottomBarHeight = 0; - screen_get_texture_size(&topScreenBottomBarWidth, &topScreenBottomBarHeight, TEXTURE_TOP_SCREEN_BOTTOM_BAR); - - u32 topScreenBottomBarShadowWidth = 0; - u32 topScreenBottomBarShadowHeight = 0; - screen_get_texture_size(&topScreenBottomBarShadowWidth, &topScreenBottomBarShadowHeight, TEXTURE_TOP_SCREEN_BOTTOM_BAR_SHADOW); - - screen_draw_texture(TEXTURE_TOP_SCREEN_BG, (TOP_SCREEN_WIDTH - topScreenBgWidth) / 2, (TOP_SCREEN_HEIGHT - topScreenBgHeight) / 2, topScreenBgWidth, topScreenBgHeight); - - if(ui->drawTop != NULL) { - ui->drawTop(ui, ui->data, 0, topScreenTopBarHeight, TOP_SCREEN_WIDTH, TOP_SCREEN_HEIGHT - topScreenBottomBarHeight); - } - - float topScreenTopBarX = (TOP_SCREEN_WIDTH - topScreenTopBarWidth) / 2; - float topScreenTopBarY = 0; - screen_draw_texture(TEXTURE_TOP_SCREEN_TOP_BAR, topScreenTopBarX, topScreenTopBarY, topScreenTopBarWidth, topScreenTopBarHeight); - screen_draw_texture(TEXTURE_TOP_SCREEN_TOP_BAR_SHADOW, topScreenTopBarX, topScreenTopBarY + topScreenTopBarHeight, topScreenTopBarShadowWidth, topScreenTopBarShadowHeight); - - float topScreenBottomBarX = (TOP_SCREEN_WIDTH - topScreenBottomBarWidth) / 2; - float topScreenBottomBarY = TOP_SCREEN_HEIGHT - topScreenBottomBarHeight; - screen_draw_texture(TEXTURE_TOP_SCREEN_BOTTOM_BAR, topScreenBottomBarX, topScreenBottomBarY, topScreenBottomBarWidth, topScreenBottomBarHeight); - screen_draw_texture(TEXTURE_TOP_SCREEN_BOTTOM_BAR_SHADOW, topScreenBottomBarX, topScreenBottomBarY - topScreenBottomBarShadowHeight, topScreenBottomBarShadowWidth, topScreenBottomBarShadowHeight); - - screen_set_base_alpha(ui_fade_alpha); - - char verText[64]; - snprintf(verText, 64, "Ver. %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO); - - float verWidth; - float verHeight; - screen_get_string_size(&verWidth, &verHeight, verText, 0.5f, 0.5f); - screen_draw_string(verText, topScreenTopBarX + 2, topScreenTopBarY + (topScreenTopBarHeight - verHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); - - time_t t = time(NULL); - char* timeText = ctime(&t); - timeText[strlen(timeText) - 1] = '\0'; - - float timeTextWidth; - float timeTextHeight; - screen_get_string_size(&timeTextWidth, &timeTextHeight, timeText, 0.5f, 0.5f); - screen_draw_string(timeText, topScreenTopBarX + (topScreenTopBarWidth - timeTextWidth) / 2, topScreenTopBarY + (topScreenTopBarHeight - timeTextHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); - - u32 batteryIcon = 0; - u8 batteryChargeState = 0; - u8 batteryLevel = 0; - if(R_SUCCEEDED(PTMU_GetBatteryChargeState(&batteryChargeState)) && batteryChargeState) { - batteryIcon = TEXTURE_BATTERY_CHARGING; - } else if(R_SUCCEEDED(PTMU_GetBatteryLevel(&batteryLevel))) { - batteryIcon = TEXTURE_BATTERY_0 + batteryLevel; - } else { - batteryIcon = TEXTURE_BATTERY_0; - } - - u32 batteryWidth; - u32 batteryHeight; - screen_get_texture_size(&batteryWidth, &batteryHeight, batteryIcon); - - float batteryX = topScreenTopBarX + topScreenTopBarWidth - 2 - batteryWidth; - float batteryY = topScreenTopBarY + (topScreenTopBarHeight - batteryHeight) / 2; - screen_draw_texture(batteryIcon, batteryX, batteryY, batteryWidth, batteryHeight); - - u32 wifiIcon = 0; - u32 wifiStatus = 0; - if(R_SUCCEEDED(ACU_GetWifiStatus(&wifiStatus)) && wifiStatus) { - wifiIcon = TEXTURE_WIFI_0 + osGetWifiStrength(); - } else { - wifiIcon = TEXTURE_WIFI_DISCONNECTED; - } - - u32 wifiWidth; - u32 wifiHeight; - screen_get_texture_size(&wifiWidth, &wifiHeight, wifiIcon); - - float wifiX = topScreenTopBarX + topScreenTopBarWidth - 2 - batteryWidth - 4 - wifiWidth; - float wifiY = topScreenTopBarY + (topScreenTopBarHeight - wifiHeight) / 2; - screen_draw_texture(wifiIcon, wifiX, wifiY, wifiWidth, wifiHeight); - - if(osGetTime() >= ui_free_space_last_update + 1000) { - char* currBuffer = ui_free_space_buffer; - FS_ArchiveResource resource = {0}; - - if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_SD)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { - if(currBuffer != ui_free_space_buffer) { - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); - currBuffer += strlen(currBuffer); - } - - u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "SD: %.1f %s", - ui_get_display_size(size), ui_get_display_size_units(size)); - currBuffer += strlen(currBuffer); - } - - if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_CTR_NAND)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { - if(currBuffer != ui_free_space_buffer) { - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); - currBuffer += strlen(currBuffer); - } - - u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "CTR NAND: %.1f %s", - ui_get_display_size(size), ui_get_display_size_units(size)); - currBuffer += strlen(currBuffer); - } - - if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_TWL_NAND)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { - if(currBuffer != ui_free_space_buffer) { - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); - currBuffer += strlen(currBuffer); - } - - u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "TWL NAND: %.1f %s", - ui_get_display_size(size), ui_get_display_size_units(size)); - currBuffer += strlen(currBuffer); - } - - if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_TWL_PHOTO)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { - if(currBuffer != ui_free_space_buffer) { - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); - currBuffer += strlen(currBuffer); - } - - u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; - snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "TWL Photo: %.1f %s", - ui_get_display_size(size), ui_get_display_size_units(size)); - currBuffer += strlen(currBuffer); - } - - ui_free_space_last_update = osGetTime(); - } - - float freeSpaceHeight; - screen_get_string_size(NULL, &freeSpaceHeight, ui_free_space_buffer, 0.35f, 0.35f); - - screen_draw_string(ui_free_space_buffer, topScreenBottomBarX + 2, topScreenBottomBarY + (topScreenBottomBarHeight - freeSpaceHeight) / 2, 0.35f, 0.35f, COLOR_TEXT, true); - - screen_set_base_alpha(0xFF); -} - -static void ui_draw_bottom(ui_view* ui) { - screen_select(GFX_BOTTOM); - - u32 bottomScreenBgWidth = 0; - u32 bottomScreenBgHeight = 0; - screen_get_texture_size(&bottomScreenBgWidth, &bottomScreenBgHeight, TEXTURE_BOTTOM_SCREEN_BG); - - u32 bottomScreenTopBarWidth = 0; - u32 bottomScreenTopBarHeight = 0; - screen_get_texture_size(&bottomScreenTopBarWidth, &bottomScreenTopBarHeight, TEXTURE_BOTTOM_SCREEN_TOP_BAR); - - u32 bottomScreenTopBarShadowWidth = 0; - u32 bottomScreenTopBarShadowHeight = 0; - screen_get_texture_size(&bottomScreenTopBarShadowWidth, &bottomScreenTopBarShadowHeight, TEXTURE_BOTTOM_SCREEN_TOP_BAR_SHADOW); - - u32 bottomScreenBottomBarWidth = 0; - u32 bottomScreenBottomBarHeight = 0; - screen_get_texture_size(&bottomScreenBottomBarWidth, &bottomScreenBottomBarHeight, TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR); - - u32 bottomScreenBottomBarShadowWidth = 0; - u32 bottomScreenBottomBarShadowHeight = 0; - screen_get_texture_size(&bottomScreenBottomBarShadowWidth, &bottomScreenBottomBarShadowHeight, TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR_SHADOW); - - screen_draw_texture(TEXTURE_BOTTOM_SCREEN_BG, (BOTTOM_SCREEN_WIDTH - bottomScreenBgWidth) / 2, (BOTTOM_SCREEN_HEIGHT - bottomScreenBgHeight) / 2, bottomScreenBgWidth, bottomScreenBgHeight); - - screen_set_base_alpha(ui_fade_alpha); - - if(ui->drawBottom != NULL) { - ui->drawBottom(ui, ui->data, 0, bottomScreenTopBarHeight, BOTTOM_SCREEN_WIDTH, BOTTOM_SCREEN_HEIGHT - bottomScreenBottomBarHeight); - } - - screen_set_base_alpha(0xFF); - - float bottomScreenTopBarX = (BOTTOM_SCREEN_WIDTH - bottomScreenTopBarWidth) / 2; - float bottomScreenTopBarY = 0; - screen_draw_texture(TEXTURE_BOTTOM_SCREEN_TOP_BAR, bottomScreenTopBarX, bottomScreenTopBarY, bottomScreenTopBarWidth, bottomScreenTopBarHeight); - screen_draw_texture(TEXTURE_BOTTOM_SCREEN_TOP_BAR_SHADOW, bottomScreenTopBarX, bottomScreenTopBarY + bottomScreenTopBarHeight, bottomScreenTopBarShadowWidth, bottomScreenTopBarShadowHeight); - - float bottomScreenBottomBarX = (BOTTOM_SCREEN_WIDTH - bottomScreenBottomBarWidth) / 2; - float bottomScreenBottomBarY = BOTTOM_SCREEN_HEIGHT - bottomScreenBottomBarHeight; - screen_draw_texture(TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR, bottomScreenBottomBarX, bottomScreenBottomBarY, bottomScreenBottomBarWidth, bottomScreenBottomBarHeight); - screen_draw_texture(TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR_SHADOW, bottomScreenBottomBarX, bottomScreenBottomBarY - bottomScreenBottomBarShadowHeight, bottomScreenBottomBarShadowWidth, bottomScreenBottomBarShadowHeight); - - screen_set_base_alpha(ui_fade_alpha); - - if(ui->name != NULL) { - float nameWidth; - float nameHeight; - screen_get_string_size(&nameWidth, &nameHeight, ui->name, 0.5f, 0.5f); - screen_draw_string(ui->name, (BOTTOM_SCREEN_WIDTH - nameWidth) / 2, (bottomScreenTopBarHeight - nameHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); - } - - if(ui->info != NULL) { - float infoWidth; - float infoHeight; - screen_get_string_size(&infoWidth, &infoHeight, ui->info, 0.5f, 0.5f); - screen_draw_string(ui->info, (BOTTOM_SCREEN_WIDTH - infoWidth) / 2, BOTTOM_SCREEN_HEIGHT - (bottomScreenBottomBarHeight + infoHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); - } - - screen_set_base_alpha(0xFF); -} - -bool ui_update() { - ui_view* ui = NULL; - - hidScanInput(); - - ui = ui_top(); - if(ui != NULL && ui->update != NULL) { - u32 bottomScreenTopBarHeight = 0; - screen_get_texture_size(NULL, &bottomScreenTopBarHeight, TEXTURE_BOTTOM_SCREEN_TOP_BAR); - - u32 bottomScreenBottomBarHeight = 0; - screen_get_texture_size(NULL, &bottomScreenBottomBarHeight, TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR); - - ui->update(ui, ui->data, 0, bottomScreenTopBarHeight, BOTTOM_SCREEN_WIDTH, BOTTOM_SCREEN_HEIGHT - bottomScreenBottomBarHeight); - } - - u64 time = osGetTime(); - if(!envIsHomebrew() && time - ui_fade_begin_time < 500) { - ui_fade_alpha = (u8) (((time - ui_fade_begin_time) / 500.0f) * 0xFF); - } else { - ui_fade_alpha = 0xFF; - } - - ui = ui_top(); - if(ui != NULL) { - screen_begin_frame(); - ui_draw_top(ui); - ui_draw_bottom(ui); - screen_end_frame(); - } - - return ui != NULL; -} - -const char* ui_get_display_eta(u32 seconds) { - static char disp[12]; - - u8 hours = seconds / 3600; - seconds -= hours * 3600; - u8 minutes = seconds / 60; - seconds -= minutes* 60; - - snprintf(disp, 12, "%02u:%02u:%02u", hours, minutes, (u8) seconds); - return disp; -} - -double ui_get_display_size(u64 size) { - double s = size; - if(s > 1024) { - s /= 1024; - } - - if(s > 1024) { - s /= 1024; - } - - if(s > 1024) { - s /= 1024; - } - - return s; -} - -const char* ui_get_display_size_units(u64 size) { - if(size > 1024 * 1024 * 1024) { - return "GiB"; - } - - if(size > 1024 * 1024) { - return "MiB"; - } - - if(size > 1024) { - return "KiB"; - } - - return "B"; -} - -void ui_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - meta_info* info = (meta_info*) data; - - u32 metaInfoBoxShadowWidth; - u32 metaInfoBoxShadowHeight; - screen_get_texture_size(&metaInfoBoxShadowWidth, &metaInfoBoxShadowHeight, TEXTURE_META_INFO_BOX_SHADOW); - - float metaInfoBoxShadowX = x1 + (x2 - x1 - metaInfoBoxShadowWidth) / 2; - float metaInfoBoxShadowY = y1 + (y2 - y1) / 4 - metaInfoBoxShadowHeight / 2; - screen_draw_texture(TEXTURE_META_INFO_BOX_SHADOW, metaInfoBoxShadowX, metaInfoBoxShadowY, metaInfoBoxShadowWidth, metaInfoBoxShadowHeight); - - u32 metaInfoBoxWidth; - u32 metaInfoBoxHeight; - screen_get_texture_size(&metaInfoBoxWidth, &metaInfoBoxHeight, TEXTURE_META_INFO_BOX); - - float metaInfoBoxX = x1 + (x2 - x1 - metaInfoBoxWidth) / 2; - float metaInfoBoxY = y1 + (y2 - y1) / 4 - metaInfoBoxHeight / 2; - screen_draw_texture(TEXTURE_META_INFO_BOX, metaInfoBoxX, metaInfoBoxY, metaInfoBoxWidth, metaInfoBoxHeight); - - if(info->texture != 0) { - u32 iconWidth; - u32 iconHeight; - screen_get_texture_size(&iconWidth, &iconHeight, info->texture); - - float iconX = metaInfoBoxX + (64 - iconWidth) / 2; - float iconY = metaInfoBoxY + (metaInfoBoxHeight - iconHeight) / 2; - screen_draw_texture(info->texture, iconX, iconY, iconWidth, iconHeight); - } - - float metaTextX = metaInfoBoxX + 64; - - float shortDescriptionHeight; - screen_get_string_size_wrap(NULL, &shortDescriptionHeight, info->shortDescription, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX); - - float longDescriptionHeight; - screen_get_string_size_wrap(NULL, &longDescriptionHeight, info->longDescription, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX); - - float publisherHeight; - screen_get_string_size_wrap(NULL, &publisherHeight, info->publisher, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX); - - float shortDescriptionY = metaInfoBoxY + (64 - shortDescriptionHeight - 2 - longDescriptionHeight - 2 - publisherHeight) / 2; - screen_draw_string_wrap(info->shortDescription, metaTextX, shortDescriptionY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8); - - float longDescriptionY = shortDescriptionY + shortDescriptionHeight + 2; - screen_draw_string_wrap(info->longDescription, metaTextX, longDescriptionY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8); - - float publisherY = longDescriptionY + longDescriptionHeight + 2; - screen_draw_string_wrap(info->publisher, metaTextX, publisherY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8); -} - -void ui_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ext_save_data_info* info = (ext_save_data_info*) data; - - if(info->hasMeta) { - ui_draw_meta_info(view, &info->meta, x1, y1, x2, y2); - } - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), - "Ext Save Data ID: %016llX\n" - "Shared: %s", - info->extSaveDataId, - info->shared ? "Yes" : "No"); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - file_info* info = (file_info*) data; - - char infoText[512]; - size_t infoTextPos = 0; - - if(strlen(info->name) > 48) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Name: %.45s...\n", info->name); - } else { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Name: %.48s\n", info->name); - } - - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Attributes: "); - - if(info->attributes & (FS_ATTRIBUTE_DIRECTORY | FS_ATTRIBUTE_HIDDEN | FS_ATTRIBUTE_ARCHIVE | FS_ATTRIBUTE_READ_ONLY)) { - bool needsSeparator = false; - - if(info->attributes & FS_ATTRIBUTE_DIRECTORY) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Directory"); - needsSeparator = true; - } - - if(info->attributes & FS_ATTRIBUTE_HIDDEN) { - if(needsSeparator) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", "); - } - - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Hidden"); - needsSeparator = true; - } - - if(info->attributes & FS_ATTRIBUTE_ARCHIVE) { - if(needsSeparator) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", "); - } - - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Archive"); - needsSeparator = true; - } - - if(info->attributes & FS_ATTRIBUTE_READ_ONLY) { - if(needsSeparator) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", "); - } - - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Read Only"); - needsSeparator = true; - } - } else { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "None"); - } - - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "\n"); - - if(!(info->attributes & FS_ATTRIBUTE_DIRECTORY)) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Size: %.2f %s\n", - ui_get_display_size(info->size), ui_get_display_size_units(info->size)); - - if(info->isCia) { - char regionString[64]; - - if(info->ciaInfo.hasMeta) { - ui_draw_meta_info(view, &info->ciaInfo.meta, x1, y1, x2, y2); - - smdh_region_to_string(regionString, info->ciaInfo.meta.region, sizeof(regionString)); - } else { - snprintf(regionString, sizeof(regionString), "Unknown"); - } - - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, - "Title ID: %016llX\n" - "Version: %hu (%d.%d.%d)\n" - "Region: %s\n" - "Installed Size: %.2f %s", - info->ciaInfo.titleId, - info->ciaInfo.version, (info->ciaInfo.version >> 10) & 0x3F, (info->ciaInfo.version >> 4) & 0x3F, info->ciaInfo.version & 0xF, - regionString, - ui_get_display_size(info->ciaInfo.installedSize), - ui_get_display_size_units(info->ciaInfo.installedSize)); - } else if(info->isTicket) { - infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Ticket ID: %016llX", info->ticketInfo.titleId); - } - } - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - pending_title_info* info = (pending_title_info*) data; - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), - "Pending Title ID: %016llX\n" - "Media Type: %s\n" - "Version: %hu (%d.%d.%d)", - info->titleId, - info->mediaType == MEDIATYPE_NAND ? "NAND" : info->mediaType == MEDIATYPE_SD ? "SD" : "Game Card", - info->version, (info->version >> 10) & 0x3F, (info->version >> 4) & 0x3F, info->version & 0xF); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - system_save_data_info* info = (system_save_data_info*) data; - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), "System Save Data ID: %08lX", info->systemSaveDataId); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ticket_info* info = (ticket_info*) data; - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), "Title ID: %016llX", info->titleId); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - title_info* info = (title_info*) data; - - char regionString[64]; - - if(info->hasMeta) { - ui_draw_meta_info(view, &info->meta, x1, y1, x2, y2); - - smdh_region_to_string(regionString, info->meta.region, sizeof(regionString)); - } else { - snprintf(regionString, sizeof(regionString), "Unknown"); - } - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), - "Title ID: %016llX\n" - "Media Type: %s\n" - "Version: %hu (%d.%d.%d)\n" - "Product Code: %s\n" - "Region: %s\n" - "Size: %.2f %s", - info->titleId, - info->mediaType == MEDIATYPE_NAND ? "NAND" : info->mediaType == MEDIATYPE_SD ? "SD" : "Game Card", - info->version, (info->version >> 10) & 0x3F, (info->version >> 4) & 0x3F, info->version & 0xF, - info->productCode, - regionString, - ui_get_display_size(info->installedSize), ui_get_display_size_units(info->installedSize)); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - titledb_info* info = (titledb_info*) data; - - ui_draw_meta_info(view, &info->meta, x1, y1, x2, y2); - - char infoText[1024]; - - snprintf(infoText, sizeof(infoText), - "%s\n" - "\n" - "Category: %s\n", - info->headline, - info->category); - - float infoWidth; - screen_get_string_size_wrap(&infoWidth, NULL, infoText, 0.5f, 0.5f, x2 - x1 - 10); - - // TODO: Wrap by word, not character? - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string_wrap(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true, infoX + infoWidth + 1); -} - -void ui_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - titledb_info* info = (titledb_info*) data; - - ui_draw_meta_info(view, &info->meta, x1, y1, x2, y2); - - char updatedDate[32] = ""; - char updatedTime[32] = ""; - - sscanf(info->cia.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime); - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), - "Title ID: %016llX\n" - "TitleDB Version: %s\n" - "Installed Version: %hu (%d.%d.%d)\n" - "Size: %.2f %s\n" - "Updated At: %s %s", - info->cia.titleId, - info->cia.version, - info->cia.installedVersion, (info->cia.installedVersion >> 10) & 0x3F, (info->cia.installedVersion >> 4) & 0x3F, info->cia.installedVersion & 0xF, - ui_get_display_size(info->cia.size), ui_get_display_size_units(info->cia.size), - updatedDate, updatedTime); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); -} - -void ui_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - titledb_info* info = (titledb_info*) data; - - ui_draw_meta_info(view, &info->meta, x1, y1, x2, y2); - - char updatedDate[32] = ""; - char updatedTime[32] = ""; - - sscanf(info->tdsx.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime); - - char infoText[512]; - - snprintf(infoText, sizeof(infoText), - "TitleDB Version: %s\n" - "Size: %.2f %s\n" - "Updated At: %s %s", - info->tdsx.version, - ui_get_display_size(info->tdsx.size), ui_get_display_size_units(info->tdsx.size), - updatedDate, updatedTime); - - float infoWidth; - screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); - - float infoX = x1 + (x2 - x1 - infoWidth) / 2; - float infoY = y1 + (y2 - y1) / 2 - 8; - screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +#include +#include +#include + +#include <3ds.h> +#include + +#include "ui.h" +#include "../error.h" +#include "../screen.h" +#include "../data/smdh.h" +#include "../../fbi/resources.h" + +#define MAX_UI_VIEWS 16 + +static ui_view* ui_stack[MAX_UI_VIEWS]; +static int ui_stack_top = -1; + +static Handle ui_stack_mutex = 0; + +static u64 ui_free_space_last_update = 0; +static char ui_free_space_buffer[128]; + +static u64 ui_fade_begin_time = 0; +static u8 ui_fade_alpha = 0; + +void ui_init() { + if(ui_stack_mutex == 0) { + svcCreateMutex(&ui_stack_mutex, false); + } + + ui_fade_begin_time = osGetTime(); +} + +void ui_exit() { + if(ui_stack_mutex != 0) { + svcCloseHandle(ui_stack_mutex); + ui_stack_mutex = 0; + } +} + +ui_view* ui_create() { + ui_view* view = (ui_view*) calloc(1, sizeof(ui_view)); + if(view == NULL) { + error_panic("Failed to allocate UI view."); + return NULL; + } + + Result res = 0; + if(R_FAILED(res = svcCreateEvent(&view->active, RESET_STICKY))) { + error_panic("Failed to create view active event: 0x%08lX", res); + + free(view); + return NULL; + } + + return view; +} + +void ui_destroy(ui_view* view) { + if(view != NULL) { + svcCloseHandle(view->active); + free(view); + } +} + +ui_view* ui_top() { + svcWaitSynchronization(ui_stack_mutex, U64_MAX); + + ui_view* ui = NULL; + if(ui_stack_top >= 0) { + ui = ui_stack[ui_stack_top]; + } + + svcReleaseMutex(ui_stack_mutex); + + return ui; +} + +bool ui_push(ui_view* view) { + if(view == NULL) { + return false; + } + + svcWaitSynchronization(ui_stack_mutex, U64_MAX); + + bool space = ui_stack_top < MAX_UI_VIEWS - 1; + if(space) { + ui_stack[++ui_stack_top] = view; + + svcClearEvent(view->active); + } + + svcReleaseMutex(ui_stack_mutex); + + return space; +} + +void ui_pop() { + svcWaitSynchronization(ui_stack_mutex, U64_MAX); + + if(ui_stack_top >= 0) { + svcSignalEvent(ui_stack[ui_stack_top]->active); + + ui_stack[ui_stack_top--] = NULL; + } + + svcReleaseMutex(ui_stack_mutex); +} + +static void ui_draw_top(ui_view* ui) { + screen_select(GFX_TOP); + + u32 topScreenBgWidth = 0; + u32 topScreenBgHeight = 0; + screen_get_texture_size(&topScreenBgWidth, &topScreenBgHeight, TEXTURE_TOP_SCREEN_BG); + + u32 topScreenTopBarWidth = 0; + u32 topScreenTopBarHeight = 0; + screen_get_texture_size(&topScreenTopBarWidth, &topScreenTopBarHeight, TEXTURE_TOP_SCREEN_TOP_BAR); + + u32 topScreenTopBarShadowWidth = 0; + u32 topScreenTopBarShadowHeight = 0; + screen_get_texture_size(&topScreenTopBarShadowWidth, &topScreenTopBarShadowHeight, TEXTURE_TOP_SCREEN_TOP_BAR_SHADOW); + + u32 topScreenBottomBarWidth = 0; + u32 topScreenBottomBarHeight = 0; + screen_get_texture_size(&topScreenBottomBarWidth, &topScreenBottomBarHeight, TEXTURE_TOP_SCREEN_BOTTOM_BAR); + + u32 topScreenBottomBarShadowWidth = 0; + u32 topScreenBottomBarShadowHeight = 0; + screen_get_texture_size(&topScreenBottomBarShadowWidth, &topScreenBottomBarShadowHeight, TEXTURE_TOP_SCREEN_BOTTOM_BAR_SHADOW); + + screen_draw_texture(TEXTURE_TOP_SCREEN_BG, (TOP_SCREEN_WIDTH - topScreenBgWidth) / 2, (TOP_SCREEN_HEIGHT - topScreenBgHeight) / 2, topScreenBgWidth, topScreenBgHeight); + + if(ui->drawTop != NULL) { + ui->drawTop(ui, ui->data, 0, topScreenTopBarHeight, TOP_SCREEN_WIDTH, TOP_SCREEN_HEIGHT - topScreenBottomBarHeight); + } + + float topScreenTopBarX = (TOP_SCREEN_WIDTH - topScreenTopBarWidth) / 2; + float topScreenTopBarY = 0; + screen_draw_texture(TEXTURE_TOP_SCREEN_TOP_BAR, topScreenTopBarX, topScreenTopBarY, topScreenTopBarWidth, topScreenTopBarHeight); + screen_draw_texture(TEXTURE_TOP_SCREEN_TOP_BAR_SHADOW, topScreenTopBarX, topScreenTopBarY + topScreenTopBarHeight, topScreenTopBarShadowWidth, topScreenTopBarShadowHeight); + + float topScreenBottomBarX = (TOP_SCREEN_WIDTH - topScreenBottomBarWidth) / 2; + float topScreenBottomBarY = TOP_SCREEN_HEIGHT - topScreenBottomBarHeight; + screen_draw_texture(TEXTURE_TOP_SCREEN_BOTTOM_BAR, topScreenBottomBarX, topScreenBottomBarY, topScreenBottomBarWidth, topScreenBottomBarHeight); + screen_draw_texture(TEXTURE_TOP_SCREEN_BOTTOM_BAR_SHADOW, topScreenBottomBarX, topScreenBottomBarY - topScreenBottomBarShadowHeight, topScreenBottomBarShadowWidth, topScreenBottomBarShadowHeight); + + screen_set_base_alpha(ui_fade_alpha); + + char verText[64]; + snprintf(verText, 64, "Ver. %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO); + + float verWidth; + float verHeight; + screen_get_string_size(&verWidth, &verHeight, verText, 0.5f, 0.5f); + screen_draw_string(verText, topScreenTopBarX + 2, topScreenTopBarY + (topScreenTopBarHeight - verHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); + + time_t t = time(NULL); + char* timeText = ctime(&t); + timeText[strlen(timeText) - 1] = '\0'; + + float timeTextWidth; + float timeTextHeight; + screen_get_string_size(&timeTextWidth, &timeTextHeight, timeText, 0.5f, 0.5f); + screen_draw_string(timeText, topScreenTopBarX + (topScreenTopBarWidth - timeTextWidth) / 2, topScreenTopBarY + (topScreenTopBarHeight - timeTextHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); + + u32 batteryIcon = 0; + u8 batteryChargeState = 0; + u8 batteryLevel = 0; + if(R_SUCCEEDED(PTMU_GetBatteryChargeState(&batteryChargeState)) && batteryChargeState) { + batteryIcon = TEXTURE_BATTERY_CHARGING; + } else if(R_SUCCEEDED(PTMU_GetBatteryLevel(&batteryLevel))) { + batteryIcon = TEXTURE_BATTERY_0 + batteryLevel; + } else { + batteryIcon = TEXTURE_BATTERY_0; + } + + u32 batteryWidth; + u32 batteryHeight; + screen_get_texture_size(&batteryWidth, &batteryHeight, batteryIcon); + + float batteryX = topScreenTopBarX + topScreenTopBarWidth - 2 - batteryWidth; + float batteryY = topScreenTopBarY + (topScreenTopBarHeight - batteryHeight) / 2; + screen_draw_texture(batteryIcon, batteryX, batteryY, batteryWidth, batteryHeight); + + u32 wifiIcon = 0; + u32 wifiStatus = 0; + if(R_SUCCEEDED(ACU_GetWifiStatus(&wifiStatus)) && wifiStatus) { + wifiIcon = TEXTURE_WIFI_0 + osGetWifiStrength(); + } else { + wifiIcon = TEXTURE_WIFI_DISCONNECTED; + } + + u32 wifiWidth; + u32 wifiHeight; + screen_get_texture_size(&wifiWidth, &wifiHeight, wifiIcon); + + float wifiX = topScreenTopBarX + topScreenTopBarWidth - 2 - batteryWidth - 4 - wifiWidth; + float wifiY = topScreenTopBarY + (topScreenTopBarHeight - wifiHeight) / 2; + screen_draw_texture(wifiIcon, wifiX, wifiY, wifiWidth, wifiHeight); + + if(osGetTime() >= ui_free_space_last_update + 1000) { + char* currBuffer = ui_free_space_buffer; + FS_ArchiveResource resource = {0}; + + if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_SD)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { + if(currBuffer != ui_free_space_buffer) { + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); + currBuffer += strlen(currBuffer); + } + + u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "SD: %.1f %s", + ui_get_display_size(size), ui_get_display_size_units(size)); + currBuffer += strlen(currBuffer); + } + + if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_CTR_NAND)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { + if(currBuffer != ui_free_space_buffer) { + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); + currBuffer += strlen(currBuffer); + } + + u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "CTR NAND: %.1f %s", + ui_get_display_size(size), ui_get_display_size_units(size)); + currBuffer += strlen(currBuffer); + } + + if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_TWL_NAND)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { + if(currBuffer != ui_free_space_buffer) { + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); + currBuffer += strlen(currBuffer); + } + + u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "TWL NAND: %.1f %s", + ui_get_display_size(size), ui_get_display_size_units(size)); + currBuffer += strlen(currBuffer); + } + + if(R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, SYSTEM_MEDIATYPE_TWL_PHOTO)) && currBuffer < ui_free_space_buffer + sizeof(ui_free_space_buffer)) { + if(currBuffer != ui_free_space_buffer) { + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), ", "); + currBuffer += strlen(currBuffer); + } + + u64 size = (u64) resource.freeClusters * (u64) resource.clusterSize; + snprintf(currBuffer, sizeof(ui_free_space_buffer) - (currBuffer - ui_free_space_buffer), "TWL Photo: %.1f %s", + ui_get_display_size(size), ui_get_display_size_units(size)); + currBuffer += strlen(currBuffer); + } + + ui_free_space_last_update = osGetTime(); + } + + float freeSpaceHeight; + screen_get_string_size(NULL, &freeSpaceHeight, ui_free_space_buffer, 0.35f, 0.35f); + + screen_draw_string(ui_free_space_buffer, topScreenBottomBarX + 2, topScreenBottomBarY + (topScreenBottomBarHeight - freeSpaceHeight) / 2, 0.35f, 0.35f, COLOR_TEXT, true); + + screen_set_base_alpha(0xFF); +} + +static void ui_draw_bottom(ui_view* ui) { + screen_select(GFX_BOTTOM); + + u32 bottomScreenBgWidth = 0; + u32 bottomScreenBgHeight = 0; + screen_get_texture_size(&bottomScreenBgWidth, &bottomScreenBgHeight, TEXTURE_BOTTOM_SCREEN_BG); + + u32 bottomScreenTopBarWidth = 0; + u32 bottomScreenTopBarHeight = 0; + screen_get_texture_size(&bottomScreenTopBarWidth, &bottomScreenTopBarHeight, TEXTURE_BOTTOM_SCREEN_TOP_BAR); + + u32 bottomScreenTopBarShadowWidth = 0; + u32 bottomScreenTopBarShadowHeight = 0; + screen_get_texture_size(&bottomScreenTopBarShadowWidth, &bottomScreenTopBarShadowHeight, TEXTURE_BOTTOM_SCREEN_TOP_BAR_SHADOW); + + u32 bottomScreenBottomBarWidth = 0; + u32 bottomScreenBottomBarHeight = 0; + screen_get_texture_size(&bottomScreenBottomBarWidth, &bottomScreenBottomBarHeight, TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR); + + u32 bottomScreenBottomBarShadowWidth = 0; + u32 bottomScreenBottomBarShadowHeight = 0; + screen_get_texture_size(&bottomScreenBottomBarShadowWidth, &bottomScreenBottomBarShadowHeight, TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR_SHADOW); + + screen_draw_texture(TEXTURE_BOTTOM_SCREEN_BG, (BOTTOM_SCREEN_WIDTH - bottomScreenBgWidth) / 2, (BOTTOM_SCREEN_HEIGHT - bottomScreenBgHeight) / 2, bottomScreenBgWidth, bottomScreenBgHeight); + + screen_set_base_alpha(ui_fade_alpha); + + if(ui->drawBottom != NULL) { + ui->drawBottom(ui, ui->data, 0, bottomScreenTopBarHeight, BOTTOM_SCREEN_WIDTH, BOTTOM_SCREEN_HEIGHT - bottomScreenBottomBarHeight); + } + + screen_set_base_alpha(0xFF); + + float bottomScreenTopBarX = (BOTTOM_SCREEN_WIDTH - bottomScreenTopBarWidth) / 2; + float bottomScreenTopBarY = 0; + screen_draw_texture(TEXTURE_BOTTOM_SCREEN_TOP_BAR, bottomScreenTopBarX, bottomScreenTopBarY, bottomScreenTopBarWidth, bottomScreenTopBarHeight); + screen_draw_texture(TEXTURE_BOTTOM_SCREEN_TOP_BAR_SHADOW, bottomScreenTopBarX, bottomScreenTopBarY + bottomScreenTopBarHeight, bottomScreenTopBarShadowWidth, bottomScreenTopBarShadowHeight); + + float bottomScreenBottomBarX = (BOTTOM_SCREEN_WIDTH - bottomScreenBottomBarWidth) / 2; + float bottomScreenBottomBarY = BOTTOM_SCREEN_HEIGHT - bottomScreenBottomBarHeight; + screen_draw_texture(TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR, bottomScreenBottomBarX, bottomScreenBottomBarY, bottomScreenBottomBarWidth, bottomScreenBottomBarHeight); + screen_draw_texture(TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR_SHADOW, bottomScreenBottomBarX, bottomScreenBottomBarY - bottomScreenBottomBarShadowHeight, bottomScreenBottomBarShadowWidth, bottomScreenBottomBarShadowHeight); + + screen_set_base_alpha(ui_fade_alpha); + + if(ui->name != NULL) { + float nameWidth; + float nameHeight; + screen_get_string_size(&nameWidth, &nameHeight, ui->name, 0.5f, 0.5f); + screen_draw_string(ui->name, (BOTTOM_SCREEN_WIDTH - nameWidth) / 2, (bottomScreenTopBarHeight - nameHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); + } + + if(ui->info != NULL) { + float infoWidth; + float infoHeight; + screen_get_string_size(&infoWidth, &infoHeight, ui->info, 0.5f, 0.5f); + screen_draw_string(ui->info, (BOTTOM_SCREEN_WIDTH - infoWidth) / 2, BOTTOM_SCREEN_HEIGHT - (bottomScreenBottomBarHeight + infoHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); + } + + screen_set_base_alpha(0xFF); +} + +bool ui_update() { + ui_view* ui = NULL; + + hidScanInput(); + + ui = ui_top(); + if(ui != NULL && ui->update != NULL) { + u32 bottomScreenTopBarHeight = 0; + screen_get_texture_size(NULL, &bottomScreenTopBarHeight, TEXTURE_BOTTOM_SCREEN_TOP_BAR); + + u32 bottomScreenBottomBarHeight = 0; + screen_get_texture_size(NULL, &bottomScreenBottomBarHeight, TEXTURE_BOTTOM_SCREEN_BOTTOM_BAR); + + ui->update(ui, ui->data, 0, bottomScreenTopBarHeight, BOTTOM_SCREEN_WIDTH, BOTTOM_SCREEN_HEIGHT - bottomScreenBottomBarHeight); + } + + u64 time = osGetTime(); + if(!envIsHomebrew() && time - ui_fade_begin_time < 500) { + ui_fade_alpha = (u8) (((time - ui_fade_begin_time) / 500.0f) * 0xFF); + } else { + ui_fade_alpha = 0xFF; + } + + ui = ui_top(); + if(ui != NULL) { + screen_begin_frame(); + ui_draw_top(ui); + ui_draw_bottom(ui); + screen_end_frame(); + } + + return ui != NULL; +} + +const char* ui_get_display_eta(u32 seconds) { + static char disp[12]; + + u8 hours = seconds / 3600; + seconds -= hours * 3600; + u8 minutes = seconds / 60; + seconds -= minutes* 60; + + snprintf(disp, 12, "%02u:%02u:%02u", hours, minutes, (u8) seconds); + return disp; +} + +double ui_get_display_size(u64 size) { + double s = size; + if(s > 1024) { + s /= 1024; + } + + if(s > 1024) { + s /= 1024; + } + + if(s > 1024) { + s /= 1024; + } + + return s; +} + +const char* ui_get_display_size_units(u64 size) { + if(size > 1024 * 1024 * 1024) { + return "GiB"; + } + + if(size > 1024 * 1024) { + return "MiB"; + } + + if(size > 1024) { + return "KiB"; + } + + return "B"; } \ No newline at end of file diff --git a/source/core/ui/ui.h b/source/core/ui/ui.h new file mode 100644 index 0000000..b8397ee --- /dev/null +++ b/source/core/ui/ui.h @@ -0,0 +1,33 @@ +#pragma once + +typedef struct ui_view_s { + const char* name; + const char* info; + void* data; + void (*update)(struct ui_view_s* view, void* data, float bx1, float by1, float bx2, float by2); + void (*drawTop)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2); + void (*drawBottom)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2); + + Handle active; +} ui_view; + +void ui_init(); +void ui_exit(); + +ui_view* ui_create(); +void ui_destroy(ui_view* view); + +ui_view* ui_top(); +bool ui_push(ui_view* view); +void ui_pop(); +bool ui_update(); + +const char* ui_get_display_eta(u32 seconds); +double ui_get_display_size(u64 size); +const char* ui_get_display_size_units(u64 size); + +#include "error.h" +#include "info.h" +#include "kbd.h" +#include "list.h" +#include "prompt.h" \ No newline at end of file diff --git a/source/ui/section/action/action.h b/source/fbi/action/action.h similarity index 100% rename from source/ui/section/action/action.h rename to source/fbi/action/action.h diff --git a/source/ui/section/action/browsebossextsavedata.c b/source/fbi/action/browsebossextsavedata.c similarity index 89% rename from source/ui/section/action/browsebossextsavedata.c rename to source/fbi/action/browsebossextsavedata.c index 150e494..28dc397 100644 --- a/source/ui/section/action/browsebossextsavedata.c +++ b/source/fbi/action/browsebossextsavedata.c @@ -3,8 +3,7 @@ #include "action.h" #include "../section.h" #include "../task/uitask.h" -#include "../../list.h" -#include "../../../core/fs.h" +#include "../../core/core.h" void action_browse_boss_ext_save_data(linked_list* items, list_item* selected) { ext_save_data_info* info = (ext_save_data_info*) selected->data; diff --git a/source/ui/section/action/browsesystemsavedata.c b/source/fbi/action/browsesystemsavedata.c similarity index 87% rename from source/ui/section/action/browsesystemsavedata.c rename to source/fbi/action/browsesystemsavedata.c index 244dc41..7869ce9 100644 --- a/source/ui/section/action/browsesystemsavedata.c +++ b/source/fbi/action/browsesystemsavedata.c @@ -3,8 +3,7 @@ #include "action.h" #include "../section.h" #include "../task/uitask.h" -#include "../../list.h" -#include "../../../core/fs.h" +#include "../../core/core.h" void action_browse_system_save_data(linked_list* items, list_item* selected) { system_save_data_info* info = (system_save_data_info*) selected->data; diff --git a/source/ui/section/action/browsetitlesavedata.c b/source/fbi/action/browsetitlesavedata.c similarity index 88% rename from source/ui/section/action/browsetitlesavedata.c rename to source/fbi/action/browsetitlesavedata.c index da45ad6..baf3205 100644 --- a/source/ui/section/action/browsetitlesavedata.c +++ b/source/fbi/action/browsetitlesavedata.c @@ -3,8 +3,7 @@ #include "action.h" #include "../section.h" #include "../task/uitask.h" -#include "../../list.h" -#include "../../../core/fs.h" +#include "../../core/core.h" void action_browse_title_save_data(linked_list* items, list_item* selected) { title_info* info = (title_info*) selected->data; diff --git a/source/ui/section/action/browseuserextsavedata.c b/source/fbi/action/browseuserextsavedata.c similarity index 90% rename from source/ui/section/action/browseuserextsavedata.c rename to source/fbi/action/browseuserextsavedata.c index 2401686..a3bec6c 100644 --- a/source/ui/section/action/browseuserextsavedata.c +++ b/source/fbi/action/browseuserextsavedata.c @@ -3,8 +3,7 @@ #include "action.h" #include "../section.h" #include "../task/uitask.h" -#include "../../list.h" -#include "../../../core/fs.h" +#include "../../core/core.h" void action_browse_user_ext_save_data(linked_list* items, list_item* selected) { ext_save_data_info* info = (ext_save_data_info*) selected->data; diff --git a/source/ui/section/action/deletecontents.c b/source/fbi/action/deletecontents.c similarity index 94% rename from source/ui/section/action/deletecontents.c rename to source/fbi/action/deletecontents.c index 0d72438..ac1f25c 100644 --- a/source/ui/section/action/deletecontents.c +++ b/source/fbi/action/deletecontents.c @@ -5,17 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -33,9 +25,9 @@ static void action_delete_draw_top(ui_view* view, void* data, float x1, float y1 u32 curr = deleteData->deleteInfo.processed; if(curr < deleteData->deleteInfo.total) { - ui_draw_file_info(view, ((list_item*) linked_list_get(&deleteData->contents, linked_list_size(&deleteData->contents) - curr - 1))->data, x1, y1, x2, y2); + task_draw_file_info(view, ((list_item*) linked_list_get(&deleteData->contents, linked_list_size(&deleteData->contents) - curr - 1))->data, x1, y1, x2, y2); } else { - ui_draw_file_info(view, deleteData->target, x1, y1, x2, y2); + task_draw_file_info(view, deleteData->target, x1, y1, x2, y2); } } diff --git a/source/ui/section/action/deleteextsavedata.c b/source/fbi/action/deleteextsavedata.c similarity index 81% rename from source/ui/section/action/deleteextsavedata.c rename to source/fbi/action/deleteextsavedata.c index 663584f..8b0d89a 100644 --- a/source/ui/section/action/deleteextsavedata.c +++ b/source/fbi/action/deleteextsavedata.c @@ -3,15 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -19,7 +13,7 @@ typedef struct { } delete_ext_save_data_data; static void action_delete_ext_save_data_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_ext_save_data_info(view, ((delete_ext_save_data_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_ext_save_data_info(view, ((delete_ext_save_data_data*) data)->selected->data, x1, y1, x2, y2); } static void action_delete_ext_save_data_update(ui_view* view, void* data, float* progress, char* text) { @@ -33,7 +27,7 @@ static void action_delete_ext_save_data_update(ui_view* view, void* data, float* info_destroy(view); if(R_FAILED(res)) { - error_display_res(info, ui_draw_ext_save_data_info, res, "Failed to delete ext save data."); + error_display_res(info, task_draw_ext_save_data_info, res, "Failed to delete ext save data."); } else { linked_list_remove(deleteData->items, deleteData->selected); task_free_ext_save_data(deleteData->selected); diff --git a/source/ui/section/action/deletependingtitles.c b/source/fbi/action/deletependingtitles.c similarity index 95% rename from source/ui/section/action/deletependingtitles.c rename to source/fbi/action/deletependingtitles.c index 804b5f9..b3a635a 100644 --- a/source/ui/section/action/deletependingtitles.c +++ b/source/fbi/action/deletependingtitles.c @@ -5,15 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -30,7 +24,7 @@ static void action_delete_pending_titles_draw_top(ui_view* view, void* data, flo u32 index = deleteData->deleteInfo.processed; if(index < deleteData->deleteInfo.total) { - ui_draw_pending_title_info(view, (pending_title_info*) ((list_item*) linked_list_get(&deleteData->contents, index))->data, x1, y1, x2, y2); + task_draw_pending_title_info(view, (pending_title_info*) ((list_item*) linked_list_get(&deleteData->contents, index))->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/action/deletesecurevalue.c b/source/fbi/action/deletesecurevalue.c similarity index 63% rename from source/ui/section/action/deletesecurevalue.c rename to source/fbi/action/deletesecurevalue.c index f09cce1..0dbca33 100644 --- a/source/ui/section/action/deletesecurevalue.c +++ b/source/fbi/action/deletesecurevalue.c @@ -3,15 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" static void action_delete_secure_value_update(ui_view* view, void* data, float* progress, char* text) { title_info* info = (title_info*) data; @@ -24,18 +18,18 @@ static void action_delete_secure_value_update(ui_view* view, void* data, float* info_destroy(view); if(R_FAILED(res)) { - error_display_res(info, ui_draw_title_info, res, "Failed to delete secure value."); + error_display_res(info, task_draw_title_info, res, "Failed to delete secure value."); } else { - prompt_display_notify("Success", "Secure value deleted.", COLOR_TEXT, info, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Secure value deleted.", COLOR_TEXT, info, task_draw_title_info, NULL); } } static void action_delete_secure_value_onresponse(ui_view* view, void* data, u32 response) { if(response == PROMPT_YES) { - info_display("Deleting Secure Value", "", false, data, action_delete_secure_value_update, ui_draw_title_info); + info_display("Deleting Secure Value", "", false, data, action_delete_secure_value_update, task_draw_title_info); } } void action_delete_secure_value(linked_list* items, list_item* selected) { - prompt_display_yes_no("Confirmation", "Delete the secure value of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_delete_secure_value_onresponse); + prompt_display_yes_no("Confirmation", "Delete the secure value of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_delete_secure_value_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/deletesystemsavedata.c b/source/fbi/action/deletesystemsavedata.c similarity index 81% rename from source/ui/section/action/deletesystemsavedata.c rename to source/fbi/action/deletesystemsavedata.c index 9920ace..1e3ffeb 100644 --- a/source/ui/section/action/deletesystemsavedata.c +++ b/source/fbi/action/deletesystemsavedata.c @@ -3,15 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -19,7 +13,7 @@ typedef struct { } delete_system_save_data_data; static void action_delete_system_save_data_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_system_save_data_info(view, ((delete_system_save_data_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_system_save_data_info(view, ((delete_system_save_data_data*) data)->selected->data, x1, y1, x2, y2); } static void action_delete_system_save_data_update(ui_view* view, void* data, float* progress, char* text) { @@ -34,7 +28,7 @@ static void action_delete_system_save_data_update(ui_view* view, void* data, flo info_destroy(view); if(R_FAILED(res)) { - error_display_res(info, ui_draw_system_save_data_info, res, "Failed to delete system save data."); + error_display_res(info, task_draw_system_save_data_info, res, "Failed to delete system save data."); } else { linked_list_remove(deleteData->items, deleteData->selected); task_free_system_save_data(deleteData->selected); diff --git a/source/ui/section/action/deletetickets.c b/source/fbi/action/deletetickets.c similarity index 95% rename from source/ui/section/action/deletetickets.c rename to source/fbi/action/deletetickets.c index cbacebd..a21e70f 100644 --- a/source/ui/section/action/deletetickets.c +++ b/source/fbi/action/deletetickets.c @@ -4,15 +4,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -28,7 +22,7 @@ static void action_delete_tickets_draw_top(ui_view* view, void* data, float x1, u32 curr = deleteData->deleteInfo.processed; if(curr < deleteData->deleteInfo.total) { - ui_draw_ticket_info(view, ((list_item*) linked_list_get(&deleteData->contents, curr))->data, x1, y1, x2, y2); + task_draw_ticket_info(view, ((list_item*) linked_list_get(&deleteData->contents, curr))->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/action/deletetitle.c b/source/fbi/action/deletetitle.c similarity index 84% rename from source/ui/section/action/deletetitle.c rename to source/fbi/action/deletetitle.c index e71d56a..b265dcc 100644 --- a/source/ui/section/action/deletetitle.c +++ b/source/fbi/action/deletetitle.c @@ -3,15 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -20,7 +14,7 @@ typedef struct { } delete_title_data; static void action_delete_title_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_title_info(view, ((delete_title_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_title_info(view, ((delete_title_data*) data)->selected->data, x1, y1, x2, y2); } static void action_delete_title_update(ui_view* view, void* data, float* progress, char* text) { @@ -38,7 +32,7 @@ static void action_delete_title_update(ui_view* view, void* data, float* progres info_destroy(view); if(R_FAILED(res)) { - error_display_res(info, ui_draw_title_info, res, "Failed to delete title."); + error_display_res(info, task_draw_title_info, res, "Failed to delete title."); } else { linked_list_remove(deleteData->items, deleteData->selected); task_free_title(deleteData->selected); diff --git a/source/ui/section/action/erasetwlsave.c b/source/fbi/action/erasetwlsave.c similarity index 90% rename from source/ui/section/action/erasetwlsave.c rename to source/fbi/action/erasetwlsave.c index 93d50b5..af432c0 100644 --- a/source/ui/section/action/erasetwlsave.c +++ b/source/fbi/action/erasetwlsave.c @@ -5,17 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/spi.h" -#include "../../../core/stringutil.h" +#include "../../core/core.h" typedef struct { title_info* title; @@ -24,7 +16,7 @@ typedef struct { } erase_twl_save_data; static void action_erase_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_title_info(view, ((erase_twl_save_data*) data)->title, x1, y1, x2, y2); + task_draw_title_info(view, ((erase_twl_save_data*) data)->title, x1, y1, x2, y2); } static Result action_erase_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { @@ -91,7 +83,7 @@ static Result action_erase_twl_save_restore(void* data, u32 index) { } static bool action_erase_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) { - *errorView = error_display_res(((erase_twl_save_data*) data)->title, ui_draw_title_info, res, "Failed to erase save."); + *errorView = error_display_res(((erase_twl_save_data*) data)->title, task_draw_title_info, res, "Failed to erase save."); return true; } @@ -103,7 +95,7 @@ static void action_erase_twl_save_update(ui_view* view, void* data, float* progr info_destroy(view); if(R_SUCCEEDED(eraseData->eraseInfo.result)) { - prompt_display_notify("Success", "Save erased.", COLOR_TEXT, eraseData->title, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Save erased.", COLOR_TEXT, eraseData->title, task_draw_title_info, NULL); } free(data); @@ -134,7 +126,7 @@ static void action_erase_twl_save_onresponse(ui_view* view, void* data, u32 resp if(R_SUCCEEDED(res)) { info_display("Erasing Save", "Press B to cancel.", true, data, action_erase_twl_save_update, action_erase_twl_save_draw_top); } else { - error_display_res(eraseData->title, ui_draw_title_info, res, "Failed to initiate save erase."); + error_display_res(eraseData->title, task_draw_title_info, res, "Failed to initiate save erase."); free(data); } } else { diff --git a/source/ui/section/action/exportsecurevalue.c b/source/fbi/action/exportsecurevalue.c similarity index 77% rename from source/ui/section/action/exportsecurevalue.c rename to source/fbi/action/exportsecurevalue.c index b0070d5..c77503b 100644 --- a/source/ui/section/action/exportsecurevalue.c +++ b/source/fbi/action/exportsecurevalue.c @@ -3,17 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" static void action_export_secure_value_update(ui_view* view, void* data, float* progress, char* text) { title_info* info = (title_info*) data; @@ -27,7 +19,7 @@ static void action_export_secure_value_update(ui_view* view, void* data, float* ui_pop(); info_destroy(view); - prompt_display_notify("Failure", "Secure value not set.", COLOR_TEXT, info, ui_draw_title_info, NULL); + prompt_display_notify("Failure", "Secure value not set.", COLOR_TEXT, info, task_draw_title_info, NULL); return; } @@ -61,18 +53,18 @@ static void action_export_secure_value_update(ui_view* view, void* data, float* info_destroy(view); if(R_SUCCEEDED(res)) { - prompt_display_notify("Success", "Secure value exported.", COLOR_TEXT, info, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Secure value exported.", COLOR_TEXT, info, task_draw_title_info, NULL); } else { - error_display_res(info, ui_draw_title_info, res, "Failed to export secure value."); + error_display_res(info, task_draw_title_info, res, "Failed to export secure value."); } } static void action_export_secure_value_onresponse(ui_view* view, void* data, u32 response) { if(response == PROMPT_YES) { - info_display("Exporting Secure Value", "", false, data, action_export_secure_value_update, ui_draw_title_info); + info_display("Exporting Secure Value", "", false, data, action_export_secure_value_update, task_draw_title_info); } } void action_export_secure_value(linked_list* items, list_item* selected) { - prompt_display_yes_no("Confirmation", "Export the secure value of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_export_secure_value_onresponse); + prompt_display_yes_no("Confirmation", "Export the secure value of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_export_secure_value_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/exporttwlsave.c b/source/fbi/action/exporttwlsave.c similarity index 91% rename from source/ui/section/action/exporttwlsave.c rename to source/fbi/action/exporttwlsave.c index 9073268..6497ce1 100644 --- a/source/ui/section/action/exporttwlsave.c +++ b/source/fbi/action/exporttwlsave.c @@ -4,19 +4,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/spi.h" -#include "../../../core/stringutil.h" +#include "../../core/core.h" typedef struct { title_info* title; @@ -25,7 +15,7 @@ typedef struct { } export_twl_save_data; static void action_export_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_title_info(view, ((export_twl_save_data*) data)->title, x1, y1, x2, y2); + task_draw_title_info(view, ((export_twl_save_data*) data)->title, x1, y1, x2, y2); } static Result action_export_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { @@ -115,7 +105,7 @@ static Result action_export_twl_save_restore(void* data, u32 index) { } static bool action_export_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) { - *errorView = error_display_res(((export_twl_save_data*) data)->title, ui_draw_title_info, res, "Failed to export save."); + *errorView = error_display_res(((export_twl_save_data*) data)->title, task_draw_title_info, res, "Failed to export save."); return true; } @@ -127,7 +117,7 @@ static void action_export_twl_save_update(ui_view* view, void* data, float* prog info_destroy(view); if(R_SUCCEEDED(exportData->exportInfo.result)) { - prompt_display_notify("Success", "Save exported.", COLOR_TEXT, exportData->title, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Save exported.", COLOR_TEXT, exportData->title, task_draw_title_info, NULL); } free(data); @@ -158,7 +148,7 @@ static void action_export_twl_save_onresponse(ui_view* view, void* data, u32 res if(R_SUCCEEDED(res)) { info_display("Exporting Save", "Press B to cancel.", true, data, action_export_twl_save_update, action_export_twl_save_draw_top); } else { - error_display_res(exportData->title, ui_draw_title_info, res, "Failed to initiate save export."); + error_display_res(exportData->title, task_draw_title_info, res, "Failed to initiate save export."); free(data); } } else { diff --git a/source/ui/section/action/extractsmdh.c b/source/fbi/action/extractsmdh.c similarity index 83% rename from source/ui/section/action/extractsmdh.c rename to source/fbi/action/extractsmdh.c index 2ff985b..e103142 100644 --- a/source/ui/section/action/extractsmdh.c +++ b/source/fbi/action/extractsmdh.c @@ -4,18 +4,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/data/smdh.h" +#include "../../core/core.h" static void action_extract_smdh_update(ui_view* view, void* data, float* progress, char* text) { title_info* info = (title_info*) data; @@ -70,18 +61,18 @@ static void action_extract_smdh_update(ui_view* view, void* data, float* progres info_destroy(view); if(R_SUCCEEDED(res)) { - prompt_display_notify("Success", "SMDH extracted.", COLOR_TEXT, info, ui_draw_title_info, NULL); + prompt_display_notify("Success", "SMDH extracted.", COLOR_TEXT, info, task_draw_title_info, NULL); } else { - error_display_res(info, ui_draw_title_info, res, "Failed to extract SMDH."); + error_display_res(info, task_draw_title_info, res, "Failed to extract SMDH."); } } static void action_extract_smdh_onresponse(ui_view* view, void* data, u32 response) { if(response == PROMPT_YES) { - info_display("Extracting SMDH", "", false, data, action_extract_smdh_update, ui_draw_title_info); + info_display("Extracting SMDH", "", false, data, action_extract_smdh_update, task_draw_title_info); } } void action_extract_smdh(linked_list* items, list_item* selected) { - prompt_display_yes_no("Confirmation", "Extract the SMDH of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_extract_smdh_onresponse); + prompt_display_yes_no("Confirmation", "Extract the SMDH of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_extract_smdh_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/importsecurevalue.c b/source/fbi/action/importsecurevalue.c similarity index 72% rename from source/ui/section/action/importsecurevalue.c rename to source/fbi/action/importsecurevalue.c index 23a866c..7919f6c 100644 --- a/source/ui/section/action/importsecurevalue.c +++ b/source/fbi/action/importsecurevalue.c @@ -3,17 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" static void action_import_secure_value_update(ui_view* view, void* data, float* progress, char* text) { title_info* info = (title_info*) data; @@ -45,18 +37,18 @@ static void action_import_secure_value_update(ui_view* view, void* data, float* info_destroy(view); if(R_SUCCEEDED(res)) { - prompt_display_notify("Success", "Secure value imported.", COLOR_TEXT, info, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Secure value imported.", COLOR_TEXT, info, task_draw_title_info, NULL); } else { - error_display_res(info, ui_draw_title_info, res, "Failed to import secure value."); + error_display_res(info, task_draw_title_info, res, "Failed to import secure value."); } } static void action_import_secure_value_onresponse(ui_view* view, void* data, u32 response) { if(response == PROMPT_YES) { - info_display("Importing Secure Value", "", false, data, action_import_secure_value_update, ui_draw_title_info); + info_display("Importing Secure Value", "", false, data, action_import_secure_value_update, task_draw_title_info); } } void action_import_secure_value(linked_list* items, list_item* selected) { - prompt_display_yes_no("Confirmation", "Import the secure value of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_import_secure_value_onresponse); + prompt_display_yes_no("Confirmation", "Import the secure value of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_import_secure_value_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/importseed.c b/source/fbi/action/importseed.c similarity index 60% rename from source/ui/section/action/importseed.c rename to source/fbi/action/importseed.c index 62ab6e9..d20c07d 100644 --- a/source/ui/section/action/importseed.c +++ b/source/fbi/action/importseed.c @@ -3,15 +3,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" static void action_import_seed_update(ui_view* view, void* data, float* progress, char* text) { title_info* info = (title_info*) data; @@ -22,18 +16,18 @@ static void action_import_seed_update(ui_view* view, void* data, float* progress info_destroy(view); if(R_SUCCEEDED(res)) { - prompt_display_notify("Success", "Seed imported.", COLOR_TEXT, info, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Seed imported.", COLOR_TEXT, info, task_draw_title_info, NULL); } else { - error_display_res(info, ui_draw_title_info, res, "Failed to import seed."); + error_display_res(info, task_draw_title_info, res, "Failed to import seed."); } } static void action_import_seed_onresponse(ui_view* view, void* data, u32 response) { if(response == PROMPT_YES) { - info_display("Importing Seed", "", false, data, action_import_seed_update, ui_draw_title_info); + info_display("Importing Seed", "", false, data, action_import_seed_update, task_draw_title_info); } } void action_import_seed(linked_list* items, list_item* selected) { - prompt_display_yes_no("Confirmation", "Import the seed of the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_import_seed_onresponse); + prompt_display_yes_no("Confirmation", "Import the seed of the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_import_seed_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/importtwlsave.c b/source/fbi/action/importtwlsave.c similarity index 90% rename from source/ui/section/action/importtwlsave.c rename to source/fbi/action/importtwlsave.c index b38eacb..a5722c1 100644 --- a/source/ui/section/action/importtwlsave.c +++ b/source/fbi/action/importtwlsave.c @@ -4,19 +4,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/spi.h" -#include "../../../core/stringutil.h" +#include "../../core/core.h" typedef struct { title_info* title; @@ -25,7 +15,7 @@ typedef struct { } import_twl_save_data; static void action_import_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_title_info(view, ((import_twl_save_data*) data)->title, x1, y1, x2, y2); + task_draw_title_info(view, ((import_twl_save_data*) data)->title, x1, y1, x2, y2); } static Result action_import_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { @@ -101,7 +91,7 @@ static Result action_import_twl_save_restore(void* data, u32 index) { } static bool action_import_twl_save_error(void* data, u32 index, Result res, ui_view** errorView) { - *errorView = error_display_res(((import_twl_save_data*) data)->title, ui_draw_title_info, res, "Failed to import save."); + *errorView = error_display_res(((import_twl_save_data*) data)->title, task_draw_title_info, res, "Failed to import save."); return true; } @@ -113,7 +103,7 @@ static void action_import_twl_save_update(ui_view* view, void* data, float* prog info_destroy(view); if(R_SUCCEEDED(importData->importInfo.result)) { - prompt_display_notify("Success", "Save imported.", COLOR_TEXT, importData->title, ui_draw_title_info, NULL); + prompt_display_notify("Success", "Save imported.", COLOR_TEXT, importData->title, task_draw_title_info, NULL); } free(data); @@ -144,7 +134,7 @@ static void action_import_twl_save_onresponse(ui_view* view, void* data, u32 res if(R_SUCCEEDED(res)) { info_display("Importing Save", "Press B to cancel.", true, data, action_import_twl_save_update, action_import_twl_save_draw_top); } else { - error_display_res(importData->title, ui_draw_title_info, res, "Failed to initiate save import."); + error_display_res(importData->title, task_draw_title_info, res, "Failed to initiate save import."); free(data); } } else { diff --git a/source/ui/section/action/installcdn.c b/source/fbi/action/installcdn.c similarity index 93% rename from source/ui/section/action/installcdn.c rename to source/fbi/action/installcdn.c index 10f77b2..1c0e318 100644 --- a/source/ui/section/action/installcdn.c +++ b/source/fbi/action/installcdn.c @@ -5,20 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../kbd.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/http.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/data/tmd.h" +#include "../../core/core.h" #define CONTENTS_MAX 256 @@ -178,13 +167,13 @@ static Result action_install_cdn_restore(void* data, u32 index) { bool action_install_cdn_error(void* data, u32 index, Result res, ui_view** errorView) { install_cdn_data* installData = (install_cdn_data*) data; - *errorView = error_display_res(installData->ticket, ui_draw_ticket_info, res, "Failed to install %s from CDN.", index == 0 ? "TMD" : "content"); + *errorView = error_display_res(installData->ticket, task_draw_ticket_info, res, "Failed to install %s from CDN.", index == 0 ? "TMD" : "content"); return false; } static void action_install_cdn_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { - ui_draw_ticket_info(view, ((install_cdn_data*) data)->ticket, x1, y1, x2, y2); + task_draw_ticket_info(view, ((install_cdn_data*) data)->ticket, x1, y1, x2, y2); } static void action_install_cdn_free_data(install_cdn_data* data) { @@ -221,13 +210,13 @@ static void action_install_cdn_update(ui_view* view, void* data, float* progress task_populate_tickets_update_use(installData->item); } - prompt_display_notify("Success", "Install finished.", COLOR_TEXT, installData->ticket, ui_draw_ticket_info, NULL); + prompt_display_notify("Success", "Install finished.", COLOR_TEXT, installData->ticket, task_draw_ticket_info, NULL); } } else { AM_InstallTitleAbort(); if(R_FAILED(res)) { - error_display_res(installData->ticket, ui_draw_ticket_info, res, "Failed to install CDN title."); + error_display_res(installData->ticket, task_draw_ticket_info, res, "Failed to install CDN title."); } } @@ -273,7 +262,7 @@ static void action_install_cdn_n3ds_onresponse(ui_view* view, void* data, u32 re } if(R_FAILED(res)) { - error_display_res(installData->ticket, ui_draw_ticket_info, res, "Failed to initiate CDN title installation."); + error_display_res(installData->ticket, task_draw_ticket_info, res, "Failed to initiate CDN title installation."); action_install_cdn_free_data(data); } @@ -375,5 +364,5 @@ static void action_install_cdn_onresponse(ui_view* view, void* data, u32 respons void action_install_cdn(linked_list* items, list_item* selected) { static const char* options[3] = {"Default\nVersion", "Select\nVersion", "No"}; static u32 optionButtons[3] = {KEY_A, KEY_X, KEY_B}; - prompt_display_multi_choice("Confirmation", "Install the selected title from the CDN?", COLOR_TEXT, options, optionButtons, 3, selected, ui_draw_ticket_info, action_install_cdn_onresponse); + prompt_display_multi_choice("Confirmation", "Install the selected title from the CDN?", COLOR_TEXT, options, optionButtons, 3, selected, task_draw_ticket_info, action_install_cdn_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/installcias.c b/source/fbi/action/installcias.c similarity index 96% rename from source/ui/section/action/installcias.c rename to source/fbi/action/installcias.c index 12d9d4f..62fa21d 100644 --- a/source/ui/section/action/installcias.c +++ b/source/fbi/action/installcias.c @@ -5,17 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -41,9 +33,9 @@ static void action_install_cias_draw_top(ui_view* view, void* data, float x1, fl u32 curr = installData->installInfo.processed; if(curr < installData->installInfo.total) { - ui_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); + task_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); } else { - ui_draw_file_info(view, installData->target, x1, y1, x2, y2); + task_draw_file_info(view, installData->target, x1, y1, x2, y2); } } diff --git a/source/ui/section/action/installtickets.c b/source/fbi/action/installtickets.c similarity index 96% rename from source/ui/section/action/installtickets.c rename to source/fbi/action/installtickets.c index 8b6bfa3..6c04e78 100644 --- a/source/ui/section/action/installtickets.c +++ b/source/fbi/action/installtickets.c @@ -5,17 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -37,9 +29,9 @@ static void action_install_tickets_draw_top(ui_view* view, void* data, float x1, u32 curr = installData->installInfo.processed; if(curr < installData->installInfo.total) { - ui_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); + task_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2); } else { - ui_draw_file_info(view, installData->target, x1, y1, x2, y2); + task_draw_file_info(view, installData->target, x1, y1, x2, y2); } } diff --git a/source/ui/section/action/installtitledb.c b/source/fbi/action/installtitledb.c similarity index 81% rename from source/ui/section/action/installtitledb.c rename to source/fbi/action/installtitledb.c index 93ec732..14484c3 100644 --- a/source/ui/section/action/installtitledb.c +++ b/source/fbi/action/installtitledb.c @@ -1,61 +1,57 @@ -#include -#include - -#include <3ds.h> - -#include "action.h" -#include "../task/uitask.h" -#include "../../error.h" -#include "../../list.h" -#include "../../ui.h" -#include "../../../core/linkedlist.h" -#include "../../../core/stringutil.h" - -typedef struct { - list_item* selected; - bool cia; -} install_titledb_data; - -static void action_install_titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index) { - install_titledb_data* installData = (install_titledb_data*) data; - - if(installData->cia) { - ui_draw_titledb_info_cia(view, installData->selected->data, x1, y1, x2, y2); - } else { - ui_draw_titledb_info_tdsx(view, installData->selected->data, x1, y1, x2, y2); - } -} - -static void action_update_titledb_finished(void* data) { - task_populate_titledb_update_status(((install_titledb_data*) data)->selected); - - free(data); -} - -void action_install_titledb(linked_list* items, list_item* selected, bool cia) { - install_titledb_data* data = (install_titledb_data*) calloc(1, sizeof(install_titledb_data)); - if(data == NULL) { - error_display(NULL, NULL, "Failed to allocate install TitleDB data."); - - return; - } - - data->selected = selected; - data->cia = cia; - - titledb_info* info = (titledb_info*) selected->data; - - char url[64]; - char path3dsx[FILE_PATH_MAX]; - if(data->cia) { - snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/cia/%lu/download", info->cia.id); - } else { - snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/tdsx/%lu/download", info->tdsx.id); - - char name[FILE_NAME_MAX]; - string_escape_file_name(name, info->meta.shortDescription, sizeof(name)); - snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name); - } - - action_install_url("Install the selected title from TitleDB?", url, path3dsx, data, action_update_titledb_finished, action_install_titledb_draw_top); +#include +#include + +#include <3ds.h> + +#include "action.h" +#include "../task/uitask.h" +#include "../../core/core.h" + +typedef struct { + list_item* selected; + bool cia; +} install_titledb_data; + +static void action_install_titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index) { + install_titledb_data* installData = (install_titledb_data*) data; + + if(installData->cia) { + task_draw_titledb_info_cia(view, installData->selected->data, x1, y1, x2, y2); + } else { + task_draw_titledb_info_tdsx(view, installData->selected->data, x1, y1, x2, y2); + } +} + +static void action_update_titledb_finished(void* data) { + task_populate_titledb_update_status(((install_titledb_data*) data)->selected); + + free(data); +} + +void action_install_titledb(linked_list* items, list_item* selected, bool cia) { + install_titledb_data* data = (install_titledb_data*) calloc(1, sizeof(install_titledb_data)); + if(data == NULL) { + error_display(NULL, NULL, "Failed to allocate install TitleDB data."); + + return; + } + + data->selected = selected; + data->cia = cia; + + titledb_info* info = (titledb_info*) selected->data; + + char url[64]; + char path3dsx[FILE_PATH_MAX]; + if(data->cia) { + snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/cia/%lu/download", info->cia.id); + } else { + snprintf(url, DOWNLOAD_URL_MAX, "https://3ds.titledb.com/v1/tdsx/%lu/download", info->tdsx.id); + + char name[FILE_NAME_MAX]; + string_escape_file_name(name, info->meta.shortDescription, sizeof(name)); + snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name); + } + + action_install_url("Install the selected title from TitleDB?", url, path3dsx, data, action_update_titledb_finished, action_install_titledb_draw_top); } \ No newline at end of file diff --git a/source/ui/section/action/installurl.c b/source/fbi/action/installurl.c similarity index 97% rename from source/ui/section/action/installurl.c rename to source/fbi/action/installurl.c index 55d7c3a..08609eb 100644 --- a/source/ui/section/action/installurl.c +++ b/source/fbi/action/installurl.c @@ -4,20 +4,10 @@ #include <3ds.h> -#include "../action/action.h" +#include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/http.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" -#include "../../../core/data/cia.h" -#include "../../../core/data/ticket.h" +#include "../../core/core.h" typedef enum content_type_e { CONTENT_CIA, diff --git a/source/ui/section/action/launchtitle.c b/source/fbi/action/launchtitle.c similarity index 68% rename from source/ui/section/action/launchtitle.c rename to source/fbi/action/launchtitle.c index ec6fefa..67e0f09 100644 --- a/source/ui/section/action/launchtitle.c +++ b/source/fbi/action/launchtitle.c @@ -1,14 +1,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/screen.h" +#include "../../core/core.h" static void action_launch_title_update(ui_view* view, void* data, float* progress, char* text) { title_info* info = (title_info*) data; @@ -26,16 +21,16 @@ static void action_launch_title_update(ui_view* view, void* data, float* progres ui_pop(); info_destroy(view); - error_display_res(info, ui_draw_title_info, res, "Failed to launch title."); + error_display_res(info, task_draw_title_info, res, "Failed to launch title."); } } static void action_launch_title_onresponse(ui_view* view, void* data, u32 response) { if(response == PROMPT_YES) { - info_display("Launching Title", "", false, data, action_launch_title_update, ui_draw_title_info); + info_display("Launching Title", "", false, data, action_launch_title_update, task_draw_title_info); } } void action_launch_title(linked_list* items, list_item* selected) { - prompt_display_yes_no("Confirmation", "Launch the selected title?", COLOR_TEXT, selected->data, ui_draw_title_info, action_launch_title_onresponse); + prompt_display_yes_no("Confirmation", "Launch the selected title?", COLOR_TEXT, selected->data, task_draw_title_info, action_launch_title_onresponse); } \ No newline at end of file diff --git a/source/ui/section/action/newfolder.c b/source/fbi/action/newfolder.c similarity index 85% rename from source/ui/section/action/newfolder.c rename to source/fbi/action/newfolder.c index 09b7ab6..fe503e4 100644 --- a/source/ui/section/action/newfolder.c +++ b/source/fbi/action/newfolder.c @@ -4,19 +4,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../kbd.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" +#include "../../core/core.h" typedef struct { linked_list* items; diff --git a/source/ui/section/action/pastecontents.c b/source/fbi/action/pastecontents.c similarity index 96% rename from source/ui/section/action/pastecontents.c rename to source/fbi/action/pastecontents.c index 1d0bad1..b6a2198 100644 --- a/source/ui/section/action/pastecontents.c +++ b/source/fbi/action/pastecontents.c @@ -5,19 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/clipboard.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" +#include "../../core/core.h" typedef struct { linked_list* items; @@ -35,9 +25,9 @@ static void action_paste_contents_draw_top(ui_view* view, void* data, float x1, u32 curr = pasteData->pasteInfo.processed; if(curr < pasteData->pasteInfo.total) { - ui_draw_file_info(view, ((list_item*) linked_list_get(&pasteData->contents, curr))->data, x1, y1, x2, y2); + task_draw_file_info(view, ((list_item*) linked_list_get(&pasteData->contents, curr))->data, x1, y1, x2, y2); } else { - ui_draw_file_info(view, pasteData->target, x1, y1, x2, y2); + task_draw_file_info(view, pasteData->target, x1, y1, x2, y2); } } diff --git a/source/ui/section/action/rename.c b/source/fbi/action/rename.c similarity index 89% rename from source/ui/section/action/rename.c rename to source/fbi/action/rename.c index 1fd3f75..61c75ef 100644 --- a/source/ui/section/action/rename.c +++ b/source/fbi/action/rename.c @@ -5,19 +5,9 @@ #include <3ds.h> #include "action.h" +#include "../resources.h" #include "../task/uitask.h" -#include "../../error.h" -#include "../../info.h" -#include "../../kbd.h" -#include "../../list.h" -#include "../../prompt.h" -#include "../../resources.h" -#include "../../ui.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" +#include "../../core/core.h" typedef struct { linked_list* items; diff --git a/source/ui/section/dumpnand.c b/source/fbi/dumpnand.c similarity index 96% rename from source/ui/section/dumpnand.c rename to source/fbi/dumpnand.c index 64673c3..518bff8 100644 --- a/source/ui/section/dumpnand.c +++ b/source/fbi/dumpnand.c @@ -5,16 +5,10 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "task/uitask.h" -#include "../error.h" -#include "../info.h" -#include "../prompt.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/error.h" -#include "../../core/fs.h" -#include "../../core/screen.h" +#include "../core/core.h" static Result dumpnand_is_src_directory(void* data, u32 index, bool* isDirectory) { *isDirectory = false; diff --git a/source/ui/section/extsavedata.c b/source/fbi/extsavedata.c similarity index 95% rename from source/ui/section/extsavedata.c rename to source/fbi/extsavedata.c index 8fae887..af57925 100644 --- a/source/ui/section/extsavedata.c +++ b/source/fbi/extsavedata.c @@ -4,16 +4,11 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" -#include "../../core/stringutil.h" +#include "../core/core.h" static list_item browse_user_save_data = {"Browse User Save Data", COLOR_TEXT, action_browse_user_ext_save_data}; static list_item browse_spotpass_save_data = {"Browse SpotPass Save Data", COLOR_TEXT, action_browse_boss_ext_save_data}; @@ -36,7 +31,7 @@ typedef struct { } extsavedata_action_data; static void extsavedata_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_ext_save_data_info(view, ((extsavedata_action_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_ext_save_data_info(view, ((extsavedata_action_data*) data)->selected->data, x1, y1, x2, y2); } static void extsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -153,7 +148,7 @@ static void extsavedata_options_open(extsavedata_data* data) { static void extsavedata_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(selected != NULL && selected->data != NULL) { - ui_draw_ext_save_data_info(view, selected->data, x1, y1, x2, y2); + task_draw_ext_save_data_info(view, selected->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/files.c b/source/fbi/files.c similarity index 96% rename from source/ui/section/files.c rename to source/fbi/files.c index 45a4fa3..788118a 100644 --- a/source/ui/section/files.c +++ b/source/fbi/files.c @@ -4,19 +4,11 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../prompt.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/clipboard.h" -#include "../../core/fs.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" -#include "../../core/stringutil.h" +#include "../core/core.h" static list_item rename_opt = {"Rename", COLOR_TEXT, action_rename}; static list_item copy = {"Copy", COLOR_TEXT, NULL}; @@ -71,7 +63,7 @@ typedef struct { } files_action_data; static void files_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_file_info(view, ((files_action_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_file_info(view, ((files_action_data*) data)->selected->data, x1, y1, x2, y2); } static void files_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -97,9 +89,9 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l Result res = 0; if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archive, info->path, selected == ©_all_contents))) { - prompt_display_notify("Success", selected == ©_all_contents ? "Current directory contents copied to clipboard." : (info->attributes & FS_ATTRIBUTE_DIRECTORY) ? "Current directory copied to clipboard." : "File copied to clipboard.", COLOR_TEXT, info, ui_draw_file_info, NULL); + prompt_display_notify("Success", selected == ©_all_contents ? "Current directory contents copied to clipboard." : (info->attributes & FS_ATTRIBUTE_DIRECTORY) ? "Current directory copied to clipboard." : "File copied to clipboard.", COLOR_TEXT, info, task_draw_file_info, NULL); } else { - error_display_res(info, ui_draw_file_info, res, "Failed to copy to clipboard."); + error_display_res(info, task_draw_file_info, res, "Failed to copy to clipboard."); } } else { action(actionData->items, actionData->selected); @@ -236,7 +228,7 @@ static void files_options_open(files_data* data) { static void files_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(selected != NULL && selected->data != NULL) { - ui_draw_file_info(view, selected->data, x1, y1, x2, y2); + task_draw_file_info(view, selected->data, x1, y1, x2, y2); } } diff --git a/source/main.c b/source/fbi/main.c similarity index 91% rename from source/main.c rename to source/fbi/main.c index 5a85c57..74aee4f 100644 --- a/source/main.c +++ b/source/fbi/main.c @@ -1,191 +1,191 @@ -#include -#include - -#include <3ds.h> -#include - -#include "core/clipboard.h" -#include "core/error.h" -#include "core/fs.h" -#include "core/screen.h" -#include "core/task/task.h" -#include "ui/mainmenu.h" -#include "ui/ui.h" - -#define CURRENT_KPROCESS (*(void**) 0xFFFF9004) - -#define KPROCESS_PID_OFFSET_OLD (0xB4) -#define KPROCESS_PID_OFFSET_NEW (0xBC) - -static bool backdoor_ran = false; -static bool n3ds = false; -static u32 old_pid = 0; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wreturn-type" -static __attribute__((naked)) Result svcGlobalBackdoor(s32 (*callback)()) { - asm volatile( - "svc 0x30\n" - "bx lr" - ); -} -#pragma GCC diagnostic pop - -static s32 patch_pid_kernel() { - u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD)); - - old_pid = *pidPtr; - *pidPtr = 0; - - backdoor_ran = true; - return 0; -} - -static s32 restore_pid_kernel() { - u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD)); - - *pidPtr = old_pid; - - backdoor_ran = true; - return 0; -} - -static bool attempt_patch_pid() { - backdoor_ran = false; - APT_CheckNew3DS(&n3ds); - - svcGlobalBackdoor(patch_pid_kernel); - srvExit(); - srvInit(); - svcGlobalBackdoor(restore_pid_kernel); - - return backdoor_ran; -} - -static void (*exit_funcs[16])()= {NULL}; -static u32 exit_func_count = 0; - -static void* soc_buffer = NULL; - -void cleanup_services() { - for(u32 i = 0; i < exit_func_count; i++) { - if(exit_funcs[i] != NULL) { - exit_funcs[i](); - exit_funcs[i] = NULL; - } - } - - exit_func_count = 0; - - if(soc_buffer != NULL) { - free(soc_buffer); - soc_buffer = NULL; - } -} - -#define INIT_SERVICE(initStatement, exitFunc) (R_SUCCEEDED(res = (initStatement)) && (exit_funcs[exit_func_count++] = (exitFunc))) - -Result init_services() { - Result res = 0; - - soc_buffer = memalign(0x1000, 0x100000); - if(soc_buffer != NULL) { - Handle tempAM = 0; - if(R_SUCCEEDED(res = srvGetServiceHandle(&tempAM, "am:net"))) { - svcCloseHandle(tempAM); - - if(INIT_SERVICE(amInit(), amExit) - && INIT_SERVICE(cfguInit(), cfguExit) - && INIT_SERVICE(acInit(), acExit) - && INIT_SERVICE(ptmuInit(), ptmuExit) - && INIT_SERVICE(pxiDevInit(), pxiDevExit) - && INIT_SERVICE(httpcInit(0), httpcExit) - && INIT_SERVICE(socInit(soc_buffer, 0x100000), (void (*)()) socExit)); - } - } else { - res = R_APP_OUT_OF_MEMORY; - } - - if(R_FAILED(res)) { - cleanup_services(); - } - - return res; -} - -static u32 old_time_limit = UINT32_MAX; - -void init() { - gfxInitDefault(); - - Result romfsRes = romfsInit(); - if(R_FAILED(romfsRes)) { - error_panic("Failed to mount RomFS: %08lX", romfsRes); - return; - } - - if(R_FAILED(init_services())) { - if(!attempt_patch_pid()) { - error_panic("Kernel backdoor not installed.\nPlease run a kernel exploit and try again."); - return; - } - - Result initRes = init_services(); - if(R_FAILED(initRes)) { - error_panic("Failed to initialize services: %08lX", initRes); - return; - } - } - - osSetSpeedupEnable(true); - - APT_GetAppCpuTimeLimit(&old_time_limit); - Result cpuRes = APT_SetAppCpuTimeLimit(30); - if(R_FAILED(cpuRes)) { - error_panic("Failed to set syscore CPU time limit: %08lX", cpuRes); - return; - } - - AM_InitializeExternalTitleDatabase(false); - - curl_global_init(CURL_GLOBAL_ALL); - - screen_init(); - ui_init(); - task_init(); -} - -void cleanup() { - clipboard_clear(); - - task_exit(); - ui_exit(); - screen_exit(); - - if(old_time_limit != UINT32_MAX) { - APT_SetAppCpuTimeLimit(old_time_limit); - } - - osSetSpeedupEnable(false); - - cleanup_services(); - - romfsExit(); - - gfxExit(); -} - -int main(int argc, const char* argv[]) { - if(argc > 0 && envIsHomebrew()) { - fs_set_3dsx_path(argv[0]); - } - - init(); - - mainmenu_open(); - while(aptMainLoop() && ui_update()); - - cleanup(); - - return 0; +#include +#include + +#include <3ds.h> +#include + +#include "../core/clipboard.h" +#include "../core/error.h" +#include "../core/fs.h" +#include "../core/screen.h" +#include "../core/task/task.h" +#include "../core/ui/ui.h" +#include "section.h" + +#define CURRENT_KPROCESS (*(void**) 0xFFFF9004) + +#define KPROCESS_PID_OFFSET_OLD (0xB4) +#define KPROCESS_PID_OFFSET_NEW (0xBC) + +static bool backdoor_ran = false; +static bool n3ds = false; +static u32 old_pid = 0; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreturn-type" +static __attribute__((naked)) Result svcGlobalBackdoor(s32 (*callback)()) { + asm volatile( + "svc 0x30\n" + "bx lr" + ); +} +#pragma GCC diagnostic pop + +static s32 patch_pid_kernel() { + u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD)); + + old_pid = *pidPtr; + *pidPtr = 0; + + backdoor_ran = true; + return 0; +} + +static s32 restore_pid_kernel() { + u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD)); + + *pidPtr = old_pid; + + backdoor_ran = true; + return 0; +} + +static bool attempt_patch_pid() { + backdoor_ran = false; + APT_CheckNew3DS(&n3ds); + + svcGlobalBackdoor(patch_pid_kernel); + srvExit(); + srvInit(); + svcGlobalBackdoor(restore_pid_kernel); + + return backdoor_ran; +} + +static void (*exit_funcs[16])()= {NULL}; +static u32 exit_func_count = 0; + +static void* soc_buffer = NULL; + +void cleanup_services() { + for(u32 i = 0; i < exit_func_count; i++) { + if(exit_funcs[i] != NULL) { + exit_funcs[i](); + exit_funcs[i] = NULL; + } + } + + exit_func_count = 0; + + if(soc_buffer != NULL) { + free(soc_buffer); + soc_buffer = NULL; + } +} + +#define INIT_SERVICE(initStatement, exitFunc) (R_SUCCEEDED(res = (initStatement)) && (exit_funcs[exit_func_count++] = (exitFunc))) + +Result init_services() { + Result res = 0; + + soc_buffer = memalign(0x1000, 0x100000); + if(soc_buffer != NULL) { + Handle tempAM = 0; + if(R_SUCCEEDED(res = srvGetServiceHandle(&tempAM, "am:net"))) { + svcCloseHandle(tempAM); + + if(INIT_SERVICE(amInit(), amExit) + && INIT_SERVICE(cfguInit(), cfguExit) + && INIT_SERVICE(acInit(), acExit) + && INIT_SERVICE(ptmuInit(), ptmuExit) + && INIT_SERVICE(pxiDevInit(), pxiDevExit) + && INIT_SERVICE(httpcInit(0), httpcExit) + && INIT_SERVICE(socInit(soc_buffer, 0x100000), (void (*)()) socExit)); + } + } else { + res = R_APP_OUT_OF_MEMORY; + } + + if(R_FAILED(res)) { + cleanup_services(); + } + + return res; +} + +static u32 old_time_limit = UINT32_MAX; + +void init() { + gfxInitDefault(); + + Result romfsRes = romfsInit(); + if(R_FAILED(romfsRes)) { + error_panic("Failed to mount RomFS: %08lX", romfsRes); + return; + } + + if(R_FAILED(init_services())) { + if(!attempt_patch_pid()) { + error_panic("Kernel backdoor not installed.\nPlease run a kernel exploit and try again."); + return; + } + + Result initRes = init_services(); + if(R_FAILED(initRes)) { + error_panic("Failed to initialize services: %08lX", initRes); + return; + } + } + + osSetSpeedupEnable(true); + + APT_GetAppCpuTimeLimit(&old_time_limit); + Result cpuRes = APT_SetAppCpuTimeLimit(30); + if(R_FAILED(cpuRes)) { + error_panic("Failed to set syscore CPU time limit: %08lX", cpuRes); + return; + } + + AM_InitializeExternalTitleDatabase(false); + + curl_global_init(CURL_GLOBAL_ALL); + + screen_init(); + ui_init(); + task_init(); +} + +void cleanup() { + clipboard_clear(); + + task_exit(); + ui_exit(); + screen_exit(); + + if(old_time_limit != UINT32_MAX) { + APT_SetAppCpuTimeLimit(old_time_limit); + } + + osSetSpeedupEnable(false); + + cleanup_services(); + + romfsExit(); + + gfxExit(); +} + +int main(int argc, const char* argv[]) { + if(argc > 0 && envIsHomebrew()) { + fs_set_3dsx_path(argv[0]); + } + + init(); + + mainmenu_open(); + while(aptMainLoop() && ui_update()); + + cleanup(); + + return 0; } \ No newline at end of file diff --git a/source/ui/mainmenu.c b/source/fbi/mainmenu.c similarity index 94% rename from source/ui/mainmenu.c rename to source/fbi/mainmenu.c index 50d1510..135dea2 100644 --- a/source/ui/mainmenu.c +++ b/source/fbi/mainmenu.c @@ -3,13 +3,9 @@ #include <3ds.h> -#include "list.h" -#include "mainmenu.h" #include "resources.h" -#include "ui.h" -#include "section/section.h" -#include "../core/linkedlist.h" -#include "../core/screen.h" +#include "section.h" +#include "../core/core.h" static list_item sd = {"SD", COLOR_TEXT, files_open_sd}; static list_item ctr_nand = {"CTR NAND", COLOR_TEXT, files_open_ctr_nand}; @@ -68,5 +64,7 @@ static void mainmenu_update(ui_view* view, void* data, linked_list* items, list_ } void mainmenu_open() { + resources_load(); + list_display("Main Menu", "A: Select, START: Exit", NULL, mainmenu_update, mainmenu_draw_top); } diff --git a/source/ui/section/pendingtitles.c b/source/fbi/pendingtitles.c similarity index 92% rename from source/ui/section/pendingtitles.c rename to source/fbi/pendingtitles.c index ce61bbd..7269c07 100644 --- a/source/ui/section/pendingtitles.c +++ b/source/fbi/pendingtitles.c @@ -3,15 +3,11 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" +#include "../core/core.h" static list_item delete_pending_title = {"Delete Pending Title", COLOR_TEXT, action_delete_pending_title}; static list_item delete_all_pending_titles = {"Delete All Pending Titles", COLOR_TEXT, action_delete_all_pending_titles}; @@ -28,7 +24,7 @@ typedef struct { } pendingtitles_action_data; static void pendingtitles_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_pending_title_info(view, ((pendingtitles_action_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_pending_title_info(view, ((pendingtitles_action_data*) data)->selected->data, x1, y1, x2, y2); } static void pendingtitles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -78,7 +74,7 @@ static void pendingtitles_action_open(linked_list* items, list_item* selected) { static void pendingtitles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(selected != NULL && selected->data != NULL) { - ui_draw_pending_title_info(view, selected->data, x1, y1, x2, y2); + task_draw_pending_title_info(view, selected->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/remoteinstall.c b/source/fbi/remoteinstall.c similarity index 97% rename from source/ui/section/remoteinstall.c rename to source/fbi/remoteinstall.c index c362d91..bc57561 100644 --- a/source/ui/section/remoteinstall.c +++ b/source/fbi/remoteinstall.c @@ -8,22 +8,12 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../info.h" -#include "../kbd.h" -#include "../list.h" -#include "../prompt.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/error.h" -#include "../../core/fs.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" -#include "../../core/task/capturecam.h" -#include "../../libs/quirc/quirc_internal.h" +#include "../core/core.h" +#include "../libs/quirc/quirc_internal.h" static bool remoteinstall_get_last_urls(char* out, size_t size) { if(out == NULL || size == 0) { diff --git a/source/ui/resources.c b/source/fbi/resources.c similarity index 97% rename from source/ui/resources.c rename to source/fbi/resources.c index f9ca7cb..be07a18 100644 --- a/source/ui/resources.c +++ b/source/fbi/resources.c @@ -5,10 +5,7 @@ #include <3ds.h> #include "resources.h" -#include "../core/error.h" -#include "../core/fs.h" -#include "../core/screen.h" -#include "../core/task/task.h" +#include "../core/core.h" static FILE* resources_open_file(const char* path) { char realPath[FILE_PATH_MAX]; diff --git a/source/ui/resources.h b/source/fbi/resources.h similarity index 98% rename from source/ui/resources.h rename to source/fbi/resources.h index 5a1a6f5..4025364 100644 --- a/source/ui/resources.h +++ b/source/fbi/resources.h @@ -31,7 +31,6 @@ #define TEXTURE_WIFI_2 29 #define TEXTURE_WIFI_3 30 -#define COLOR_TEXT 0 #define COLOR_NAND 1 #define COLOR_SD 2 #define COLOR_GAME_CARD 3 diff --git a/source/ui/section/section.h b/source/fbi/section.h similarity index 94% rename from source/ui/section/section.h rename to source/fbi/section.h index 839fcab..a7a4fc1 100644 --- a/source/ui/section/section.h +++ b/source/fbi/section.h @@ -1,5 +1,7 @@ #pragma once +void mainmenu_open(); + void dumpnand_open(); void extsavedata_open(); void files_open(FS_ArchiveID archiveId, FS_Path archivePath); diff --git a/source/ui/section/systemsavedata.c b/source/fbi/systemsavedata.c similarity index 92% rename from source/ui/section/systemsavedata.c rename to source/fbi/systemsavedata.c index b37d36b..2c0bac7 100644 --- a/source/ui/section/systemsavedata.c +++ b/source/fbi/systemsavedata.c @@ -3,15 +3,11 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" +#include "../core/core.h" static list_item browse_save_data = {"Browse Save Data", COLOR_TEXT, action_browse_system_save_data}; static list_item delete_save_data = {"Delete Save Data", COLOR_TEXT, action_delete_system_save_data}; @@ -28,7 +24,7 @@ typedef struct { } systemsavedata_action_data; static void systemsavedata_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_system_save_data_info(view, ((systemsavedata_action_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_system_save_data_info(view, ((systemsavedata_action_data*) data)->selected->data, x1, y1, x2, y2); } static void systemsavedata_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -78,7 +74,7 @@ static void systemsavedata_action_open(linked_list* items, list_item* selected) static void systemsavedata_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(selected != NULL && selected->data != NULL) { - ui_draw_system_save_data_info(view, selected->data, x1, y1, x2, y2); + task_draw_system_save_data_info(view, selected->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/task/listextsavedata.c b/source/fbi/task/listextsavedata.c similarity index 95% rename from source/ui/section/task/listextsavedata.c rename to source/fbi/task/listextsavedata.c index d7439b0..df9aff0 100644 --- a/source/ui/section/task/listextsavedata.c +++ b/source/fbi/task/listextsavedata.c @@ -6,14 +6,9 @@ #include <3ds.h> #include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" -#include "../../../core/data/smdh.h" -#include "../../../core/task/task.h" +#include "listextsavedata.h" +#include "../resources.h" +#include "../../core/core.h" #define MAX_EXT_SAVE_DATA 512 diff --git a/source/fbi/task/listextsavedata.h b/source/fbi/task/listextsavedata.h new file mode 100644 index 0000000..6f6005a --- /dev/null +++ b/source/fbi/task/listextsavedata.h @@ -0,0 +1,28 @@ +#pragma once + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct ext_save_data_info_s { + FS_MediaType mediaType; + u64 extSaveDataId; + bool shared; + bool hasMeta; + meta_info meta; +} ext_save_data_info; + +typedef struct populate_ext_save_data_data_s { + linked_list* items; + + void* userData; + bool (*filter)(void* data, u64 extSaveDataId, FS_MediaType mediaType); + int (*compare)(void* data, const void* p1, const void* p2); + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_ext_save_data_data; + +void task_free_ext_save_data(list_item* item); +void task_clear_ext_save_data(linked_list* items); +Result task_populate_ext_save_data(populate_ext_save_data_data* data); \ No newline at end of file diff --git a/source/ui/section/task/listfiles.c b/source/fbi/task/listfiles.c similarity index 97% rename from source/ui/section/task/listfiles.c rename to source/fbi/task/listfiles.c index 7b6a38b..75a0bf1 100644 --- a/source/ui/section/task/listfiles.c +++ b/source/fbi/task/listfiles.c @@ -6,16 +6,9 @@ #include <3ds.h> #include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" -#include "../../../core/data/cia.h" -#include "../../../core/data/smdh.h" -#include "../../../core/task/task.h" +#include "listfiles.h" +#include "../resources.h" +#include "../../core/core.h" #define MAX_FILES 1024 diff --git a/source/fbi/task/listfiles.h b/source/fbi/task/listfiles.h new file mode 100644 index 0000000..836f770 --- /dev/null +++ b/source/fbi/task/listfiles.h @@ -0,0 +1,54 @@ +#pragma once + +#ifndef FILE_NAME_MAX +#define FILE_NAME_MAX 512 +#define FILE_PATH_MAX 512 +#endif + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct cia_info_s { + u64 titleId; + u16 version; + u64 installedSize; + bool hasMeta; + meta_info meta; +} cia_info; + +typedef struct file_info_s { + FS_Archive archive; + char name[FILE_NAME_MAX]; + char path[FILE_PATH_MAX]; + u32 attributes; + + // Files only + u64 size; + bool isCia; + cia_info ciaInfo; + bool isTicket; + ticket_info ticketInfo; +} file_info; + +typedef struct populate_files_data_s { + linked_list* items; + + FS_Archive archive; + char path[FILE_PATH_MAX]; + + bool recursive; + bool includeBase; + + bool (*filter)(void* data, const char* name, u32 attributes); + void* filterData; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_files_data; + +int task_compare_files(void* userData, const void* p1, const void* p2); +void task_free_file(list_item* item); +void task_clear_files(linked_list* items); +Result task_create_file_item(list_item** out, FS_Archive archive, const char* path, u32 attributes); +Result task_populate_files(populate_files_data* data); \ No newline at end of file diff --git a/source/ui/section/task/listpendingtitles.c b/source/fbi/task/listpendingtitles.c similarity index 96% rename from source/ui/section/task/listpendingtitles.c rename to source/fbi/task/listpendingtitles.c index eda4f8b..3619cd0 100644 --- a/source/ui/section/task/listpendingtitles.c +++ b/source/fbi/task/listpendingtitles.c @@ -4,13 +4,9 @@ #include <3ds.h> -#include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/task/task.h" +#include "listpendingtitles.h" +#include "../resources.h" +#include "../../core/core.h" static int task_populate_pending_titles_compare_ids(const void* e1, const void* e2) { u64 id1 = *(u64*) e1; diff --git a/source/fbi/task/listpendingtitles.h b/source/fbi/task/listpendingtitles.h new file mode 100644 index 0000000..4fb36c4 --- /dev/null +++ b/source/fbi/task/listpendingtitles.h @@ -0,0 +1,22 @@ +#pragma once + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct pending_title_info_s { + FS_MediaType mediaType; + u64 titleId; + u16 version; +} pending_title_info; + +typedef struct populate_pending_titles_data_s { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_pending_titles_data; + +void task_free_pending_title(list_item* item); +void task_clear_pending_titles(linked_list* items); +Result task_populate_pending_titles(populate_pending_titles_data* data); \ No newline at end of file diff --git a/source/ui/section/task/listsystemsavedata.c b/source/fbi/task/listsystemsavedata.c similarity index 93% rename from source/ui/section/task/listsystemsavedata.c rename to source/fbi/task/listsystemsavedata.c index 6a17c4a..d3a9fa7 100644 --- a/source/ui/section/task/listsystemsavedata.c +++ b/source/fbi/task/listsystemsavedata.c @@ -4,13 +4,9 @@ #include <3ds.h> -#include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/task/task.h" +#include "listsystemsavedata.h" +#include "../resources.h" +#include "../../core/core.h" #define MAX_SYSTEM_SAVE_DATA 512 diff --git a/source/fbi/task/listsystemsavedata.h b/source/fbi/task/listsystemsavedata.h new file mode 100644 index 0000000..860ff98 --- /dev/null +++ b/source/fbi/task/listsystemsavedata.h @@ -0,0 +1,20 @@ +#pragma once + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct system_save_data_info_s { + u32 systemSaveDataId; +} system_save_data_info; + +typedef struct populate_system_save_data_data_s { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_system_save_data_data; + +void task_free_system_save_data(list_item* item); +void task_clear_system_save_data(linked_list* items); +Result task_populate_system_save_data(populate_system_save_data_data* data); \ No newline at end of file diff --git a/source/ui/section/task/listtickets.c b/source/fbi/task/listtickets.c similarity index 94% rename from source/ui/section/task/listtickets.c rename to source/fbi/task/listtickets.c index e748ce6..b1e675f 100644 --- a/source/ui/section/task/listtickets.c +++ b/source/fbi/task/listtickets.c @@ -4,13 +4,9 @@ #include <3ds.h> -#include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/task/task.h" +#include "listtickets.h" +#include "../resources.h" +#include "../../core/core.h" static int task_populate_tickets_compare_ids(const void* e1, const void* e2) { u64 id1 = *(u64*) e1; diff --git a/source/fbi/task/listtickets.h b/source/fbi/task/listtickets.h new file mode 100644 index 0000000..8da7e8c --- /dev/null +++ b/source/fbi/task/listtickets.h @@ -0,0 +1,22 @@ +#pragma once + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct ticket_info_s { + u64 titleId; + bool inUse; +} ticket_info; + +typedef struct populate_tickets_data_s { + linked_list* items; + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_tickets_data; + +void task_populate_tickets_update_use(list_item* item); +void task_free_ticket(list_item* item); +void task_clear_tickets(linked_list* items); +Result task_populate_tickets(populate_tickets_data* data); \ No newline at end of file diff --git a/source/ui/section/task/listtitledb.c b/source/fbi/task/listtitledb.c similarity index 94% rename from source/ui/section/task/listtitledb.c rename to source/fbi/task/listtitledb.c index 4a0e231..f7cd60a 100644 --- a/source/ui/section/task/listtitledb.c +++ b/source/fbi/task/listtitledb.c @@ -1,302 +1,297 @@ -#include -#include -#include -#include - -#include <3ds.h> -#include - -#include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" -#include "../../../core/task/task.h" -#include "../../../libs/stb_image/stb_image.h" - -#define json_object_get_string(obj, name, def) (json_is_string(json_object_get(obj, name)) ? json_string_value(json_object_get(obj, name)) : def) -#define json_object_get_integer(obj, name, def) (json_is_integer(json_object_get(obj, name)) ? json_integer_value(json_object_get(obj, name)) : def) - -void task_populate_titledb_update_status(list_item* item) { - titledb_info* info = (titledb_info*) item->data; - - if(info->cia.exists) { - AM_TitleEntry entry; - info->cia.installed = R_SUCCEEDED(AM_GetTitleInfo(fs_get_title_destination(info->cia.titleId), 1, &info->cia.titleId, &entry)); - info->cia.installedVersion = info->cia.installed ? entry.version : (u16) 0; - } - - if(info->tdsx.exists) { - info->tdsx.installed = false; - - char name[FILE_NAME_MAX]; - string_escape_file_name(name, info->meta.shortDescription, sizeof(name)); - - char path3dsx[FILE_PATH_MAX]; - snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name); - - FS_Path* fsPath = fs_make_path_utf8(path3dsx); - if(fsPath != NULL) { - Handle handle = 0; - if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) { - FSFILE_Close(handle); - - info->tdsx.installed = true; - } - - fs_free_path_utf8(fsPath); - } - } - - // TODO: Outdated color(?) - if((info->cia.exists && info->cia.installed) || (info->tdsx.exists && info->tdsx.installed)) { - item->color = COLOR_TITLEDB_INSTALLED; - } else { - item->color = COLOR_TITLEDB_NOT_INSTALLED; - } -} - -static int task_populate_titledb_compare(void* userData, const void* p1, const void* p2) { - list_item* info1 = (list_item*) p1; - list_item* info2 = (list_item*) p2; - - return strncasecmp(info1->name, info2->name, LIST_ITEM_NAME_MAX); -} - -static void task_populate_titledb_thread(void* arg) { - populate_titledb_data* data = (populate_titledb_data*) arg; - - Result res = 0; - - json_t* root = NULL; - if(R_SUCCEEDED(res = task_download_json_sync("https://api.titledb.com/v1/entry?nested=true" - "&only=id&only=name&only=author&only=headline&only=category" - "&only=cia.id&only=cia.updated_at&only=cia.version&only=cia.size&only=cia.titleid" - "&only=tdsx.id&only=tdsx.updated_at&only=tdsx.version&only=tdsx.size&only=tdsx.smdh.id", - &root, 1024 * 1024))) { - if(json_is_array(root)) { - linked_list titles; - linked_list_init(&titles); - - for(u32 i = 0; i < json_array_size(root) && R_SUCCEEDED(res); i++) { - svcWaitSynchronization(task_get_pause_event(), U64_MAX); - if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { - break; - } - - json_t* entry = json_array_get(root, i); - if(json_is_object(entry)) { - list_item* item = (list_item*) calloc(1, sizeof(list_item)); - if(item != NULL) { - titledb_info* titledbInfo = (titledb_info*) calloc(1, sizeof(titledb_info)); - if(titledbInfo != NULL) { - titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0); - strncpy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category)); - strncpy(titledbInfo->headline, json_object_get_string(entry, "headline", ""), sizeof(titledbInfo->headline)); - strncpy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription)); - strncpy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher)); - - json_t* cias = json_object_get(entry, "cia"); - if(json_is_array(cias)) { - for(u32 j = 0; j < json_array_size(cias); j++) { - json_t* cia = json_array_get(cias, j); - if(json_is_object(cia)) { - const char* updatedAt = json_object_get_string(cia, "updated_at", ""); - if(!titledbInfo->cia.exists || strncmp(updatedAt, titledbInfo->cia.updatedAt, sizeof(titledbInfo->cia.updatedAt)) >= 0) { - titledbInfo->cia.exists = true; - - titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0); - strncpy(titledbInfo->cia.updatedAt, updatedAt, sizeof(titledbInfo->cia.updatedAt)); - strncpy(titledbInfo->cia.version, json_object_get_string(cia, "version", "Unknown"), sizeof(titledbInfo->cia.version)); - titledbInfo->cia.size = (u32) json_object_get_integer(cia, "size", 0); - titledbInfo->cia.titleId = strtoull(json_object_get_string(cia, "titleid", "0"), NULL, 16); - } - } - } - } - - json_t* tdsxs = json_object_get(entry, "tdsx"); - if(json_is_array(tdsxs)) { - for(u32 j = 0; j < json_array_size(tdsxs); j++) { - json_t* tdsx = json_array_get(tdsxs, j); - if(json_is_object(tdsx)) { - const char* updatedAt = json_object_get_string(tdsx, "updated_at", ""); - if(!titledbInfo->tdsx.exists || strncmp(updatedAt, titledbInfo->tdsx.updatedAt, sizeof(titledbInfo->tdsx.updatedAt)) >= 0) { - titledbInfo->tdsx.exists = true; - - titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0); - strncpy(titledbInfo->tdsx.updatedAt, updatedAt, sizeof(titledbInfo->tdsx.updatedAt)); - strncpy(titledbInfo->tdsx.version, json_object_get_string(tdsx, "version", "Unknown"), sizeof(titledbInfo->tdsx.version)); - titledbInfo->tdsx.size = (u32) json_object_get_integer(tdsx, "size", 0); - - json_t* smdh = json_object_get(tdsx, "smdh"); - if(json_is_object(smdh)) { - titledbInfo->tdsx.smdh.exists = true; - - titledbInfo->tdsx.smdh.id = (u32) json_object_get_integer(smdh, "id", 0); - } - } - } - } - } - - strncpy(item->name, titledbInfo->meta.shortDescription, LIST_ITEM_NAME_MAX); - item->data = titledbInfo; - - task_populate_titledb_update_status(item); - - linked_list_add_sorted(&titles, item, NULL, task_populate_titledb_compare); - } else { - free(item); - - res = R_APP_OUT_OF_MEMORY; - } - } else { - res = R_APP_OUT_OF_MEMORY; - } - } - } - - linked_list_iter iter; - linked_list_iterate(&titles, &iter); - - while(linked_list_iter_has_next(&iter)) { - list_item* item = linked_list_iter_next(&iter); - - if(R_SUCCEEDED(res)) { - linked_list_add(data->items, item); - } else { - task_free_titledb(item); - } - } - - linked_list_destroy(&titles); - } else { - res = R_APP_BAD_DATA; - } - - json_decref(root); - } - - data->itemsListed = true; - - if(R_SUCCEEDED(res)) { - linked_list_iter iter; - linked_list_iterate(data->items, &iter); - - while(linked_list_iter_has_next(&iter)) { - svcWaitSynchronization(task_get_pause_event(), U64_MAX); - - Handle events[2] = {data->resumeEvent, data->cancelEvent}; - s32 index = 0; - svcWaitSynchronizationN(&index, events, 2, false, U64_MAX); - - if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { - break; - } - - list_item* item = (list_item*) linked_list_iter_next(&iter); - titledb_info* titledbInfo = (titledb_info*) item->data; - - char url[128]; - if(titledbInfo->cia.exists) { - snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/cia/%lu/icon_l.bin", titledbInfo->cia.id); - } else if(titledbInfo->tdsx.exists && titledbInfo->tdsx.smdh.exists) { - snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/smdh/%lu/icon_l.bin", titledbInfo->tdsx.smdh.id); - } else { - continue; - } - - u8 icon[0x1200]; - u32 iconSize = 0; - if(R_SUCCEEDED(task_download_sync(url, &iconSize, &icon, sizeof(icon))) && iconSize == sizeof(icon)) { - titledbInfo->meta.texture = screen_allocate_free_texture(); - screen_load_texture_tiled(titledbInfo->meta.texture, icon, sizeof(icon), 48, 48, GPU_RGB565, false); - } - } - } - - svcCloseHandle(data->resumeEvent); - svcCloseHandle(data->cancelEvent); - - data->result = res; - data->finished = true; -} - -void task_free_titledb(list_item* item) { - if(item == NULL) { - return; - } - - if(item->data != NULL) { - titledb_info* titledbInfo = (titledb_info*) item->data; - if(titledbInfo->meta.texture != 0) { - screen_unload_texture(titledbInfo->meta.texture); - titledbInfo->meta.texture = 0; - } - - free(item->data); - } - - free(item); -} - -void task_clear_titledb(linked_list* items) { - if(items == NULL) { - return; - } - - linked_list_iter iter; - linked_list_iterate(items, &iter); - - while(linked_list_iter_has_next(&iter)) { - list_item* item = (list_item*) linked_list_iter_next(&iter); - - linked_list_iter_remove(&iter); - task_free_titledb(item); - } -} - -Result task_populate_titledb(populate_titledb_data* data) { - if(data == NULL || data->items == NULL) { - return R_APP_INVALID_ARGUMENT; - } - - task_clear_titledb(data->items); - - data->itemsListed = false; - data->finished = false; - data->result = 0; - data->cancelEvent = 0; - - Result res = 0; - if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, RESET_STICKY))) { - if(R_SUCCEEDED(res = svcCreateEvent(&data->resumeEvent, RESET_STICKY))) { - svcSignalEvent(data->resumeEvent); - - if(threadCreate(task_populate_titledb_thread, data, 0x10000, 0x19, 1, true) == NULL) { - res = R_APP_THREAD_CREATE_FAILED; - } - } - } - - if(R_FAILED(res)) { - data->itemsListed = true; - data->finished = true; - - if(data->resumeEvent != 0) { - svcCloseHandle(data->resumeEvent); - data->resumeEvent = 0; - } - - if(data->cancelEvent != 0) { - svcCloseHandle(data->cancelEvent); - data->cancelEvent = 0; - } - } - - return res; +#include +#include +#include +#include + +#include <3ds.h> +#include + +#include "uitask.h" +#include "listtitledb.h" +#include "../resources.h" +#include "../../core/core.h" +#include "../../core/task/dataop.h" +#include "../../libs/stb_image/stb_image.h" + +#define json_object_get_string(obj, name, def) (json_is_string(json_object_get(obj, name)) ? json_string_value(json_object_get(obj, name)) : def) +#define json_object_get_integer(obj, name, def) (json_is_integer(json_object_get(obj, name)) ? json_integer_value(json_object_get(obj, name)) : def) + +void task_populate_titledb_update_status(list_item* item) { + titledb_info* info = (titledb_info*) item->data; + + if(info->cia.exists) { + AM_TitleEntry entry; + info->cia.installed = R_SUCCEEDED(AM_GetTitleInfo(fs_get_title_destination(info->cia.titleId), 1, &info->cia.titleId, &entry)); + info->cia.installedVersion = info->cia.installed ? entry.version : (u16) 0; + } + + if(info->tdsx.exists) { + info->tdsx.installed = false; + + char name[FILE_NAME_MAX]; + string_escape_file_name(name, info->meta.shortDescription, sizeof(name)); + + char path3dsx[FILE_PATH_MAX]; + snprintf(path3dsx, sizeof(path3dsx), "/3ds/%s/%s.3dsx", name, name); + + FS_Path* fsPath = fs_make_path_utf8(path3dsx); + if(fsPath != NULL) { + Handle handle = 0; + if(R_SUCCEEDED(FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) { + FSFILE_Close(handle); + + info->tdsx.installed = true; + } + + fs_free_path_utf8(fsPath); + } + } + + if((info->cia.exists && info->cia.installed) || (info->tdsx.exists && info->tdsx.installed)) { + item->color = COLOR_TITLEDB_INSTALLED; + } else { + item->color = COLOR_TITLEDB_NOT_INSTALLED; + } +} + +static int task_populate_titledb_compare(void* userData, const void* p1, const void* p2) { + list_item* info1 = (list_item*) p1; + list_item* info2 = (list_item*) p2; + + return strncasecmp(info1->name, info2->name, LIST_ITEM_NAME_MAX); +} + +static void task_populate_titledb_thread(void* arg) { + populate_titledb_data* data = (populate_titledb_data*) arg; + + Result res = 0; + + json_t* root = NULL; + if(R_SUCCEEDED(res = task_download_json_sync("https://api.titledb.com/v1/entry?nested=true" + "&only=id&only=name&only=author&only=headline&only=category" + "&only=cia.id&only=cia.updated_at&only=cia.version&only=cia.size&only=cia.titleid" + "&only=tdsx.id&only=tdsx.updated_at&only=tdsx.version&only=tdsx.size&only=tdsx.smdh.id", + &root, 1024 * 1024))) { + if(json_is_array(root)) { + linked_list titles; + linked_list_init(&titles); + + for(u32 i = 0; i < json_array_size(root) && R_SUCCEEDED(res); i++) { + svcWaitSynchronization(task_get_pause_event(), U64_MAX); + if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { + break; + } + + json_t* entry = json_array_get(root, i); + if(json_is_object(entry)) { + list_item* item = (list_item*) calloc(1, sizeof(list_item)); + if(item != NULL) { + titledb_info* titledbInfo = (titledb_info*) calloc(1, sizeof(titledb_info)); + if(titledbInfo != NULL) { + titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0); + strncpy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category)); + strncpy(titledbInfo->headline, json_object_get_string(entry, "headline", ""), sizeof(titledbInfo->headline)); + strncpy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription)); + strncpy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher)); + + json_t* cias = json_object_get(entry, "cia"); + if(json_is_array(cias)) { + for(u32 j = 0; j < json_array_size(cias); j++) { + json_t* cia = json_array_get(cias, j); + if(json_is_object(cia)) { + const char* updatedAt = json_object_get_string(cia, "updated_at", ""); + if(!titledbInfo->cia.exists || strncmp(updatedAt, titledbInfo->cia.updatedAt, sizeof(titledbInfo->cia.updatedAt)) >= 0) { + titledbInfo->cia.exists = true; + + titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0); + strncpy(titledbInfo->cia.updatedAt, updatedAt, sizeof(titledbInfo->cia.updatedAt)); + strncpy(titledbInfo->cia.version, json_object_get_string(cia, "version", "Unknown"), sizeof(titledbInfo->cia.version)); + titledbInfo->cia.size = (u32) json_object_get_integer(cia, "size", 0); + titledbInfo->cia.titleId = strtoull(json_object_get_string(cia, "titleid", "0"), NULL, 16); + } + } + } + } + + json_t* tdsxs = json_object_get(entry, "tdsx"); + if(json_is_array(tdsxs)) { + for(u32 j = 0; j < json_array_size(tdsxs); j++) { + json_t* tdsx = json_array_get(tdsxs, j); + if(json_is_object(tdsx)) { + const char* updatedAt = json_object_get_string(tdsx, "updated_at", ""); + if(!titledbInfo->tdsx.exists || strncmp(updatedAt, titledbInfo->tdsx.updatedAt, sizeof(titledbInfo->tdsx.updatedAt)) >= 0) { + titledbInfo->tdsx.exists = true; + + titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0); + strncpy(titledbInfo->tdsx.updatedAt, updatedAt, sizeof(titledbInfo->tdsx.updatedAt)); + strncpy(titledbInfo->tdsx.version, json_object_get_string(tdsx, "version", "Unknown"), sizeof(titledbInfo->tdsx.version)); + titledbInfo->tdsx.size = (u32) json_object_get_integer(tdsx, "size", 0); + + json_t* smdh = json_object_get(tdsx, "smdh"); + if(json_is_object(smdh)) { + titledbInfo->tdsx.smdh.exists = true; + + titledbInfo->tdsx.smdh.id = (u32) json_object_get_integer(smdh, "id", 0); + } + } + } + } + } + + strncpy(item->name, titledbInfo->meta.shortDescription, LIST_ITEM_NAME_MAX); + item->data = titledbInfo; + + task_populate_titledb_update_status(item); + + linked_list_add_sorted(&titles, item, NULL, task_populate_titledb_compare); + } else { + free(item); + + res = R_APP_OUT_OF_MEMORY; + } + } else { + res = R_APP_OUT_OF_MEMORY; + } + } + } + + linked_list_iter iter; + linked_list_iterate(&titles, &iter); + + while(linked_list_iter_has_next(&iter)) { + list_item* item = linked_list_iter_next(&iter); + + if(R_SUCCEEDED(res)) { + linked_list_add(data->items, item); + } else { + task_free_titledb(item); + } + } + + linked_list_destroy(&titles); + } else { + res = R_APP_BAD_DATA; + } + + json_decref(root); + } + + data->itemsListed = true; + + if(R_SUCCEEDED(res)) { + linked_list_iter iter; + linked_list_iterate(data->items, &iter); + + while(linked_list_iter_has_next(&iter)) { + svcWaitSynchronization(task_get_pause_event(), U64_MAX); + + Handle events[2] = {data->resumeEvent, data->cancelEvent}; + s32 index = 0; + svcWaitSynchronizationN(&index, events, 2, false, U64_MAX); + + if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) { + break; + } + + list_item* item = (list_item*) linked_list_iter_next(&iter); + titledb_info* titledbInfo = (titledb_info*) item->data; + + char url[128]; + if(titledbInfo->cia.exists) { + snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/cia/%lu/icon_l.bin", titledbInfo->cia.id); + } else if(titledbInfo->tdsx.exists && titledbInfo->tdsx.smdh.exists) { + snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/smdh/%lu/icon_l.bin", titledbInfo->tdsx.smdh.id); + } else { + continue; + } + + u8 icon[0x1200]; + u32 iconSize = 0; + if(R_SUCCEEDED(task_download_sync(url, &iconSize, &icon, sizeof(icon))) && iconSize == sizeof(icon)) { + titledbInfo->meta.texture = screen_allocate_free_texture(); + screen_load_texture_tiled(titledbInfo->meta.texture, icon, sizeof(icon), 48, 48, GPU_RGB565, false); + } + } + } + + svcCloseHandle(data->resumeEvent); + svcCloseHandle(data->cancelEvent); + + data->result = res; + data->finished = true; +} + +void task_free_titledb(list_item* item) { + if(item == NULL) { + return; + } + + if(item->data != NULL) { + titledb_info* titledbInfo = (titledb_info*) item->data; + if(titledbInfo->meta.texture != 0) { + screen_unload_texture(titledbInfo->meta.texture); + titledbInfo->meta.texture = 0; + } + + free(item->data); + } + + free(item); +} + +void task_clear_titledb(linked_list* items) { + if(items == NULL) { + return; + } + + linked_list_iter iter; + linked_list_iterate(items, &iter); + + while(linked_list_iter_has_next(&iter)) { + list_item* item = (list_item*) linked_list_iter_next(&iter); + + linked_list_iter_remove(&iter); + task_free_titledb(item); + } +} + +Result task_populate_titledb(populate_titledb_data* data) { + if(data == NULL || data->items == NULL) { + return R_APP_INVALID_ARGUMENT; + } + + task_clear_titledb(data->items); + + data->itemsListed = false; + data->finished = false; + data->result = 0; + data->cancelEvent = 0; + + Result res = 0; + if(R_SUCCEEDED(res = svcCreateEvent(&data->cancelEvent, RESET_STICKY))) { + if(R_SUCCEEDED(res = svcCreateEvent(&data->resumeEvent, RESET_STICKY))) { + svcSignalEvent(data->resumeEvent); + + if(threadCreate(task_populate_titledb_thread, data, 0x10000, 0x19, 1, true) == NULL) { + res = R_APP_THREAD_CREATE_FAILED; + } + } + } + + if(R_FAILED(res)) { + data->itemsListed = true; + data->finished = true; + + if(data->resumeEvent != 0) { + svcCloseHandle(data->resumeEvent); + data->resumeEvent = 0; + } + + if(data->cancelEvent != 0) { + svcCloseHandle(data->cancelEvent); + data->cancelEvent = 0; + } + } + + return res; } \ No newline at end of file diff --git a/source/fbi/task/listtitledb.h b/source/fbi/task/listtitledb.h new file mode 100644 index 0000000..d09028a --- /dev/null +++ b/source/fbi/task/listtitledb.h @@ -0,0 +1,60 @@ +#pragma once + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct titledb_cia_info_s { + bool exists; + + u32 id; + char updatedAt[32]; + char version[32]; + u64 size; + u64 titleId; + + bool installed; + u16 installedVersion; +} titledb_cia_info; + +typedef struct titledb_smdh_info_s { + bool exists; + + u32 id; +} titledb_smdh_info; + +typedef struct titledb_tdsx_info_s { + bool exists; + + u32 id; + char updatedAt[32]; + char version[32]; + u64 size; + titledb_smdh_info smdh; + + bool installed; +} titledb_tdsx_info; + +typedef struct titledb_info_s { + u32 id; + char category[64]; + char headline[512]; + titledb_cia_info cia; + titledb_tdsx_info tdsx; + + meta_info meta; +} titledb_info; + +typedef struct populate_titledb_data_s { + linked_list* items; + + volatile bool itemsListed; + volatile bool finished; + Result result; + Handle cancelEvent; + Handle resumeEvent; +} populate_titledb_data; + +void task_populate_titledb_update_status(list_item* item); +void task_free_titledb(list_item* item); +void task_clear_titledb(linked_list* items); +Result task_populate_titledb(populate_titledb_data* data); \ No newline at end of file diff --git a/source/ui/section/task/listtitles.c b/source/fbi/task/listtitles.c similarity index 97% rename from source/ui/section/task/listtitles.c rename to source/fbi/task/listtitles.c index 3293c24..3b53b92 100644 --- a/source/ui/section/task/listtitles.c +++ b/source/fbi/task/listtitles.c @@ -6,16 +6,9 @@ #include <3ds.h> #include "uitask.h" -#include "../../list.h" -#include "../../resources.h" -#include "../../../core/error.h" -#include "../../../core/fs.h" -#include "../../../core/linkedlist.h" -#include "../../../core/screen.h" -#include "../../../core/stringutil.h" -#include "../../../core/data/bnr.h" -#include "../../../core/data/smdh.h" -#include "../../../core/task/task.h" +#include "listtitles.h" +#include "../resources.h" +#include "../../core/core.h" static Result task_populate_titles_add_ctr(populate_titles_data* data, FS_MediaType mediaType, u64 titleId) { Result res = 0; diff --git a/source/fbi/task/listtitles.h b/source/fbi/task/listtitles.h new file mode 100644 index 0000000..3acd264 --- /dev/null +++ b/source/fbi/task/listtitles.h @@ -0,0 +1,31 @@ +#pragma once + +typedef struct linked_list_s linked_list; +typedef struct list_item_s list_item; + +typedef struct title_info_s { + FS_MediaType mediaType; + u64 titleId; + char productCode[0x10]; + u16 version; + u64 installedSize; + bool twl; + bool hasMeta; + meta_info meta; +} title_info; + +typedef struct populate_titles_data_s { + linked_list* items; + + void* userData; + bool (*filter)(void* data, u64 titleId, FS_MediaType mediaType); + int (*compare)(void* data, const void* p1, const void* p2); + + volatile bool finished; + Result result; + Handle cancelEvent; +} populate_titles_data; + +void task_free_title(list_item* item); +void task_clear_titles(linked_list* items); +Result task_populate_titles(populate_titles_data* data); \ No newline at end of file diff --git a/source/fbi/task/uitask.c b/source/fbi/task/uitask.c new file mode 100644 index 0000000..bebd16d --- /dev/null +++ b/source/fbi/task/uitask.c @@ -0,0 +1,344 @@ +#include +#include + +#include <3ds.h> + +#include "uitask.h" +#include "../resources.h" +#include "../../core/core.h" + +void task_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + meta_info* info = (meta_info*) data; + + u32 metaInfoBoxShadowWidth; + u32 metaInfoBoxShadowHeight; + screen_get_texture_size(&metaInfoBoxShadowWidth, &metaInfoBoxShadowHeight, TEXTURE_META_INFO_BOX_SHADOW); + + float metaInfoBoxShadowX = x1 + (x2 - x1 - metaInfoBoxShadowWidth) / 2; + float metaInfoBoxShadowY = y1 + (y2 - y1) / 4 - metaInfoBoxShadowHeight / 2; + screen_draw_texture(TEXTURE_META_INFO_BOX_SHADOW, metaInfoBoxShadowX, metaInfoBoxShadowY, metaInfoBoxShadowWidth, metaInfoBoxShadowHeight); + + u32 metaInfoBoxWidth; + u32 metaInfoBoxHeight; + screen_get_texture_size(&metaInfoBoxWidth, &metaInfoBoxHeight, TEXTURE_META_INFO_BOX); + + float metaInfoBoxX = x1 + (x2 - x1 - metaInfoBoxWidth) / 2; + float metaInfoBoxY = y1 + (y2 - y1) / 4 - metaInfoBoxHeight / 2; + screen_draw_texture(TEXTURE_META_INFO_BOX, metaInfoBoxX, metaInfoBoxY, metaInfoBoxWidth, metaInfoBoxHeight); + + if(info->texture != 0) { + u32 iconWidth; + u32 iconHeight; + screen_get_texture_size(&iconWidth, &iconHeight, info->texture); + + float iconX = metaInfoBoxX + (64 - iconWidth) / 2; + float iconY = metaInfoBoxY + (metaInfoBoxHeight - iconHeight) / 2; + screen_draw_texture(info->texture, iconX, iconY, iconWidth, iconHeight); + } + + float metaTextX = metaInfoBoxX + 64; + + float shortDescriptionHeight; + screen_get_string_size_wrap(NULL, &shortDescriptionHeight, info->shortDescription, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX); + + float longDescriptionHeight; + screen_get_string_size_wrap(NULL, &longDescriptionHeight, info->longDescription, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX); + + float publisherHeight; + screen_get_string_size_wrap(NULL, &publisherHeight, info->publisher, 0.5f, 0.5f, metaInfoBoxX + metaInfoBoxWidth - 8 - metaTextX); + + float shortDescriptionY = metaInfoBoxY + (64 - shortDescriptionHeight - 2 - longDescriptionHeight - 2 - publisherHeight) / 2; + screen_draw_string_wrap(info->shortDescription, metaTextX, shortDescriptionY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8); + + float longDescriptionY = shortDescriptionY + shortDescriptionHeight + 2; + screen_draw_string_wrap(info->longDescription, metaTextX, longDescriptionY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8); + + float publisherY = longDescriptionY + longDescriptionHeight + 2; + screen_draw_string_wrap(info->publisher, metaTextX, publisherY, 0.5f, 0.5f, COLOR_TEXT, false, metaInfoBoxX + metaInfoBoxWidth - 8); +} + +void task_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + ext_save_data_info* info = (ext_save_data_info*) data; + + if(info->hasMeta) { + task_draw_meta_info(view, &info->meta, x1, y1, x2, y2); + } + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), + "Ext Save Data ID: %016llX\n" + "Shared: %s", + info->extSaveDataId, + info->shared ? "Yes" : "No"); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + file_info* info = (file_info*) data; + + char infoText[512]; + size_t infoTextPos = 0; + + if(strlen(info->name) > 48) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Name: %.45s...\n", info->name); + } else { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Name: %.48s\n", info->name); + } + + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Attributes: "); + + if(info->attributes & (FS_ATTRIBUTE_DIRECTORY | FS_ATTRIBUTE_HIDDEN | FS_ATTRIBUTE_ARCHIVE | FS_ATTRIBUTE_READ_ONLY)) { + bool needsSeparator = false; + + if(info->attributes & FS_ATTRIBUTE_DIRECTORY) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Directory"); + needsSeparator = true; + } + + if(info->attributes & FS_ATTRIBUTE_HIDDEN) { + if(needsSeparator) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", "); + } + + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Hidden"); + needsSeparator = true; + } + + if(info->attributes & FS_ATTRIBUTE_ARCHIVE) { + if(needsSeparator) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", "); + } + + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Archive"); + needsSeparator = true; + } + + if(info->attributes & FS_ATTRIBUTE_READ_ONLY) { + if(needsSeparator) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, ", "); + } + + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Read Only"); + needsSeparator = true; + } + } else { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "None"); + } + + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "\n"); + + if(!(info->attributes & FS_ATTRIBUTE_DIRECTORY)) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Size: %.2f %s\n", + ui_get_display_size(info->size), ui_get_display_size_units(info->size)); + + if(info->isCia) { + char regionString[64]; + + if(info->ciaInfo.hasMeta) { + task_draw_meta_info(view, &info->ciaInfo.meta, x1, y1, x2, y2); + + smdh_region_to_string(regionString, info->ciaInfo.meta.region, sizeof(regionString)); + } else { + snprintf(regionString, sizeof(regionString), "Unknown"); + } + + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, + "Title ID: %016llX\n" + "Version: %hu (%d.%d.%d)\n" + "Region: %s\n" + "Installed Size: %.2f %s", + info->ciaInfo.titleId, + info->ciaInfo.version, (info->ciaInfo.version >> 10) & 0x3F, (info->ciaInfo.version >> 4) & 0x3F, info->ciaInfo.version & 0xF, + regionString, + ui_get_display_size(info->ciaInfo.installedSize), + ui_get_display_size_units(info->ciaInfo.installedSize)); + } else if(info->isTicket) { + infoTextPos += snprintf(infoText + infoTextPos, sizeof(infoText) - infoTextPos, "Ticket ID: %016llX", info->ticketInfo.titleId); + } + } + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + pending_title_info* info = (pending_title_info*) data; + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), + "Pending Title ID: %016llX\n" + "Media Type: %s\n" + "Version: %hu (%d.%d.%d)", + info->titleId, + info->mediaType == MEDIATYPE_NAND ? "NAND" : info->mediaType == MEDIATYPE_SD ? "SD" : "Game Card", + info->version, (info->version >> 10) & 0x3F, (info->version >> 4) & 0x3F, info->version & 0xF); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + system_save_data_info* info = (system_save_data_info*) data; + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), "System Save Data ID: %08lX", info->systemSaveDataId); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + ticket_info* info = (ticket_info*) data; + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), "Title ID: %016llX", info->titleId); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + title_info* info = (title_info*) data; + + char regionString[64]; + + if(info->hasMeta) { + task_draw_meta_info(view, &info->meta, x1, y1, x2, y2); + + smdh_region_to_string(regionString, info->meta.region, sizeof(regionString)); + } else { + snprintf(regionString, sizeof(regionString), "Unknown"); + } + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), + "Title ID: %016llX\n" + "Media Type: %s\n" + "Version: %hu (%d.%d.%d)\n" + "Product Code: %s\n" + "Region: %s\n" + "Size: %.2f %s", + info->titleId, + info->mediaType == MEDIATYPE_NAND ? "NAND" : info->mediaType == MEDIATYPE_SD ? "SD" : "Game Card", + info->version, (info->version >> 10) & 0x3F, (info->version >> 4) & 0x3F, info->version & 0xF, + info->productCode, + regionString, + ui_get_display_size(info->installedSize), ui_get_display_size_units(info->installedSize)); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + titledb_info* info = (titledb_info*) data; + + task_draw_meta_info(view, &info->meta, x1, y1, x2, y2); + + char infoText[1024]; + + snprintf(infoText, sizeof(infoText), + "%s\n" + "\n" + "Category: %s\n", + info->headline, + info->category); + + float infoWidth; + screen_get_string_size_wrap(&infoWidth, NULL, infoText, 0.5f, 0.5f, x2 - x1 - 10); + + // TODO: Wrap by word, not character? + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string_wrap(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true, infoX + infoWidth + 1); +} + +void task_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + titledb_info* info = (titledb_info*) data; + + task_draw_meta_info(view, &info->meta, x1, y1, x2, y2); + + char updatedDate[32] = ""; + char updatedTime[32] = ""; + + sscanf(info->cia.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime); + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), + "Title ID: %016llX\n" + "TitleDB Version: %s\n" + "Installed Version: %hu (%d.%d.%d)\n" + "Size: %.2f %s\n" + "Updated At: %s %s", + info->cia.titleId, + info->cia.version, + info->cia.installedVersion, (info->cia.installedVersion >> 10) & 0x3F, (info->cia.installedVersion >> 4) & 0x3F, info->cia.installedVersion & 0xF, + ui_get_display_size(info->cia.size), ui_get_display_size_units(info->cia.size), + updatedDate, updatedTime); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} + +void task_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + titledb_info* info = (titledb_info*) data; + + task_draw_meta_info(view, &info->meta, x1, y1, x2, y2); + + char updatedDate[32] = ""; + char updatedTime[32] = ""; + + sscanf(info->tdsx.updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime); + + char infoText[512]; + + snprintf(infoText, sizeof(infoText), + "TitleDB Version: %s\n" + "Size: %.2f %s\n" + "Updated At: %s %s", + info->tdsx.version, + ui_get_display_size(info->tdsx.size), ui_get_display_size_units(info->tdsx.size), + updatedDate, updatedTime); + + float infoWidth; + screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); + + float infoX = x1 + (x2 - x1 - infoWidth) / 2; + float infoY = y1 + (y2 - y1) / 2 - 8; + screen_draw_string(infoText, infoX, infoY, 0.5f, 0.5f, COLOR_TEXT, true); +} \ No newline at end of file diff --git a/source/fbi/task/uitask.h b/source/fbi/task/uitask.h new file mode 100644 index 0000000..4b4f9c5 --- /dev/null +++ b/source/fbi/task/uitask.h @@ -0,0 +1,30 @@ +#pragma once + +typedef struct ui_view_s ui_view; + +typedef struct meta_info_s { + char shortDescription[0x100]; + char longDescription[0x200]; + char publisher[0x100]; + u32 region; + u32 texture; +} meta_info; + +void task_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2); +void task_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2); + +#include "listextsavedata.h" +#include "listpendingtitles.h" +#include "listsystemsavedata.h" +#include "listtickets.h" +#include "listtitledb.h" +#include "listtitles.h" +#include "listfiles.h" \ No newline at end of file diff --git a/source/ui/section/tickets.c b/source/fbi/tickets.c similarity index 92% rename from source/ui/section/tickets.c rename to source/fbi/tickets.c index 0ef5fb7..8708173 100644 --- a/source/ui/section/tickets.c +++ b/source/fbi/tickets.c @@ -3,15 +3,11 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" +#include "../core/core.h" static list_item install_from_cdn = {"Install from CDN", COLOR_TEXT, action_install_cdn}; static list_item delete_ticket = {"Delete Ticket", COLOR_TEXT, action_delete_ticket}; @@ -29,7 +25,7 @@ typedef struct { } tickets_action_data; static void tickets_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_ticket_info(view, ((tickets_action_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_ticket_info(view, ((tickets_action_data*) data)->selected->data, x1, y1, x2, y2); } static void tickets_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -80,7 +76,7 @@ static void tickets_action_open(linked_list* items, list_item* selected) { static void tickets_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(selected != NULL && selected->data != NULL) { - ui_draw_ticket_info(view, selected->data, x1, y1, x2, y2); + task_draw_ticket_info(view, selected->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/titledb.c b/source/fbi/titledb.c similarity index 90% rename from source/ui/section/titledb.c rename to source/fbi/titledb.c index 37296da..ca5d627 100644 --- a/source/ui/section/titledb.c +++ b/source/fbi/titledb.c @@ -1,248 +1,244 @@ -#include -#include -#include - -#include <3ds.h> - -#include "section.h" -#include "action/action.h" -#include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" - -static list_item install = {"Install", COLOR_TEXT, action_install_titledb}; - -typedef struct { - populate_titledb_data populateData; - - bool populated; -} titledb_data; - -typedef struct { - linked_list* items; - list_item* selected; -} titledb_entry_data; - -typedef struct { - linked_list* items; - list_item* selected; - bool cia; -} titledb_action_data; - -static void titledb_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - titledb_action_data* actionData = (titledb_action_data*) data; - - if(actionData->cia) { - ui_draw_titledb_info_cia(view, actionData->selected->data, x1, y1, x2, y2); - } else { - ui_draw_titledb_info_tdsx(view, actionData->selected->data, x1, y1, x2, y2); - } -} - -static void titledb_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { - titledb_action_data* actionData = (titledb_action_data*) data; - - if(hidKeysDown() & KEY_B) { - ui_pop(); - list_destroy(view); - - free(data); - - return; - } - - if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { - void(*action)(linked_list*, list_item*, bool) = (void(*)(linked_list*, list_item*, bool)) selected->data; - - ui_pop(); - list_destroy(view); - - action(actionData->items, actionData->selected, actionData->cia); - - free(data); - - return; - } - - if(linked_list_size(items) == 0) { - linked_list_add(items, &install); - } -} - -static void titledb_action_open(linked_list* items, list_item* selected, bool cia) { - titledb_action_data* data = (titledb_action_data*) calloc(1, sizeof(titledb_action_data)); - if(data == NULL) { - error_display(NULL, NULL, "Failed to allocate TitleDB action data."); - - return; - } - - data->items = items; - data->selected = selected; - data->cia = cia; - - list_display("TitleDB Action", "A: Select, B: Return", data, titledb_action_update, titledb_action_draw_top); -} - -static void titledb_entry_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - titledb_entry_data* entryData = (titledb_entry_data*) data; - - if(selected != NULL) { - if(strncmp(selected->name, "CIA", sizeof(selected->name)) == 0) { - ui_draw_titledb_info_cia(view, entryData->selected->data, x1, y1, x2, y2); - } else if(strncmp(selected->name, "3DSX", sizeof(selected->name)) == 0) { - ui_draw_titledb_info_tdsx(view, entryData->selected->data, x1, y1, x2, y2); - } - } -} - -static void titledb_entry_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { - titledb_entry_data* entryData = (titledb_entry_data*) data; - - if(hidKeysDown() & KEY_B) { - ui_pop(); - - linked_list_iter iter; - linked_list_iterate(items, &iter); - - while(linked_list_iter_has_next(&iter)) { - free(linked_list_iter_next(&iter)); - linked_list_iter_remove(&iter); - } - - list_destroy(view); - free(data); - - return; - } - - if(selected != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { - titledb_action_open(entryData->items, entryData->selected, (bool) selected->data); - return; - } - - if(linked_list_size(items) == 0) { - titledb_info* info = (titledb_info*) entryData->selected->data; - - if(info->cia.exists) { - list_item* item = (list_item*) calloc(1, sizeof(list_item)); - if(item != NULL) { - strncpy(item->name, "CIA", sizeof(item->name)); - item->data = (void*) true; - item->color = info->cia.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; - - linked_list_add(items, item); - } - } - - if(info->tdsx.exists) { - list_item* item = (list_item*) calloc(1, sizeof(list_item)); - if(item != NULL) { - strncpy(item->name, "3DSX", sizeof(item->name)); - item->data = (void*) false; - item->color = info->tdsx.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; - - linked_list_add(items, item); - } - } - } -} - -static void titledb_entry_open(linked_list* items, list_item* selected) { - titledb_entry_data* data = (titledb_entry_data*) calloc(1, sizeof(titledb_entry_data)); - if(data == NULL) { - error_display(NULL, NULL, "Failed to allocate TitleDB entry data."); - - return; - } - - data->items = items; - data->selected = selected; - - list_display("TitleDB Entry", "A: Select, B: Return", data, titledb_entry_update, titledb_entry_draw_top); -} - -static void titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - titledb_data* listData = (titledb_data*) data; - - if(!listData->populateData.itemsListed) { - static const char* text = "Loading title list, please wait...\nNOTE: Cancelling may take up to 15 seconds."; - - float textWidth; - float textHeight; - screen_get_string_size(&textWidth, &textHeight, text, 0.5f, 0.5f); - screen_draw_string(text, x1 + (x2 - x1 - textWidth) / 2, y1 + (y2 - y1 - textHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); - } else if(selected != NULL && selected->data != NULL) { - ui_draw_titledb_info(view, selected->data, x1, y1, x2, y2); - } -} - -static void titledb_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { - titledb_data* listData = (titledb_data*) data; - - svcSignalEvent(listData->populateData.resumeEvent); - - if(hidKeysDown() & KEY_B) { - if(!listData->populateData.finished) { - svcSignalEvent(listData->populateData.cancelEvent); - while(!listData->populateData.finished) { - svcSleepThread(1000000); - } - } - - ui_pop(); - - task_clear_titledb(items); - list_destroy(view); - - free(listData); - return; - } - - if(!listData->populated || (hidKeysDown() & KEY_X)) { - if(!listData->populateData.finished) { - svcSignalEvent(listData->populateData.cancelEvent); - while(!listData->populateData.finished) { - svcSleepThread(1000000); - } - } - - listData->populateData.items = items; - Result res = task_populate_titledb(&listData->populateData); - if(R_FAILED(res)) { - error_display_res(NULL, NULL, res, "Failed to initiate TitleDB list population."); - } - - listData->populated = true; - } - - if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { - error_display_res(NULL, NULL, listData->populateData.result, "Failed to populate TitleDB list."); - - listData->populateData.result = 0; - } - - if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { - svcClearEvent(listData->populateData.resumeEvent); - - titledb_entry_open(items, selected); - return; - } -} - -void titledb_open() { - titledb_data* data = (titledb_data*) calloc(1, sizeof(titledb_data)); - if(data == NULL) { - error_display(NULL, NULL, "Failed to allocate TitleDB data."); - - return; - } - - data->populateData.finished = true; - - list_display("TitleDB.com", "A: Select, B: Return, X: Refresh", data, titledb_update, titledb_draw_top); +#include +#include +#include + +#include <3ds.h> + +#include "resources.h" +#include "section.h" +#include "action/action.h" +#include "task/uitask.h" +#include "../core/core.h" + +static list_item install = {"Install", COLOR_TEXT, action_install_titledb}; + +typedef struct { + populate_titledb_data populateData; + + bool populated; +} titledb_data; + +typedef struct { + linked_list* items; + list_item* selected; +} titledb_entry_data; + +typedef struct { + linked_list* items; + list_item* selected; + bool cia; +} titledb_action_data; + +static void titledb_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { + titledb_action_data* actionData = (titledb_action_data*) data; + + if(actionData->cia) { + task_draw_titledb_info_cia(view, actionData->selected->data, x1, y1, x2, y2); + } else { + task_draw_titledb_info_tdsx(view, actionData->selected->data, x1, y1, x2, y2); + } +} + +static void titledb_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { + titledb_action_data* actionData = (titledb_action_data*) data; + + if(hidKeysDown() & KEY_B) { + ui_pop(); + list_destroy(view); + + free(data); + + return; + } + + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { + void(*action)(linked_list*, list_item*, bool) = (void(*)(linked_list*, list_item*, bool)) selected->data; + + ui_pop(); + list_destroy(view); + + action(actionData->items, actionData->selected, actionData->cia); + + free(data); + + return; + } + + if(linked_list_size(items) == 0) { + linked_list_add(items, &install); + } +} + +static void titledb_action_open(linked_list* items, list_item* selected, bool cia) { + titledb_action_data* data = (titledb_action_data*) calloc(1, sizeof(titledb_action_data)); + if(data == NULL) { + error_display(NULL, NULL, "Failed to allocate TitleDB action data."); + + return; + } + + data->items = items; + data->selected = selected; + data->cia = cia; + + list_display("TitleDB Action", "A: Select, B: Return", data, titledb_action_update, titledb_action_draw_top); +} + +static void titledb_entry_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { + titledb_entry_data* entryData = (titledb_entry_data*) data; + + if(selected != NULL) { + if(strncmp(selected->name, "CIA", sizeof(selected->name)) == 0) { + task_draw_titledb_info_cia(view, entryData->selected->data, x1, y1, x2, y2); + } else if(strncmp(selected->name, "3DSX", sizeof(selected->name)) == 0) { + task_draw_titledb_info_tdsx(view, entryData->selected->data, x1, y1, x2, y2); + } + } +} + +static void titledb_entry_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { + titledb_entry_data* entryData = (titledb_entry_data*) data; + + if(hidKeysDown() & KEY_B) { + ui_pop(); + + linked_list_iter iter; + linked_list_iterate(items, &iter); + + while(linked_list_iter_has_next(&iter)) { + free(linked_list_iter_next(&iter)); + linked_list_iter_remove(&iter); + } + + list_destroy(view); + free(data); + + return; + } + + if(selected != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { + titledb_action_open(entryData->items, entryData->selected, (bool) selected->data); + return; + } + + if(linked_list_size(items) == 0) { + titledb_info* info = (titledb_info*) entryData->selected->data; + + if(info->cia.exists) { + list_item* item = (list_item*) calloc(1, sizeof(list_item)); + if(item != NULL) { + strncpy(item->name, "CIA", sizeof(item->name)); + item->data = (void*) true; + item->color = info->cia.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; + + linked_list_add(items, item); + } + } + + if(info->tdsx.exists) { + list_item* item = (list_item*) calloc(1, sizeof(list_item)); + if(item != NULL) { + strncpy(item->name, "3DSX", sizeof(item->name)); + item->data = (void*) false; + item->color = info->tdsx.installed ? COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; + + linked_list_add(items, item); + } + } + } +} + +static void titledb_entry_open(linked_list* items, list_item* selected) { + titledb_entry_data* data = (titledb_entry_data*) calloc(1, sizeof(titledb_entry_data)); + if(data == NULL) { + error_display(NULL, NULL, "Failed to allocate TitleDB entry data."); + + return; + } + + data->items = items; + data->selected = selected; + + list_display("TitleDB Entry", "A: Select, B: Return", data, titledb_entry_update, titledb_entry_draw_top); +} + +static void titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { + titledb_data* listData = (titledb_data*) data; + + if(!listData->populateData.itemsListed) { + static const char* text = "Loading title list, please wait...\nNOTE: Cancelling may take up to 15 seconds."; + + float textWidth; + float textHeight; + screen_get_string_size(&textWidth, &textHeight, text, 0.5f, 0.5f); + screen_draw_string(text, x1 + (x2 - x1 - textWidth) / 2, y1 + (y2 - y1 - textHeight) / 2, 0.5f, 0.5f, COLOR_TEXT, true); + } else if(selected != NULL && selected->data != NULL) { + task_draw_titledb_info(view, selected->data, x1, y1, x2, y2); + } +} + +static void titledb_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { + titledb_data* listData = (titledb_data*) data; + + svcSignalEvent(listData->populateData.resumeEvent); + + if(hidKeysDown() & KEY_B) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { + svcSleepThread(1000000); + } + } + + ui_pop(); + + task_clear_titledb(items); + list_destroy(view); + + free(listData); + return; + } + + if(!listData->populated || (hidKeysDown() & KEY_X)) { + if(!listData->populateData.finished) { + svcSignalEvent(listData->populateData.cancelEvent); + while(!listData->populateData.finished) { + svcSleepThread(1000000); + } + } + + listData->populateData.items = items; + Result res = task_populate_titledb(&listData->populateData); + if(R_FAILED(res)) { + error_display_res(NULL, NULL, res, "Failed to initiate TitleDB list population."); + } + + listData->populated = true; + } + + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { + error_display_res(NULL, NULL, listData->populateData.result, "Failed to populate TitleDB list."); + + listData->populateData.result = 0; + } + + if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) { + svcClearEvent(listData->populateData.resumeEvent); + + titledb_entry_open(items, selected); + return; + } +} + +void titledb_open() { + titledb_data* data = (titledb_data*) calloc(1, sizeof(titledb_data)); + if(data == NULL) { + error_display(NULL, NULL, "Failed to allocate TitleDB data."); + + return; + } + + data->populateData.finished = true; + + list_display("TitleDB.com", "A: Select, B: Return, X: Refresh", data, titledb_update, titledb_draw_top); } \ No newline at end of file diff --git a/source/ui/section/titles.c b/source/fbi/titles.c similarity index 96% rename from source/ui/section/titles.c rename to source/fbi/titles.c index b0d024d..8f94428 100644 --- a/source/ui/section/titles.c +++ b/source/fbi/titles.c @@ -4,16 +4,11 @@ #include <3ds.h> +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../list.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/linkedlist.h" -#include "../../core/screen.h" -#include "../../core/stringutil.h" +#include "../core/core.h" static list_item launch_title = {"Launch Title", COLOR_TEXT, action_launch_title}; static list_item delete_title = {"Delete Title", COLOR_TEXT, action_delete_title}; @@ -47,7 +42,7 @@ typedef struct { } titles_action_data; static void titles_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { - ui_draw_title_info(view, ((titles_action_data*) data)->selected->data, x1, y1, x2, y2); + task_draw_title_info(view, ((titles_action_data*) data)->selected->data, x1, y1, x2, y2); } static void titles_action_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) { @@ -196,7 +191,7 @@ static void titles_options_open(titles_data* data) { static void titles_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) { if(selected != NULL && selected->data != NULL) { - ui_draw_title_info(view, selected->data, x1, y1, x2, y2); + task_draw_title_info(view, selected->data, x1, y1, x2, y2); } } diff --git a/source/ui/section/update.c b/source/fbi/update.c similarity index 93% rename from source/ui/section/update.c rename to source/fbi/update.c index cebfd78..664178d 100644 --- a/source/ui/section/update.c +++ b/source/fbi/update.c @@ -5,17 +5,11 @@ #include <3ds.h> #include +#include "resources.h" #include "section.h" #include "action/action.h" #include "task/uitask.h" -#include "../error.h" -#include "../info.h" -#include "../prompt.h" -#include "../resources.h" -#include "../ui.h" -#include "../../core/error.h" -#include "../../core/fs.h" -#include "../../core/screen.h" +#include "../core/core.h" static void update_check_update(ui_view* view, void* data, float* progress, char* text) { bool hasUpdate = false; diff --git a/source/ui/mainmenu.h b/source/ui/mainmenu.h deleted file mode 100644 index fbf3382..0000000 --- a/source/ui/mainmenu.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void mainmenu_open(); diff --git a/source/ui/section/task/uitask.h b/source/ui/section/task/uitask.h deleted file mode 100644 index 5a2666e..0000000 --- a/source/ui/section/task/uitask.h +++ /dev/null @@ -1,297 +0,0 @@ -#pragma once - -// TODO: Find a way to get rid of this? -#ifndef FILE_NAME_MAX -#define FILE_NAME_MAX 512 -#define FILE_PATH_MAX 512 -#endif - -#define DOWNLOAD_URL_MAX 1024 - -typedef struct json_t json_t; - -typedef struct linked_list_s linked_list; -typedef struct list_item_s list_item; -typedef struct ui_view_s ui_view; - -typedef struct meta_info_s { - char shortDescription[0x100]; - char longDescription[0x200]; - char publisher[0x100]; - u32 region; - u32 texture; -} meta_info; - -typedef struct title_info_s { - FS_MediaType mediaType; - u64 titleId; - char productCode[0x10]; - u16 version; - u64 installedSize; - bool twl; - bool hasMeta; - meta_info meta; -} title_info; - -typedef struct pending_title_info_s { - FS_MediaType mediaType; - u64 titleId; - u16 version; -} pending_title_info; - -typedef struct ticket_info_s { - u64 titleId; - bool inUse; -} ticket_info; - -typedef struct ext_save_data_info_s { - FS_MediaType mediaType; - u64 extSaveDataId; - bool shared; - bool hasMeta; - meta_info meta; -} ext_save_data_info; - -typedef struct system_save_data_info_s { - u32 systemSaveDataId; -} system_save_data_info; - -typedef struct cia_info_s { - u64 titleId; - u16 version; - u64 installedSize; - bool hasMeta; - meta_info meta; -} cia_info; - -typedef struct file_info_s { - FS_Archive archive; - char name[FILE_NAME_MAX]; - char path[FILE_PATH_MAX]; - u32 attributes; - - // Files only - u64 size; - bool isCia; - cia_info ciaInfo; - bool isTicket; - ticket_info ticketInfo; -} file_info; - -typedef struct titledb_cia_info_s { - bool exists; - - u32 id; - char updatedAt[32]; - char version[32]; - u64 size; - u64 titleId; - - bool installed; - u16 installedVersion; -} titledb_cia_info; - -typedef struct titledb_smdh_info_s { - bool exists; - - u32 id; -} titledb_smdh_info; - -typedef struct titledb_tdsx_info_s { - bool exists; - - u32 id; - char updatedAt[32]; - char version[32]; - u64 size; - titledb_smdh_info smdh; - - bool installed; -} titledb_tdsx_info; - -typedef struct titledb_info_s { - u32 id; - char category[64]; - char headline[512]; - titledb_cia_info cia; - titledb_tdsx_info tdsx; - - meta_info meta; -} titledb_info; - -typedef enum data_op_e { - DATAOP_COPY, - DATAOP_DOWNLOAD, - DATAOP_DELETE -} data_op; - -typedef struct data_op_data_s { - void* data; - - data_op op; - - u32 processed; - u32 total; - - // Copy - bool copyEmpty; - - Result (*isSrcDirectory)(void* data, u32 index, bool* isDirectory); - Result (*makeDstDirectory)(void* data, u32 index); - - Result (*openSrc)(void* data, u32 index, u32* handle); - Result (*closeSrc)(void* data, u32 index, bool succeeded, u32 handle); - - Result (*getSrcSize)(void* data, u32 handle, u64* size); - Result (*readSrc)(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size); - - // Download - char (*downloadUrls)[DOWNLOAD_URL_MAX]; - - // Copy/Download - u64 currProcessed; - u64 currTotal; - - u32 bytesPerSecond; - u32 estimatedRemainingSeconds; - - u32 bufferSize; - - Result (*openDst)(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle); - Result (*closeDst)(void* data, u32 index, bool succeeded, u32 handle); - - Result (*writeDst)(void* data, u32 handle, u32* bytesWritten, void* buffer, u64 offset, u32 size); - - Result (*suspendTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle); - Result (*restoreTransfer)(void* data, u32 index, u32* srcHandle, u32* dstHandle); - - // Delete - Result (*delete)(void* data, u32 index); - - // Suspend - Result (*suspend)(void* data, u32 index); - Result (*restore)(void* data, u32 index); - - // Errors - bool (*error)(void* data, u32 index, Result res, ui_view** errorView); - - // General - volatile bool finished; - Result result; - Handle cancelEvent; - - // Internal - volatile bool retryResponse; -} data_op_data; - -typedef struct populate_ext_save_data_data_s { - linked_list* items; - - void* userData; - bool (*filter)(void* data, u64 extSaveDataId, FS_MediaType mediaType); - int (*compare)(void* data, const void* p1, const void* p2); - - volatile bool finished; - Result result; - Handle cancelEvent; -} populate_ext_save_data_data; - -typedef struct populate_files_data_s { - linked_list* items; - - FS_Archive archive; - char path[FILE_PATH_MAX]; - - bool recursive; - bool includeBase; - - bool (*filter)(void* data, const char* name, u32 attributes); - void* filterData; - - volatile bool finished; - Result result; - Handle cancelEvent; -} populate_files_data; - -typedef struct populate_pending_titles_data_s { - linked_list* items; - - volatile bool finished; - Result result; - Handle cancelEvent; -} populate_pending_titles_data; - -typedef struct populate_system_save_data_data_s { - linked_list* items; - - volatile bool finished; - Result result; - Handle cancelEvent; -} populate_system_save_data_data; - -typedef struct populate_tickets_data_s { - linked_list* items; - - volatile bool finished; - Result result; - Handle cancelEvent; -} populate_tickets_data; - -typedef struct populate_titles_data_s { - linked_list* items; - - void* userData; - bool (*filter)(void* data, u64 titleId, FS_MediaType mediaType); - int (*compare)(void* data, const void* p1, const void* p2); - - volatile bool finished; - Result result; - Handle cancelEvent; -} populate_titles_data; - -typedef struct populate_titledb_data_s { - linked_list* items; - - volatile bool itemsListed; - volatile bool finished; - Result result; - Handle cancelEvent; - Handle resumeEvent; -} populate_titledb_data; - -Result task_download_sync(const char* url, u32* downloadedSize, void* buf, size_t size); -Result task_download_json_sync(const char* url, json_t** json, size_t maxSize); -Result task_download_seed_sync(u64 titleId); -Result task_data_op(data_op_data* data); - -void task_free_ext_save_data(list_item* item); -void task_clear_ext_save_data(linked_list* items); -Result task_populate_ext_save_data(populate_ext_save_data_data* data); - -int task_compare_files(void* userData, const void* p1, const void* p2); -void task_free_file(list_item* item); -void task_clear_files(linked_list* items); -Result task_create_file_item(list_item** out, FS_Archive archive, const char* path, u32 attributes); -Result task_populate_files(populate_files_data* data); - -void task_free_pending_title(list_item* item); -void task_clear_pending_titles(linked_list* items); -Result task_populate_pending_titles(populate_pending_titles_data* data); - -void task_free_system_save_data(list_item* item); -void task_clear_system_save_data(linked_list* items); -Result task_populate_system_save_data(populate_system_save_data_data* data); - -void task_populate_tickets_update_use(list_item* item); -void task_free_ticket(list_item* item); -void task_clear_tickets(linked_list* items); -Result task_populate_tickets(populate_tickets_data* data); - -void task_free_title(list_item* item); -void task_clear_titles(linked_list* items); -Result task_populate_titles(populate_titles_data* data); - -void task_populate_titledb_update_status(list_item* item); -void task_free_titledb(list_item* item); -void task_clear_titledb(linked_list* items); -Result task_populate_titledb(populate_titledb_data* data); \ No newline at end of file diff --git a/source/ui/ui.h b/source/ui/ui.h deleted file mode 100644 index 826d97c..0000000 --- a/source/ui/ui.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -typedef struct ui_view_s { - const char* name; - const char* info; - void* data; - void (*update)(struct ui_view_s* view, void* data, float bx1, float by1, float bx2, float by2); - void (*drawTop)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2); - void (*drawBottom)(struct ui_view_s* view, void* data, float x1, float y1, float x2, float y2); - - Handle active; -} ui_view; - -void ui_init(); -void ui_exit(); - -ui_view* ui_create(); -void ui_destroy(ui_view* view); - -ui_view* ui_top(); -bool ui_push(ui_view* view); -void ui_pop(); -bool ui_update(); - -const char* ui_get_display_eta(u32 seconds); -double ui_get_display_size(u64 size); -const char* ui_get_display_size_units(u64 size); - -void ui_draw_meta_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_ext_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_file_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_pending_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_system_save_data_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_ticket_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_title_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, float x2, float y2); -void ui_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, float x2, float y2); \ No newline at end of file