diff --git a/romfs/textcolor.cfg b/romfs/textcolor.cfg index 245b3bb..a976134 100644 --- a/romfs/textcolor.cfg +++ b/romfs/textcolor.cfg @@ -8,6 +8,7 @@ directory=FF0000FF enabled=FF00FF00 disabled=FF0000FF titledbinstalled=FF00FF00 +titledboutdated=FFFF0000 titledbnotinstalled=FF0000FF ticketinuse=FF00FF00 ticketnotinuse=FF0000FF \ No newline at end of file diff --git a/source/fbi/action/action.h b/source/fbi/action/action.h index b3589ce..27d33c2 100644 --- a/source/fbi/action/action.h +++ b/source/fbi/action/action.h @@ -52,7 +52,10 @@ void action_import_secure_value(linked_list* items, list_item* selected); void action_export_secure_value(linked_list* items, list_item* selected); void action_delete_secure_value(linked_list* items, list_item* selected); -void action_install_url(const char* confirmMessage, const char* urls, const char* path3dsx, void* userData, void (*finished)(void* data), - void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index)); +void action_install_url(const char* confirmMessage, const char* urls, const char* path3dsx, void* userData, + void (*finishedURL)(void* data, u32 index), + void (*finishedAll)(void* data), + void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index)); -void action_install_titledb(linked_list* items, list_item* selected, bool cia); \ No newline at end of file +void action_install_titledb(linked_list* items, list_item* selected, bool cia); +void action_update_titledb(linked_list* items, list_item* selected); \ No newline at end of file diff --git a/source/fbi/action/installtitledb.c b/source/fbi/action/installtitledb.c index 14484c3..83a592b 100644 --- a/source/fbi/action/installtitledb.c +++ b/source/fbi/action/installtitledb.c @@ -22,9 +22,15 @@ static void action_install_titledb_draw_top(ui_view* view, void* data, float x1, } } -static void action_update_titledb_finished(void* data) { - task_populate_titledb_update_status(((install_titledb_data*) data)->selected); +static void action_install_titledb_finished_url(void* data, u32 index) { + install_titledb_data* installData = (install_titledb_data*) data; + list_item* item = installData->selected; + task_populate_titledb_cache_installed((titledb_info*) item->data, installData->cia); + task_populate_titledb_update_status(item); +} + +static void action_install_titledb_finished_all(void* data) { free(data); } @@ -53,5 +59,5 @@ void action_install_titledb(linked_list* items, list_item* selected, bool cia) { 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); + action_install_url("Install the selected title from TitleDB?", url, path3dsx, data, action_install_titledb_finished_url, action_install_titledb_finished_all, action_install_titledb_draw_top); } \ No newline at end of file diff --git a/source/fbi/action/installurl.c b/source/fbi/action/installurl.c index a655db9..d158f49 100644 --- a/source/fbi/action/installurl.c +++ b/source/fbi/action/installurl.c @@ -18,10 +18,11 @@ typedef enum content_type_e { typedef struct { char urls[INSTALL_URLS_MAX][DOWNLOAD_URL_MAX]; - char path3dsx[FILE_PATH_MAX]; + char paths3dsx[INSTALL_URLS_MAX][FILE_PATH_MAX]; void* userData; - void (*finished)(void* data); + void (*finishedURL)(void* data, u32 index); + void (*finishedAll)(void* data); void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index); bool cdn; @@ -39,8 +40,8 @@ typedef struct { } install_url_data; static void action_install_url_free_data(install_url_data* data) { - if(data->finished != NULL) { - data->finished(data->userData); + if(data->finishedAll != NULL) { + data->finishedAll(data->userData); } free(data); @@ -202,9 +203,9 @@ static Result action_install_url_open_dst(void* data, u32 index, void* initialRe FS_Archive sdmcArchive = 0; if(R_SUCCEEDED(res = FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")))) { char dir[FILE_PATH_MAX]; - if(strlen(installData->path3dsx) > 0) { - string_get_parent_path(dir, installData->path3dsx, FILE_PATH_MAX); - strncpy(installData->curr3dsxPath, installData->path3dsx, FILE_PATH_MAX); + if(strlen(installData->paths3dsx[index]) > 0) { + string_get_parent_path(dir, installData->paths3dsx[index], FILE_PATH_MAX); + strncpy(installData->curr3dsxPath, installData->paths3dsx[index], FILE_PATH_MAX); } else { char filename[FILE_NAME_MAX]; if(R_FAILED(http_get_file_name(installData->currContext, filename, FILE_NAME_MAX))) { @@ -288,6 +289,10 @@ static Result action_install_url_close_dst(void* data, u32 index, bool succeeded } } + if(R_SUCCEEDED(res) && installData->finishedURL != NULL) { + installData->finishedURL(installData->userData, index); + } + return res; } @@ -372,8 +377,10 @@ static void action_install_url_confirm_onresponse(ui_view* view, void* data, u32 } } -void action_install_url(const char* confirmMessage, const char* urls, const char* path3dsx, void* userData, void (*finished)(void* data), - void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index)) { +void action_install_url(const char* confirmMessage, const char* urls, const char* paths3dsx, void* userData, + void (*finishedURL)(void* data, u32 index), + void (*finishedAll)(void* data), + void (*drawTop)(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index)) { install_url_data* data = (install_url_data*) calloc(1, sizeof(install_url_data)); if(data == NULL) { error_display(NULL, NULL, "Failed to allocate URL install data."); @@ -414,12 +421,31 @@ void action_install_url(const char* confirmMessage, const char* urls, const char } } - if(path3dsx != NULL) { - strncpy(data->path3dsx, path3dsx, FILE_PATH_MAX); + if(paths3dsx != NULL) { + size_t pathsLen = strlen(paths3dsx); + if(pathsLen > 0) { + const char* currStart = paths3dsx; + for(u32 i = 0; i < data->installInfo.total && currStart - paths3dsx < pathsLen; i++) { + const char* currEnd = strchr(currStart, '\n'); + if(currEnd == NULL) { + currEnd = paths3dsx + pathsLen; + } + + u32 len = currEnd - currStart; + if(len > FILE_PATH_MAX) { + len = FILE_PATH_MAX; + } + + strncpy(data->paths3dsx[i], currStart, len); + + currStart = currEnd + 1; + } + } } data->userData = userData; - data->finished = finished; + data->finishedURL = finishedURL; + data->finishedAll = finishedAll; data->drawTop = drawTop; data->cdn = false; diff --git a/source/fbi/action/updatetitledb.c b/source/fbi/action/updatetitledb.c new file mode 100644 index 0000000..f2ee14c --- /dev/null +++ b/source/fbi/action/updatetitledb.c @@ -0,0 +1,87 @@ +#include +#include +#include + +#include <3ds.h> + +#include "action.h" +#include "../task/uitask.h" +#include "../../core/core.h" + +typedef struct { + bool cia[INSTALL_URLS_MAX]; + char urls[INSTALL_URLS_MAX * DOWNLOAD_URL_MAX]; + char paths3dsx[INSTALL_URLS_MAX * FILE_PATH_MAX]; + list_item* items[INSTALL_URLS_MAX]; +} update_titledb_data; + +static void action_update_titledb_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, u32 index) { + update_titledb_data* updateData = (update_titledb_data*) data; + + if(updateData->items[index] != NULL) { + if(updateData->cia[index]) { + task_draw_titledb_info_cia(view, updateData->items[index]->data, x1, y1, x2, y2); + } else { + task_draw_titledb_info_tdsx(view, updateData->items[index]->data, x1, y1, x2, y2); + } + } +} + +static void action_update_titledb_finished_url(void* data, u32 index) { + update_titledb_data* updateData = (update_titledb_data*) data; + list_item* item = updateData->items[index]; + + task_populate_titledb_cache_installed((titledb_info*) item->data, updateData->cia[index]); + task_populate_titledb_update_status(item); +} + +static void action_update_titledb_finished_all(void* data) { + free(data); +} + +void action_update_titledb(linked_list* items, list_item* selected) { + update_titledb_data* data = (update_titledb_data*) calloc(1, sizeof(update_titledb_data)); + if(data == NULL) { + error_display(NULL, NULL, "Failed to allocate install TitleDB data."); + + return; + } + + linked_list_iter iter; + linked_list_iterate(items, &iter); + + u32 index = 0; + u32 urlsPos = 0; + u32 pathsPos = 0; + while(linked_list_iter_has_next(&iter) && index < INSTALL_URLS_MAX && urlsPos < INSTALL_URLS_MAX * DOWNLOAD_URL_MAX && pathsPos < INSTALL_URLS_MAX * FILE_PATH_MAX) { + list_item* item = linked_list_iter_next(&iter); + titledb_info* info = (titledb_info*) item->data; + + if(info->cia.outdated) { + data->cia[index] = true; + urlsPos += snprintf(data->urls + urlsPos, INSTALL_URLS_MAX * DOWNLOAD_URL_MAX - urlsPos, "https://3ds.titledb.com/v1/cia/%lu/download\n", info->cia.id); + pathsPos += snprintf(data->paths3dsx + pathsPos, INSTALL_URLS_MAX * FILE_PATH_MAX - pathsPos, "\n"); + data->items[index] = item; + + index++; + } + + if(info->tdsx.outdated) { + char name[FILE_NAME_MAX]; + string_escape_file_name(name, info->meta.shortDescription, sizeof(name)); + + data->cia[index] = false; + urlsPos += snprintf(data->urls + urlsPos, INSTALL_URLS_MAX * DOWNLOAD_URL_MAX - urlsPos, "https://3ds.titledb.com/v1/tdsx/%lu/download\n", info->tdsx.id); + pathsPos += snprintf(data->paths3dsx + pathsPos, INSTALL_URLS_MAX * FILE_PATH_MAX - pathsPos, "/3ds/%s/%s.3dsx\n", name, name); + data->items[index] = item; + + index++; + } + } + + if(index > 0) { + action_install_url("Install all updates from TitleDB?", data->urls, data->paths3dsx, data, action_update_titledb_finished_url, action_update_titledb_finished_all, action_update_titledb_draw_top); + } else { + prompt_display_notify("Success", "All titles are up to date.", COLOR_TEXT, NULL, NULL, NULL); + } +} \ No newline at end of file diff --git a/source/fbi/main.c b/source/fbi/main.c index 74aee4f..05e7a98 100644 --- a/source/fbi/main.c +++ b/source/fbi/main.c @@ -11,6 +11,7 @@ #include "../core/task/task.h" #include "../core/ui/ui.h" #include "section.h" +#include "task/uitask.h" #define CURRENT_KPROCESS (*(void**) 0xFFFF9004) @@ -157,6 +158,7 @@ void init() { void cleanup() { clipboard_clear(); + task_populate_titledb_unload_cache(); task_exit(); ui_exit(); diff --git a/source/fbi/remoteinstall.c b/source/fbi/remoteinstall.c index bc57561..ccdce7d 100644 --- a/source/fbi/remoteinstall.c +++ b/source/fbi/remoteinstall.c @@ -111,6 +111,7 @@ static void remoteinstall_network_close_client(void* data) { } } + static void remoteinstall_network_free_data(remoteinstall_network_data* data) { remoteinstall_network_close_client(data); @@ -174,7 +175,7 @@ static void remoteinstall_network_update(ui_view* view, void* data, float* progr } remoteinstall_set_last_urls(urls); - action_install_url("Install from the received URL(s)?", urls, NULL, data, remoteinstall_network_close_client, NULL); + action_install_url("Install from the received URL(s)?", urls, NULL, data, NULL, remoteinstall_network_close_client, NULL); free(urls); } else if(errno != EAGAIN) { @@ -375,7 +376,7 @@ static void remoteinstall_qr_update(ui_view* view, void* data, float* progress, remoteinstall_set_last_urls((const char*) qrData.payload); - action_install_url("Install from the scanned QR code?", (const char*) qrData.payload, NULL, NULL, NULL, NULL); + action_install_url("Install from the scanned QR code?", (const char*) qrData.payload, NULL, NULL, NULL, NULL, NULL); return; } } @@ -434,7 +435,7 @@ static void remoteinstall_manually_enter_urls_onresponse(ui_view* view, void* da if(button == SWKBD_BUTTON_CONFIRM) { remoteinstall_set_last_urls(response); - action_install_url("Install from the entered URL(s)?", response, NULL, NULL, NULL, NULL); + action_install_url("Install from the entered URL(s)?", response, NULL, NULL, NULL, NULL, NULL); } } @@ -446,7 +447,7 @@ static void remoteinstall_repeat_last_request() { char* textBuf = (char*) calloc(1, DOWNLOAD_URL_MAX * INSTALL_URLS_MAX); if(textBuf != NULL) { if(remoteinstall_get_last_urls(textBuf, DOWNLOAD_URL_MAX * INSTALL_URLS_MAX)) { - action_install_url("Install from the last requested URL(s)?", textBuf, NULL, NULL, NULL, NULL); + action_install_url("Install from the last requested URL(s)?", textBuf, NULL, NULL, NULL, NULL, NULL); } else { prompt_display_notify("Failure", "No previously requested URL(s) could be found.", COLOR_TEXT, NULL, NULL, NULL); } diff --git a/source/fbi/resources.c b/source/fbi/resources.c index be07a18..1adcce9 100644 --- a/source/fbi/resources.c +++ b/source/fbi/resources.c @@ -68,6 +68,8 @@ void resources_load() { screen_set_color(COLOR_DISABLED, color); } else if(strcasecmp(key, "titledbinstalled") == 0) { screen_set_color(COLOR_TITLEDB_INSTALLED, color); + } else if(strcasecmp(key, "titledboutdated") == 0) { + screen_set_color(COLOR_TITLEDB_OUTDATED, color); } else if(strcasecmp(key, "titledbnotinstalled") == 0) { screen_set_color(COLOR_TITLEDB_NOT_INSTALLED, color); } else if(strcasecmp(key, "ticketinuse") == 0) { diff --git a/source/fbi/resources.h b/source/fbi/resources.h index 4025364..d52502e 100644 --- a/source/fbi/resources.h +++ b/source/fbi/resources.h @@ -40,8 +40,9 @@ #define COLOR_ENABLED 7 #define COLOR_DISABLED 8 #define COLOR_TITLEDB_INSTALLED 9 -#define COLOR_TITLEDB_NOT_INSTALLED 10 -#define COLOR_TICKET_IN_USE 11 -#define COLOR_TICKET_NOT_IN_USE 12 +#define COLOR_TITLEDB_OUTDATED 10 +#define COLOR_TITLEDB_NOT_INSTALLED 11 +#define COLOR_TICKET_IN_USE 12 +#define COLOR_TICKET_NOT_IN_USE 13 void resources_load(); \ No newline at end of file diff --git a/source/fbi/task/listtitledb.c b/source/fbi/task/listtitledb.c index cc1256e..87bcdcf 100644 --- a/source/fbi/task/listtitledb.c +++ b/source/fbi/task/listtitledb.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -16,6 +17,79 @@ #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) +#define TITLEDB_CACHE_DIR "sdmc:/fbi/" +#define TITLEDB_CACHE_FILE TITLEDB_CACHE_DIR "titledb_cache.json" + +static json_t* installedApps = NULL; + +static void task_populate_titledb_load_cache() { + if(installedApps != NULL) { + json_decref(installedApps); + } + + json_error_t error; + installedApps = json_load_file(TITLEDB_CACHE_FILE, 0, &error); + + if(!json_is_object(installedApps)) { + if(installedApps != NULL) { + json_decref(installedApps); + } + + installedApps = json_object(); + } +} + +static void task_populate_titledb_save_cache() { + if(json_is_object(installedApps)) { + mkdir(TITLEDB_CACHE_DIR, 755); + + json_dump_file(installedApps, TITLEDB_CACHE_FILE, 0); + } +} + +void task_populate_titledb_unload_cache() { + if(json_is_object(installedApps)) { + task_populate_titledb_save_cache(); + + json_decref(installedApps); + installedApps = NULL; + } +} + +static json_t* task_populate_titledb_get_cache_entry(u32 id) { + if(!json_is_object(installedApps)) { + task_populate_titledb_load_cache(); + } + + if(json_is_object(installedApps)) { + char idString[16]; + itoa(id, idString, 10); + + json_t* cache = json_object_get(installedApps, idString); + if(!json_is_object(cache)) { + cache = json_object(); + json_object_set(installedApps, idString, cache); + } + + return cache; + } else { + return NULL; + } +} + +void task_populate_titledb_cache_installed(titledb_info* info, bool cia) { + json_t* cache = task_populate_titledb_get_cache_entry(info->id); + if(json_is_object(cache)) { + if(cia) { + json_object_set(cache, "cia_id", json_integer(info->cia.id)); + } else { + json_object_set(cache, "tdsx_id", json_integer(info->tdsx.id)); + } + + task_populate_titledb_save_cache(); + } +} + void task_populate_titledb_update_status(list_item* item) { titledb_info* info = (titledb_info*) item->data; @@ -48,7 +122,21 @@ void task_populate_titledb_update_status(list_item* item) { } if((info->cia.exists && info->cia.installed) || (info->tdsx.exists && info->tdsx.installed)) { - item->color = COLOR_TITLEDB_INSTALLED; + json_t* cache = task_populate_titledb_get_cache_entry(info->id); + if(json_is_object(cache)) { + info->cia.outdated = info->cia.installed && json_object_get_integer(cache, "cia_id", 0) < info->cia.id; + info->tdsx.outdated = info->tdsx.installed && json_object_get_integer(cache, "tdsx_id", 0) < info->tdsx.id; + } else { + // If unknown, assume outdated. + info->cia.outdated = true; + info->tdsx.outdated = true; + } + + if(info->cia.outdated || info->tdsx.outdated) { + item->color = COLOR_TITLEDB_OUTDATED; + } else { + item->color = COLOR_TITLEDB_INSTALLED; + } } else { item->color = COLOR_TITLEDB_NOT_INSTALLED; } diff --git a/source/fbi/task/listtitledb.h b/source/fbi/task/listtitledb.h index d09028a..acf0c93 100644 --- a/source/fbi/task/listtitledb.h +++ b/source/fbi/task/listtitledb.h @@ -13,6 +13,7 @@ typedef struct titledb_cia_info_s { u64 titleId; bool installed; + bool outdated; u16 installedVersion; } titledb_cia_info; @@ -32,6 +33,7 @@ typedef struct titledb_tdsx_info_s { titledb_smdh_info smdh; bool installed; + bool outdated; } titledb_tdsx_info; typedef struct titledb_info_s { @@ -54,6 +56,9 @@ typedef struct populate_titledb_data_s { Handle resumeEvent; } populate_titledb_data; +void task_populate_titledb_unload_cache(); +void task_populate_titledb_cache_installed(titledb_info* info, bool cia); + void task_populate_titledb_update_status(list_item* item); void task_free_titledb(list_item* item); void task_clear_titledb(linked_list* items); diff --git a/source/fbi/task/uitask.c b/source/fbi/task/uitask.c index 7c2d909..0300ec8 100644 --- a/source/fbi/task/uitask.c +++ b/source/fbi/task/uitask.c @@ -272,9 +272,11 @@ void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float snprintf(infoText, sizeof(infoText), "%s\n" "\n" - "Category: %s\n", + "Category: %s\n" + "Update Available: %s", info->headline, - info->category); + info->category, + info->cia.outdated || info->tdsx.outdated ? "Yes" : "No"); float infoWidth; screen_get_string_size_wrap(&infoWidth, NULL, infoText, 0.5f, 0.5f, x2 - x1 - 10); @@ -302,12 +304,14 @@ void task_draw_titledb_info_cia(ui_view* view, void* data, float x1, float y1, f "TitleDB Version: %s\n" "Installed Version: %hu (%d.%d.%d)\n" "Size: %.2f %s\n" - "Updated At: %s %s", + "Updated At: %s %s\n" + "Update Available: %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); + updatedDate, updatedTime, + info->cia.outdated ? "Yes" : "No"); float infoWidth; screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); @@ -332,10 +336,12 @@ void task_draw_titledb_info_tdsx(ui_view* view, void* data, float x1, float y1, snprintf(infoText, sizeof(infoText), "TitleDB Version: %s\n" "Size: %.2f %s\n" - "Updated At: %s %s", + "Updated At: %s %s\n" + "Update Available: %s", info->tdsx.version, ui_get_display_size(info->tdsx.size), ui_get_display_size_units(info->tdsx.size), - updatedDate, updatedTime); + updatedDate, updatedTime, + info->tdsx.outdated ? "Yes" : "No"); float infoWidth; screen_get_string_size(&infoWidth, NULL, infoText, 0.5f, 0.5f); diff --git a/source/fbi/titledb.c b/source/fbi/titledb.c index ca5d627..a4d975b 100644 --- a/source/fbi/titledb.c +++ b/source/fbi/titledb.c @@ -121,15 +121,14 @@ static void titledb_entry_update(ui_view* view, void* data, linked_list* items, return; } + titledb_info* info = (titledb_info*) entryData->selected->data; 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; + item->color = info->cia.installed ? info->cia.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; linked_list_add(items, item); } @@ -140,11 +139,24 @@ static void titledb_entry_update(ui_view* view, void* data, linked_list* items, 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; + item->color = info->tdsx.installed ? info->tdsx.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; linked_list_add(items, item); } } + } else { + 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); + + if((bool) item->data) { + item->color = info->cia.installed ? info->cia.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; + } else { + item->color = info->tdsx.installed ? info->tdsx.outdated ? COLOR_TITLEDB_OUTDATED : COLOR_TITLEDB_INSTALLED : COLOR_TITLEDB_NOT_INSTALLED; + } + } } } @@ -216,6 +228,11 @@ static void titledb_update(ui_view* view, void* data, linked_list* items, list_i listData->populated = true; } + if(hidKeysDown() & KEY_Y) { + action_update_titledb(items, selected); + return; + } + if(listData->populateData.finished && R_FAILED(listData->populateData.result)) { error_display_res(NULL, NULL, listData->populateData.result, "Failed to populate TitleDB list."); @@ -240,5 +257,5 @@ void titledb_open() { data->populateData.finished = true; - list_display("TitleDB.com", "A: Select, B: Return, X: Refresh", data, titledb_update, titledb_draw_top); + list_display("TitleDB.com", "A: Select, B: Return, X: Refresh, Y: Update All", data, titledb_update, titledb_draw_top); } \ No newline at end of file diff --git a/source/fbi/update.c b/source/fbi/update.c index 664178d..3491107 100644 --- a/source/fbi/update.c +++ b/source/fbi/update.c @@ -66,7 +66,7 @@ static void update_check_update(ui_view* view, void* data, float* progress, char info_destroy(view); if(hasUpdate) { - action_install_url("Update FBI to the latest version?", updateURL, fs_get_3dsx_path(), NULL, NULL, NULL); + action_install_url("Update FBI to the latest version?", updateURL, fs_get_3dsx_path(), NULL, NULL, NULL, NULL); } else { if(R_FAILED(res)) { error_display_res(NULL, NULL, res, "Failed to check for update.");