feat(contacts): revamp edit dialog with live preview + avatar picker

Rebuild the add/edit contact dialog on the portfolio-editor design language:

- A live preview card at the top shows the contact exactly as it renders in the
  list (avatar + name + address), updating as you type and pick an avatar.
- An avatar picker (Badge / Icon / Image segmented control) lets you keep the
  default Z/T type badge, choose a Material wallet icon from a searchable grid,
  or set a custom image. The picker area is fixed-height so the modal doesn't
  jump when switching modes.
- Custom images go through a new in-app ImagePicker (image_picker.h): a
  Material overlay that browses the filesystem starting at the user's Pictures
  folder, shows a thumbnail grid (decoded to raw pixels, box-downscaled to a
  small texture, cached per directory and freed on navigate/close, budgeted a
  few decodes per frame so large folders don't hitch), and returns the chosen
  path. The chosen image is copied into <config>/contact-avatars/ (named by an
  FNV hash of the source path, so re-picking is idempotent) and stored as
  "img:<path>". Like FolderPicker, it takes over the modal surface while open.
- Paste is now available on both add and edit; buttons are content-sized.

Adds three sweep surfaces (contacts-edit-{icon,badge,image}) that open the
dialog on a seeded contact in each avatar mode, plus i18n keys (+ 8-language
translations; reworded two zh/ja strings to stay within the existing CJK
subset, so no font rebuild).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-15 07:10:00 -05:00
parent 2249bc31d5
commit 2d4ba89c00
13 changed files with 809 additions and 25 deletions

View File

@@ -32,6 +32,7 @@
#include "ui/windows/shield_dialog.h"
#include "ui/windows/address_transfer_dialog.h"
#include "ui/windows/key_export_dialog.h"
#include "ui/windows/contacts_tab.h"
#include "ui/pages/settings_page.h"
#include "util/platform.h"
#include "wallet/wallet_capabilities.h"
@@ -408,6 +409,19 @@ void App::buildSweepCatalog()
add("contacts-table", ui::NavPage::Contacts,
[](App& a) { seedSweepContacts(a); if (a.settings()) a.settings()->setContactsViewMode(2); },
[](App& a) { restoreSweepContacts(a); });
// Revamped edit dialog: live preview + avatar picker, one surface per avatar mode.
add("contacts-edit-icon", ui::NavPage::Contacts,
[](App& a) { seedSweepContacts(a); if (a.settings()) a.settings()->setContactsViewMode(1);
ui::ContactsSweepOpenEditDialog(1); },
[](App& a) { ui::ContactsSweepCloseDialog(); restoreSweepContacts(a); });
add("contacts-edit-badge", ui::NavPage::Contacts,
[](App& a) { seedSweepContacts(a); if (a.settings()) a.settings()->setContactsViewMode(1);
ui::ContactsSweepOpenEditDialog(0); },
[](App& a) { ui::ContactsSweepCloseDialog(); restoreSweepContacts(a); });
add("contacts-edit-image", ui::NavPage::Contacts,
[](App& a) { seedSweepContacts(a); if (a.settings()) a.settings()->setContactsViewMode(1);
ui::ContactsSweepOpenEditDialog(2); },
[](App& a) { ui::ContactsSweepCloseDialog(); restoreSweepContacts(a); });
add("modal-about", ui::NavPage::Overview,
[](App& a) { a.show_about_ = true; }, [](App& a) { a.show_about_ = false; });
add("modal-settings", ui::NavPage::Settings,