mirror of
https://gitlab.com/Theopse/fbi-i18n-zh.git
synced 2025-06-11 09:39:16 +08:00
Add sorting and filtering options to TitleDB list.
This commit is contained in:
parent
faf0c7d878
commit
599c631b11
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user