Build 15: clean the returning-user wallet list of GRIM node chrome

The wallet-list screen (wallets exist, none open) still wore GRIM's
node-first chrome: a yellow INTEGRATED NODE / WALLETS bar and a forced-
open left node column with ENABLE NODE / Autorun / stat tabs. That
fights the payments-first philosophy the open-wallet surface set — the
node is plumbing, chosen in onboarding and managed in settings, not a
console you stare at to reach your wallets.

Now the list is full-bleed dark like the rest of the goblin surface:
- the node panel no longer force-opens on this screen (content.rs);
  it's demoted to a tappable status chip that opens the SAME panel,
  every Enable/Autorun/mining/stat feature intact — just opt-in
- the yellow title bar is suppressed here (wallet_list_screen()), its
  GEAR (app settings) and node access rehomed into a slim goblin header
  (node chip left, gear right) above the GOBLIN logo + wallet rows + "+"

Verified desktop + mobile + panel open/close; unlock still lands on the
unchanged open-wallet surface. 34 lib tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-06-11 13:26:50 -04:00
parent d53345ffdd
commit c72cda3039
2 changed files with 100 additions and 4 deletions
+11 -1
View File
@@ -98,6 +98,16 @@ impl ContentContainer for Content {
// its sidebar, so the network column stays hidden while it shows.
// Same for first-run onboarding, which owns the whole window.
let wallet_open = self.wallets.showing_wallet() || self.wallets.onboarding_active();
// On the returning-user wallet list the node is demoted to a chip:
// the panel opens only when explicitly toggled, never forced open by
// dual-panel mode (otherwise GRIM's node column dominates the list).
let list_screen = self.wallets.wallet_list_screen();
let show_network = !wallet_open
&& if list_screen {
Self::is_network_panel_open()
} else {
is_panel_open
};
// Show network content.
egui::SidePanel::left("network_panel")
@@ -106,7 +116,7 @@ impl ContentContainer for Content {
.frame(egui::Frame {
..Default::default()
})
.show_animated_inside(ui, is_panel_open && !wallet_open, |ui| {
.show_animated_inside(ui, show_network, |ui| {
self.network.ui(ui, cb);
});
+89 -3
View File
@@ -210,9 +210,11 @@ impl ContentContainer for WalletsContent {
|| self.wallets.list().is_empty()
|| (showing_wallet && (!dual_panel || !AppConfig::show_wallets_at_dual_panel()));
// Show title panel, except over the full-bleed Goblin wallet surface
// and onboarding (they have their own header/navigation).
if !showing_wallet && !onboarding_active {
// Show title panel, except over the full-bleed Goblin wallet surface,
// onboarding, and the returning-user wallet list (all carry their own
// header; the yellow GRIM bar is off-brand on those surfaces).
let wallet_list_screen = self.wallet_list_screen();
if !showing_wallet && !onboarding_active && !wallet_list_screen {
self.title_ui(ui, dual_panel, cb);
}
@@ -423,6 +425,17 @@ impl WalletsContent {
self.settings_content.is_some()
}
/// Check if the returning-user wallet list owns the surface (wallets
/// exist, none open, not mid-onboarding/creation/settings). On this
/// screen the node panel is demoted to an opt-in chip, not a column.
pub fn wallet_list_screen(&self) -> bool {
!self.showing_wallet()
&& !self.onboarding_active()
&& !self.showing_settings()
&& !self.creating_wallet()
&& !self.wallets.list().is_empty()
}
/// Handle data from deeplink or opened file.
fn on_data(&mut self, ui: &mut egui::Ui, data: Option<String>, cb: &dyn PlatformCallbacks) {
let wallets_size = self.wallets.list().len();
@@ -561,6 +574,72 @@ impl WalletsContent {
}
}
/// Slim header for the wallet-list surface: a tappable integrated-node
/// status chip (opens the full node panel — every feature intact, just
/// opt-in) on the left, and the app-settings gear on the right.
fn wallet_list_header_ui(&mut self, ui: &mut egui::Ui) {
use crate::node::Node;
ui.add_space(6.0);
ui.horizontal(|ui| {
// Node status chip.
let running = Node::is_running();
let synced = running && Node::not_syncing();
let (dot, label) = if !running {
(Colors::gray(), "Node")
} else if synced {
(Colors::pos(), "Node synced")
} else {
(Colors::gold(), "Syncing…")
};
let galley = ui.painter().layout_no_wrap(
label.to_string(),
eframe::epaint::FontId::proportional(14.0),
Colors::text(false),
);
let pad = egui::Vec2::new(12.0, 7.0);
let chip_w = 10.0 + 8.0 + galley.size().x + pad.x * 2.0;
let (rect, resp) =
ui.allocate_exact_size(egui::Vec2::new(chip_w, 34.0), Sense::click());
ui.painter()
.rect_filled(rect, CornerRadius::same(17), Colors::fill_lite());
let dot_c = egui::pos2(rect.min.x + pad.x + 5.0, rect.center().y);
ui.painter().circle_filled(dot_c, 4.0, dot);
ui.painter().galley(
egui::pos2(dot_c.x + 13.0, rect.center().y - galley.size().y / 2.0),
galley,
Colors::text(false),
);
if resp
.on_hover_cursor(CursorIcon::PointingHand)
.on_hover_text("Node settings")
.clicked()
{
Content::toggle_network_panel();
}
// App-settings gear, right-aligned. Drawn manually (the title-bar
// button uses dark-on-yellow ink, invisible on this dark surface).
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
let (g_rect, g_resp) =
ui.allocate_exact_size(egui::Vec2::splat(34.0), Sense::click());
ui.painter().text(
g_rect.center(),
egui::Align2::CENTER_CENTER,
GEAR,
eframe::epaint::FontId::proportional(20.0),
Colors::text(false),
);
if g_resp
.on_hover_cursor(CursorIcon::PointingHand)
.on_hover_text("Settings")
.clicked()
{
self.settings_content = Some(SettingsContent::default());
}
});
});
}
/// Draw list of wallets.
fn wallet_list_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
ScrollArea::vertical()
@@ -569,6 +648,13 @@ impl WalletsContent {
.auto_shrink([false; 2])
.show(ui, |ui| {
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
// Slim goblin header: node-status chip (opens the node
// panel) on the left, app-settings gear on the right —
// the controls the suppressed yellow title bar used to
// carry, restyled to match the open-wallet surface.
self.wallet_list_header_ui(ui);
ui.add_space(8.0);
// Show application logo and name.
View::app_logo_name_version(ui);
ui.add_space(15.0);