1
0
forked from GRIN/grim

goblin: add-identity sheet gets real Generate/Import buttons, Cancel beneath (Build 150)

This commit is contained in:
2ro
2026-07-06 03:27:56 -04:00
parent 355e606da7
commit c5ee854805
7 changed files with 102 additions and 86 deletions
+90 -68
View File
@@ -5432,40 +5432,96 @@ impl GoblinWalletView {
});
}
ui.add_space(10.0);
// ONE mode toggle instead of the old Generate/Import pair (whose
// "Generate new" half was the already-active default and read as
// a dead button). Tapping switches the sheet's mode, revealing or
// hiding the import inputs; the label always names the OTHER mode.
let toggle_label = if self.identity_switch.import {
t!("goblin.identities.generate_instead")
} else {
t!("goblin.identities.import_instead")
};
if w::big_action_on_card(ui, &toggle_label).clicked() {
self.identity_switch.import = !self.identity_switch.import;
self.identity_switch.error.clear();
}
ui.add_space(10.0);
let import = self.identity_switch.import;
// Generate is always ready; import needs either a selected
// .backup or a pasted nsec. The password is entered in the modal.
let busy = self.identity_switch.busy;
// Two real actions instead of a mode toggle: Generate is always
// ready; Import first reveals the .backup/nsec inputs, then
// confirms once one of them is filled. The password is entered
// in the modal.
let has_import = !self.identity_switch.backup_input.trim().is_empty()
|| self.identity_switch.nsec.trim().starts_with("nsec1");
let armed = (!import || has_import) && !self.identity_switch.busy;
let import_armed = (!import || has_import) && !busy;
// The password-gated add to launch this frame: `Some(None)` for
// a fresh key, `Some(Some(blob))` for an import.
let mut open_add: Option<Option<String>> = None;
ui.horizontal(|ui| {
let half = (ui.available_width() - 10.0) / 2.0;
// Generate on the LEFT, the positive (green) action: a
// fresh anonymous key via the existing password step.
ui.scope_builder(
egui::UiBuilder::new().max_rect(egui::Rect::from_min_size(
ui.cursor().min,
Vec2::new(half, 44.0),
)),
|ui| {
ui.add_enabled_ui(!busy, |ui| {
if w::big_action_on_card_ink(
ui,
&t!("goblin.identities.generate"),
if busy { t.surface_text_mute } else { t.pos },
)
.clicked()
{
open_add = Some(None);
}
});
},
);
ui.add_space(10.0);
// Import on the RIGHT, neutral: reveal-then-confirm.
ui.scope_builder(
egui::UiBuilder::new().max_rect(egui::Rect::from_min_size(
ui.cursor().min,
Vec2::new(half, 44.0),
)),
|ui| {
ui.add_enabled_ui(import_armed, |ui| {
if w::big_action_on_card_ink(
ui,
&t!("goblin.identities.import"),
if import_armed {
t.surface_text
} else {
t.surface_text_mute
},
)
.clicked()
{
if !import {
// First tap: reveal the import inputs.
self.identity_switch.import = true;
self.identity_switch.error.clear();
} else {
// Confirm: the selected .backup wins over
// a pasted nsec.
let b = self.identity_switch.backup_input.trim();
let blob = if b.is_empty() {
self.identity_switch.nsec.trim().to_string()
} else {
b.to_string()
};
open_add = Some(Some(blob));
}
}
});
},
);
});
// Cancel centered BENEATH the pair: red, same uniform size.
ui.add_space(10.0);
ui.horizontal(|ui| {
let half = (ui.available_width() - 10.0) / 2.0;
ui.add_space((ui.available_width() - half) / 2.0);
ui.scope_builder(
egui::UiBuilder::new().max_rect(egui::Rect::from_min_size(
ui.cursor().min,
Vec2::new(half, 44.0),
)),
|ui| {
// Uniform paired buttons (the Generate/Import toggle
// pattern): same widget, size and shape for both halves.
if w::big_action_on_card_ink(
ui,
&t!("goblin.settings.cancel"),
t.surface_text,
t.neg,
)
.clicked()
{
@@ -5477,55 +5533,21 @@ impl GoblinWalletView {
}
},
);
ui.add_space(10.0);
ui.scope_builder(
egui::UiBuilder::new().max_rect(egui::Rect::from_min_size(
ui.cursor().min,
Vec2::new(half, 44.0),
)),
|ui| {
ui.add_enabled_ui(armed, |ui| {
if w::big_action_on_card_ink(
ui,
&t!("goblin.identities.add_confirm"),
if armed { t.pos } else { t.surface_text_mute },
)
.clicked()
{
// Open the password modal to encrypt+store the
// new identity. It is added WITHOUT switching;
// the user activates it later by tapping it. The
// import blob is the selected .backup if any,
// else the pasted nsec.
let import_blob = if import {
let b = self.identity_switch.backup_input.trim();
if b.is_empty() {
Some(
self.identity_switch
.nsec
.trim()
.to_string(),
)
} else {
Some(b.to_string())
}
} else {
None
};
self.identity_switch.error.clear();
self.identity_switch.pass.clear();
self.identity_switch.wrong_pass = false;
self.identity_switch.pending =
Some(PendingPassAction::Add(import_blob));
Modal::new(IDENTITY_PASS_MODAL)
.position(ModalPosition::CenterTop)
.title(t!("goblin.identities.add_title"))
.show();
}
});
},
);
});
if let Some(import_blob) = open_add {
// Open the password modal to encrypt+store the new
// identity. It is added WITHOUT switching; the user
// activates it later by tapping it.
self.identity_switch.error.clear();
self.identity_switch.pass.clear();
self.identity_switch.wrong_pass = false;
self.identity_switch.pending =
Some(PendingPassAction::Add(import_blob));
Modal::new(IDENTITY_PASS_MODAL)
.position(ModalPosition::CenterTop)
.title(t!("goblin.identities.add_title"))
.show();
}
});
}