From 035bf5c318515406912678716e059b8e8546ce02 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sun, 12 Oct 2025 14:13:32 +0200 Subject: contact search filter --- TODO | 2 -- include/administration.hpp | 9 +++++++-- src/administration.cpp | 22 ++++++++++++++++++---- src/locales/en.cpp | 1 + src/ui/ui_contacts.cpp | 15 +++++++++++++-- 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/TODO b/TODO index b205b9e..349f83d 100644 --- a/TODO +++ b/TODO @@ -12,8 +12,6 @@ TODO: - refactor _add functions to use _import functions - write tests that check error handling for corrupt files. (e.g. references to tax rates, project and cost center that failed to load) - it is possible a referenced tax rate is loaded after an invoice is loaded. This means all invoices need to be recalculated after file load. (try to write a test for this). -- invoice sequential number should be modifyable & checked for uniqueness (for external invoices being imported) -- allow cost centers to be deleted that have 0 references - Send invoice by email - create invoice from image of receipt - create invoice from UBL file diff --git a/include/administration.hpp b/include/administration.hpp index ebb30d0..c046dba 100644 --- a/include/administration.hpp +++ b/include/administration.hpp @@ -96,6 +96,11 @@ typedef struct char bank_account[MAX_LEN_BANK]; } contact; +typedef struct +{ + char name_filter[MAX_LEN_LONG_DESC]; +} contact_filter; + typedef enum { PROJECT_RUNNING, @@ -477,7 +482,7 @@ namespace administration { // Contact functions. // ======================= - u32 contact_count(); + u32 contact_count(contact_filter* filter = 0); contact contact_create_empty(); a_err contact_import(contact data); a_err contact_add(contact data); @@ -490,7 +495,7 @@ namespace administration { a_err contact_get_by_id(contact* buffer, char* id); int contact_get_autocompletions(contact* buffer, int buf_size, char* name); - u32 contact_get_partial_list(u32 page_index, u32 page_size, contact* buffer); + u32 contact_get_partial_list(u32 page_index, u32 page_size, contact* buffer, contact_filter* filter = 0); u32 contact_get_all(contact* buffer); // Project functions. diff --git a/src/administration.cpp b/src/administration.cpp index 6e6cfb4..a6f7187 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -882,9 +882,20 @@ a_err administration::contact_remove(contact data) return A_ERR_NOT_FOUND; } -u32 administration::contact_count() +u32 administration::contact_count(contact_filter* filter) { - return list_size(&g_administration.contacts); + if (!filter) return list_size(&g_administration.contacts); + + u32 count = 0; + list_iterator_start(&g_administration.contacts); + while (list_iterator_hasnext(&g_administration.contacts)) { + contact c = *(contact *)list_iterator_next(&g_administration.contacts); + + if (!strops::contains(c.name, filter->name_filter)) continue; + count++; + } + list_iterator_stop(&g_administration.contacts); + return count; } u32 administration::contact_get_all(contact* buffer) @@ -901,19 +912,22 @@ u32 administration::contact_get_all(contact* buffer) return write_cursor; } -u32 administration::contact_get_partial_list(u32 page_index, u32 page_size, contact* buffer) +u32 administration::contact_get_partial_list(u32 page_index, u32 page_size, contact* buffer, contact_filter* filter) { assert(buffer); u32 write_cursor = 0; u32 read_start = page_index * page_size; + u32 read_cursor = 0; list_iterator_start(&g_administration.contacts); while (list_iterator_hasnext(&g_administration.contacts)) { contact c = *(contact *)list_iterator_next(&g_administration.contacts); - if (g_administration.contacts.iter_pos <= read_start) continue; + if (!strops::contains(c.name, filter->name_filter)) continue; + + if (++read_cursor <= read_start) continue; buffer[write_cursor++] = c; if (write_cursor >= page_size) break; diff --git a/src/locales/en.cpp b/src/locales/en.cpp index 8ab4eaf..20d482e 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -128,6 +128,7 @@ locale_entry en_locales[] = { {"contact.table.identifier", "Identifier"}, {"contact.table.name", "Name"}, {"contact.table.address", "Address"}, + {"contact.table.filter.search", "Search..."}, // Project strings. {"project.form.identifier", "Identifier"}, diff --git a/src/ui/ui_contacts.cpp b/src/ui/ui_contacts.cpp index 30d01de..cc5a7e0 100644 --- a/src/ui/ui_contacts.cpp +++ b/src/ui/ui_contacts.cpp @@ -104,9 +104,14 @@ void draw_contact_form(contact* buffer, bool viewing_only = false) static void draw_contact_list() { + static char search_buffer[MAX_LEN_LONG_DESC]; + + contact_filter filter; + strops::copy(filter.name_filter, search_buffer, MAX_LEN_LONG_DESC); + const u32 items_per_page = 50; static s32 current_page = 0; - s32 max_page = (administration::contact_count() + items_per_page - 1) / items_per_page; + s32 max_page = (administration::contact_count(&filter) + items_per_page - 1) / items_per_page; if (max_page == 0) max_page = 1; // Table header controls: create button and pagination. @@ -136,6 +141,12 @@ static void draw_contact_list() if (ImGui::Button(locale::get("ui.next")) && current_page < max_page-1) current_page++; if (!enable_next) ImGui::EndDisabled(); + // Filters + ImGui::SameLine(); + ImGui::PushItemWidth(200.0f); + ImGui::InputTextWithHint("##searchFilter", locale::get("contact.table.filter.search"), search_buffer, MAX_LEN_LONG_DESC); + ImGui::PopItemWidth(); + ImGui::Spacing(); if (ImGui::BeginTable("TableContacts", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { @@ -147,7 +158,7 @@ static void draw_contact_list() ImGui::TableHeadersRow(); contact contact_list[items_per_page]; - u32 contact_count = administration::contact_get_partial_list(current_page, items_per_page, contact_list); + u32 contact_count = administration::contact_get_partial_list(current_page, items_per_page, contact_list, &filter); for (u32 i = 0; i < contact_count; i++) { contact c = contact_list[i]; -- cgit v1.2.3-70-g09d2