fix(ui): keep a chosen send-from address from auto-select overwrite
The Send tab auto-selected the highest-balance address on first load. When another tab had already pre-filled the source with "Send from this address", that first-load pick overwrote the user's choice, and the dropdown's selected index could drift out of step with the address that would actually be debited when the address list changed. - The send-from string is now the single source of truth. The one-shot auto-pick only fills an empty source and never replaces one the user or another tab set, and the list index is re-derived from the string each frame so it cannot desync. - An explicit "Send from this address" choice latches the auto-pick off, so the first visit cannot undo it. - A chosen source the dropdown does not list (zero balance, view-only, or the list still loading) now previews the address that will be debited instead of the "Select a source" placeholder. User-visible: a send-from address chosen from another tab survives the first load and later refresh ticks. Tests: the source resolver keeps a pre-fill on first visit, fills an empty source with the best spendable address, keeps a source missing from a short list with index -1, latches nothing while disconnected or with an empty list, and re-derives a stale index from the string. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,32 @@ int bestSpendableAddressIndex(const std::vector<AddressInfo>& addresses)
|
||||
return bestIndex;
|
||||
}
|
||||
|
||||
int addressIndexByString(const std::vector<AddressInfo>& addresses, const std::string& address)
|
||||
{
|
||||
if (address.empty()) return -1;
|
||||
for (size_t i = 0; i < addresses.size(); ++i) {
|
||||
if (addresses[i].address == address) return static_cast<int>(i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
SourceSelection resolveSourceSelection(const std::vector<AddressInfo>& addresses, const std::string& current,
|
||||
bool autoLatched, bool connected)
|
||||
{
|
||||
SourceSelection r;
|
||||
r.address = current;
|
||||
r.autoLatched = autoLatched;
|
||||
r.index = addressIndexByString(addresses, current);
|
||||
if (!autoLatched && connected && !addresses.empty()) {
|
||||
if (current.empty()) { // only ever fill an empty source
|
||||
const int best = bestSpendableAddressIndex(addresses);
|
||||
if (best >= 0) { r.address = addresses[best].address; r.index = best; }
|
||||
}
|
||||
r.autoLatched = true; // one shot, whether or not it picked
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string TransactionInfo::getTimeString() const
|
||||
{
|
||||
if (timestamp == 0) return "Unknown";
|
||||
|
||||
@@ -42,6 +42,20 @@ struct AddressInfo {
|
||||
std::vector<size_t> sortedSpendableAddressIndices(const std::vector<AddressInfo>& addresses,
|
||||
bool requirePositiveBalance = true);
|
||||
int bestSpendableAddressIndex(const std::vector<AddressInfo>& addresses);
|
||||
// Index of the address whose string equals `address` (exact match), or -1 (empty string / not listed).
|
||||
int addressIndexByString(const std::vector<AddressInfo>& addresses, const std::string& address);
|
||||
|
||||
// The Send tab's source-address resolution, pure. `current` (s_from_address) is the single source of truth:
|
||||
// the one-shot auto-pick (highest confirmed balance) only fills an EMPTY source, and never replaces one the
|
||||
// user - or another tab's "Send from this address" - already set. A source that is not in the list (the list
|
||||
// can be transiently short) is kept as is with index -1; it must NOT trigger a re-pick.
|
||||
struct SourceSelection {
|
||||
std::string address; // what s_from_address must hold afterwards
|
||||
int index = -1; // its row in `addresses`, -1 if not listed
|
||||
bool autoLatched = false; // new value of the one-shot latch
|
||||
};
|
||||
SourceSelection resolveSourceSelection(const std::vector<AddressInfo>& addresses, const std::string& current,
|
||||
bool autoLatched, bool connected);
|
||||
|
||||
/**
|
||||
* @brief Represents a wallet transaction
|
||||
|
||||
Reference in New Issue
Block a user