fix(overview): mining addresses visible at 0 balance; drag-reorder always applies
- Address list: a mining-flagged address stays visible even at 0 balance when "hide zero balances" is on (payout addresses shouldn't vanish). - Drag-reorder: persist dense sort orders (0..N-1) for the whole visible list on drop via App::reorderAddresses, instead of a pairwise swap that no-ops when both rows are still at the default un-ordered state. First drag now always takes effect, and explicit order keeps overriding the starred/type/balance sort. - Tests: 0-balance mining row survives hide-zero; ordered non-favorite outranks a favorite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -252,6 +252,10 @@ public:
|
||||
void setAddressSortOrder(const std::string& addr, int order);
|
||||
int getNextSortOrder() const;
|
||||
void swapAddressOrder(const std::string& a, const std::string& b);
|
||||
// Assign dense sort orders (0..N-1) to the given addresses in the given order and
|
||||
// persist once. Used by drag-reorder so a drop always takes effect (even from the
|
||||
// default un-ordered state, where a pairwise swap would be a no-op).
|
||||
void reorderAddresses(const std::vector<std::string>& orderedAddrs);
|
||||
bool isMiningAddress(const std::string& addr) const;
|
||||
void setMiningAddress(const std::string& addr, bool mining);
|
||||
void invalidateAddressValidationCache();
|
||||
|
||||
@@ -2094,6 +2094,14 @@ void App::swapAddressOrder(const std::string& a, const std::string& b)
|
||||
}
|
||||
}
|
||||
|
||||
void App::reorderAddresses(const std::vector<std::string>& orderedAddrs)
|
||||
{
|
||||
if (!settings_) return;
|
||||
for (size_t i = 0; i < orderedAddrs.size(); ++i)
|
||||
settings_->setAddressSortOrder(orderedAddrs[i], static_cast<int>(i));
|
||||
settings_->save();
|
||||
}
|
||||
|
||||
bool App::isMiningAddress(const std::string& addr) const
|
||||
{
|
||||
return settings_ && settings_->isMiningAddress(addr);
|
||||
|
||||
@@ -41,7 +41,8 @@ std::vector<AddressListRow> BuildAddressListRows(const std::vector<AddressListIn
|
||||
if (!input.info) continue;
|
||||
if (!AddressListMatchesFilter(input, filter)) continue;
|
||||
if (input.hidden && !showHidden) continue;
|
||||
if (hideZeroBalances && input.info->balance < 1e-9 && !input.hidden && !input.favorite) continue;
|
||||
// Keep mining-flagged addresses visible even at 0 balance (they receive payouts).
|
||||
if (hideZeroBalances && input.info->balance < 1e-9 && !input.hidden && !input.favorite && !input.mining) continue;
|
||||
rows.push_back({input.info, input.isZ, input.hidden, input.favorite, input.mining,
|
||||
input.label, input.icon, input.sortOrder});
|
||||
}
|
||||
|
||||
@@ -343,12 +343,20 @@ void RenderSharedAddressList(App* app, float listH, float availW,
|
||||
for (int i = 0; i < (int)rows.size(); ++i) {
|
||||
if (mousePos.y > rowY[i] + rowH * 0.5f) insertIdx = i + 1;
|
||||
}
|
||||
if (insertIdx != s_dragIdx && insertIdx != s_dragIdx + 1) {
|
||||
int targetIdx = (insertIdx > s_dragIdx) ? insertIdx - 1 : insertIdx;
|
||||
if (targetIdx >= 0 && targetIdx < (int)rows.size() && s_dragIdx < (int)rows.size()) {
|
||||
app->swapAddressOrder(rows[s_dragIdx].info->address,
|
||||
rows[targetIdx].info->address);
|
||||
}
|
||||
if (insertIdx != s_dragIdx && insertIdx != s_dragIdx + 1 &&
|
||||
s_dragIdx < (int)rows.size()) {
|
||||
// Build the new visible order (move the dragged row to insertIdx) and
|
||||
// persist dense sort orders 0..N-1 in one shot. This works even when the
|
||||
// rows were still at the default order (a pairwise swap would no-op).
|
||||
std::vector<std::string> newOrder;
|
||||
newOrder.reserve(rows.size());
|
||||
for (int i = 0; i < (int)rows.size(); ++i)
|
||||
if (i != s_dragIdx) newOrder.push_back(rows[i].info->address);
|
||||
int clamped = std::min(insertIdx, (int)rows.size());
|
||||
int destIdx = (insertIdx > s_dragIdx) ? clamped - 1 : clamped;
|
||||
destIdx = std::max(0, std::min(destIdx, (int)newOrder.size()));
|
||||
newOrder.insert(newOrder.begin() + destIdx, rows[s_dragIdx].info->address);
|
||||
app->reorderAddresses(newOrder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2491,6 +2491,27 @@ void testBalanceAddressListModel()
|
||||
EXPECT_EQ(rows.size(), static_cast<size_t>(1));
|
||||
EXPECT_EQ(rows[0].info->address, std::string("zs-high"));
|
||||
|
||||
// Mining-flagged addresses stay visible at 0 balance even with hide-zero on.
|
||||
dragonx::AddressInfo tMine;
|
||||
tMine.address = "R-miner"; tMine.label = "Payout"; tMine.balance = 0.0; tMine.type = "transparent";
|
||||
std::vector<dragonx::ui::AddressListInput> mineInputs = {
|
||||
{&addresses[0], true, false, false, false, "Vault", "", -1}, // funded
|
||||
{&tMine, false, false, false, /*mining=*/true, "Payout", "", -1}, // 0-balance mining
|
||||
};
|
||||
auto mineRows = dragonx::ui::BuildAddressListRows(mineInputs, "", /*hideZero=*/true, false);
|
||||
EXPECT_EQ(mineRows.size(), static_cast<size_t>(2));
|
||||
bool sawMiner = false;
|
||||
for (const auto& r : mineRows) if (r.info->address == std::string("R-miner")) sawMiner = true;
|
||||
EXPECT_TRUE(sawMiner);
|
||||
|
||||
// Explicit sort order overrides starred: a non-favorite ordered row outranks a favorite.
|
||||
std::vector<dragonx::ui::AddressListInput> ordInputs = {
|
||||
{&addresses[0], true, false, false, false, "Vault", "", 0}, // ordered (0)
|
||||
{&addresses[2], false, false, true, false, "Favorite", "", -1}, // favorite, unordered
|
||||
};
|
||||
auto ordRows = dragonx::ui::BuildAddressListRows(ordInputs, "", false, false);
|
||||
EXPECT_EQ(ordRows[0].info->address, std::string("zs-high"));
|
||||
|
||||
auto layout = dragonx::ui::ComputeAddressRowLayout(10.0f, 20.0f, 300.0f, 50.0f,
|
||||
12.0f, 16.0f, 6.0f, 4.0f, 2.0f);
|
||||
EXPECT_NEAR(layout.contentStartX, 22.0, 0.0001);
|
||||
|
||||
Reference in New Issue
Block a user