refactor(data): make AddressBook an App-owned shared instance
Phase 0a of the Contacts/Chat plan. The address book was a file-scoped singleton (`s_address_book` + `getAddressBook()`) trapped inside address_book_dialog.cpp, reachable only from that TU. Promote it to an App-owned member so the upcoming Contacts tab, the Send contact picker, and a future Chat roster all read one source of truth. - app.h: add `data::AddressBook address_book_;` + `App::addressBook()` accessors, next to the other owned data models. - app.cpp: load it once in App::init() (idempotent; missing file is fine; purely local, no daemon dependency). - address_book_dialog.cpp: delete the singleton + getAddressBook(); read through the App* the dialog already carries (dropping the dead `(void)app;`). show() is static so it can't reach the App — drop its per-open reload (the book is authoritative for the app lifetime and self-saves on mutation). Drop the now-unused <memory> include. No behavior change; groundwork for the Contacts tab. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -454,6 +454,10 @@ bool App::init()
|
|||||||
tryConnect();
|
tryConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate the shared contact store from disk (per-variant addressbook.json).
|
||||||
|
// Idempotent; a missing file is fine (returns true). Purely local — no daemon/RPC dependency.
|
||||||
|
address_book_.load();
|
||||||
|
|
||||||
DEBUG_LOGF("Initialization complete\n");
|
DEBUG_LOGF("Initialization complete\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include "data/transaction_history_cache.h"
|
#include "data/transaction_history_cache.h"
|
||||||
|
#include "data/address_book.h"
|
||||||
#include "data/wallet_state.h"
|
#include "data/wallet_state.h"
|
||||||
#include "rpc/connection.h"
|
#include "rpc/connection.h"
|
||||||
#include "services/network_refresh_service.h"
|
#include "services/network_refresh_service.h"
|
||||||
@@ -175,6 +176,10 @@ public:
|
|||||||
WalletState& state() { return state_; }
|
WalletState& state() { return state_; }
|
||||||
const WalletState& state() const { return state_; }
|
const WalletState& state() const { return state_; }
|
||||||
const WalletState& getWalletState() const { return state_; }
|
const WalletState& getWalletState() const { return state_; }
|
||||||
|
// Shared contact store (Contacts tab / Send picker / future Chat roster). App-owned so
|
||||||
|
// every surface reads one source of truth instead of a per-dialog singleton.
|
||||||
|
data::AddressBook& addressBook() { return address_book_; }
|
||||||
|
const data::AddressBook& addressBook() const { return address_book_; }
|
||||||
|
|
||||||
// Connection state (convenience wrappers)
|
// Connection state (convenience wrappers)
|
||||||
bool isConnected() const { return state_.connected; }
|
bool isConnected() const { return state_.connected; }
|
||||||
@@ -814,6 +819,7 @@ private:
|
|||||||
// PIN vault
|
// PIN vault
|
||||||
std::unique_ptr<util::SecureVault> vault_;
|
std::unique_ptr<util::SecureVault> vault_;
|
||||||
data::TransactionHistoryCache transaction_history_cache_;
|
data::TransactionHistoryCache transaction_history_cache_;
|
||||||
|
data::AddressBook address_book_; // shared contact store; loaded once in init(), self-saves on mutation
|
||||||
std::string pending_transaction_history_cache_passphrase_;
|
std::string pending_transaction_history_cache_passphrase_;
|
||||||
bool transaction_history_cache_loaded_ = false;
|
bool transaction_history_cache_loaded_ = false;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "../material/draw_helpers.h"
|
#include "../material/draw_helpers.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace dragonx {
|
namespace dragonx {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@@ -26,17 +25,6 @@ char AddressBookDialog::s_edit_label[128] = "";
|
|||||||
char AddressBookDialog::s_edit_address[512] = "";
|
char AddressBookDialog::s_edit_address[512] = "";
|
||||||
char AddressBookDialog::s_edit_notes[512] = "";
|
char AddressBookDialog::s_edit_notes[512] = "";
|
||||||
|
|
||||||
// Shared address book instance
|
|
||||||
static std::unique_ptr<data::AddressBook> s_address_book;
|
|
||||||
|
|
||||||
static data::AddressBook& getAddressBook() {
|
|
||||||
if (!s_address_book) {
|
|
||||||
s_address_book = std::make_unique<data::AddressBook>();
|
|
||||||
s_address_book->load();
|
|
||||||
}
|
|
||||||
return *s_address_book;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copyEditField(char* dest, size_t destSize, const std::string& source) {
|
static void copyEditField(char* dest, size_t destSize, const std::string& source) {
|
||||||
if (destSize == 0) return;
|
if (destSize == 0) return;
|
||||||
std::strncpy(dest, source.c_str(), destSize - 1);
|
std::strncpy(dest, source.c_str(), destSize - 1);
|
||||||
@@ -49,9 +37,9 @@ void AddressBookDialog::show()
|
|||||||
s_selected_index = -1;
|
s_selected_index = -1;
|
||||||
s_show_add_dialog = false;
|
s_show_add_dialog = false;
|
||||||
s_show_edit_dialog = false;
|
s_show_edit_dialog = false;
|
||||||
|
// The address book is App-owned and loaded once at startup (App::init); it stays
|
||||||
// Reload address book
|
// authoritative for the app lifetime and self-saves on every mutation, so there is
|
||||||
getAddressBook().load();
|
// nothing to reload here. (show() is static and has no App* to reach it anyway.)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddressBookDialog::isOpen()
|
bool AddressBookDialog::isOpen()
|
||||||
@@ -61,8 +49,6 @@ bool AddressBookDialog::isOpen()
|
|||||||
|
|
||||||
void AddressBookDialog::render(App* app)
|
void AddressBookDialog::render(App* app)
|
||||||
{
|
{
|
||||||
(void)app; // May use for send-to feature later
|
|
||||||
|
|
||||||
if (!s_open) return;
|
if (!s_open) return;
|
||||||
|
|
||||||
auto& S = schema::UI();
|
auto& S = schema::UI();
|
||||||
@@ -137,14 +123,14 @@ void AddressBookDialog::render(App* app)
|
|||||||
};
|
};
|
||||||
data::AddressBookEntry entry(trimAB(s_edit_label), trimAB(s_edit_address), s_edit_notes);
|
data::AddressBookEntry entry(trimAB(s_edit_label), trimAB(s_edit_address), s_edit_notes);
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
if (getAddressBook().updateEntry(s_selected_index, entry)) {
|
if (app->addressBook().updateEntry(s_selected_index, entry)) {
|
||||||
Notifications::instance().success(TR("address_book_updated"));
|
Notifications::instance().success(TR("address_book_updated"));
|
||||||
s_show_edit_dialog = false;
|
s_show_edit_dialog = false;
|
||||||
} else {
|
} else {
|
||||||
Notifications::instance().error(TR("address_book_update_failed"));
|
Notifications::instance().error(TR("address_book_update_failed"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (getAddressBook().addEntry(entry)) {
|
if (app->addressBook().addEntry(entry)) {
|
||||||
Notifications::instance().success(TR("address_book_added"));
|
Notifications::instance().success(TR("address_book_added"));
|
||||||
s_show_add_dialog = false;
|
s_show_add_dialog = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -165,7 +151,7 @@ void AddressBookDialog::render(App* app)
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (material::BeginOverlayDialog(TR("address_book_title"), &s_open, win.width, 0.94f)) {
|
if (material::BeginOverlayDialog(TR("address_book_title"), &s_open, win.width, 0.94f)) {
|
||||||
auto& book = getAddressBook();
|
auto& book = app->addressBook();
|
||||||
|
|
||||||
// Toolbar
|
// Toolbar
|
||||||
if (material::StyledButton(TR("address_book_add_new"), ImVec2(0,0), S.resolveFont(actionBtn.font))) {
|
if (material::StyledButton(TR("address_book_add_new"), ImVec2(0,0), S.resolveFont(actionBtn.font))) {
|
||||||
|
|||||||
Reference in New Issue
Block a user