diff options
| author | Aldrik Ramaekers <aldrik@mailbox.org> | 2026-01-12 16:21:23 +0100 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrik@mailbox.org> | 2026-01-12 16:21:23 +0100 |
| commit | 6d1c29533ab455dabe7e7b4f0dd31d5a11f02048 (patch) | |
| tree | 808791dcf137ca9bfbf24a18fce8138c7ffa5729 | |
| parent | 4a2500299e8fd58f40b545d62dae0282ff20bb01 (diff) | |
refactor project view
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | include/ui.hpp | 1 | ||||
| -rw-r--r-- | src/locales/en.cpp | 3 | ||||
| -rw-r--r-- | src/ui/imgui_extensions.cpp | 16 | ||||
| -rw-r--r-- | src/ui/ui_contacts.cpp | 12 | ||||
| -rw-r--r-- | src/ui/ui_invoices.cpp | 2 | ||||
| -rw-r--r-- | src/ui/ui_projects.cpp | 175 | ||||
| -rw-r--r-- | src/ui/ui_settings.cpp | 6 |
8 files changed, 133 insertions, 83 deletions
@@ -24,7 +24,6 @@ Features: - Button to mark invoice as paid - status window for ongoing requests, used can click on item when result is ready. Should be usefull for batch imports. - implement gemini and perplexity api backends -- Refactor contact and project UI to be like invoice & expenses - Handle invalid api key response from AI backends and display in settings UI - error log for tax report to display invoices not yet supported for tax generation or invoices with invalid tax rates - minimum invoice date for tax report generation, show warnings for unsupported invoices diff --git a/include/ui.hpp b/include/ui.hpp index 6ed2acb..bb8edc0 100644 --- a/include/ui.hpp +++ b/include/ui.hpp @@ -113,6 +113,7 @@ namespace ImGui void InputTextWithErrorHint(const char* hint, char* buffer, size_t buf_size, bool has_error); bool FileSelect(const char* text, char* buffer); + void ProjectForm(project* buffer, bool viewing_only); void ContactForm(contact* buffer, bool viewing_only = false, bool with_autocomplete = false, bool active_countries_only = false); void DeliveryInfoForm(delivery_info* buffer, bool viewing_only = false); void AddressForm(address* buffer, a_err last_err, bool active_countries_only = false); diff --git a/src/locales/en.cpp b/src/locales/en.cpp index bc87b10..48ae24f 100644 --- a/src/locales/en.cpp +++ b/src/locales/en.cpp @@ -60,7 +60,6 @@ locale_entry en_locales[] = { {"form.create", ICON_FA_PLUS_SQUARE" Create"}, {"form.back", ICON_FA_CARET_SQUARE_LEFT" Back"}, {"form.save", ICON_FA_SAVE" Save"}, - {"form.cancel", "Cancel"}, {"form.sending", "Sending"}, {"form.success", "Success"}, {"form.failed", "Failed"}, @@ -69,7 +68,7 @@ locale_entry en_locales[] = { {"form.change", ICON_FA_PEN_SQUARE" Change"}, {"form.view", "View"}, {"form.delete", ICON_FA_TRASH_ALT" Delete"}, - {"form.cancel", "Cancel"}, + {"form.cancel", ICON_FA_BAN" Cancel"}, {"form.confirmDelete", "Are you sure you want to delete this item?"}, {"form.confirmCancelProject", "Are you sure you want to cancel this Project?"}, {"form.required", "required"}, diff --git a/src/ui/imgui_extensions.cpp b/src/ui/imgui_extensions.cpp index dee36a7..9ce5bf9 100644 --- a/src/ui/imgui_extensions.cpp +++ b/src/ui/imgui_extensions.cpp @@ -472,6 +472,22 @@ namespace ImGui } } + void ProjectForm(project* buffer, bool viewing_only) + { + float widthAvailable = ImGui::GetContentRegionAvail().x; + ImGui::BeginDisabled(); + + a_err last_err = administration::project_is_valid(*buffer); + + ImGui::SetNextItemWidth(widthAvailable*0.5f); + ImGui::InputText(locale::get("project.form.identifier"), buffer->id, IM_ARRAYSIZE(buffer->id)); + if (!viewing_only) ImGui::EndDisabled(); + + ImGui::InputTextWithErrorHint(locale::get("project.form.description"), buffer->description, IM_ARRAYSIZE(buffer->description), last_err & A_ERR_MISSING_DESCRIPTION); + + if (viewing_only) ImGui::EndDisabled(); + } + void ContactForm(contact* buffer, bool viewing_only, bool with_autocomplete, bool active_countries_only) { a_err last_err = administration::contact_is_valid(*buffer); diff --git a/src/ui/ui_contacts.cpp b/src/ui/ui_contacts.cpp index b41180e..7b8c21c 100644 --- a/src/ui/ui_contacts.cpp +++ b/src/ui/ui_contacts.cpp @@ -155,6 +155,10 @@ static void draw_contacts_create() } if (!can_save) ImGui::EndDisabled(); + ImGui::Spacing(); + ImGui::Separator(1.0f); + ImGui::Spacing(); + ImGui::ContactForm(&active_contact, false, false); } @@ -182,6 +186,10 @@ static void draw_contacts_update() ImGui::OpenPopup("ConfirmDeletePopup"); } + ImGui::Spacing(); + ImGui::Separator(1.0f); + ImGui::Spacing(); + ImGui::ContactForm(&active_contact, false, false); // Confirmation popup before contact is deleted permanently. @@ -211,6 +219,10 @@ static void draw_contact_view() if (ImGui::Button(locale::get("form.change"))) { current_view_state = ui::view_state::EDIT_EXISTING; } + + ImGui::Spacing(); + ImGui::Separator(1.0f); + ImGui::Spacing(); ImGui::ContactForm(&active_contact, true, false); } diff --git a/src/ui/ui_invoices.cpp b/src/ui/ui_invoices.cpp index 16dcc52..70db412 100644 --- a/src/ui/ui_invoices.cpp +++ b/src/ui/ui_invoices.cpp @@ -324,7 +324,7 @@ static void draw_invoices_list() if (ImGui::BeginTable("TableInvoices", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn(locale::get("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 130); + ImGui::TableSetupColumn(locale::get("invoice.table.invoicenumber"), ImGuiTableColumnFlags_WidthFixed, 120); ImGui::TableSetupColumn(locale::get("invoice.table.customer")); ImGui::TableSetupColumn(locale::get("invoice.table.addressee")); ImGui::TableSetupColumn(locale::get("invoice.table.issuedat"), ImGuiTableColumnFlags_WidthFixed, 90); diff --git a/src/ui/ui_projects.cpp b/src/ui/ui_projects.cpp index a43cd9b..55125de 100644 --- a/src/ui/ui_projects.cpp +++ b/src/ui/ui_projects.cpp @@ -38,51 +38,93 @@ void ui::setup_projects() _reset_to_default_view(); } -static void draw_project_form() +static void draw_project_create() { - float widthAvailable = ImGui::GetContentRegionAvail().x; - bool viewing_only = (current_view_state == ui::view_state::VIEW_EXISTING); - if (ImGui::Button(locale::get("form.back"), true, false)) { _reset_to_default_view(); - return; } - ImGui::Spacing(); - ImGui::BeginDisabled(); - - a_err last_err = administration::project_is_valid(active_project); - - ImGui::SetNextItemWidth(widthAvailable*0.2f); - ImGui::InputText(locale::get("project.form.identifier"), active_project.id, IM_ARRAYSIZE(active_project.id)); - if (!viewing_only) ImGui::EndDisabled(); + + ImGui::SameLine(); - ImGui::InputTextWithErrorHint(locale::get("project.form.description"), active_project.description, IM_ARRAYSIZE(active_project.description), last_err & A_ERR_MISSING_DESCRIPTION); + bool can_save = administration::project_is_valid(active_project) == A_ERR_SUCCESS; + if (!can_save) ImGui::BeginDisabled(); + if (ImGui::Button(locale::get("form.save"), true)) { + administration_writer::set_write_completed_event_callback(0); + administration::project_add(active_project); + current_view_state = ui::view_state::EDIT_EXISTING; + } + if (!can_save) ImGui::EndDisabled(); - if (viewing_only) ImGui::EndDisabled(); + ImGui::Spacing(); + ImGui::Separator(1.0f); + ImGui::Spacing(); - if (!viewing_only) { - bool can_save = administration::project_is_valid(active_project) == A_ERR_SUCCESS; + ImGui::ProjectForm(&active_project, false); +} - if (!can_save) ImGui::BeginDisabled(); - // Save button - ImGui::Spacing(); - if (ImGui::Button(locale::get("form.save"), true)) { +static void draw_project_update() +{ + if (ImGui::Button(locale::get("form.back"), true, false)) { + current_view_state = ui::view_state::VIEW_EXISTING; + } - administration_writer::set_write_completed_event_callback(_reset_to_default_view); + ImGui::SameLine(); + + bool can_save = administration::project_is_valid(active_project) == A_ERR_SUCCESS; + if (!can_save) ImGui::BeginDisabled(); + if (ImGui::Button(locale::get("form.save"), true)) { + administration_writer::set_write_completed_event_callback(0); + administration::project_update(active_project); + } + if (!can_save) ImGui::EndDisabled(); - if (current_view_state == ui::view_state::CREATE) { - administration::project_add(active_project); - } + if (active_project.state == project_state::PROJECT_RUNNING) + { + ImGui::SameLine(); + if (ImGui::Button(locale::get("form.cancel"))) { + selected_for_cancellation = active_project; + ImGui::OpenPopup("ConfirmCancelProject"); + } + } - else if (current_view_state == ui::view_state::EDIT_EXISTING) { - administration::project_update(active_project); - } + if (ImGui::BeginPopupModal("ConfirmCancelProject", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { + ImGui::Text(locale::get("form.confirmCancelProject")); + ImGui::Separator(); + + if (ImGui::Button(locale::get("form.yes"), ImVec2(120, 0))) { + administration::project_cancel(selected_for_cancellation); + ImGui::CloseCurrentPopup(); + _reset_to_default_view(); } - if (!can_save) ImGui::EndDisabled(); + ImGui::SameLine(); + if (ImGui::Button(locale::get("form.no"), ImVec2(120, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + ImGui::Spacing(); + ImGui::Separator(1.0f); + ImGui::Spacing(); + + ImGui::ProjectForm(&active_project, false); +} + +static void draw_project_view() +{ + if (ImGui::Button(locale::get("form.back"), true, false)) { + _reset_to_default_view(); } - else { - // TODO list invoices connected to project. + ImGui::SameLine(); + if (ImGui::Button(locale::get("form.change"))) { + current_view_state = ui::view_state::EDIT_EXISTING; } + + ImGui::Spacing(); + ImGui::Separator(1.0f); + ImGui::Spacing(); + + ImGui::ProjectForm(&active_project, true); } static void draw_project_list() @@ -120,22 +162,38 @@ static void draw_project_list() ImGui::Spacing(); - if (ImGui::BeginTable("TableProjects", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + if (ImGui::BeginTable("TableProjects", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { ImGui::TableSetupColumn(locale::get("project.table.identifier"), ImGuiTableColumnFlags_WidthFixed, 80); ImGui::TableSetupColumn(locale::get("project.table.status"), ImGuiTableColumnFlags_WidthFixed, 140); ImGui::TableSetupColumn(locale::get("project.table.description"), ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 175); + ImGui::PushFont(ui::fontBold); ImGui::TableHeadersRow(); + ImGui::PopFont(); project project_list[items_per_page]; u32 project_count = administration::project_get_partial_list(current_page, items_per_page, project_list); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); for (u32 i = 0; i < project_count; i++) { project c = project_list[i]; ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text(c.id); + ImGui::TableSetColumnIndex(0); + + ImGui::PushID(i); + ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap; + bool selected = false; + if (ImGui::Selectable("##invisible_selectable", selected, selectable_flags, ImVec2(0, ImGui::GetFrameHeight()+2.0f))) + { + active_project = c; + current_view_state = ui::view_state::VIEW_EXISTING; + } + ImGui::SetItemAllowOverlap(); + ImGui::SameLine(); + ImGui::PopID(); + + ImGui::Text(c.id); if (administration::project_is_valid(c) != A_ERR_SUCCESS) { @@ -146,49 +204,8 @@ static void draw_project_list() ImGui::TableSetColumnIndex(1); ImGui::Text(locale::get(administration::project_get_status_string(c))); ImGui::TableSetColumnIndex(2); ImGui::Text(c.description); - - ImGui::TableSetColumnIndex(3); - - char btn_name[20]; - strops::format(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.view"), i); - if (ImGui::Button(btn_name)) { - active_project = c; - current_view_state = ui::view_state::VIEW_EXISTING; - } - - if (c.state == project_state::PROJECT_RUNNING) - { - ImGui::SameLine(); - strops::format(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.change"), i); - if (ImGui::Button(btn_name)) { - active_project = c; - current_view_state = ui::view_state::EDIT_EXISTING; - } - - ImGui::SameLine(); - strops::format(btn_name, sizeof(btn_name), "%s##%d", locale::get("form.cancel"), i); - if (ImGui::Button(btn_name)) { - selected_for_cancellation = c; - ImGui::OpenPopup("ConfirmCancelProject"); - } - } } - - if (ImGui::BeginPopupModal("ConfirmCancelProject", nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar)) { - ImGui::Text(locale::get("form.confirmCancelProject")); - ImGui::Separator(); - - if (ImGui::Button(locale::get("form.yes"), ImVec2(120, 0))) { - administration::project_cancel(selected_for_cancellation); - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button(locale::get("form.no"), ImVec2(120, 0))) { - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); - } - + ImGui::PopStyleVar(); ImGui::EndTable(); } } @@ -198,9 +215,9 @@ void ui::draw_projects() switch(current_view_state) { case ui::view_state::LIST_ALL: draw_project_list(); break; - case ui::view_state::CREATE: draw_project_form(); break; - case ui::view_state::EDIT_EXISTING: draw_project_form(); break; - case ui::view_state::VIEW_EXISTING: draw_project_form(); break; + case ui::view_state::CREATE: draw_project_create(); break; + case ui::view_state::EDIT_EXISTING: draw_project_update(); break; + case ui::view_state::VIEW_EXISTING: draw_project_view(); break; default: break; } diff --git a/src/ui/ui_settings.cpp b/src/ui/ui_settings.cpp index ab3664a..4644001 100644 --- a/src/ui/ui_settings.cpp +++ b/src/ui/ui_settings.cpp @@ -93,7 +93,9 @@ static void draw_vat_rates() ImGui::TableSetupColumn(locale::get("settings.vat.table.outgoing"), ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn(locale::get("settings.vat.table.rates"), ImGuiTableColumnFlags_WidthFixed, 120); ImGui::TableSetupColumn(locale::get("settings.vat.table.section"), ImGuiTableColumnFlags_WidthFixed, 200); + ImGui::PushFont(ui::fontBold); ImGui::TableHeadersRow(); + ImGui::PopFont(); for (u32 i = 0; i < tax_rate_count; i++) { tax_rate c = tax_rates[i]; @@ -160,7 +162,9 @@ static void draw_cost_centers() ImGui::TableSetupColumn(locale::get("settings.costcenters.table.code"), ImGuiTableColumnFlags_WidthFixed, 140); ImGui::TableSetupColumn(locale::get("settings.costcenters.table.description")); + ImGui::PushFont(ui::fontBold); ImGui::TableHeadersRow(); + ImGui::PopFont(); for (u32 i = 0; i < cost_center_count; i++) { cost_center c = cost_centers[i]; @@ -466,11 +470,13 @@ void ui::draw_settings() draw_vat_rates(); ImGui::EndTabItem(); } + if (ImGui::BeginTabItem(locale::get("settings.table.costcenters"))) { draw_cost_centers(); ImGui::EndTabItem(); } + if (ImGui::BeginTabItem(locale::get("settings.table.services"))) { draw_services(); |
