refactor(market): lift portfolio-editor lambdas to file-static functions

Convert the four [&]-capturing lambdas (persist / buildWorking / workingMatches /
commitIfNeeded) into file-static pfPersist / pfBuildWorking / pfWorkingMatches /
pfCommitIfNeeded that operate on the s_pfEdit struct + take Settings*. Removes
the per-frame closure setup and lets the upcoming section helpers reuse them.
No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-04 00:13:42 -05:00
parent b8cfc1c79c
commit 88f1415bcc

View File

@@ -386,6 +386,51 @@ static void PortfolioBeginEdit(App* app, int index)
s_pfEdit.fundedOnly = false;
}
// ---- Portfolio-editor persistence helpers (operate on the s_pfEdit working state) ----
// Build a PortfolioEntry from the working set, preserving off-form fields (grid geometry) from base.
static config::Settings::PortfolioEntry pfBuildWorking(const config::Settings::PortfolioEntry& base)
{
config::Settings::PortfolioEntry e = base;
e.label = s_pfEdit.label; e.addresses = s_pfEdit.addrs; e.icon = s_pfEdit.icon;
e.color = s_pfEdit.color; e.outlineOpacity = s_pfEdit.outlineOpacity;
e.priceBasis = s_pfEdit.priceBasis; e.manualPrice = s_pfEdit.manualPrice; e.manualCurrency = s_pfEdit.manualCcy;
e.showDrgx = s_pfEdit.showDrgx; e.showValue = s_pfEdit.showValue; e.show24h = s_pfEdit.show24h;
e.showSparkline = s_pfEdit.showSparkline; e.sparklineInterval = s_pfEdit.sparkInterval;
return e;
}
// True when the working set matches a stored entry (i.e. there are no uncommitted edits).
static bool pfWorkingMatches(const config::Settings::PortfolioEntry& e)
{
return e.label == std::string(s_pfEdit.label) && e.addresses == s_pfEdit.addrs && e.icon == s_pfEdit.icon
&& e.color == s_pfEdit.color && e.outlineOpacity == s_pfEdit.outlineOpacity
&& e.priceBasis == s_pfEdit.priceBasis && e.manualPrice == s_pfEdit.manualPrice
&& e.manualCurrency == std::string(s_pfEdit.manualCcy)
&& e.showDrgx == s_pfEdit.showDrgx && e.showValue == s_pfEdit.showValue && e.show24h == s_pfEdit.show24h
&& e.showSparkline == s_pfEdit.showSparkline && e.sparklineInterval == s_pfEdit.sparkInterval;
}
static void pfPersist(config::Settings* settings, const std::vector<config::Settings::PortfolioEntry>& entries)
{
settings->setPortfolioEntries(entries);
settings->save();
}
// Persist the working group when it is named and actually changed; unnamed drafts are dropped.
static void pfCommitIfNeeded(config::Settings* settings)
{
if (s_pfEdit.label[0] == '\0') return;
auto entries = settings->getPortfolioEntries();
bool existing = (s_pfEdit.sel >= 0 && s_pfEdit.sel < (int)entries.size());
config::Settings::PortfolioEntry base;
if (existing) { base = entries[s_pfEdit.sel]; if (pfWorkingMatches(base)) return; }
auto e = pfBuildWorking(base);
if (existing) entries[s_pfEdit.sel] = e;
else { entries.push_back(e); s_pfEdit.sel = (int)entries.size() - 1; }
pfPersist(settings, entries);
}
// The "Manage portfolio" modal: list/add/edit/delete entries, each a label tied to a group
// of wallet addresses. Persists to Settings on every mutation (like the address book).
static void RenderPortfolioEditor(App* app)
@@ -401,40 +446,7 @@ static void RenderPortfolioEditor(App* app)
ImFont* iconFont = Type().iconSmall();
float iconFsz = iconFont->LegacySize;
auto persist = [&](const std::vector<config::Settings::PortfolioEntry>& entries) {
settings->setPortfolioEntries(entries);
settings->save();
};
// Build a PortfolioEntry from the working set, preserving off-form fields (grid geometry) from base.
auto buildWorking = [&](const config::Settings::PortfolioEntry& base) {
config::Settings::PortfolioEntry e = base;
e.label = s_pfEdit.label; e.addresses = s_pfEdit.addrs; e.icon = s_pfEdit.icon;
e.color = s_pfEdit.color; e.outlineOpacity = s_pfEdit.outlineOpacity;
e.priceBasis = s_pfEdit.priceBasis; e.manualPrice = s_pfEdit.manualPrice; e.manualCurrency = s_pfEdit.manualCcy;
e.showDrgx = s_pfEdit.showDrgx; e.showValue = s_pfEdit.showValue; e.show24h = s_pfEdit.show24h;
e.showSparkline = s_pfEdit.showSparkline; e.sparklineInterval = s_pfEdit.sparkInterval;
return e;
};
auto workingMatches = [&](const config::Settings::PortfolioEntry& e) {
return e.label == std::string(s_pfEdit.label) && e.addresses == s_pfEdit.addrs && e.icon == s_pfEdit.icon
&& e.color == s_pfEdit.color && e.outlineOpacity == s_pfEdit.outlineOpacity
&& e.priceBasis == s_pfEdit.priceBasis && e.manualPrice == s_pfEdit.manualPrice
&& e.manualCurrency == std::string(s_pfEdit.manualCcy)
&& e.showDrgx == s_pfEdit.showDrgx && e.showValue == s_pfEdit.showValue && e.show24h == s_pfEdit.show24h
&& e.showSparkline == s_pfEdit.showSparkline && e.sparklineInterval == s_pfEdit.sparkInterval;
};
// Persist the working group when it is named and actually changed; unnamed drafts are dropped.
auto commitIfNeeded = [&]() {
if (s_pfEdit.label[0] == '\0') return;
auto entries = settings->getPortfolioEntries();
bool existing = (s_pfEdit.sel >= 0 && s_pfEdit.sel < (int)entries.size());
config::Settings::PortfolioEntry base;
if (existing) { base = entries[s_pfEdit.sel]; if (workingMatches(base)) return; }
auto e = buildWorking(base);
if (existing) entries[s_pfEdit.sel] = e;
else { entries.push_back(e); s_pfEdit.sel = (int)entries.size() - 1; }
persist(entries);
};
// Persistence helpers are file-static (pfBuildWorking / pfWorkingMatches / pfCommitIfNeeded).
// ---------------- Full-window overlay frame ----------------
material::MarkOverlayDialogActive();
@@ -526,7 +538,7 @@ static void RenderPortfolioEditor(App* app)
bool selDirty = false;
{
const auto& es = settings->getPortfolioEntries();
if (s_pfEdit.sel >= 0 && s_pfEdit.sel < (int)es.size()) selDirty = !workingMatches(es[s_pfEdit.sel]);
if (s_pfEdit.sel >= 0 && s_pfEdit.sel < (int)es.size()) selDirty = !pfWorkingMatches(es[s_pfEdit.sel]);
}
// ================= MASTER: scrollable group list + a pinned Add button below it =================
@@ -601,7 +613,7 @@ static void RenderPortfolioEditor(App* app)
auto es = settings->getPortfolioEntries();
if (delRow < (int)es.size()) {
es.erase(es.begin() + delRow);
persist(es);
pfPersist(settings, es);
if (es.empty()) s_pfEdit.sel = -1;
else if (delRow < s_pfEdit.sel) s_pfEdit.sel -= 1;
else if (delRow == s_pfEdit.sel) s_pfEdit.sel = std::min(delRow, (int)es.size() - 1);
@@ -620,7 +632,7 @@ static void RenderPortfolioEditor(App* app)
config::Settings::PortfolioEntry ne;
ne.label = TR("portfolio_untitled");
es.push_back(ne);
persist(es);
pfPersist(settings, es);
s_pfEdit.sel = (int)es.size() - 1;
PortfolioBeginEdit(app, s_pfEdit.sel);
}
@@ -1077,7 +1089,7 @@ static void RenderPortfolioEditor(App* app)
PortfolioBeginEdit(app, s_pfEdit.sel); // reload the working set from the stored entry
ImGui::SameLine(0, sp);
ImGui::BeginDisabled(s_pfEdit.label[0] == '\0');
if (ImGui::Button(TR("portfolio_save"), ImVec2(bw, addH))) commitIfNeeded();
if (ImGui::Button(TR("portfolio_save"), ImVec2(bw, addH))) pfCommitIfNeeded(settings);
ImGui::EndDisabled();
ImGui::EndDisabled();
}
@@ -1088,7 +1100,7 @@ static void RenderPortfolioEditor(App* app)
{
float bh = 40.0f * dp, bw = 120.0f * dp;
pfRightAlignX(bw);
if (ImGui::Button(TR("portfolio_close"), ImVec2(bw, bh))) { commitIfNeeded(); s_pfEdit.open = false; }
if (ImGui::Button(TR("portfolio_close"), ImVec2(bw, bh))) { pfCommitIfNeeded(settings); s_pfEdit.open = false; }
}
ImGui::EndChild(); // ##pfCard