feat: modernize address list with drag-transfer, labels, and UX polish
- Rewrite RenderSharedAddressList with two-pass layout architecture - Add drag-to-transfer: drag address onto another to open transfer dialog - Add AddressLabelDialog with custom label text and 20-icon picker - Add AddressTransferDialog with amount input, fee, and balance preview - Add AddressMeta persistence (label, icon, sortOrder) in settings.json - Gold favorite border inset 2dp from container edge - Show hide button on all addresses, not just zero-balance - Smaller star/hide buttons to clear favorite border - Semi-transparent dragged row with context-aware tooltip - Copy-to-clipboard deferred to mouse-up (no copy on drag) - Themed colors via resolveColor() with CSS variable fallbacks - Keyboard nav (Up/Down/J/K, Enter to copy, F2 to edit label) - Add i18n keys for all new UI strings
This commit is contained in:
@@ -126,6 +126,19 @@ bool Settings::load(const std::string& path)
|
||||
for (const auto& a : j["favorite_addresses"])
|
||||
if (a.is_string()) favorite_addresses_.insert(a.get<std::string>());
|
||||
}
|
||||
if (j.contains("address_meta") && j["address_meta"].is_object()) {
|
||||
address_meta_.clear();
|
||||
for (auto& [addr, meta] : j["address_meta"].items()) {
|
||||
AddressMeta m;
|
||||
if (meta.contains("label") && meta["label"].is_string())
|
||||
m.label = meta["label"].get<std::string>();
|
||||
if (meta.contains("icon") && meta["icon"].is_string())
|
||||
m.icon = meta["icon"].get<std::string>();
|
||||
if (meta.contains("order") && meta["order"].is_number_integer())
|
||||
m.sortOrder = meta["order"].get<int>();
|
||||
address_meta_[addr] = m;
|
||||
}
|
||||
}
|
||||
if (j.contains("wizard_completed")) wizard_completed_ = j["wizard_completed"].get<bool>();
|
||||
if (j.contains("auto_lock_timeout")) auto_lock_timeout_ = j["auto_lock_timeout"].get<int>();
|
||||
if (j.contains("unlock_duration")) unlock_duration_ = j["unlock_duration"].get<int>();
|
||||
@@ -230,6 +243,18 @@ bool Settings::save(const std::string& path)
|
||||
j["favorite_addresses"] = json::array();
|
||||
for (const auto& addr : favorite_addresses_)
|
||||
j["favorite_addresses"].push_back(addr);
|
||||
{
|
||||
json meta_obj = json::object();
|
||||
for (const auto& [addr, m] : address_meta_) {
|
||||
if (m.label.empty() && m.icon.empty() && m.sortOrder < 0) continue;
|
||||
json entry = json::object();
|
||||
if (!m.label.empty()) entry["label"] = m.label;
|
||||
if (!m.icon.empty()) entry["icon"] = m.icon;
|
||||
if (m.sortOrder >= 0) entry["order"] = m.sortOrder;
|
||||
meta_obj[addr] = entry;
|
||||
}
|
||||
j["address_meta"] = meta_obj;
|
||||
}
|
||||
j["wizard_completed"] = wizard_completed_;
|
||||
j["auto_lock_timeout"] = auto_lock_timeout_;
|
||||
j["unlock_duration"] = unlock_duration_;
|
||||
|
||||
Reference in New Issue
Block a user