diff --git a/src/ui/windows/market_tab.cpp b/src/ui/windows/market_tab.cpp index c543dc7..86375c5 100644 --- a/src/ui/windows/market_tab.cpp +++ b/src/ui/windows/market_tab.cpp @@ -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& 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& 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