diff --git a/src/ui/windows/market_tab.cpp b/src/ui/windows/market_tab.cpp index 8d70981..5fc134c 100644 --- a/src/ui/windows/market_tab.cpp +++ b/src/ui/windows/market_tab.cpp @@ -349,8 +349,11 @@ static void pfPersist(config::Settings* settings, const std::vectorsettings(); @@ -360,12 +363,34 @@ static void pfCommitIfNeeded(App* app) config::Settings::PortfolioEntry base; if (existing) { base = entries[s_pfEdit.sel]; if (pfWorkingMatches(base)) return; } auto e = pfBuildWorking(base); - if (!existing) e.scope = app->activeWalletIdentityHash(); + if (e.scope.empty()) { + const std::string h = app->activeWalletIdentityHash(); + if (!h.empty()) e.scope = h; + } if (existing) entries[s_pfEdit.sel] = e; else { entries.push_back(e); s_pfEdit.sel = (int)entries.size() - 1; } pfPersist(settings, entries); } +// A group is visible to the active wallet when it carries the wallet's scope, is unscoped (legacy — +// shown everywhere), or the wallet identity isn't resolved yet. The editor mirrors the Market summary's +// scope filter so it only lists/edits the current wallet's groups. +static bool pfIndexVisible(App* app, int i) +{ + const auto& es = app->settings()->getPortfolioEntries(); + if (i < 0 || i >= (int)es.size()) return false; + const std::string h = app->activeWalletIdentityHash(); + return es[i].scope.empty() || h.empty() || es[i].scope == h; +} +static int pfFirstVisibleIndex(App* app) +{ + const auto& es = app->settings()->getPortfolioEntries(); + const std::string h = app->activeWalletIdentityHash(); + for (int i = 0; i < (int)es.size(); i++) + if (es[i].scope.empty() || h.empty() || es[i].scope == h) return i; + return -1; +} + // ---- Detail-pane section renderers (drawn inside ##pfDetailBody; operate on s_pfEdit) ---- // Appearance: accent-color picker (+ custom), outline-opacity slider, icon grid. @@ -759,11 +784,12 @@ static void RenderPortfolioEditor(App* app) } { // Clamp/validate the selection. The in-editor delete already reloads the working state, but if the - // list shrank via any other path, reload after clamping so a later commit can't overlay stale - // fields onto the clamped entry. + // list shrank or the selection landed on a group outside this wallet's scope via any other path, + // reset to the first visible group and reload so a later commit can't overlay stale fields. const auto& entriesRO = settings->getPortfolioEntries(); - if (s_pfEdit.sel >= (int)entriesRO.size()) { - s_pfEdit.sel = entriesRO.empty() ? -1 : 0; + if (s_pfEdit.sel >= (int)entriesRO.size() || + (s_pfEdit.sel >= 0 && !pfIndexVisible(app, s_pfEdit.sel))) { + s_pfEdit.sel = pfFirstVisibleIndex(app); PortfolioBeginEdit(app, s_pfEdit.sel); } } @@ -792,12 +818,20 @@ static void RenderPortfolioEditor(App* app) ImGui::BeginChild("##pfMasterList", ImVec2(masterW, std::max(48.0f, bodyH - addH - Layout::spacingSm())), false); { ImDrawList* mdl = ImGui::GetWindowDrawList(); - if (entries.empty()) + // Only list groups scoped to the active wallet (or legacy/unscoped) — same filter the + // Market summary uses. `i` stays the storage index (selection/delete operate on storage). + const std::string activeHash = app->activeWalletIdentityHash(); + std::vector vis; + for (int i = 0; i < (int)entries.size(); i++) + if (entries[i].scope.empty() || activeHash.empty() || entries[i].scope == activeHash) + vis.push_back(i); + if (vis.empty()) Type().textColored(TypeStyle::Caption, OnSurfaceDisabled(), TR("portfolio_no_entries")); float rowH = 46.0f * dp; float delSlot = 36.0f * dp; // reserved trailing space for the delete icon + margin int clickedSel = -999, delRow = -1; // deferred: don't mutate `entries` mid-loop - for (int i = 0; i < (int)entries.size(); i++) { + for (int vi = 0; vi < (int)vis.size(); vi++) { + int i = vis[vi]; ImGui::PushID(i); const auto& en = entries[i]; bool selRow = (s_pfEdit.sel == i); @@ -1824,8 +1858,9 @@ static void mktDrawPortfolio(const MktCtx& cx) ImGui::SameLine(); material::RightAlignX(mBtnW); if (material::TactileButton(ml, ImVec2(mBtnW, 0))) { - // Open the combined editor selecting the first group (or the empty state if none). - PortfolioBeginEdit(app, app->settings()->getPortfolioEntries().empty() ? -1 : 0); + // Open the editor on the first group visible to this wallet (or the empty state if none) — + // never a raw index 0 that might belong to a different wallet. + PortfolioBeginEdit(app, pfFirstVisibleIndex(app)); s_pfEdit.open = true; } }