goblin: add-identity sheet gets real Generate/Import buttons, Cancel beneath (Build 150)
This commit is contained in:
+2
-3
@@ -702,8 +702,8 @@ goblin:
|
||||
add_title: "Eine Identität hinzufügen"
|
||||
nsec_hint: "Nsec einfügen"
|
||||
generate_note: "Ein neuer, anonymer Schlüssel wird für diese Wallet erstellt."
|
||||
import_instead: "Stattdessen eine bestehende Identität importieren"
|
||||
generate_instead: "Stattdessen einen neuen Schlüssel erstellen"
|
||||
generate: "Erstellen"
|
||||
import: "Importieren"
|
||||
choose_backup: "Eine .backup-Datei wählen"
|
||||
backup_selected: "Backup-Datei ausgewählt"
|
||||
delete_short: "Identität löschen"
|
||||
@@ -715,7 +715,6 @@ goblin:
|
||||
tag_note: "Gib ihr einen privaten Namen. Nur du siehst ihn — er wird nie geteilt."
|
||||
tag_hint: "Privater Name"
|
||||
tag_save: "Speichern"
|
||||
add_confirm: "Hinzufügen"
|
||||
pass_prompt: "Dein Wallet-Passwort verschlüsselt und entsperrt jede Identität. Gib es ein, um fortzufahren."
|
||||
working: "Arbeite…"
|
||||
onboarding:
|
||||
|
||||
+2
-3
@@ -702,8 +702,8 @@ goblin:
|
||||
add_title: "Add an identity"
|
||||
nsec_hint: "Paste an nsec"
|
||||
generate_note: "A fresh, anonymous key will be created for this wallet."
|
||||
import_instead: "Import an existing identity instead"
|
||||
generate_instead: "Create a new key instead"
|
||||
generate: "Generate"
|
||||
import: "Import"
|
||||
choose_backup: "Choose a .backup file"
|
||||
backup_selected: "Backup file selected"
|
||||
delete_short: "Delete identity"
|
||||
@@ -715,7 +715,6 @@ goblin:
|
||||
tag_note: "Give it a private name. Only you see it — it is never shared."
|
||||
tag_hint: "Private name"
|
||||
tag_save: "Save"
|
||||
add_confirm: "Add"
|
||||
pass_prompt: "Your wallet password encrypts and unlocks each identity. Enter it to continue."
|
||||
working: "Working…"
|
||||
onboarding:
|
||||
|
||||
+2
-3
@@ -702,8 +702,8 @@ goblin:
|
||||
add_title: "Ajouter une identité"
|
||||
nsec_hint: "Coller un nsec"
|
||||
generate_note: "Une nouvelle clé anonyme sera créée pour ce portefeuille."
|
||||
import_instead: "Importer plutôt une identité existante"
|
||||
generate_instead: "Créer plutôt une nouvelle clé"
|
||||
generate: "Créer"
|
||||
import: "Importer"
|
||||
choose_backup: "Choisir un fichier .backup"
|
||||
backup_selected: "Fichier de sauvegarde sélectionné"
|
||||
delete_short: "Supprimer l'identité"
|
||||
@@ -715,7 +715,6 @@ goblin:
|
||||
tag_note: "Donnez-lui un nom privé. Vous seul le voyez — il n’est jamais partagé."
|
||||
tag_hint: "Nom privé"
|
||||
tag_save: "Enregistrer"
|
||||
add_confirm: "Ajouter"
|
||||
pass_prompt: "Le mot de passe de votre portefeuille chiffre et déverrouille chaque identité. Saisissez-le pour continuer."
|
||||
working: "En cours…"
|
||||
onboarding:
|
||||
|
||||
+2
-3
@@ -702,8 +702,8 @@ goblin:
|
||||
add_title: "Добавить личность"
|
||||
nsec_hint: "Вставьте nsec"
|
||||
generate_note: "Для этого кошелька будет создан новый анонимный ключ."
|
||||
import_instead: "Вместо этого импортировать существующую личность"
|
||||
generate_instead: "Вместо этого создать новый ключ"
|
||||
generate: "Создать"
|
||||
import: "Импортировать"
|
||||
choose_backup: "Выбрать файл .backup"
|
||||
backup_selected: "Файл резервной копии выбран"
|
||||
delete_short: "Удалить личность"
|
||||
@@ -715,7 +715,6 @@ goblin:
|
||||
tag_note: "Дайте ей приватное имя. Его видите только вы — оно никогда не передаётся."
|
||||
tag_hint: "Приватное имя"
|
||||
tag_save: "Сохранить"
|
||||
add_confirm: "Добавить"
|
||||
pass_prompt: "Пароль кошелька шифрует и разблокирует каждую личность. Введите его, чтобы продолжить."
|
||||
working: "Обработка…"
|
||||
onboarding:
|
||||
|
||||
+2
-3
@@ -702,8 +702,8 @@ goblin:
|
||||
add_title: "Bir kimlik ekle"
|
||||
nsec_hint: "Bir nsec yapıştır"
|
||||
generate_note: "Bu cüzdan için yeni, anonim bir anahtar oluşturulacak."
|
||||
import_instead: "Bunun yerine mevcut bir kimliği içe aktar"
|
||||
generate_instead: "Bunun yerine yeni bir anahtar oluştur"
|
||||
generate: "Oluştur"
|
||||
import: "İçe aktar"
|
||||
choose_backup: "Bir .backup dosyası seç"
|
||||
backup_selected: "Yedek dosyası seçildi"
|
||||
delete_short: "Kimliği sil"
|
||||
@@ -715,7 +715,6 @@ goblin:
|
||||
tag_note: "Ona özel bir ad ver. Sadece sen görürsün — asla paylaşılmaz."
|
||||
tag_hint: "Özel ad"
|
||||
tag_save: "Kaydet"
|
||||
add_confirm: "Ekle"
|
||||
pass_prompt: "Cüzdan parolan her kimliği şifreler ve açar. Devam etmek için gir."
|
||||
working: "Çalışıyor…"
|
||||
onboarding:
|
||||
|
||||
+2
-3
@@ -702,8 +702,8 @@ goblin:
|
||||
add_title: "添加一个身份"
|
||||
nsec_hint: "粘贴 nsec"
|
||||
generate_note: "将为此钱包创建一个全新的匿名密钥。"
|
||||
import_instead: "改为导入现有身份"
|
||||
generate_instead: "改为创建新密钥"
|
||||
generate: "创建"
|
||||
import: "导入"
|
||||
choose_backup: "选择 .backup 文件"
|
||||
backup_selected: "已选择备份文件"
|
||||
delete_short: "删除身份"
|
||||
@@ -715,7 +715,6 @@ goblin:
|
||||
tag_note: "给它起一个私密名称。只有你能看到——绝不会被分享。"
|
||||
tag_hint: "私密名称"
|
||||
tag_save: "保存"
|
||||
add_confirm: "添加"
|
||||
pass_prompt: "钱包密码用于加密和解锁每个身份。输入以继续。"
|
||||
working: "处理中…"
|
||||
onboarding:
|
||||
|
||||
+90
-68
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user