Add sorting and filtering options to TitleDB list.

This commit is contained in:
Steven Smith 2018-02-17 20:28:32 -08:00
parent faf0c7d878
commit 599c631b11
5 changed files with 171 additions and 22 deletions

View File

@ -317,10 +317,19 @@ static void ui_draw_bottom(ui_view* ui) {
}
if(ui->info != NULL) {
float baseInfoWidth;
screen_get_string_size(&baseInfoWidth, NULL, ui->info, 0.5f, 0.5f);
float scale = BOTTOM_SCREEN_WIDTH / (baseInfoWidth + 10);
if(scale > 1) {
scale = 1;
}
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_get_string_size(&infoWidth, &infoHeight, ui->info, 0.5f * scale, 0.5f * scale);
screen_draw_string(ui->info, (BOTTOM_SCREEN_WIDTH - infoWidth) / 2, BOTTOM_SCREEN_HEIGHT - (bottomScreenBottomBarHeight + infoHeight) / 2, 0.5f * scale, 0.5f * scale, COLOR_TEXT, true);
}
screen_set_base_alpha(0xFF);

View File

@ -142,28 +142,21 @@ void task_populate_titledb_update_status(list_item* item) {
}
}
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;
linked_list titles;
linked_list_init(&titles);
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=id&only=name&only=author&only=headline&only=category&only=updated_at"
"&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) {
@ -179,6 +172,7 @@ static void task_populate_titledb_thread(void* arg) {
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->updatedAt, json_object_get_string(entry, "updated_at", ""), sizeof(titledbInfo->updatedAt));
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));
@ -226,13 +220,13 @@ static void task_populate_titledb_thread(void* arg) {
}
}
if(titledbInfo->cia.exists || titledbInfo->tdsx.exists) {
if((titledbInfo->cia.exists || titledbInfo->tdsx.exists) && (data->filter == NULL || data->filter(data->userData, titledbInfo))) {
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);
linked_list_add_sorted(&titles, item, data->userData, data->compare);
} else {
free(titledbInfo);
free(item);
@ -258,10 +252,9 @@ static void task_populate_titledb_thread(void* arg) {
linked_list_add(data->items, item);
} else {
task_free_titledb(item);
linked_list_iter_remove(&iter);
}
}
linked_list_destroy(&titles);
} else {
res = R_APP_BAD_DATA;
}
@ -273,7 +266,7 @@ static void task_populate_titledb_thread(void* arg) {
if(R_SUCCEEDED(res)) {
linked_list_iter iter;
linked_list_iterate(data->items, &iter);
linked_list_iterate(&titles, &iter);
while(linked_list_iter_has_next(&iter)) {
svcWaitSynchronization(task_get_pause_event(), U64_MAX);
@ -307,6 +300,8 @@ static void task_populate_titledb_thread(void* arg) {
}
}
linked_list_destroy(&titles);
svcCloseHandle(data->resumeEvent);
svcCloseHandle(data->cancelEvent);

View File

@ -40,6 +40,7 @@ typedef struct titledb_info_s {
u32 id;
char category[64];
char headline[512];
char updatedAt[32];
titledb_cia_info cia;
titledb_tdsx_info tdsx;
@ -49,6 +50,10 @@ typedef struct titledb_info_s {
typedef struct populate_titledb_data_s {
linked_list* items;
void* userData;
bool (*filter)(void* data, titledb_info* info);
int (*compare)(void* data, const void* p1, const void* p2);
volatile bool itemsListed;
volatile bool finished;
Result result;

View File

@ -267,15 +267,22 @@ void task_draw_titledb_info(ui_view* view, void* data, float x1, float y1, float
task_draw_meta_info(view, &info->meta, x1, y1, x2, y2);
char updatedDate[32] = "";
char updatedTime[32] = "";
sscanf(info->updatedAt, "%31[^T]T%31[^Z]Z", updatedDate, updatedTime);
char infoText[1024];
snprintf(infoText, sizeof(infoText),
"%s\n"
"\n"
"Category: %s\n"
"Updated At: %s %s\n"
"Update Available: %s",
info->headline,
info->category,
updatedDate, updatedTime,
info->cia.outdated || info->tdsx.outdated ? "Yes" : "No");
float infoWidth;

View File

@ -15,9 +15,19 @@ static list_item install = {"Install", COLOR_TEXT, action_install_titledb};
typedef struct {
populate_titledb_data populateData;
bool showCIAs;
bool show3DSXs;
bool sortByName;
bool sortByUpdate;
bool populated;
} titledb_data;
typedef struct {
titledb_data* parent;
linked_list* items;
} titledb_options_data;
typedef struct {
linked_list* items;
list_item* selected;
@ -174,6 +184,107 @@ static void titledb_entry_open(linked_list* items, list_item* selected) {
list_display("TitleDB Entry", "A: Select, B: Return", data, titledb_entry_update, titledb_entry_draw_top);
}
static int titledb_compare(void* data, const void* p1, const void* p2) {
titledb_data* listData = (titledb_data*) data;
list_item* info1 = (list_item*) p1;
list_item* info2 = (list_item*) p2;
titledb_info* data1 = (titledb_info*) info1->data;
titledb_info* data2 = (titledb_info*) info2->data;
if(listData->sortByName) {
return strncasecmp(info1->name, info2->name, sizeof(info1->name));
} else if(listData->sortByUpdate) {
return strncasecmp(data2->updatedAt, data1->updatedAt, sizeof(data2->updatedAt));
} else {
return 0;
}
}
static void titledb_options_add_entry(linked_list* items, const char* name, bool* val) {
list_item* item = (list_item*) calloc(1, sizeof(list_item));
if(item != NULL) {
snprintf(item->name, LIST_ITEM_NAME_MAX, "%s", name);
item->color = *val ? COLOR_ENABLED : COLOR_DISABLED;
item->data = val;
linked_list_add(items, item);
}
}
static void titledb_options_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
titledb_options_data* optionsData = (titledb_options_data*) data;
titledb_data* listData = optionsData->parent;
if(hidKeysDown() & KEY_B) {
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);
}
ui_pop();
list_destroy(view);
return;
}
if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) {
bool* val = (bool*) selected->data;
*val = !(*val);
if(val == &listData->sortByName || val == &listData->sortByUpdate) {
if(*val) {
if(val == &listData->sortByName) {
listData->sortByUpdate = false;
} else if(val == &listData->sortByUpdate) {
listData->sortByName = false;
}
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);
item->color = *(bool*) item->data ? COLOR_ENABLED : COLOR_DISABLED;
}
} else {
selected->color = *val ? COLOR_ENABLED : COLOR_DISABLED;
}
linked_list_sort(optionsData->items, listData, titledb_compare);
} else {
selected->color = *val ? COLOR_ENABLED : COLOR_DISABLED;
listData->populated = false;
}
}
if(linked_list_size(items) == 0) {
titledb_options_add_entry(items, "Show CIAs", &listData->showCIAs);
titledb_options_add_entry(items, "Show 3DSXs", &listData->show3DSXs);
titledb_options_add_entry(items, "Sort by name", &listData->sortByName);
titledb_options_add_entry(items, "Sort by update date", &listData->sortByUpdate);
}
}
static void titledb_options_open(titledb_data* parent, linked_list* items) {
titledb_options_data* data = (titledb_options_data*) calloc(1, sizeof(titledb_options_data));
if(data == NULL) {
error_display(NULL, NULL, "Failed to allocate TitleDB options data.");
return;
}
data->parent = parent;
data->items = items;
list_display("Options", "A: Toggle, B: Return", data, titledb_options_update, NULL);
}
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;
@ -228,9 +339,16 @@ 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.itemsListed) {
if(hidKeysDown() & KEY_Y) {
action_update_titledb(items, selected);
return;
}
if(hidKeysDown() & KEY_SELECT) {
titledb_options_open(listData, items);
return;
}
}
if(listData->populateData.finished && R_FAILED(listData->populateData.result)) {
@ -247,6 +365,12 @@ static void titledb_update(ui_view* view, void* data, linked_list* items, list_i
}
}
static bool titledb_filter(void* data, titledb_info* info) {
titledb_data* listData = (titledb_data*) data;
return (info->cia.exists && listData->showCIAs) || (info->tdsx.exists && listData->show3DSXs);
}
void titledb_open() {
titledb_data* data = (titledb_data*) calloc(1, sizeof(titledb_data));
if(data == NULL) {
@ -255,7 +379,16 @@ void titledb_open() {
return;
}
data->showCIAs = true;
data->show3DSXs = true;
data->sortByName = true;
data->sortByUpdate = false;
data->populateData.finished = true;
list_display("TitleDB.com", "A: Select, B: Return, X: Refresh, Y: Update All", data, titledb_update, titledb_draw_top);
data->populateData.userData = data;
data->populateData.filter = titledb_filter;
data->populateData.compare = titledb_compare;
list_display("TitleDB.com", "A: Select, B: Return, X: Refresh, Y: Update All, Select: Options", data, titledb_update, titledb_draw_top);
}