diff --git a/locales/de.yml b/locales/de.yml index 9916203d..927a354c 100644 --- a/locales/de.yml +++ b/locales/de.yml @@ -834,8 +834,6 @@ goblin: title: "Richte dein Wallet ein" create_new: "Neu erstellen" restore_from_seed: "Aus Seed wiederherstellen" - import_identity: "Identität importieren" - import_identity_hint: "Nach diesem Schritt bringst du deinen vorhandenen Schlüssel mit (eine .backup-Datei oder nsec)." name_hint: "Wallet-Name" password_hint: "Passwort" repeat_password_hint: "Passwort wiederholen" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "Freunde können dich jetzt per Namen bezahlen. Alles bereit — öffne dein Wallet." open_wallet: "Mein Wallet öffnen" skip_for_now: "Vorerst überspringen" - import_existing: "Schon eine Goblin-Identität? Importieren" - import_title: "Identität importieren" - import_blurb: "Füge deinen nsec ein oder wähle eine .backup-Datei, um deinen vorhandenen Schlüssel und Benutzernamen zu behalten statt diesen neuen." errors: cant_open: "Wallet konnte nicht geöffnet werden: %{err}" cant_create: "Wallet konnte nicht erstellt werden: %{err}" diff --git a/locales/en.yml b/locales/en.yml index 5200d4b0..38a01c9b 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -834,8 +834,6 @@ goblin: title: "Set up your wallet" create_new: "Create new" restore_from_seed: "Restore from seed" - import_identity: "Import identity" - import_identity_hint: "You'll bring in your existing key (a .backup file or nsec) after this step." name_hint: "Wallet name" password_hint: "Password" repeat_password_hint: "Repeat password" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "Friends can now pay you by name. You're all set — open your wallet." open_wallet: "Open my wallet" skip_for_now: "Skip for now" - import_existing: "Already have a Goblin identity? Import it" - import_title: "Import your identity" - import_blurb: "Paste your nsec or pick a .backup file to keep your existing key and username instead of this new one." errors: cant_open: "Couldn't open the wallet: %{err}" cant_create: "Couldn't create the wallet: %{err}" diff --git a/locales/es.yml b/locales/es.yml index f471ff15..f808d316 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -834,8 +834,6 @@ goblin: title: "Configura tu billetera" create_new: "Crear nueva" restore_from_seed: "Restaurar desde la frase semilla" - import_identity: "Importar identidad" - import_identity_hint: "Traerás tu clave existente (un archivo .backup o nsec) después de este paso." name_hint: "Nombre de la billetera" password_hint: "Contraseña" repeat_password_hint: "Repite la contraseña" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "Tus amigos ya pueden pagarte por nombre. Todo listo — abre tu billetera." open_wallet: "Abrir mi billetera" skip_for_now: "Saltar por ahora" - import_existing: "¿Ya tienes una identidad de Goblin? Impórtala" - import_title: "Importa tu identidad" - import_blurb: "Pega tu nsec o elige un archivo .backup para conservar tu clave y nombre de usuario existentes en lugar de este nuevo." errors: cant_open: "No se pudo abrir la billetera: %{err}" cant_create: "No se pudo crear la billetera: %{err}" diff --git a/locales/fr.yml b/locales/fr.yml index ca9e717f..23d0ddda 100644 --- a/locales/fr.yml +++ b/locales/fr.yml @@ -834,8 +834,6 @@ goblin: title: "Configurez votre portefeuille" create_new: "Créer un nouveau" restore_from_seed: "Restaurer depuis la phrase" - import_identity: "Importer une identité" - import_identity_hint: "Vous importerez votre clé existante (un fichier .backup ou un nsec) après cette étape." name_hint: "Nom du portefeuille" password_hint: "Mot de passe" repeat_password_hint: "Répéter le mot de passe" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "Vos amis peuvent désormais vous payer par votre nom. Tout est prêt — ouvrez votre portefeuille." open_wallet: "Ouvrir mon portefeuille" skip_for_now: "Passer pour l'instant" - import_existing: "Vous avez déjà une identité Goblin ? Importez-la" - import_title: "Importer votre identité" - import_blurb: "Collez votre nsec ou choisissez un fichier .backup pour conserver votre clé et votre nom existants au lieu de ce nouveau." errors: cant_open: "Impossible d'ouvrir le portefeuille : %{err}" cant_create: "Impossible de créer le portefeuille : %{err}" diff --git a/locales/ko.yml b/locales/ko.yml index e01da3dc..5a5e241c 100644 --- a/locales/ko.yml +++ b/locales/ko.yml @@ -834,8 +834,6 @@ goblin: title: "지갑을 설정하세요" create_new: "새로 만들기" restore_from_seed: "복구 문구로 복원" - import_identity: "신원 가져오기" - import_identity_hint: "이 단계 이후에 기존 키(.backup 파일 또는 nsec)를 가져오게 됩니다." name_hint: "지갑 이름" password_hint: "비밀번호" repeat_password_hint: "비밀번호 확인" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "이제 친구들이 이름으로 결제할 수 있습니다. 모든 준비가 끝났습니다 — 지갑을 열어 보세요." open_wallet: "내 지갑 열기" skip_for_now: "지금은 건너뛰기" - import_existing: "이미 Goblin 신원이 있나요? 가져오기" - import_title: "신원 가져오기" - import_blurb: "nsec을 붙여넣거나 .backup 파일을 선택해서, 새 신원 대신 기존 키와 사용자 이름을 유지하세요." errors: cant_open: "지갑을 열 수 없습니다: %{err}" cant_create: "지갑을 만들 수 없습니다: %{err}" diff --git a/locales/ru.yml b/locales/ru.yml index b88e3e5e..a8cfa8e1 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -834,8 +834,6 @@ goblin: title: "Настройте кошелёк" create_new: "Создать новый" restore_from_seed: "Восстановить из seed" - import_identity: "Импорт личности" - import_identity_hint: "После этого шага вы добавите свой существующий ключ (файл .backup или nsec)." name_hint: "Имя кошелька" password_hint: "Пароль" repeat_password_hint: "Повторите пароль" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "Друзья теперь могут платить вам по имени. Всё готово — откройте кошелёк." open_wallet: "Открыть кошелёк" skip_for_now: "Пропустить пока" - import_existing: "Уже есть личность Goblin? Импортируйте её" - import_title: "Импорт личности" - import_blurb: "Вставьте свой nsec или выберите файл .backup, чтобы сохранить существующий ключ и имя вместо нового." errors: cant_open: "Не удалось открыть кошелёк: %{err}" cant_create: "Не удалось создать кошелёк: %{err}" diff --git a/locales/tr.yml b/locales/tr.yml index 5e9b607b..46adfe2a 100644 --- a/locales/tr.yml +++ b/locales/tr.yml @@ -834,8 +834,6 @@ goblin: title: "Cüzdanını kur" create_new: "Yeni oluştur" restore_from_seed: "Tohumdan geri yükle" - import_identity: "Kimliği içe aktar" - import_identity_hint: "Bu adımdan sonra mevcut anahtarını (bir .backup dosyası veya nsec) getireceksin." name_hint: "Cüzdan adı" password_hint: "Parola" repeat_password_hint: "Parolayı tekrarla" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "Arkadaşların artık sana adınla ödeme yapabilir. Her şey hazır — cüzdanını aç." open_wallet: "Cüzdanımı aç" skip_for_now: "Şimdilik atla" - import_existing: "Zaten bir Goblin kimliğin var mı? İçe aktar" - import_title: "Kimliğini içe aktar" - import_blurb: "Bu yeni anahtar yerine mevcut anahtarını ve kullanıcı adını korumak için nsec'ini yapıştır veya bir .backup dosyası seç." errors: cant_open: "Cüzdan açılamadı: %{err}" cant_create: "Cüzdan oluşturulamadı: %{err}" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 02be2501..28dd1d3d 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -834,8 +834,6 @@ goblin: title: "设置你的钱包" create_new: "新建" restore_from_seed: "从助记词恢复" - import_identity: "导入身份" - import_identity_hint: "此步骤之后,你将导入现有密钥(.backup 文件或 nsec)。" name_hint: "钱包名称" password_hint: "密码" repeat_password_hint: "重复密码" @@ -880,9 +878,6 @@ goblin: claimed_blurb: "朋友现在可以用你的用户名向你付款。一切就绪——打开钱包吧。" open_wallet: "打开我的钱包" skip_for_now: "暂时跳过" - import_existing: "已有 Goblin 身份?导入它" - import_title: "导入你的身份" - import_blurb: "粘贴你的 nsec 或选择一个 .backup 文件,保留你现有的密钥和用户名,而不是这个新的。" errors: cant_open: "无法打开钱包:%{err}" cant_create: "无法创建钱包:%{err}" diff --git a/src/gui/views/goblin/onboarding.rs b/src/gui/views/goblin/onboarding.rs index 2f5b2fcc..4b32ce6c 100644 --- a/src/gui/views/goblin/onboarding.rs +++ b/src/gui/views/goblin/onboarding.rs @@ -28,7 +28,6 @@ use crate::gui::views::types::{ContentContainer, ModalPosition, QrScanResult}; use crate::gui::views::wallets::creation::MnemonicSetup; use crate::gui::views::{CameraScanContent, Content, Modal, TextEdit, View}; use crate::node::Node; -use crate::nostr::NostrIdentity; use crate::wallet::types::{ConnectionMethod, PhraseMode, PhraseSize}; use crate::wallet::{ConnectionsConfig, ExternalConnection, Wallet, WalletList}; @@ -58,11 +57,6 @@ pub struct OnboardingContent { ext_url: String, /// Wallet setup inputs. restore: bool, - /// The user chose "Import identity" on the wallet step: after the wallet is - /// created the identity step opens the import panel straight away (bringing - /// over an existing key from a `.backup` or nsec), instead of the fresh - /// random key. Composes with either seed choice above it. - want_import: bool, name: String, pass: String, pass2: String, @@ -76,34 +70,10 @@ pub struct OnboardingContent { wallet: Option, /// Optional username claim state (same machinery as Settings). claim: ClaimState, - /// Optional "import an existing identity" sub-flow, opened from the identity - /// step so a returning user can keep their old npub + username instead of the - /// freshly-generated random key. - import: Option, /// Moment the recovery phrase was copied, for the transient "Copied" check. words_copied: Option, } -/// Onboarding identity-import state. Reuses the wallet password the user just -/// set, so it only needs the backup file / nsec (and the backup's own password -/// when restoring a sealed `.backup`). -#[derive(Default)] -struct OnbImport { - /// 0 = form, 1 = working, 2 = error. - stage: u8, - /// Pasted nsec or the read-in contents of a `.backup` / identity JSON file. - nsec: String, - /// Password the backup was sealed under (blank for a bare nsec, or when it - /// matches this wallet's password). - backup_password: String, - /// Last import error, shown on stage 2. - error: String, - /// A native file pick is in flight (Android resolves the path asynchronously). - picking: bool, - /// Worker result: Ok(new npub) or Err(message). - result: std::sync::Arc>>>, -} - impl Default for OnboardingContent { fn default() -> Self { Self { @@ -113,7 +83,6 @@ impl Default for OnboardingContent { integrated: false, ext_url: "https://grincoin.org".to_string(), restore: false, - want_import: false, name: "Main wallet".to_string(), pass: String::new(), pass2: String::new(), @@ -122,7 +91,6 @@ impl Default for OnboardingContent { scan_modal: None, wallet: None, claim: ClaimState::default(), - import: None, words_copied: None, } } @@ -420,37 +388,6 @@ impl OnboardingContent { ui.add_space(10.0); } }); - ui.add_space(10.0); - - // First-class "Import identity" option, standing alongside Create/Restore: - // bring an existing key over (from a .backup file or a bare nsec). It - // composes with either seed choice above — the import panel itself opens - // on the identity step, once the wallet exists. - ui.scope_builder( - egui::UiBuilder::new().max_rect(egui::Rect::from_min_size( - ui.cursor().min, - Vec2::new(ui.available_width(), 44.0), - )), - |ui| { - if w::chip( - ui, - &t!("goblin.onboarding.wallet.import_identity"), - self.want_import, - ) - .clicked() - { - self.want_import = !self.want_import; - } - }, - ); - if self.want_import { - ui.add_space(6.0); - ui.label( - RichText::new(t!("goblin.onboarding.wallet.import_identity_hint")) - .font(FontId::new(12.5, fonts::regular())) - .color(t.text_mute), - ); - } ui.add_space(14.0); w::field_well(ui, |ui| { @@ -901,17 +838,7 @@ impl OnboardingContent { .nostr_service() .map(|s| s.identity.read().nip05.is_some()) .unwrap_or(false); - // Came in via the wallet step's "Import identity" button: open the import - // panel straight away (offers both a .backup file and a bare nsec), rather - // than the fresh-key claim card. - if self.want_import && self.import.is_none() { - self.import = Some(OnbImport::default()); - self.want_import = false; - } - if self.import.is_some() { - // Returning user is swapping the random key for their existing identity. - self.import_ui(ui, &wallet, cb); - } else if !registered { + if !registered { w::card(ui, |ui| { ui.set_min_width(ui.available_width()); ui.label( @@ -989,14 +916,6 @@ impl OnboardingContent { } } }); - ui.add_space(10.0); - // Returning user? A centered, first-class "Import identity" button - // (was a left-aligned text link) restores their existing identity - // from a .backup file or a bare nsec instead of the fresh random key. - // The .backup-or-nsec choice lives behind it, in import_ui. - if w::big_action(ui, &t!("goblin.onboarding.wallet.import_identity"), true).clicked() { - self.import = Some(OnbImport::default()); - } ui.add_space(16.0); } else { // Claimed: show a clear success confirmation so the user knows the @@ -1048,199 +967,6 @@ impl OnboardingContent { None } - /// Onboarding identity-import sub-flow: paste an nsec or pick a `.backup` - /// file to swap the freshly-generated random key for the user's existing - /// identity (keeping their npub and any claimed username). Reuses the wallet - /// password the user just set; a sealed `.backup` may carry its own password. - fn import_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) { - let t = theme::tokens(); - // Poll the worker first, WITHOUT holding a borrow across the reset below. - if self.import.as_ref().map(|i| i.stage) == Some(1) { - let res = self.import.as_ref().unwrap().result.lock().unwrap().take(); - if let Some(res) = res { - match res { - // Identity replaced: drop the sub-flow; the identity card and the - // claim/success state re-render from the new service next frame. - Ok(_) => { - self.import = None; - return; - } - Err(e) => { - let imp = self.import.as_mut().unwrap(); - imp.error = e; - imp.stage = 2; - } - } - } - } - let wallet_pass = self.pass.clone(); - let imp = self.import.as_mut().unwrap(); - let mut close = false; - w::card(ui, |ui| { - ui.set_min_width(ui.available_width()); - match imp.stage { - 1 => { - ui.horizontal(|ui| { - View::small_loading_spinner(ui); - ui.add_space(8.0); - ui.label( - RichText::new(t!("goblin.settings.importing")) - .font(FontId::new(13.0, fonts::regular())) - .color(t.surface_text_dim), - ); - }); - ui.ctx().request_repaint(); - } - 2 => { - ui.label( - RichText::new(t!("goblin.settings.import_failed")) - .font(FontId::new(15.0, fonts::semibold())) - .color(t.neg), - ); - ui.add_space(4.0); - ui.label( - RichText::new(&imp.error) - .font(FontId::new(13.0, fonts::regular())) - .color(t.surface_text_dim), - ); - ui.add_space(10.0); - if w::big_action_on_card(ui, &t!("goblin.settings.close")).clicked() { - close = true; - } - } - _ => { - ui.label( - RichText::new(t!("goblin.onboarding.identity.import_title")) - .font(FontId::new(15.0, fonts::semibold())) - .color(t.surface_text), - ); - ui.add_space(6.0); - ui.label( - RichText::new(t!("goblin.onboarding.identity.import_blurb")) - .font(FontId::new(12.5, fonts::regular())) - .color(t.surface_text_dim), - ); - ui.add_space(10.0); - // Native ".backup file" picker. Desktop returns the path now; - // Android resolves it asynchronously (poll picked_file()). - if imp.picking { - if let Some(path) = cb.picked_file() { - imp.picking = false; - if !path.is_empty() { - match std::fs::read_to_string(&path) { - Ok(contents) => imp.nsec = contents.trim().to_string(), - Err(_) => { - imp.error = - t!("goblin.settings.backup_read_failed").to_string(); - } - } - } - } else { - ui.ctx().request_repaint(); - } - } - if w::big_action_on_card(ui, &t!("goblin.settings.choose_backup_file")) - .clicked() - { - imp.error.clear(); - match cb.pick_file() { - Some(path) if !path.is_empty() => { - match std::fs::read_to_string(&path) { - Ok(contents) => imp.nsec = contents.trim().to_string(), - Err(_) => { - imp.error = - t!("goblin.settings.backup_read_failed").to_string(); - } - } - } - // Empty string = Android async pick in flight. - Some(_) => imp.picking = true, - None => {} - } - } - ui.add_space(8.0); - w::field_well(ui, |ui| { - TextEdit::new(egui::Id::from("onb_import_nsec")) - .focus(false) - .hint_text(t!("goblin.settings.import_nsec_hint")) - .password() - .text_color(t.surface_text) - .body() - .ui(ui, &mut imp.nsec, cb); - }); - ui.add_space(8.0); - w::field_well(ui, |ui| { - TextEdit::new(egui::Id::from("onb_import_bpw")) - .focus(false) - .hint_text(t!("goblin.settings.backup_password_hint")) - .password() - .text_color(t.surface_text) - .body() - .ui(ui, &mut imp.backup_password, cb); - }); - if !imp.error.is_empty() { - ui.add_space(6.0); - ui.label( - RichText::new(&imp.error) - .font(FontId::new(12.5, fonts::regular())) - .color(t.neg), - ); - } - ui.add_space(10.0); - let pasted = imp.nsec.trim(); - // Only an nsec paste or a sealed .backup file — nothing else. - let armed = - pasted.starts_with("nsec1") || NostrIdentity::is_encrypted_backup(pasted); - ui.horizontal(|ui| { - let half = (ui.available_width() - 10.0) / 2.0; - ui.scope_builder( - egui::UiBuilder::new().max_rect(egui::Rect::from_min_size( - ui.cursor().min, - Vec2::new(half, 44.0), - )), - |ui| { - if w::big_action_on_card(ui, &t!("goblin.settings.cancel")) - .clicked() - { - close = true; - } - }, - ); - 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(ui, &t!("goblin.settings.import_btn"), false) - .clicked() - { - imp.stage = 1; - let slot = imp.result.clone(); - let nsec = std::mem::take(&mut imp.nsec); - let bpw = std::mem::take(&mut imp.backup_password); - let bpw = if bpw.is_empty() { None } else { Some(bpw) }; - let wallet = wallet.clone(); - let pass = wallet_pass.clone(); - std::thread::spawn(move || { - let res = wallet.import_nostr_identity(nsec, pass, bpw); - *slot.lock().unwrap() = Some(res); - }); - } - }); - }, - ); - }); - } - } - }); - if close { - self.import = None; - } - } - /// Recovery-phrase QR scan modal content. fn scan_modal_ui(&mut self, ui: &mut egui::Ui, _: &Modal, cb: &dyn PlatformCallbacks) { if let Some(content) = self.scan_modal.as_mut() {