feat(market): portfolio row-style redesign + per-wallet scope
Replace the drag/resize dashboard grid on the Market tab's portfolio with
three full-width row styles — compact (single-line), detailed (two-line),
and value-hero — cycled with Left/Right arrows like the Overview layouts.
Rows live in an internal scroll region bounded to the portfolio's height
budget, so the section stays put as groups are added.
- pfDrawRow renders each group in the selected style, reusing the icon /
value / DRGX / 24h / sparkline pieces; per-entry field toggles honored.
- portfolio_style setting (0/1/2) persisted; arrow-key switcher + toast.
- Portfolio groups gain a per-wallet scope: new groups default to the
active wallet's identity hash; legacy groups (empty scope) stay visible
in every wallet. Scope filter drives both the height budget and the rows.
- Remove the now-dead grid machinery (mktDrawCard, pfComputeGridLayout,
PfCell, PfGridDrag, MktCardCtx + MktCtx grid fields) — net code drop.
- Full UI sweep: seed demo portfolio groups + wavy price history and add
market-rows-{compact,detailed,featured} surfaces so the styles are
captured per skin (snapshot/restore the real portfolio + market data).
- i18n: portfolio_style_{label,compact,detailed,featured} + 8 langs; CJK
subset rebuilt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "app.h"
|
||||
|
||||
#include "config/settings.h"
|
||||
#include "ui/schema/skin_manager.h"
|
||||
#include "ui/notifications.h"
|
||||
#include "ui/sidebar.h"
|
||||
@@ -23,6 +24,7 @@
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
@@ -31,6 +33,13 @@ namespace dragonx {
|
||||
namespace {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// The real portfolio, snapshotted while demo groups are shown during a full sweep. Settings are
|
||||
// forward-declared in app.h, so this can't live in the app.h SweepStateSnapshot struct.
|
||||
std::vector<config::Settings::PortfolioEntry> g_pfSnapshot;
|
||||
int g_pfStyleSnapshot = 0;
|
||||
bool g_pfSnapshotValid = false;
|
||||
std::vector<double> g_marketHistorySnapshot; // real price history, restored at sweep end
|
||||
|
||||
// Filesystem-safe one-word tab name.
|
||||
const char* sweepPageName(ui::NavPage page)
|
||||
{
|
||||
@@ -93,6 +102,7 @@ void App::installDemoWalletData()
|
||||
s.addresses = state_.addresses; s.z_addresses = state_.z_addresses; s.t_addresses = state_.t_addresses;
|
||||
s.transactions = state_.transactions;
|
||||
s.market_price_usd = state_.market.price_usd;
|
||||
s.market_change_24h = state_.market.change_24h;
|
||||
s.valid = true;
|
||||
|
||||
applyHealthyDemoState();
|
||||
@@ -102,6 +112,18 @@ void App::installDemoWalletData()
|
||||
state_.privateBalance = 12.50000000; state_.transparentBalance = 3.25000000;
|
||||
state_.totalBalance = 15.75000000; state_.unconfirmedBalance = 0.50000000;
|
||||
state_.market.price_usd = 0.01336200;
|
||||
state_.market.change_24h = 5.24000000;
|
||||
// Wavy, gently-rising price history so the row sparklines render (restored at sweep end).
|
||||
g_marketHistorySnapshot = state_.market.price_history;
|
||||
{
|
||||
std::vector<double> hist;
|
||||
for (int i = 0; i < 48; i++) {
|
||||
double t = static_cast<double>(i);
|
||||
hist.push_back(0.01250 + 0.0000180 * t
|
||||
+ 0.00060 * std::sin(t * 0.55) + 0.00025 * std::sin(t * 1.7));
|
||||
}
|
||||
state_.market.price_history = hist;
|
||||
}
|
||||
|
||||
auto zaddr = [](const char* a, double bal, const char* label) {
|
||||
AddressInfo i; i.address = a; i.balance = bal; i.type = "shielded"; i.label = label; return i;
|
||||
@@ -135,6 +157,32 @@ void App::installDemoWalletData()
|
||||
1751290000, 0, "zs1demosecondaryshieldedaddressforuisweep0000000000000000000000000", "pending"),
|
||||
};
|
||||
|
||||
// Demo portfolio groups so the Market tab's row styles render with real-looking data. Snapshot
|
||||
// the user's real portfolio first; setPortfolio* only mutate memory (save() is never called
|
||||
// here), and clearDemoWalletData() restores them at sweep end.
|
||||
if (settings_) {
|
||||
g_pfSnapshot = settings_->getPortfolioEntries();
|
||||
g_pfStyleSnapshot = settings_->getPortfolioStyle();
|
||||
g_pfSnapshotValid = true;
|
||||
auto grp = [](const char* label, const char* icon, uint32_t color, const char* addr,
|
||||
bool drgx, bool value, bool ch, bool spark) {
|
||||
config::Settings::PortfolioEntry e;
|
||||
e.label = label; e.icon = icon; e.color = color; e.outlineOpacity = 30;
|
||||
e.addresses = { addr }; e.priceBasis = 0;
|
||||
e.showDrgx = drgx; e.showValue = value; e.show24h = ch; e.showSparkline = spark;
|
||||
return e;
|
||||
};
|
||||
settings_->setPortfolioEntries({
|
||||
grp("Savings", "savings", 0xFFFF9D4Fu,
|
||||
"zs1demoprimaryshieldedaddressforuisweep000000000000000000000000000", true, true, true, true),
|
||||
grp("Mining rewards", "pickaxe", 0xFF3DB0FFu,
|
||||
"t1DemoTransparentAddressForUiSweep00000", true, true, true, true),
|
||||
grp("Cold storage", "diamond", 0xFFFF7BB0u,
|
||||
"zs1demosecondaryshieldedaddressforuisweep0000000000000000000000000", true, true, false, false),
|
||||
});
|
||||
settings_->setPortfolioStyle(0);
|
||||
}
|
||||
|
||||
seedChatDemoData();
|
||||
}
|
||||
|
||||
@@ -168,7 +216,18 @@ void App::clearDemoWalletData()
|
||||
state_.addresses = s.addresses; state_.z_addresses = s.z_addresses; state_.t_addresses = s.t_addresses;
|
||||
state_.transactions = s.transactions;
|
||||
state_.market.price_usd = s.market_price_usd;
|
||||
state_.market.change_24h = s.market_change_24h;
|
||||
state_.market.price_history = g_marketHistorySnapshot;
|
||||
g_marketHistorySnapshot.clear();
|
||||
s = SweepStateSnapshot{}; // invalidate
|
||||
|
||||
// Restore the user's real portfolio (demo groups were in-memory only).
|
||||
if (g_pfSnapshotValid && settings_) {
|
||||
settings_->setPortfolioEntries(g_pfSnapshot);
|
||||
settings_->setPortfolioStyle(g_pfStyleSnapshot);
|
||||
}
|
||||
g_pfSnapshot.clear();
|
||||
g_pfSnapshotValid = false;
|
||||
}
|
||||
|
||||
// ── Catalog ──────────────────────────────────────────────────────────────────────────────────
|
||||
@@ -326,6 +385,17 @@ void App::buildSweepCatalog()
|
||||
add("popup-send-confirm", ui::NavPage::Send,
|
||||
[](App& a) { ui::SweepShowSendConfirm(&a, true); },
|
||||
[](App& a) { ui::SweepShowSendConfirm(&a, false); });
|
||||
|
||||
// Market portfolio row styles — capture all three so the redesign is reviewable per skin.
|
||||
add("market-rows-compact", ui::NavPage::Market,
|
||||
[](App& a) { if (a.settings_) a.settings_->setPortfolioStyle(0); },
|
||||
[](App& a) { if (a.settings_) a.settings_->setPortfolioStyle(0); });
|
||||
add("market-rows-detailed", ui::NavPage::Market,
|
||||
[](App& a) { if (a.settings_) a.settings_->setPortfolioStyle(1); },
|
||||
[](App& a) { if (a.settings_) a.settings_->setPortfolioStyle(0); });
|
||||
add("market-rows-featured", ui::NavPage::Market,
|
||||
[](App& a) { if (a.settings_) a.settings_->setPortfolioStyle(2); },
|
||||
[](App& a) { if (a.settings_) a.settings_->setPortfolioStyle(0); });
|
||||
}
|
||||
|
||||
// ── State machine ───────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user