Build 82: names without @, wallet management + Advanced, list header, sturdier receive
- Drop the displayed @ prefix everywhere (identity picker, slatepacks page, all copy); @ stays internal for lookups/avatars. - Settings: move wallet management to the foot — Switch wallet (deselect, stays unlocked), Lock wallet, and a new Advanced page mirroring GRIM's recovery tools (repair, restore-from-seed, reveal recovery phrase, delete). - Restore the wallet-list title header (reachable settings gear, Pay-screen accent yellow). - Transport: a transient receive/finalize failure no longer marks the gift wrap processed, so an incoming payment is retried on catch-up instead of being silently lost; finalize-post is now retry-safe (re-posts an already-finalized slate). - Guard a latent panic on a short sender key in ensure_contact. - Add more healthy public grin nodes (mainnet + testnet) for redundancy. - Default first-run onboarding to the Instant connection (public node), shown first. - Tidy leftover Tor remnants left from the fork.
This commit is contained in:
+36
-15
@@ -458,6 +458,8 @@ goblin:
|
||||
slatepacks: "Slatepacks"
|
||||
slatepacks_value: "Manuelle Transaktion"
|
||||
lock_wallet: "Wallet sperren"
|
||||
switch_wallet: "Wallet wechseln"
|
||||
advanced: "Erweitert"
|
||||
privacy: "Privatsphäre"
|
||||
mixnet_routing: "Mixnet-Routing"
|
||||
messages_lookups: "Nachrichten & Abfragen"
|
||||
@@ -485,7 +487,7 @@ goblin:
|
||||
third_party: "Drittanbieter"
|
||||
grim: "GRIM (Upstream-Wallet)"
|
||||
grin_node: "Grin-Node"
|
||||
sp_intro: "Erweitert — rohe slatepacks von Hand austauschen, so wie GRIM es macht. Nur nutzen, wenn du nicht über einen @username zahlen oder bezahlt werden kannst."
|
||||
sp_intro: "Erweitert — rohe slatepacks von Hand austauschen, so wie GRIM es macht. Nur nutzen, wenn du nicht über einen username zahlen oder bezahlt werden kannst."
|
||||
sp_receive_group: "Empfangen oder abschließen"
|
||||
sp_receive_blurb: "Füge einen slatepack ein, den dir jemand gegeben hat. Goblin empfängt die Zahlung, begleicht die Rechnung oder schließt sie ab und sendet sie."
|
||||
sp_process: "Slatepack verarbeiten"
|
||||
@@ -503,9 +505,9 @@ goblin:
|
||||
sp_copy: "Slatepack kopieren"
|
||||
rotate_line1: "• Du bekommst einen brandneuen ZUFÄLLIGEN Schlüssel; das alte npub empfängt nichts mehr. Es gibt keine Ableitungskette zwischen beiden."
|
||||
rotate_line2: "• Der neue Schlüssel ist NICHT aus deinem Seed wiederherstellbar — sichere die neue nsec direkt nach dem Wechsel."
|
||||
rotate_line3: "• Dein @username wird FREIGEGEBEN und dein Profilbild gelöscht — sichere danach denselben oder einen neuen Namen (sobald frei, kann ihn jeder andere ebenfalls greifen)."
|
||||
rotate_line3: "• Dein username wird FREIGEGEBEN und dein Profilbild gelöscht — sichere danach denselben oder einen neuen Namen (sobald frei, kann ihn jeder andere ebenfalls greifen)."
|
||||
rotate_line4: "• Zahlungen, die noch an den alten Schlüssel unterwegs sind, WERDEN gestört — warte zuerst, bis ausstehende Zahlungen abgeschlossen sind."
|
||||
rotate_line5: "• Kontakte, die dein npub direkt gespeichert haben, müssen dich neu finden — teile dein neues npub oder den neu gesicherten @username."
|
||||
rotate_line5: "• Kontakte, die dein npub direkt gespeichert haben, müssen dich neu finden — teile dein neues npub oder den neu gesicherten username."
|
||||
cancel: "Abbrechen"
|
||||
continue: "Weiter"
|
||||
final_confirmation: "Endgültige Bestätigung"
|
||||
@@ -532,13 +534,13 @@ goblin:
|
||||
import_failed: "Import fehlgeschlagen"
|
||||
registered: "%{name} registriert"
|
||||
released_msg: "Freigegeben — der Name ist frei"
|
||||
release_confirm: "@%{name} freigeben?"
|
||||
release_confirm: "%{name} freigeben?"
|
||||
release_blurb: "Er ist frei, sobald er verfügbar wird — jeder kann ihn beanspruchen, auch der nächste Schlüssel, zu dem du wechselst. Dein Profilbild wird damit gelöscht. Du kannst 10 Minuten lang keinen anderen Benutzernamen registrieren."
|
||||
releasing: "Gebe frei…"
|
||||
keep_it: "Behalten"
|
||||
release_it: "Freigeben"
|
||||
username: "Benutzername"
|
||||
username_note: "Wird als @you angezeigt. Öffentlich auf goblin.st. Zahlungen bleiben verschlüsselt."
|
||||
username_note: "Wird als you angezeigt. Öffentlich auf goblin.st. Zahlungen bleiben verschlüsselt."
|
||||
release_username: "Benutzername freigeben"
|
||||
pick_username: "Benutzernamen wählen — optional"
|
||||
working: "Arbeite…"
|
||||
@@ -553,12 +555,31 @@ goblin:
|
||||
avail_invalid: "Namen haben 3–30 Zeichen: a–z, 0–9, _ oder -"
|
||||
avail_quarantined: "Nicht verfügbar"
|
||||
avail_unknown: "Prüfung fehlgeschlagen — Verbindungsproblem. Versuche es erneut."
|
||||
advanced:
|
||||
title: "Erweitert"
|
||||
intro: "Wallet-Werkzeuge auf niedriger Ebene von GRIM. Normalerweise brauchst du diese nicht."
|
||||
repair: "Wallet reparieren"
|
||||
repair_desc: "Die Kette neu scannen und fehlende Outputs wiederherstellen. Das kann dauern."
|
||||
repair_unavailable: "Benötigt zuerst eine synchronisierte Node-Verbindung."
|
||||
repairing: "Repariere… %{pct}%"
|
||||
restore: "Wallet wiederherstellen"
|
||||
restore_desc: "Lokale Daten löschen und aus deinem Seed neu aufbauen. Nutze das, wenn eine Reparatur nicht half — danach öffnest du die Wallet erneut."
|
||||
restore_confirm: "Zum Wiederherstellen erneut tippen"
|
||||
show_phrase: "Wiederherstellungsphrase"
|
||||
phrase_desc: "Deine 24 grin-Seed-Wörter — der einzige Weg, Guthaben wiederherzustellen. Halte sie offline und privat."
|
||||
reveal: "Phrase anzeigen"
|
||||
hide: "Verbergen"
|
||||
password: "Wallet-Passwort"
|
||||
wrong_password: "Falsches Passwort."
|
||||
delete: "Wallet löschen"
|
||||
delete_desc: "Diese Wallet dauerhaft von diesem Gerät entfernen. Ohne deinen Seed sind Guthaben nicht wiederherstellbar."
|
||||
delete_confirm: "Zum Löschen erneut tippen"
|
||||
privacy:
|
||||
title: "Netzwerk-Privatsphäre"
|
||||
intro: "Goblin sendet seinen privaten Datenverkehr durch das Nym mixnet — ein Netzwerk mit fünf Sprüngen, das verbirgt, wer mit wem kommuniziert, sodass ein Relay eine Zahlung nicht zu dir zurückverfolgen kann."
|
||||
payments: "Zahlungen"
|
||||
payments_blurb: "Jede nostr-Nachricht, die einen slatepack trägt."
|
||||
usernames: "@usernames"
|
||||
usernames: "usernames"
|
||||
usernames_blurb: "NIP-05-Namensabfragen zu und von goblin.st."
|
||||
price_avatars: "Kurs & Avatare"
|
||||
price_avatars_blurb: "Die Kursvorschau und Kontaktbilder."
|
||||
@@ -594,9 +615,9 @@ goblin:
|
||||
nips:
|
||||
title: "nostr & NIPs"
|
||||
intro1: "Goblin spricht nostr — ein offenes Protokoll signierter Nachrichten, die über einfache Relay-Server weitergereicht werden. Dein Wallet trägt seine eigene nostr-Identität: einen eigenständigen Zufallsschlüssel, bewusst unabhängig von deinem Guthaben und Seed gehalten. Jede Zahlung reist als Ende-zu-Ende-verschlüsselte Direktnachricht zwischen Identitäten, mit dem slatepack im Inneren."
|
||||
intro2: "goblin.st ist Goblins Namensdienst: Das Sichern eines Benutzernamens veröffentlicht dort eine Name → Schlüssel-Zuordnung (NIP-05), sodass Leute @you statt eines langen npub bezahlen können. Der Benutzername ist öffentlich; Zahlungsinhalte sind es nie. NIPs sind die Bausteine des Protokolls — tippe auf einen, um die Spezifikation zu lesen."
|
||||
intro2: "goblin.st ist Goblins Namensdienst: Das Sichern eines Benutzernamens veröffentlicht dort eine Name → Schlüssel-Zuordnung (NIP-05), sodass Leute you statt eines langen npub bezahlen können. Der Benutzername ist öffentlich; Zahlungsinhalte sind es nie. NIPs sind die Bausteine des Protokolls — tippe auf einen, um die Spezifikation zu lesen."
|
||||
n05_title: "Namen"
|
||||
n05_blurb: "Ordnet @username@goblin.st deinem Schlüssel zu, sodass Handles wie Adressen funktionieren."
|
||||
n05_blurb: "Ordnet username@goblin.st deinem Schlüssel zu, sodass Handles wie Adressen funktionieren."
|
||||
n17_title: "Private Nachrichten"
|
||||
n17_blurb: "Die verschlüsselte DM-Hülle, in der jede Zahlung reist."
|
||||
n44_title: "Verschlüsselung"
|
||||
@@ -612,7 +633,7 @@ goblin:
|
||||
private_money_head: "Privates Geld"
|
||||
private_money_body: "Goblin ist ein Wallet für grin — digitales Bargeld ohne Beträge oder Adressen auf seiner Chain."
|
||||
send_like_message_head: "Senden wie eine Nachricht"
|
||||
send_like_message_body: "Zahle an einen @username oder npub und es kommt als Ende-zu-Ende-verschlüsselte Nachricht über nostr und das Nym mixnet an — niemand dazwischen sieht den Betrag oder die Beteiligten."
|
||||
send_like_message_body: "Zahle an einen username oder npub und es kommt als Ende-zu-Ende-verschlüsselte Nachricht über nostr und das Nym mixnet an — niemand dazwischen sieht den Betrag oder die Beteiligten."
|
||||
yours_alone_head: "Nur deins"
|
||||
yours_alone_body: "Schlüssel, Namen und Verlauf bleiben auf diesem Gerät. Basiert auf dem GRIM-Wallet."
|
||||
get_started: "Loslegen"
|
||||
@@ -668,12 +689,12 @@ goblin:
|
||||
fresh_key_blurb: "Ein frischer Schlüssel, für Zahlungen gemacht — bewusst nicht Teil deines Seeds, sodass du ihn jederzeit wechseln kannst, um deine Privatsphäre zu wahren, ohne je dein Guthaben zu berühren. Sichere ihn unter Einstellungen → Identität."
|
||||
clean_slate_blurb: "Lust auf einen Neuanfang? Tausche jederzeit einen brandneuen Schlüssel ein — das neue Du ist nicht mit dem alten verknüpft. Gleiches Wallet, frisches Gesicht."
|
||||
pick_username: "Benutzernamen wählen — optional"
|
||||
username_blurb: "Freunde zahlen an @you statt an einen langen Schlüssel. Öffentlich auf goblin.st; Zahlungen bleiben verschlüsselt. Überspringe es und du bist einfach anonym — sichere jederzeit später einen."
|
||||
username_blurb: "Freunde zahlen an you statt an einen langen Schlüssel. Öffentlich auf goblin.st; Zahlungen bleiben verschlüsselt. Überspringe es und du bist einfach anonym — sichere jederzeit später einen."
|
||||
username_field_hint: "deinname"
|
||||
working: "Arbeite…"
|
||||
claim_username: "Benutzernamen sichern"
|
||||
available_when_connected: "Verfügbar, sobald das mixnet verbindet — oder überspringen und später sichern."
|
||||
youre: "Du bist @%{name}"
|
||||
youre: "Du bist %{name}"
|
||||
open_wallet: "Mein Wallet öffnen"
|
||||
skip_for_now: "Vorerst überspringen"
|
||||
errors:
|
||||
@@ -686,9 +707,9 @@ goblin:
|
||||
tab_my_code: "Mein Code"
|
||||
request_from: "Anfordern von"
|
||||
send_to: "Senden an"
|
||||
search_hint: "@handle, npub oder Name"
|
||||
search_hint: "handle, npub oder Name"
|
||||
suggested: "%{icon} Vorgeschlagen"
|
||||
no_contacts: "Noch keine Kontakte. Finde jemanden über seinen @handle."
|
||||
no_contacts: "Noch keine Kontakte. Finde jemanden über seinen handle."
|
||||
no_profile: "kein Profil"
|
||||
tag_contact: "Kontakt"
|
||||
tag_on_nostr: "auf nostr"
|
||||
@@ -697,13 +718,13 @@ goblin:
|
||||
unverified_body: "Für diesen Schlüssel ist kein nostr-Profil veröffentlicht — er könnte brandneu, anonym oder vertippt sein. Prüfe genau, ob es der richtige ist, bevor du sendest."
|
||||
keep_looking: "Weitersuchen"
|
||||
pay_anyway: "Trotzdem zahlen"
|
||||
scan_not_recipient: "Dieser QR ist kein goblin-Empfänger — erwartet wurde ein npub oder @handle"
|
||||
scan_not_recipient: "Dieser QR ist kein goblin-Empfänger — erwartet wurde ein npub oder handle"
|
||||
scan_prompt: "Halte einen goblin-Code ins Bild, um zu aktivieren"
|
||||
scan_to_pay_me: "Scannen, um mich zu bezahlen"
|
||||
share_btn: "%{icon} Teilen"
|
||||
share_message: "Bezahl mich auf Goblin — %{handle}\n%{link}\nnpub: %{npub}"
|
||||
none_found: "Niemand gefunden für %{label}"
|
||||
enter_recipient: "Gib einen @handle, npub oder Namen ein"
|
||||
enter_recipient: "Gib einen handle, npub oder Namen ein"
|
||||
amount_title: "Betrag"
|
||||
to_name: "An %{name}"
|
||||
not_enough: "Du hast nicht genug grin"
|
||||
|
||||
+35
-14
@@ -458,6 +458,8 @@ goblin:
|
||||
slatepacks: "Slatepacks"
|
||||
slatepacks_value: "Manual transaction"
|
||||
lock_wallet: "Lock wallet"
|
||||
switch_wallet: "Switch wallet"
|
||||
advanced: "Advanced"
|
||||
privacy: "Privacy"
|
||||
mixnet_routing: "Mixnet routing"
|
||||
messages_lookups: "Messages & lookups"
|
||||
@@ -485,7 +487,7 @@ goblin:
|
||||
third_party: "Third party"
|
||||
grim: "GRIM (upstream wallet)"
|
||||
grin_node: "Grin node"
|
||||
sp_intro: "Advanced — exchange raw slatepacks by hand, the way GRIM does. Use this only when you can't pay or get paid through a @username."
|
||||
sp_intro: "Advanced — exchange raw slatepacks by hand, the way GRIM does. Use this only when you can't pay or get paid through a username."
|
||||
sp_receive_group: "Receive or finalize"
|
||||
sp_receive_blurb: "Paste a slatepack someone gave you. Goblin receives the payment, pays the invoice, or finalizes and posts it."
|
||||
sp_process: "Process slatepack"
|
||||
@@ -503,9 +505,9 @@ goblin:
|
||||
sp_copy: "Copy slatepack"
|
||||
rotate_line1: "• You get a brand-new RANDOM key; the old npub stops receiving. There is no derivation chain between them."
|
||||
rotate_line2: "• The new key is NOT recoverable from your seed — back up the new nsec right after rotating."
|
||||
rotate_line3: "• Your @username is RELEASED and your profile picture deleted — claim the same or a new name right after (anyone else can grab it too once it's free)."
|
||||
rotate_line3: "• Your username is RELEASED and your profile picture deleted — claim the same or a new name right after (anyone else can grab it too once it's free)."
|
||||
rotate_line4: "• Payments still in flight to the old key WILL be disrupted — wait for pending payments to finish first."
|
||||
rotate_line5: "• Contacts who saved your npub directly must re-find you — share your new npub or re-claimed @username."
|
||||
rotate_line5: "• Contacts who saved your npub directly must re-find you — share your new npub or re-claimed username."
|
||||
cancel: "Cancel"
|
||||
continue: "Continue"
|
||||
final_confirmation: "Final confirmation"
|
||||
@@ -532,13 +534,13 @@ goblin:
|
||||
import_failed: "Import failed"
|
||||
registered: "Registered %{name}"
|
||||
released_msg: "Released — the name is up for grabs"
|
||||
release_confirm: "Release @%{name}?"
|
||||
release_confirm: "Release %{name}?"
|
||||
release_blurb: "It's up for grabs the moment it's free — anyone can claim it, including the next key you rotate to. Your profile picture is deleted with it. You won't be able to register another username for 10 minutes."
|
||||
releasing: "Releasing…"
|
||||
keep_it: "Keep it"
|
||||
release_it: "Release it"
|
||||
username: "Username"
|
||||
username_note: "Shown as @you. Public on goblin.st. Payments stay encrypted."
|
||||
username_note: "Shown as you. Public on goblin.st. Payments stay encrypted."
|
||||
release_username: "Release username"
|
||||
pick_username: "Pick a username — optional"
|
||||
working: "Working…"
|
||||
@@ -553,12 +555,31 @@ goblin:
|
||||
avail_invalid: "Names are 3–30 chars: a–z, 0–9, _ or -"
|
||||
avail_quarantined: "Not available"
|
||||
avail_unknown: "Couldn't check — connection hiccup. Try again."
|
||||
advanced:
|
||||
title: "Advanced"
|
||||
intro: "Low-level wallet tools from GRIM. You won't normally need these."
|
||||
repair: "Repair wallet"
|
||||
repair_desc: "Re-scan the chain and restore any missing outputs. This can take a while."
|
||||
repair_unavailable: "Needs a synced node connection first."
|
||||
repairing: "Repairing… %{pct}%"
|
||||
restore: "Restore wallet"
|
||||
restore_desc: "Delete local data and rebuild from your seed. Use this if a repair didn't help — you'll re-open the wallet after."
|
||||
restore_confirm: "Tap again to restore"
|
||||
show_phrase: "Recovery phrase"
|
||||
phrase_desc: "Your 24 grin seed words — the only way to recover funds. Keep them offline and private."
|
||||
reveal: "Show phrase"
|
||||
hide: "Hide"
|
||||
password: "Wallet password"
|
||||
wrong_password: "Wrong password."
|
||||
delete: "Delete wallet"
|
||||
delete_desc: "Permanently remove this wallet from this device. Without your seed, funds can't be recovered."
|
||||
delete_confirm: "Tap again to delete"
|
||||
privacy:
|
||||
title: "Network privacy"
|
||||
intro: "Goblin sends its private traffic through the Nym mixnet — a five-hop network that hides who is talking to whom, so a relay can't link a payment back to you."
|
||||
payments: "Payments"
|
||||
payments_blurb: "Every nostr message carrying a slatepack."
|
||||
usernames: "@usernames"
|
||||
usernames: "usernames"
|
||||
usernames_blurb: "NIP-05 name lookups to and from goblin.st."
|
||||
price_avatars: "Price & avatars"
|
||||
price_avatars_blurb: "The rate preview and contact pictures."
|
||||
@@ -594,9 +615,9 @@ goblin:
|
||||
nips:
|
||||
title: "nostr & NIPs"
|
||||
intro1: "Goblin speaks nostr — an open protocol of signed messages passed through simple relay servers. Your wallet carries its own nostr identity: a standalone random key, kept deliberately independent of your funds and seed. Every payment travels as an end-to-end encrypted direct message between identities, with the slatepack riding inside."
|
||||
intro2: "goblin.st is Goblin's name service: claiming a username publishes a name → key mapping there (NIP-05), so people can pay @you instead of a long npub. The username is public; payment contents never are. NIPs are the protocol's building blocks — tap one to read the spec."
|
||||
intro2: "goblin.st is Goblin's name service: claiming a username publishes a name → key mapping there (NIP-05), so people can pay you instead of a long npub. The username is public; payment contents never are. NIPs are the protocol's building blocks — tap one to read the spec."
|
||||
n05_title: "Names"
|
||||
n05_blurb: "Maps @username@goblin.st to your key, so handles work like addresses."
|
||||
n05_blurb: "Maps username@goblin.st to your key, so handles work like addresses."
|
||||
n17_title: "Private messages"
|
||||
n17_blurb: "The encrypted DM envelope every payment travels in."
|
||||
n44_title: "Encryption"
|
||||
@@ -612,7 +633,7 @@ goblin:
|
||||
private_money_head: "Private money"
|
||||
private_money_body: "Goblin is a wallet for grin — digital cash with no amounts or addresses on its chain."
|
||||
send_like_message_head: "Send like a message"
|
||||
send_like_message_body: "Pay a @username or npub and it arrives as an end-to-end encrypted message over nostr and the Nym mixnet — no one in between can see the amount or who's involved."
|
||||
send_like_message_body: "Pay a username or npub and it arrives as an end-to-end encrypted message over nostr and the Nym mixnet — no one in between can see the amount or who's involved."
|
||||
yours_alone_head: "Yours alone"
|
||||
yours_alone_body: "Keys, names and history live on this device. Built on the GRIM wallet."
|
||||
get_started: "Get started"
|
||||
@@ -668,12 +689,12 @@ goblin:
|
||||
fresh_key_blurb: "A fresh key, made for payments — deliberately not part of your seed, so you can rotate it anytime to maintain your privacy, without ever touching your funds. Back it up in Settings → Identity."
|
||||
clean_slate_blurb: "Want a clean slate? Swap in a brand-new key any time — the new you isn't linked to the old one. Same wallet, fresh face."
|
||||
pick_username: "Pick a username — optional"
|
||||
username_blurb: "Friends pay @you instead of a long key. Public on goblin.st; payments stay encrypted. Skip it and you're simply anonymous — claim one any time later."
|
||||
username_blurb: "Friends pay you instead of a long key. Public on goblin.st; payments stay encrypted. Skip it and you're simply anonymous — claim one any time later."
|
||||
username_field_hint: "yourname"
|
||||
working: "Working…"
|
||||
claim_username: "Claim username"
|
||||
available_when_connected: "Available once the mixnet connects — or skip and claim later."
|
||||
youre: "You're @%{name}"
|
||||
youre: "You're %{name}"
|
||||
open_wallet: "Open my wallet"
|
||||
skip_for_now: "Skip for now"
|
||||
errors:
|
||||
@@ -688,7 +709,7 @@ goblin:
|
||||
send_to: "Send to"
|
||||
search_hint: "handle, npub, or name"
|
||||
suggested: "%{icon} Suggested"
|
||||
no_contacts: "No contacts yet. Find someone by their @handle."
|
||||
no_contacts: "No contacts yet. Find someone by their handle."
|
||||
no_profile: "no profile"
|
||||
tag_contact: "contact"
|
||||
tag_on_nostr: "on nostr"
|
||||
@@ -697,13 +718,13 @@ goblin:
|
||||
unverified_body: "No nostr profile is published for this key — it may be brand new, anonymous, or mistyped. Double-check it's the right one before sending."
|
||||
keep_looking: "Keep looking"
|
||||
pay_anyway: "Pay anyway"
|
||||
scan_not_recipient: "That QR isn't a goblin recipient — expected an npub or @handle"
|
||||
scan_not_recipient: "That QR isn't a goblin recipient — expected an npub or handle"
|
||||
scan_prompt: "Position a goblin code in view to activate"
|
||||
scan_to_pay_me: "Scan to pay me"
|
||||
share_btn: "%{icon} Share"
|
||||
share_message: "Pay me on Goblin — %{handle}\n%{link}\nnpub: %{npub}"
|
||||
none_found: "No one found for %{label}"
|
||||
enter_recipient: "Enter an @handle, npub, or name"
|
||||
enter_recipient: "Enter a handle, npub, or name"
|
||||
amount_title: "Amount"
|
||||
to_name: "To %{name}"
|
||||
not_enough: "You don't have enough grin"
|
||||
|
||||
+36
-15
@@ -458,6 +458,8 @@ goblin:
|
||||
slatepacks: "Slatepacks"
|
||||
slatepacks_value: "Transaction manuelle"
|
||||
lock_wallet: "Verrouiller le portefeuille"
|
||||
switch_wallet: "Changer de portefeuille"
|
||||
advanced: "Avancé"
|
||||
privacy: "Confidentialité"
|
||||
mixnet_routing: "Routage par mixnet"
|
||||
messages_lookups: "Messages et recherches"
|
||||
@@ -485,7 +487,7 @@ goblin:
|
||||
third_party: "Tiers"
|
||||
grim: "GRIM (portefeuille amont)"
|
||||
grin_node: "Nœud grin"
|
||||
sp_intro: "Avancé — échangez des slatepacks bruts à la main, comme le fait GRIM. À utiliser seulement si vous ne pouvez pas payer ou être payé via un @username."
|
||||
sp_intro: "Avancé — échangez des slatepacks bruts à la main, comme le fait GRIM. À utiliser seulement si vous ne pouvez pas payer ou être payé via un username."
|
||||
sp_receive_group: "Recevoir ou finaliser"
|
||||
sp_receive_blurb: "Collez un slatepack qu'on vous a donné. Goblin reçoit le paiement, règle la facture, ou le finalise et le publie."
|
||||
sp_process: "Traiter le slatepack"
|
||||
@@ -503,9 +505,9 @@ goblin:
|
||||
sp_copy: "Copier le slatepack"
|
||||
rotate_line1: "• Vous obtenez une toute nouvelle clé ALÉATOIRE ; l'ancien npub cesse de recevoir. Il n'y a aucune chaîne de dérivation entre eux."
|
||||
rotate_line2: "• La nouvelle clé n'est PAS récupérable depuis votre phrase de récupération — sauvegardez le nouveau nsec juste après le renouvellement."
|
||||
rotate_line3: "• Votre @username est LIBÉRÉ et votre photo de profil supprimée — réservez le même nom ou un nouveau juste après (n'importe qui peut le prendre une fois libre)."
|
||||
rotate_line3: "• Votre username est LIBÉRÉ et votre photo de profil supprimée — réservez le même nom ou un nouveau juste après (n'importe qui peut le prendre une fois libre)."
|
||||
rotate_line4: "• Les paiements encore en cours vers l'ancienne clé SERONT interrompus — attendez d'abord la fin des paiements en attente."
|
||||
rotate_line5: "• Les contacts qui ont enregistré votre npub directement doivent vous retrouver — partagez votre nouveau npub ou votre @username re-réservé."
|
||||
rotate_line5: "• Les contacts qui ont enregistré votre npub directement doivent vous retrouver — partagez votre nouveau npub ou votre username re-réservé."
|
||||
cancel: "Annuler"
|
||||
continue: "Continuer"
|
||||
final_confirmation: "Confirmation finale"
|
||||
@@ -532,13 +534,13 @@ goblin:
|
||||
import_failed: "Échec de l'importation"
|
||||
registered: "%{name} enregistré"
|
||||
released_msg: "Libéré — le nom est disponible"
|
||||
release_confirm: "Libérer @%{name} ?"
|
||||
release_confirm: "Libérer %{name} ?"
|
||||
release_blurb: "Il est disponible dès qu'il est libre — n'importe qui peut le réserver, y compris la prochaine clé vers laquelle vous renouvelez. Votre photo de profil est supprimée avec lui. Vous ne pourrez pas enregistrer un autre nom d'utilisateur pendant 10 minutes."
|
||||
releasing: "Libération…"
|
||||
keep_it: "Le garder"
|
||||
release_it: "Le libérer"
|
||||
username: "Nom d'utilisateur"
|
||||
username_note: "Affiché comme @you. Public sur goblin.st. Les paiements restent chiffrés."
|
||||
username_note: "Affiché comme you. Public sur goblin.st. Les paiements restent chiffrés."
|
||||
release_username: "Libérer le nom d'utilisateur"
|
||||
pick_username: "Choisir un nom d'utilisateur — facultatif"
|
||||
working: "En cours…"
|
||||
@@ -553,12 +555,31 @@ goblin:
|
||||
avail_invalid: "Les noms font 3 à 30 caractères : a–z, 0–9, _ ou -"
|
||||
avail_quarantined: "Indisponible"
|
||||
avail_unknown: "Vérification impossible — souci de connexion. Réessayez."
|
||||
advanced:
|
||||
title: "Avancé"
|
||||
intro: "Outils de portefeuille bas niveau de GRIM. Vous n'en aurez normalement pas besoin."
|
||||
repair: "Réparer le portefeuille"
|
||||
repair_desc: "Re-scanner la chaîne et restaurer les sorties manquantes. Cela peut prendre du temps."
|
||||
repair_unavailable: "Nécessite d'abord une connexion à un nœud synchronisé."
|
||||
repairing: "Réparation… %{pct}%"
|
||||
restore: "Restaurer le portefeuille"
|
||||
restore_desc: "Supprimer les données locales et reconstruire depuis votre seed. À utiliser si une réparation n'a pas aidé — vous rouvrirez le portefeuille ensuite."
|
||||
restore_confirm: "Touchez à nouveau pour restaurer"
|
||||
show_phrase: "Phrase de récupération"
|
||||
phrase_desc: "Vos 24 mots de seed grin — le seul moyen de récupérer les fonds. Gardez-les hors ligne et privés."
|
||||
reveal: "Afficher la phrase"
|
||||
hide: "Masquer"
|
||||
password: "Mot de passe du portefeuille"
|
||||
wrong_password: "Mot de passe incorrect."
|
||||
delete: "Supprimer le portefeuille"
|
||||
delete_desc: "Supprimer définitivement ce portefeuille de cet appareil. Sans votre seed, les fonds sont irrécupérables."
|
||||
delete_confirm: "Touchez à nouveau pour supprimer"
|
||||
privacy:
|
||||
title: "Confidentialité réseau"
|
||||
intro: "Goblin envoie son trafic privé via le mixnet Nym — un réseau à cinq sauts qui masque qui parle à qui, afin qu'un relais ne puisse pas relier un paiement à vous."
|
||||
payments: "Paiements"
|
||||
payments_blurb: "Chaque message nostr transportant un slatepack."
|
||||
usernames: "@usernames"
|
||||
usernames: "usernames"
|
||||
usernames_blurb: "Recherches de noms NIP-05 vers et depuis goblin.st."
|
||||
price_avatars: "Cours et avatars"
|
||||
price_avatars_blurb: "L'aperçu du cours et les photos de contacts."
|
||||
@@ -594,9 +615,9 @@ goblin:
|
||||
nips:
|
||||
title: "nostr et NIP"
|
||||
intro1: "Goblin parle nostr — un protocole ouvert de messages signés transmis via de simples serveurs relais. Votre portefeuille porte sa propre identité nostr : une clé aléatoire autonome, gardée délibérément indépendante de vos fonds et de votre phrase de récupération. Chaque paiement voyage comme un message direct chiffré de bout en bout entre identités, le slatepack à l'intérieur."
|
||||
intro2: "goblin.st est le service de noms de Goblin : réserver un nom d'utilisateur y publie une correspondance nom → clé (NIP-05), pour qu'on puisse payer @you au lieu d'un long npub. Le nom d'utilisateur est public ; le contenu des paiements ne l'est jamais. Les NIP sont les briques du protocole — touchez-en un pour lire la spécification."
|
||||
intro2: "goblin.st est le service de noms de Goblin : réserver un nom d'utilisateur y publie une correspondance nom → clé (NIP-05), pour qu'on puisse payer you au lieu d'un long npub. Le nom d'utilisateur est public ; le contenu des paiements ne l'est jamais. Les NIP sont les briques du protocole — touchez-en un pour lire la spécification."
|
||||
n05_title: "Noms"
|
||||
n05_blurb: "Associe @username@goblin.st à votre clé, pour que les identifiants fonctionnent comme des adresses."
|
||||
n05_blurb: "Associe username@goblin.st à votre clé, pour que les identifiants fonctionnent comme des adresses."
|
||||
n17_title: "Messages privés"
|
||||
n17_blurb: "L'enveloppe de DM chiffré dans laquelle voyage chaque paiement."
|
||||
n44_title: "Chiffrement"
|
||||
@@ -612,7 +633,7 @@ goblin:
|
||||
private_money_head: "Argent privé"
|
||||
private_money_body: "Goblin est un portefeuille pour grin — de l'argent numérique sans montants ni adresses sur sa chaîne."
|
||||
send_like_message_head: "Envoyer comme un message"
|
||||
send_like_message_body: "Payez un @username ou un npub et cela arrive comme un message chiffré de bout en bout via nostr et le mixnet Nym — personne entre les deux ne voit le montant ni les personnes impliquées."
|
||||
send_like_message_body: "Payez un username ou un npub et cela arrive comme un message chiffré de bout en bout via nostr et le mixnet Nym — personne entre les deux ne voit le montant ni les personnes impliquées."
|
||||
yours_alone_head: "À vous seul"
|
||||
yours_alone_body: "Clés, noms et historique vivent sur cet appareil. Construit sur le portefeuille GRIM."
|
||||
get_started: "Commencer"
|
||||
@@ -668,12 +689,12 @@ goblin:
|
||||
fresh_key_blurb: "Une clé neuve, créée pour les paiements — délibérément hors de votre phrase de récupération, pour la renouveler à tout moment et préserver votre confidentialité, sans jamais toucher à vos fonds. Sauvegardez-la dans Réglages → Identité."
|
||||
clean_slate_blurb: "Envie de repartir à zéro ? Remplacez par une toute nouvelle clé à tout moment — le nouveau vous n'est pas lié à l'ancien. Même portefeuille, nouveau visage."
|
||||
pick_username: "Choisir un nom d'utilisateur — facultatif"
|
||||
username_blurb: "Vos amis paient @you au lieu d'une longue clé. Public sur goblin.st ; les paiements restent chiffrés. Passez et vous restez simplement anonyme — réservez-en un à tout moment plus tard."
|
||||
username_blurb: "Vos amis paient you au lieu d'une longue clé. Public sur goblin.st ; les paiements restent chiffrés. Passez et vous restez simplement anonyme — réservez-en un à tout moment plus tard."
|
||||
username_field_hint: "votrenom"
|
||||
working: "En cours…"
|
||||
claim_username: "Réserver le nom d'utilisateur"
|
||||
available_when_connected: "Disponible une fois le mixnet connecté — ou passez et réservez plus tard."
|
||||
youre: "Vous êtes @%{name}"
|
||||
youre: "Vous êtes %{name}"
|
||||
open_wallet: "Ouvrir mon portefeuille"
|
||||
skip_for_now: "Passer pour l'instant"
|
||||
errors:
|
||||
@@ -686,9 +707,9 @@ goblin:
|
||||
tab_my_code: "Mon code"
|
||||
request_from: "Demander à"
|
||||
send_to: "Envoyer à"
|
||||
search_hint: "@handle, npub ou nom"
|
||||
search_hint: "handle, npub ou nom"
|
||||
suggested: "%{icon} Suggéré"
|
||||
no_contacts: "Aucun contact pour l'instant. Trouvez quelqu'un par son @handle."
|
||||
no_contacts: "Aucun contact pour l'instant. Trouvez quelqu'un par son handle."
|
||||
no_profile: "pas de profil"
|
||||
tag_contact: "contact"
|
||||
tag_on_nostr: "sur nostr"
|
||||
@@ -697,13 +718,13 @@ goblin:
|
||||
unverified_body: "Aucun profil nostr n'est publié pour cette clé — elle peut être toute neuve, anonyme ou mal saisie. Vérifiez bien qu'il s'agit de la bonne avant d'envoyer."
|
||||
keep_looking: "Continuer à chercher"
|
||||
pay_anyway: "Payer quand même"
|
||||
scan_not_recipient: "Ce QR n'est pas un destinataire goblin — un npub ou @handle est attendu"
|
||||
scan_not_recipient: "Ce QR n'est pas un destinataire goblin — un npub ou handle est attendu"
|
||||
scan_prompt: "Placez un code goblin dans le champ pour activer"
|
||||
scan_to_pay_me: "Scannez pour me payer"
|
||||
share_btn: "%{icon} Partager"
|
||||
share_message: "Payez-moi sur Goblin — %{handle}\n%{link}\nnpub : %{npub}"
|
||||
none_found: "Personne trouvé pour %{label}"
|
||||
enter_recipient: "Saisissez un @handle, un npub ou un nom"
|
||||
enter_recipient: "Saisissez un handle, un npub ou un nom"
|
||||
amount_title: "Montant"
|
||||
to_name: "À %{name}"
|
||||
not_enough: "Vous n'avez pas assez de grin"
|
||||
|
||||
+36
-15
@@ -458,6 +458,8 @@ goblin:
|
||||
slatepacks: "Slatepacks"
|
||||
slatepacks_value: "Ручная транзакция"
|
||||
lock_wallet: "Заблокировать кошелёк"
|
||||
switch_wallet: "Сменить кошелёк"
|
||||
advanced: "Дополнительно"
|
||||
privacy: "Приватность"
|
||||
mixnet_routing: "Маршрутизация через mixnet"
|
||||
messages_lookups: "Сообщения и поиск"
|
||||
@@ -485,7 +487,7 @@ goblin:
|
||||
third_party: "Сторонние"
|
||||
grim: "GRIM (исходный кошелёк)"
|
||||
grin_node: "Узел Grin"
|
||||
sp_intro: "Для опытных — обмен сырыми slatepacks вручную, как в GRIM. Используйте только если не можете платить или получать через @username."
|
||||
sp_intro: "Для опытных — обмен сырыми slatepacks вручную, как в GRIM. Используйте только если не можете платить или получать через username."
|
||||
sp_receive_group: "Получить или завершить"
|
||||
sp_receive_blurb: "Вставьте slatepack, который вам дали. Goblin получит платёж, оплатит счёт или завершит и опубликует его."
|
||||
sp_process: "Обработать slatepack"
|
||||
@@ -503,9 +505,9 @@ goblin:
|
||||
sp_copy: "Копировать slatepack"
|
||||
rotate_line1: "• Вы получите совершенно новый СЛУЧАЙНЫЙ ключ; старый npub перестанет принимать. Между ними нет цепочки вывода."
|
||||
rotate_line2: "• Новый ключ НЕЛЬЗЯ восстановить из seed — сохраните новый nsec сразу после смены."
|
||||
rotate_line3: "• Ваш @username ОСВОБОЖДАЕТСЯ, а фото профиля удаляется — займите то же или новое имя сразу после (любой другой тоже может его занять, как только оно свободно)."
|
||||
rotate_line3: "• Ваш username ОСВОБОЖДАЕТСЯ, а фото профиля удаляется — займите то же или новое имя сразу после (любой другой тоже может его занять, как только оно свободно)."
|
||||
rotate_line4: "• Платежи, всё ещё идущие к старому ключу, БУДУТ нарушены — сначала дождитесь завершения ожидающих платежей."
|
||||
rotate_line5: "• Контакты, сохранившие ваш npub напрямую, должны найти вас заново — поделитесь новым npub или заново занятым @username."
|
||||
rotate_line5: "• Контакты, сохранившие ваш npub напрямую, должны найти вас заново — поделитесь новым npub или заново занятым username."
|
||||
cancel: "Отмена"
|
||||
continue: "Продолжить"
|
||||
final_confirmation: "Финальное подтверждение"
|
||||
@@ -532,13 +534,13 @@ goblin:
|
||||
import_failed: "Импорт не удался"
|
||||
registered: "Зарегистрировано %{name}"
|
||||
released_msg: "Освобождено — имя свободно для занятия"
|
||||
release_confirm: "Освободить @%{name}?"
|
||||
release_confirm: "Освободить %{name}?"
|
||||
release_blurb: "Имя свободно для занятия сразу после освобождения — любой может его занять, включая следующий ключ, на который вы смените. Фото профиля удаляется вместе с ним. Вы не сможете зарегистрировать другое имя в течение 10 минут."
|
||||
releasing: "Освобождение…"
|
||||
keep_it: "Оставить"
|
||||
release_it: "Освободить"
|
||||
username: "Имя пользователя"
|
||||
username_note: "Показывается как @you. Публично на goblin.st. Платежи остаются зашифрованными."
|
||||
username_note: "Показывается как you. Публично на goblin.st. Платежи остаются зашифрованными."
|
||||
release_username: "Освободить имя"
|
||||
pick_username: "Выберите имя — необязательно"
|
||||
working: "Обработка…"
|
||||
@@ -553,12 +555,31 @@ goblin:
|
||||
avail_invalid: "Имена 3–30 символов: a–z, 0–9, _ или -"
|
||||
avail_quarantined: "Недоступно"
|
||||
avail_unknown: "Не удалось проверить — сбой соединения. Попробуйте снова."
|
||||
advanced:
|
||||
title: "Дополнительно"
|
||||
intro: "Низкоуровневые инструменты кошелька из GRIM. Обычно они вам не нужны."
|
||||
repair: "Починить кошелёк"
|
||||
repair_desc: "Повторно просканировать цепочку и восстановить недостающие выходы. Это может занять время."
|
||||
repair_unavailable: "Сначала нужно синхронизированное подключение к узлу."
|
||||
repairing: "Починка… %{pct}%"
|
||||
restore: "Восстановить кошелёк"
|
||||
restore_desc: "Удалить локальные данные и пересоздать из seed-фразы. Используйте, если починка не помогла — после этого откройте кошелёк заново."
|
||||
restore_confirm: "Нажмите ещё раз для восстановления"
|
||||
show_phrase: "Фраза восстановления"
|
||||
phrase_desc: "Ваши 24 seed-слова grin — единственный способ восстановить средства. Храните их офлайн и в тайне."
|
||||
reveal: "Показать фразу"
|
||||
hide: "Скрыть"
|
||||
password: "Пароль кошелька"
|
||||
wrong_password: "Неверный пароль."
|
||||
delete: "Удалить кошелёк"
|
||||
delete_desc: "Безвозвратно удалить этот кошелёк с этого устройства. Без seed-фразы средства не восстановить."
|
||||
delete_confirm: "Нажмите ещё раз для удаления"
|
||||
privacy:
|
||||
title: "Сетевая приватность"
|
||||
intro: "Goblin отправляет приватный трафик через mixnet Nym — сеть из пяти переходов, скрывающую, кто с кем общается, чтобы реле не могло связать платёж с вами."
|
||||
payments: "Платежи"
|
||||
payments_blurb: "Каждое nostr-сообщение, несущее slatepack."
|
||||
usernames: "@usernames"
|
||||
usernames: "usernames"
|
||||
usernames_blurb: "Поиск имён NIP-05 к и от goblin.st."
|
||||
price_avatars: "Курс и аватары"
|
||||
price_avatars_blurb: "Предпросмотр курса и фото контактов."
|
||||
@@ -594,9 +615,9 @@ goblin:
|
||||
nips:
|
||||
title: "nostr и NIPs"
|
||||
intro1: "Goblin говорит на nostr — открытом протоколе подписанных сообщений, передаваемых через простые реле-серверы. Ваш кошелёк несёт собственную nostr-личность: отдельный случайный ключ, намеренно независимый от ваших средств и seed. Каждый платёж идёт как сквозно зашифрованное личное сообщение между личностями, со slatepack внутри."
|
||||
intro2: "goblin.st — это служба имён Goblin: занятие имени публикует там сопоставление имя → ключ (NIP-05), чтобы вам платили на @you вместо длинного npub. Имя публично; содержимое платежей — никогда. NIPs — это строительные блоки протокола; коснитесь одного, чтобы прочитать спецификацию."
|
||||
intro2: "goblin.st — это служба имён Goblin: занятие имени публикует там сопоставление имя → ключ (NIP-05), чтобы вам платили на you вместо длинного npub. Имя публично; содержимое платежей — никогда. NIPs — это строительные блоки протокола; коснитесь одного, чтобы прочитать спецификацию."
|
||||
n05_title: "Имена"
|
||||
n05_blurb: "Сопоставляет @username@goblin.st с вашим ключом, чтобы имена работали как адреса."
|
||||
n05_blurb: "Сопоставляет username@goblin.st с вашим ключом, чтобы имена работали как адреса."
|
||||
n17_title: "Личные сообщения"
|
||||
n17_blurb: "Зашифрованный конверт DM, в котором идёт каждый платёж."
|
||||
n44_title: "Шифрование"
|
||||
@@ -612,7 +633,7 @@ goblin:
|
||||
private_money_head: "Приватные деньги"
|
||||
private_money_body: "Goblin — кошелёк для grin: цифровая наличность без сумм и адресов в её цепочке."
|
||||
send_like_message_head: "Отправляйте как сообщение"
|
||||
send_like_message_body: "Заплатите на @username или npub, и платёж придёт как сквозно зашифрованное сообщение через nostr и mixnet Nym — никто посередине не увидит сумму или участников."
|
||||
send_like_message_body: "Заплатите на username или npub, и платёж придёт как сквозно зашифрованное сообщение через nostr и mixnet Nym — никто посередине не увидит сумму или участников."
|
||||
yours_alone_head: "Только ваше"
|
||||
yours_alone_body: "Ключи, имена и история живут на этом устройстве. На базе кошелька GRIM."
|
||||
get_started: "Начать"
|
||||
@@ -668,12 +689,12 @@ goblin:
|
||||
fresh_key_blurb: "Новый ключ, созданный для платежей — намеренно не часть вашего seed, поэтому вы можете менять его в любой момент для сохранения приватности, не затрагивая средства. Сохраните его в Настройки → Личность."
|
||||
clean_slate_blurb: "Хотите начать с чистого листа? Подставьте совершенно новый ключ в любой момент — новый вы не связан со старым. Тот же кошелёк, новое лицо."
|
||||
pick_username: "Выберите имя — необязательно"
|
||||
username_blurb: "Друзья платят на @you вместо длинного ключа. Публично на goblin.st; платежи остаются зашифрованными. Пропустите — и вы просто аноним; имя можно занять позже."
|
||||
username_blurb: "Друзья платят на you вместо длинного ключа. Публично на goblin.st; платежи остаются зашифрованными. Пропустите — и вы просто аноним; имя можно занять позже."
|
||||
username_field_hint: "yourname"
|
||||
working: "Обработка…"
|
||||
claim_username: "Занять имя"
|
||||
available_when_connected: "Доступно после подключения mixnet — или пропустите и займите позже."
|
||||
youre: "Вы @%{name}"
|
||||
youre: "Вы %{name}"
|
||||
open_wallet: "Открыть кошелёк"
|
||||
skip_for_now: "Пропустить пока"
|
||||
errors:
|
||||
@@ -686,9 +707,9 @@ goblin:
|
||||
tab_my_code: "Мой код"
|
||||
request_from: "Запросить у"
|
||||
send_to: "Отправить"
|
||||
search_hint: "@handle, npub или имя"
|
||||
search_hint: "handle, npub или имя"
|
||||
suggested: "%{icon} Рекомендуемые"
|
||||
no_contacts: "Пока нет контактов. Найдите кого-то по их @handle."
|
||||
no_contacts: "Пока нет контактов. Найдите кого-то по их handle."
|
||||
no_profile: "нет профиля"
|
||||
tag_contact: "контакт"
|
||||
tag_on_nostr: "в nostr"
|
||||
@@ -697,13 +718,13 @@ goblin:
|
||||
unverified_body: "Для этого ключа не опубликован nostr-профиль — он может быть совсем новым, анонимным или с опечаткой. Дважды проверьте перед отправкой."
|
||||
keep_looking: "Продолжить поиск"
|
||||
pay_anyway: "Всё равно оплатить"
|
||||
scan_not_recipient: "Этот QR — не получатель goblin; ожидался npub или @handle"
|
||||
scan_not_recipient: "Этот QR — не получатель goblin; ожидался npub или handle"
|
||||
scan_prompt: "Наведите на код goblin, чтобы активировать"
|
||||
scan_to_pay_me: "Сканируйте, чтобы заплатить мне"
|
||||
share_btn: "%{icon} Поделиться"
|
||||
share_message: "Заплатите мне в Goblin — %{handle}\n%{link}\nnpub: %{npub}"
|
||||
none_found: "Никого не найдено по %{label}"
|
||||
enter_recipient: "Введите @handle, npub или имя"
|
||||
enter_recipient: "Введите handle, npub или имя"
|
||||
amount_title: "Сумма"
|
||||
to_name: "Кому %{name}"
|
||||
not_enough: "Недостаточно grin"
|
||||
|
||||
+36
-15
@@ -458,6 +458,8 @@ goblin:
|
||||
slatepacks: "Slatepackler"
|
||||
slatepacks_value: "Manuel işlem"
|
||||
lock_wallet: "Cüzdanı kilitle"
|
||||
switch_wallet: "Cüzdan değiştir"
|
||||
advanced: "Gelişmiş"
|
||||
privacy: "Gizlilik"
|
||||
mixnet_routing: "Mixnet yönlendirme"
|
||||
messages_lookups: "Mesajlar ve aramalar"
|
||||
@@ -485,7 +487,7 @@ goblin:
|
||||
third_party: "Üçüncü taraf"
|
||||
grim: "GRIM (üst kaynak cüzdan)"
|
||||
grin_node: "Grin düğümü"
|
||||
sp_intro: "Gelişmiş — GRIM'in yaptığı gibi ham slatepackleri elle değiş tokuş et. Bunu yalnızca bir @username üzerinden ödeme yapamadığında ya da alamadığında kullan."
|
||||
sp_intro: "Gelişmiş — GRIM'in yaptığı gibi ham slatepackleri elle değiş tokuş et. Bunu yalnızca bir username üzerinden ödeme yapamadığında ya da alamadığında kullan."
|
||||
sp_receive_group: "Al ya da tamamla"
|
||||
sp_receive_blurb: "Birinin sana verdiği bir slatepack'i yapıştır. Goblin ödemeyi alır, faturayı öder ya da tamamlayıp zincire gönderir."
|
||||
sp_process: "Slatepack işle"
|
||||
@@ -503,9 +505,9 @@ goblin:
|
||||
sp_copy: "Slatepack kopyala"
|
||||
rotate_line1: "• Tamamen yeni RASTGELE bir anahtar alırsın; eski npub artık almaz. Aralarında türetme zinciri yoktur."
|
||||
rotate_line2: "• Yeni anahtar tohumundan kurtarılamaz — anahtarı değiştirdikten hemen sonra yeni nsec'i yedekle."
|
||||
rotate_line3: "• @username'in BIRAKILIR ve profil fotoğrafın silinir — hemen aynı ya da yeni bir adı al (boştayken başkası da kapabilir)."
|
||||
rotate_line3: "• username'in BIRAKILIR ve profil fotoğrafın silinir — hemen aynı ya da yeni bir adı al (boştayken başkası da kapabilir)."
|
||||
rotate_line4: "• Eski anahtara hâlâ yoldaki ödemeler KESİNTİYE uğrar — önce bekleyen ödemelerin bitmesini bekle."
|
||||
rotate_line5: "• npub'unu doğrudan kaydeden kişiler seni yeniden bulmalı — yeni npub'unu ya da yeniden aldığın @username'i paylaş."
|
||||
rotate_line5: "• npub'unu doğrudan kaydeden kişiler seni yeniden bulmalı — yeni npub'unu ya da yeniden aldığın username'i paylaş."
|
||||
cancel: "İptal"
|
||||
continue: "Devam"
|
||||
final_confirmation: "Son onay"
|
||||
@@ -532,13 +534,13 @@ goblin:
|
||||
import_failed: "İçe aktarma başarısız"
|
||||
registered: "%{name} kaydedildi"
|
||||
released_msg: "Bırakıldı — ad artık alınabilir"
|
||||
release_confirm: "@%{name} bırakılsın mı?"
|
||||
release_confirm: "%{name} bırakılsın mı?"
|
||||
release_blurb: "Boşaldığı an alınabilir — değiştireceğin yeni anahtar dahil herkes kapabilir. Profil fotoğrafın da onunla silinir. 10 dakika boyunca başka kullanıcı adı kaydedemezsin."
|
||||
releasing: "Bırakılıyor…"
|
||||
keep_it: "Vazgeç"
|
||||
release_it: "Bırak"
|
||||
username: "Kullanıcı adı"
|
||||
username_note: "@you olarak gösterilir. goblin.st'de herkese açık. Ödemeler şifreli kalır."
|
||||
username_note: "you olarak gösterilir. goblin.st'de herkese açık. Ödemeler şifreli kalır."
|
||||
release_username: "Kullanıcı adını bırak"
|
||||
pick_username: "Bir kullanıcı adı seç — isteğe bağlı"
|
||||
working: "Çalışıyor…"
|
||||
@@ -553,12 +555,31 @@ goblin:
|
||||
avail_invalid: "Adlar 3–30 karakter: a–z, 0–9, _ ya da -"
|
||||
avail_quarantined: "Müsait değil"
|
||||
avail_unknown: "Kontrol edilemedi — bağlantı sorunu. Tekrar dene."
|
||||
advanced:
|
||||
title: "Gelişmiş"
|
||||
intro: "GRIM'den düşük seviyeli cüzdan araçları. Bunlara normalde ihtiyacın olmaz."
|
||||
repair: "Cüzdanı onar"
|
||||
repair_desc: "Zinciri yeniden tara ve eksik çıktıları geri yükle. Bu biraz zaman alabilir."
|
||||
repair_unavailable: "Önce senkronize bir düğüm bağlantısı gerekir."
|
||||
repairing: "Onarılıyor… %{pct}%"
|
||||
restore: "Cüzdanı geri yükle"
|
||||
restore_desc: "Yerel verileri sil ve tohumundan yeniden oluştur. Onarım işe yaramadıysa bunu kullan — sonra cüzdanı yeniden açarsın."
|
||||
restore_confirm: "Geri yüklemek için tekrar dokun"
|
||||
show_phrase: "Kurtarma ifadesi"
|
||||
phrase_desc: "24 grin tohum kelimen — fonları kurtarmanın tek yolu. Onları çevrimdışı ve gizli tut."
|
||||
reveal: "İfadeyi göster"
|
||||
hide: "Gizle"
|
||||
password: "Cüzdan parolası"
|
||||
wrong_password: "Yanlış parola."
|
||||
delete: "Cüzdanı sil"
|
||||
delete_desc: "Bu cüzdanı bu cihazdan kalıcı olarak kaldır. Tohumun olmadan fonlar kurtarılamaz."
|
||||
delete_confirm: "Silmek için tekrar dokun"
|
||||
privacy:
|
||||
title: "Ağ gizliliği"
|
||||
intro: "Goblin özel trafiğini Nym mixnet üzerinden gönderir — kimin kiminle konuştuğunu gizleyen beş atlamalı bir ağ, böylece bir relay bir ödemeyi sana bağlayamaz."
|
||||
payments: "Ödemeler"
|
||||
payments_blurb: "Slatepack taşıyan her nostr mesajı."
|
||||
usernames: "@usernamelar"
|
||||
usernames: "usernamelar"
|
||||
usernames_blurb: "goblin.st'ye ve oradan NIP-05 ad aramaları."
|
||||
price_avatars: "Fiyat ve avatarlar"
|
||||
price_avatars_blurb: "Kur önizlemesi ve kişi fotoğrafları."
|
||||
@@ -594,9 +615,9 @@ goblin:
|
||||
nips:
|
||||
title: "nostr ve NIPler"
|
||||
intro1: "Goblin nostr konuşur — basit relay sunucuları üzerinden geçen imzalı mesajların açık bir protokolü. Cüzdanın kendi nostr kimliğini taşır: bağımsız rastgele bir anahtar, paran ve tohumundan kasıtlı olarak ayrı tutulur. Her ödeme, slatepack içinde olacak şekilde, kimlikler arasında uçtan uca şifreli bir doğrudan mesaj olarak gider."
|
||||
intro2: "goblin.st, Goblin'in ad servisidir: bir kullanıcı adı almak orada bir ad → anahtar eşlemesi yayımlar (NIP-05), böylece insanlar uzun bir npub yerine @you'ya ödeme yapabilir. Kullanıcı adı herkese açıktır; ödeme içeriği asla değil. NIPler protokolün yapı taşlarıdır — özelliği okumak için birine dokun."
|
||||
intro2: "goblin.st, Goblin'in ad servisidir: bir kullanıcı adı almak orada bir ad → anahtar eşlemesi yayımlar (NIP-05), böylece insanlar uzun bir npub yerine you'ya ödeme yapabilir. Kullanıcı adı herkese açıktır; ödeme içeriği asla değil. NIPler protokolün yapı taşlarıdır — özelliği okumak için birine dokun."
|
||||
n05_title: "Adlar"
|
||||
n05_blurb: "@username@goblin.st'yi anahtarına eşler, böylece kullanıcı adları adres gibi çalışır."
|
||||
n05_blurb: "username@goblin.st'yi anahtarına eşler, böylece kullanıcı adları adres gibi çalışır."
|
||||
n17_title: "Özel mesajlar"
|
||||
n17_blurb: "Her ödemenin içinde gittiği şifreli DM zarfı."
|
||||
n44_title: "Şifreleme"
|
||||
@@ -612,7 +633,7 @@ goblin:
|
||||
private_money_head: "Özel para"
|
||||
private_money_body: "Goblin, grin için bir cüzdan — zincirinde tutar ya da adres bulunmayan dijital nakit."
|
||||
send_like_message_head: "Mesaj gibi gönder"
|
||||
send_like_message_body: "Bir @username ya da npub'a öde, nostr ve Nym mixnet üzerinden uçtan uca şifreli bir mesaj olarak ulaşır — aradaki hiç kimse tutarı ya da kimlerin dahil olduğunu göremez."
|
||||
send_like_message_body: "Bir username ya da npub'a öde, nostr ve Nym mixnet üzerinden uçtan uca şifreli bir mesaj olarak ulaşır — aradaki hiç kimse tutarı ya da kimlerin dahil olduğunu göremez."
|
||||
yours_alone_head: "Yalnızca senin"
|
||||
yours_alone_body: "Anahtarlar, adlar ve geçmiş bu cihazda yaşar. GRIM cüzdanı üzerine kuruludur."
|
||||
get_started: "Başla"
|
||||
@@ -668,12 +689,12 @@ goblin:
|
||||
fresh_key_blurb: "Ödemeler için yapılmış yepyeni bir anahtar — kasıtlı olarak tohumunun parçası değildir, böylece paranıza dokunmadan, gizliliğini korumak için onu istediğin zaman değiştirebilirsin. Ayarlar → Kimlik'ten yedekle."
|
||||
clean_slate_blurb: "Temiz bir sayfa mı istiyorsun? İstediğin zaman yepyeni bir anahtar tak — yeni sen eskisine bağlı değil. Aynı cüzdan, yeni yüz."
|
||||
pick_username: "Bir kullanıcı adı seç — isteğe bağlı"
|
||||
username_blurb: "Arkadaşların uzun bir anahtar yerine @you'ya öder. goblin.st'de herkese açık; ödemeler şifreli kalır. Atla, basitçe anonim olursun — istediğin zaman sonra bir tane alabilirsin."
|
||||
username_blurb: "Arkadaşların uzun bir anahtar yerine you'ya öder. goblin.st'de herkese açık; ödemeler şifreli kalır. Atla, basitçe anonim olursun — istediğin zaman sonra bir tane alabilirsin."
|
||||
username_field_hint: "adınız"
|
||||
working: "Çalışıyor…"
|
||||
claim_username: "Kullanıcı adı al"
|
||||
available_when_connected: "Mixnet bağlandığında müsait — ya da atla ve sonra al."
|
||||
youre: "Sen @%{name}'sin"
|
||||
youre: "Sen %{name}'sin"
|
||||
open_wallet: "Cüzdanımı aç"
|
||||
skip_for_now: "Şimdilik atla"
|
||||
errors:
|
||||
@@ -686,9 +707,9 @@ goblin:
|
||||
tab_my_code: "Kodum"
|
||||
request_from: "Şundan iste"
|
||||
send_to: "Şuna gönder"
|
||||
search_hint: "@handle, npub ya da ad"
|
||||
search_hint: "handle, npub ya da ad"
|
||||
suggested: "%{icon} Önerilen"
|
||||
no_contacts: "Henüz kişi yok. Birini @handle ile bul."
|
||||
no_contacts: "Henüz kişi yok. Birini handle ile bul."
|
||||
no_profile: "profil yok"
|
||||
tag_contact: "kişi"
|
||||
tag_on_nostr: "nostr'da"
|
||||
@@ -697,13 +718,13 @@ goblin:
|
||||
unverified_body: "Bu anahtar için yayımlanmış bir nostr profili yok — yepyeni, anonim ya da yanlış yazılmış olabilir. Göndermeden önce doğru olduğunu iki kez kontrol et."
|
||||
keep_looking: "Aramaya devam et"
|
||||
pay_anyway: "Yine de öde"
|
||||
scan_not_recipient: "O QR bir goblin alıcısı değil — bir npub ya da @handle bekleniyordu"
|
||||
scan_not_recipient: "O QR bir goblin alıcısı değil — bir npub ya da handle bekleniyordu"
|
||||
scan_prompt: "Etkinleştirmek için bir goblin kodunu görüntüye getir"
|
||||
scan_to_pay_me: "Bana ödemek için tara"
|
||||
share_btn: "%{icon} Paylaş"
|
||||
share_message: "Goblin'de bana öde — %{handle}\n%{link}\nnpub: %{npub}"
|
||||
none_found: "%{label} için kimse bulunamadı"
|
||||
enter_recipient: "Bir @handle, npub ya da ad gir"
|
||||
enter_recipient: "Bir handle, npub ya da ad gir"
|
||||
amount_title: "Tutar"
|
||||
to_name: "%{name} için"
|
||||
not_enough: "Yeterli grin yok"
|
||||
|
||||
+36
-15
@@ -458,6 +458,8 @@ goblin:
|
||||
slatepacks: "Slatepack"
|
||||
slatepacks_value: "手动交易"
|
||||
lock_wallet: "锁定钱包"
|
||||
switch_wallet: "切换钱包"
|
||||
advanced: "高级"
|
||||
privacy: "隐私"
|
||||
mixnet_routing: "mixnet 路由"
|
||||
messages_lookups: "消息和查询"
|
||||
@@ -485,7 +487,7 @@ goblin:
|
||||
third_party: "第三方"
|
||||
grim: "GRIM(上游钱包)"
|
||||
grin_node: "Grin 节点"
|
||||
sp_intro: "高级功能 — 像 GRIM 那样手动交换原始 slatepack。仅在无法通过 @username 收付款时使用。"
|
||||
sp_intro: "高级功能 — 像 GRIM 那样手动交换原始 slatepack。仅在无法通过 username 收付款时使用。"
|
||||
sp_receive_group: "接收或确认"
|
||||
sp_receive_blurb: "粘贴别人给你的 slatepack。Goblin 会接收付款、支付账单,或确认并广播到链上。"
|
||||
sp_process: "处理 slatepack"
|
||||
@@ -503,9 +505,9 @@ goblin:
|
||||
sp_copy: "复制 slatepack"
|
||||
rotate_line1: "• 你会得到一个全新的随机密钥;旧 npub 将停止接收。两者之间没有任何派生关系。"
|
||||
rotate_line2: "• 新密钥无法从助记词恢复 — 轮换后请立即备份新的 nsec。"
|
||||
rotate_line3: "• 你的 @username 将被释放,头像也会被删除 — 请立即重新注册同名或新用户名(一旦释放,任何人都可抢注)。"
|
||||
rotate_line3: "• 你的 username 将被释放,头像也会被删除 — 请立即重新注册同名或新用户名(一旦释放,任何人都可抢注)。"
|
||||
rotate_line4: "• 正在发往旧密钥的付款将受影响 — 请先等待待处理付款完成。"
|
||||
rotate_line5: "• 直接保存了你 npub 的联系人需要重新查找你 — 分享你的新 npub 或重新注册的 @username。"
|
||||
rotate_line5: "• 直接保存了你 npub 的联系人需要重新查找你 — 分享你的新 npub 或重新注册的 username。"
|
||||
cancel: "取消"
|
||||
continue: "继续"
|
||||
final_confirmation: "最终确认"
|
||||
@@ -532,13 +534,13 @@ goblin:
|
||||
import_failed: "导入失败"
|
||||
registered: "已注册 %{name}"
|
||||
released_msg: "已释放 — 用户名可被抢注"
|
||||
release_confirm: "释放 @%{name}?"
|
||||
release_confirm: "释放 %{name}?"
|
||||
release_blurb: "释放后立即可被抢注 — 任何人都能注册,包括你下次轮换到的密钥。头像也会一并删除。10 分钟内你无法注册新用户名。"
|
||||
releasing: "正在释放…"
|
||||
keep_it: "保留"
|
||||
release_it: "释放"
|
||||
username: "用户名"
|
||||
username_note: "显示为 @you。在 goblin.st 上公开。付款保持加密。"
|
||||
username_note: "显示为 you。在 goblin.st 上公开。付款保持加密。"
|
||||
release_username: "释放用户名"
|
||||
pick_username: "选择用户名 — 可选"
|
||||
working: "处理中…"
|
||||
@@ -553,12 +555,31 @@ goblin:
|
||||
avail_invalid: "用户名为 3–30 个字符:a–z、0–9、_ 或 -"
|
||||
avail_quarantined: "不可用"
|
||||
avail_unknown: "无法检查 — 连接中断。请重试。"
|
||||
advanced:
|
||||
title: "高级"
|
||||
intro: "来自 GRIM 的底层钱包工具。通常你用不到这些。"
|
||||
repair: "修复钱包"
|
||||
repair_desc: "重新扫描链并恢复任何缺失的输出。这可能需要一些时间。"
|
||||
repair_unavailable: "需要先有已同步的节点连接。"
|
||||
repairing: "修复中… %{pct}%"
|
||||
restore: "恢复钱包"
|
||||
restore_desc: "删除本地数据并从助记词重建。如果修复无效,请使用此功能 — 之后需重新打开钱包。"
|
||||
restore_confirm: "再次点击以恢复"
|
||||
show_phrase: "恢复助记词"
|
||||
phrase_desc: "你的 24 个 grin 助记词 — 恢复资金的唯一方式。请离线且私密保存。"
|
||||
reveal: "显示助记词"
|
||||
hide: "隐藏"
|
||||
password: "钱包密码"
|
||||
wrong_password: "密码错误。"
|
||||
delete: "删除钱包"
|
||||
delete_desc: "从此设备永久移除该钱包。没有助记词,资金将无法找回。"
|
||||
delete_confirm: "再次点击以删除"
|
||||
privacy:
|
||||
title: "网络隐私"
|
||||
intro: "Goblin 通过 Nym mixnet 发送其私密流量 — 这是一个五跳网络,可隐藏通信双方的身份,使中继无法将付款关联到你。"
|
||||
payments: "付款"
|
||||
payments_blurb: "每条携带 slatepack 的 nostr 消息。"
|
||||
usernames: "@用户名"
|
||||
usernames: "用户名"
|
||||
usernames_blurb: "往返 goblin.st 的 NIP-05 名称查询。"
|
||||
price_avatars: "汇率和头像"
|
||||
price_avatars_blurb: "汇率预览和联系人头像。"
|
||||
@@ -594,9 +615,9 @@ goblin:
|
||||
nips:
|
||||
title: "nostr 与 NIPs"
|
||||
intro1: "Goblin 使用 nostr — 一种通过简单中继服务器传递签名消息的开放协议。你的钱包拥有自己的 nostr 身份:一个独立的随机密钥,刻意与你的资金和助记词保持独立。每笔付款都作为身份之间的端到端加密私信传输,slatepack 就包含在其中。"
|
||||
intro2: "goblin.st 是 Goblin 的名称服务:注册用户名会在此发布名称 → 密钥的映射(NIP-05),让人们可以付款给 @you 而不必使用冗长的 npub。用户名是公开的;付款内容则永不公开。NIPs 是该协议的构建模块 — 点击任意一项可阅读规范。"
|
||||
intro2: "goblin.st 是 Goblin 的名称服务:注册用户名会在此发布名称 → 密钥的映射(NIP-05),让人们可以付款给 you 而不必使用冗长的 npub。用户名是公开的;付款内容则永不公开。NIPs 是该协议的构建模块 — 点击任意一项可阅读规范。"
|
||||
n05_title: "名称"
|
||||
n05_blurb: "将 @username@goblin.st 映射到你的密钥,让用户名像地址一样使用。"
|
||||
n05_blurb: "将 username@goblin.st 映射到你的密钥,让用户名像地址一样使用。"
|
||||
n17_title: "私密消息"
|
||||
n17_blurb: "每笔付款传输所用的加密私信信封。"
|
||||
n44_title: "加密"
|
||||
@@ -612,7 +633,7 @@ goblin:
|
||||
private_money_head: "私密货币"
|
||||
private_money_body: "Goblin 是一个 grin 钱包 — 链上无金额、无地址的数字现金。"
|
||||
send_like_message_head: "像发消息一样付款"
|
||||
send_like_message_body: "向 @username 或 npub 付款,款项会作为端到端加密消息通过 nostr 和 Nym mixnet 送达 — 中间任何人都看不到金额或参与者。"
|
||||
send_like_message_body: "向 username 或 npub 付款,款项会作为端到端加密消息通过 nostr 和 Nym mixnet 送达 — 中间任何人都看不到金额或参与者。"
|
||||
yours_alone_head: "完全属于你"
|
||||
yours_alone_body: "密钥、用户名和历史记录都存于本设备。基于 GRIM 钱包构建。"
|
||||
get_started: "开始使用"
|
||||
@@ -668,12 +689,12 @@ goblin:
|
||||
fresh_key_blurb: "一个为付款生成的全新密钥 — 刻意不属于你的助记词,因此你可随时轮换以保护隐私,而不会触及你的资金。请在 设置 → 身份 中备份它。"
|
||||
clean_slate_blurb: "想要全新开始?随时换上一个全新密钥 — 新的你与旧的毫无关联。同一个钱包,焕然一新。"
|
||||
pick_username: "选择用户名 — 可选"
|
||||
username_blurb: "朋友付款给 @you 而非冗长的密钥。在 goblin.st 上公开;付款保持加密。跳过则你只是匿名 — 之后随时可注册。"
|
||||
username_blurb: "朋友付款给 you 而非冗长的密钥。在 goblin.st 上公开;付款保持加密。跳过则你只是匿名 — 之后随时可注册。"
|
||||
username_field_hint: "你的用户名"
|
||||
working: "处理中…"
|
||||
claim_username: "注册用户名"
|
||||
available_when_connected: "mixnet 连接后可用 — 或跳过,稍后注册。"
|
||||
youre: "你是 @%{name}"
|
||||
youre: "你是 %{name}"
|
||||
open_wallet: "打开我的钱包"
|
||||
skip_for_now: "暂时跳过"
|
||||
errors:
|
||||
@@ -686,9 +707,9 @@ goblin:
|
||||
tab_my_code: "我的二维码"
|
||||
request_from: "向谁请求"
|
||||
send_to: "发送给"
|
||||
search_hint: "@handle、npub 或名称"
|
||||
search_hint: "handle、npub 或名称"
|
||||
suggested: "%{icon} 建议"
|
||||
no_contacts: "暂无联系人。通过 @handle 查找某人。"
|
||||
no_contacts: "暂无联系人。通过 handle 查找某人。"
|
||||
no_profile: "无资料"
|
||||
tag_contact: "联系人"
|
||||
tag_on_nostr: "在 nostr 上"
|
||||
@@ -697,13 +718,13 @@ goblin:
|
||||
unverified_body: "此密钥未发布 nostr 资料 — 它可能是全新的、匿名的或输错的。发送前请仔细核对是否正确。"
|
||||
keep_looking: "继续查找"
|
||||
pay_anyway: "仍然付款"
|
||||
scan_not_recipient: "该二维码不是 goblin 收款方 — 应为 npub 或 @handle"
|
||||
scan_not_recipient: "该二维码不是 goblin 收款方 — 应为 npub 或 handle"
|
||||
scan_prompt: "将 goblin 二维码对准取景框以激活"
|
||||
scan_to_pay_me: "扫码向我付款"
|
||||
share_btn: "%{icon} 分享"
|
||||
share_message: "在 Goblin 上向我付款 — %{handle}\n%{link}\nnpub:%{npub}"
|
||||
none_found: "未找到与 %{label} 匹配的人"
|
||||
enter_recipient: "输入 @handle、npub 或名称"
|
||||
enter_recipient: "输入 handle、npub 或名称"
|
||||
amount_title: "金额"
|
||||
to_name: "发送给 %{name}"
|
||||
not_enough: "你的 grin 余额不足"
|
||||
|
||||
+277
-12
@@ -80,6 +80,12 @@ pub struct GoblinWalletView {
|
||||
request_amount: Option<String>,
|
||||
/// Sub-page open inside the Settings tab.
|
||||
settings_page: SettingsPage,
|
||||
/// Inline state for the Advanced settings page (recovery/repair/delete).
|
||||
advanced: AdvancedState,
|
||||
/// One-shot signal to the wallet host: deselect this wallet (return to the
|
||||
/// chooser) without locking it, so another can be picked. Consumed by
|
||||
/// [`WalletContent::take_switch_request`].
|
||||
switch_requested: bool,
|
||||
/// Inputs for adding an external node connection.
|
||||
node_url_input: String,
|
||||
node_secret_input: String,
|
||||
@@ -111,6 +117,23 @@ enum SettingsPage {
|
||||
Pairing,
|
||||
Slatepack,
|
||||
Privacy,
|
||||
Advanced,
|
||||
}
|
||||
|
||||
/// Inline state for the Advanced (wallet-recovery) settings page: the
|
||||
/// recovery-phrase reveal and the two-step confirms for destructive actions.
|
||||
#[derive(Default)]
|
||||
struct AdvancedState {
|
||||
/// Password typed to reveal the grin recovery phrase.
|
||||
reveal_pass: String,
|
||||
/// The revealed seed words, held only while shown (cleared on hide/back).
|
||||
revealed: Option<String>,
|
||||
/// Set when the entered password didn't decrypt the seed.
|
||||
wrong_pass: bool,
|
||||
/// Armed "really restore?" confirm.
|
||||
confirm_restore: bool,
|
||||
/// Armed "really delete?" confirm.
|
||||
confirm_delete: bool,
|
||||
}
|
||||
|
||||
/// Inputs and last result for the manual slatepack page (GRIM's native flow,
|
||||
@@ -148,6 +171,8 @@ impl Default for GoblinWalletView {
|
||||
pay_shake: None,
|
||||
request_amount: None,
|
||||
settings_page: SettingsPage::Main,
|
||||
advanced: AdvancedState::default(),
|
||||
switch_requested: false,
|
||||
node_url_input: String::new(),
|
||||
node_secret_input: String::new(),
|
||||
relay_edit: Vec::new(),
|
||||
@@ -273,6 +298,12 @@ impl GoblinWalletView {
|
||||
self.send.is_some()
|
||||
}
|
||||
|
||||
/// Take the pending "switch wallet" request (set by the Settings button),
|
||||
/// resetting it. The host deselects the wallet when this returns true.
|
||||
pub fn take_switch_request(&mut self) -> bool {
|
||||
std::mem::take(&mut self.switch_requested)
|
||||
}
|
||||
|
||||
/// Handle a back navigation; returns true if not consumed.
|
||||
pub fn on_back(&mut self) -> bool {
|
||||
if self.receipt.is_some() {
|
||||
@@ -319,6 +350,7 @@ impl GoblinWalletView {
|
||||
self.pay_amount.clear();
|
||||
self.request_amount = None;
|
||||
self.settings_page = SettingsPage::Main;
|
||||
self.advanced = AdvancedState::default();
|
||||
}
|
||||
|
||||
// Send flow takes the full surface when active.
|
||||
@@ -1926,6 +1958,7 @@ impl GoblinWalletView {
|
||||
SettingsPage::Pairing => return self.pairing_settings_ui(ui),
|
||||
SettingsPage::Slatepack => return self.slatepack_ui(ui, wallet, cb),
|
||||
SettingsPage::Privacy => return self.privacy_ui(ui),
|
||||
SettingsPage::Advanced => return self.advanced_ui(ui, wallet, cb),
|
||||
SettingsPage::Main => {}
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
@@ -2160,7 +2193,7 @@ impl GoblinWalletView {
|
||||
open_node = true;
|
||||
}
|
||||
// GRIM's native by-hand slatepack exchange, for when a payment
|
||||
// can't go through a @username.
|
||||
// can't go through a username.
|
||||
if settings_row_nav(
|
||||
ui,
|
||||
&t!("goblin.settings.slatepacks"),
|
||||
@@ -2168,13 +2201,6 @@ impl GoblinWalletView {
|
||||
) {
|
||||
open_slatepack = true;
|
||||
}
|
||||
if settings_row_btn(
|
||||
ui,
|
||||
&t!("goblin.settings.lock_wallet"),
|
||||
crate::gui::icons::LOCK,
|
||||
) {
|
||||
wallet.close();
|
||||
}
|
||||
});
|
||||
if open_slatepack {
|
||||
self.slatepack = SlatepackManual::default();
|
||||
@@ -2329,7 +2355,48 @@ impl GoblinWalletView {
|
||||
if open_nips {
|
||||
self.settings_page = SettingsPage::Nips;
|
||||
}
|
||||
ui.add_space(16.0);
|
||||
|
||||
// Wallet management lives at the foot of Settings: a neutral
|
||||
// switch, the red lock, then the advanced (recovery) tools —
|
||||
// each its own outlined action, so the destructive lock reads
|
||||
// apart from the rest.
|
||||
ui.add_space(24.0);
|
||||
let dim = theme::tokens().surface_text_dim;
|
||||
if w::outlined_icon_action(
|
||||
ui,
|
||||
crate::gui::icons::USER_SWITCH,
|
||||
&t!("goblin.settings.switch_wallet"),
|
||||
dim,
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
self.settings_page = SettingsPage::Main;
|
||||
self.switch_requested = true;
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
if w::outlined_icon_action(
|
||||
ui,
|
||||
crate::gui::icons::LOCK,
|
||||
&t!("goblin.settings.lock_wallet"),
|
||||
theme::tokens().neg,
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
wallet.close();
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
if w::outlined_icon_action(
|
||||
ui,
|
||||
crate::gui::icons::WRENCH,
|
||||
&t!("goblin.settings.advanced"),
|
||||
dim,
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
self.advanced = AdvancedState::default();
|
||||
self.settings_page = SettingsPage::Advanced;
|
||||
}
|
||||
ui.add_space(20.0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2464,6 +2531,184 @@ impl GoblinWalletView {
|
||||
});
|
||||
}
|
||||
|
||||
/// Advanced (wallet-recovery) page — GRIM's low-level tools surfaced in the
|
||||
/// goblin style: repair, restore-from-seed, reveal the recovery phrase, and
|
||||
/// delete. The two destructive actions arm a tap-twice confirm.
|
||||
fn advanced_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
use crate::wallet::types::ConnectionMethod;
|
||||
let t = theme::tokens();
|
||||
if self.sub_header(ui, &t!("goblin.advanced.title")) {
|
||||
self.advanced = AdvancedState::default();
|
||||
self.settings_page = SettingsPage::Main;
|
||||
return;
|
||||
}
|
||||
// Repair needs a synced node; mirror GRIM's availability check.
|
||||
let integrated = wallet.get_current_connection() == ConnectionMethod::Integrated;
|
||||
let integrated_ready =
|
||||
crate::node::Node::get_sync_status() == Some(grin_chain::SyncStatus::NoSync);
|
||||
let repair_unavailable = wallet.sync_error() || (integrated && !integrated_ready);
|
||||
let repairing = wallet.is_repairing();
|
||||
let progress = wallet.repairing_progress();
|
||||
let mut leave = false;
|
||||
{
|
||||
let adv = &mut self.advanced;
|
||||
ScrollArea::vertical()
|
||||
.auto_shrink([false; 2])
|
||||
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
|
||||
.show(ui, |ui| {
|
||||
ui.label(
|
||||
RichText::new(t!("goblin.advanced.intro"))
|
||||
.font(FontId::new(14.0, fonts::regular()))
|
||||
.color(t.text_dim),
|
||||
);
|
||||
ui.add_space(16.0);
|
||||
|
||||
// Repair.
|
||||
w::card(ui, |ui| {
|
||||
ui.set_min_width(ui.available_width());
|
||||
advanced_head(ui, &t!("goblin.advanced.repair"), t.surface_text);
|
||||
advanced_desc(ui, &t!("goblin.advanced.repair_desc"));
|
||||
ui.add_space(10.0);
|
||||
if repairing {
|
||||
ui.label(
|
||||
RichText::new(
|
||||
t!("goblin.advanced.repairing", pct => progress.to_string()),
|
||||
)
|
||||
.font(FontId::new(13.0, fonts::medium()))
|
||||
.color(t.accent),
|
||||
);
|
||||
} else if repair_unavailable {
|
||||
ui.label(
|
||||
RichText::new(t!("goblin.advanced.repair_unavailable"))
|
||||
.font(FontId::new(13.0, fonts::medium()))
|
||||
.color(t.neg),
|
||||
);
|
||||
} else if w::big_action_on_card(ui, &t!("goblin.advanced.repair")).clicked()
|
||||
{
|
||||
wallet.repair();
|
||||
}
|
||||
});
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Restore (rebuild local data from the seed).
|
||||
w::card(ui, |ui| {
|
||||
ui.set_min_width(ui.available_width());
|
||||
advanced_head(ui, &t!("goblin.advanced.restore"), t.surface_text);
|
||||
advanced_desc(ui, &t!("goblin.advanced.restore_desc"));
|
||||
ui.add_space(10.0);
|
||||
if adv.confirm_restore {
|
||||
if w::big_action_on_card_ink(
|
||||
ui,
|
||||
&t!("goblin.advanced.restore_confirm"),
|
||||
t.neg,
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
wallet.delete_db();
|
||||
leave = true;
|
||||
}
|
||||
} else if w::big_action_on_card(ui, &t!("goblin.advanced.restore"))
|
||||
.clicked()
|
||||
{
|
||||
adv.confirm_restore = true;
|
||||
}
|
||||
});
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Recovery phrase (the grin seed words).
|
||||
w::card(ui, |ui| {
|
||||
ui.set_min_width(ui.available_width());
|
||||
advanced_head(ui, &t!("goblin.advanced.show_phrase"), t.surface_text);
|
||||
advanced_desc(ui, &t!("goblin.advanced.phrase_desc"));
|
||||
ui.add_space(10.0);
|
||||
if let Some(words) = adv.revealed.clone() {
|
||||
w::field_well(ui, |ui| {
|
||||
ui.label(
|
||||
RichText::new(words)
|
||||
.font(FontId::new(15.0, fonts::medium()))
|
||||
.color(t.surface_text),
|
||||
);
|
||||
});
|
||||
ui.add_space(10.0);
|
||||
if w::big_action_on_card(ui, &t!("goblin.advanced.hide")).clicked() {
|
||||
adv.revealed = None;
|
||||
adv.reveal_pass.clear();
|
||||
}
|
||||
} else {
|
||||
w::field_well(ui, |ui| {
|
||||
TextEdit::new(egui::Id::from("advanced_reveal_pass"))
|
||||
.focus(false)
|
||||
.hint_text(t!("goblin.advanced.password"))
|
||||
.password()
|
||||
.text_color(t.surface_text)
|
||||
.body()
|
||||
.ui(ui, &mut adv.reveal_pass, cb);
|
||||
});
|
||||
if adv.wrong_pass {
|
||||
ui.add_space(6.0);
|
||||
ui.label(
|
||||
RichText::new(t!("goblin.advanced.wrong_password"))
|
||||
.font(FontId::new(13.0, fonts::medium()))
|
||||
.color(t.neg),
|
||||
);
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
ui.add_enabled_ui(!adv.reveal_pass.is_empty(), |ui| {
|
||||
if w::big_action_on_card(ui, &t!("goblin.advanced.reveal"))
|
||||
.clicked()
|
||||
{
|
||||
match wallet.get_recovery(adv.reveal_pass.clone()) {
|
||||
Ok(phrase) => {
|
||||
adv.revealed = Some(phrase.to_string());
|
||||
adv.wrong_pass = false;
|
||||
adv.reveal_pass.clear();
|
||||
}
|
||||
Err(_) => {
|
||||
adv.wrong_pass = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
ui.add_space(12.0);
|
||||
|
||||
// Delete.
|
||||
w::card(ui, |ui| {
|
||||
ui.set_min_width(ui.available_width());
|
||||
advanced_head(ui, &t!("goblin.advanced.delete"), t.neg);
|
||||
advanced_desc(ui, &t!("goblin.advanced.delete_desc"));
|
||||
ui.add_space(10.0);
|
||||
if adv.confirm_delete {
|
||||
if w::big_action_on_card_ink(
|
||||
ui,
|
||||
&t!("goblin.advanced.delete_confirm"),
|
||||
t.neg,
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
wallet.delete_wallet();
|
||||
leave = true;
|
||||
}
|
||||
} else if w::big_action_on_card_ink(
|
||||
ui,
|
||||
&t!("goblin.advanced.delete"),
|
||||
t.neg,
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
adv.confirm_delete = true;
|
||||
}
|
||||
});
|
||||
ui.add_space(20.0);
|
||||
});
|
||||
}
|
||||
if leave {
|
||||
self.advanced = AdvancedState::default();
|
||||
self.settings_page = SettingsPage::Main;
|
||||
}
|
||||
}
|
||||
|
||||
fn node_settings_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) {
|
||||
use crate::wallet::types::ConnectionMethod;
|
||||
use crate::wallet::{ConnectionsConfig, ExternalConnection};
|
||||
@@ -3502,13 +3747,13 @@ impl GoblinWalletView {
|
||||
.color(t.surface_text),
|
||||
);
|
||||
ui.add_space(8.0);
|
||||
// The "@" lives inside the field as the placeholder ("@yourname"),
|
||||
// not as a cramped glyph outside it. A leading "@" the user types is
|
||||
// Placeholder shows the bare handle ("yourname") — we never display
|
||||
// the "@" to users. A leading "@" the user happens to type is still
|
||||
// stripped when the name is read below.
|
||||
let before = claim.input.clone();
|
||||
TextEdit::new(egui::Id::from("settings_claim"))
|
||||
.focus(false)
|
||||
.hint_text("@yourname")
|
||||
.hint_text("yourname")
|
||||
.text_color(t.surface_text)
|
||||
.body()
|
||||
.ui(ui, &mut claim.input, cb);
|
||||
@@ -3712,6 +3957,26 @@ fn settings_group(ui: &mut egui::Ui, title: &str, add: impl FnOnce(&mut egui::Ui
|
||||
w::card(ui, |ui| add(ui));
|
||||
}
|
||||
|
||||
/// Title row for an Advanced-page action card.
|
||||
fn advanced_head(ui: &mut egui::Ui, label: &str, color: Color32) {
|
||||
ui.label(
|
||||
RichText::new(label)
|
||||
.font(FontId::new(15.0, fonts::semibold()))
|
||||
.color(color),
|
||||
);
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
|
||||
/// Wrapped description line under an Advanced-page action title.
|
||||
fn advanced_desc(ui: &mut egui::Ui, text: &str) {
|
||||
let t = theme::tokens();
|
||||
ui.label(
|
||||
RichText::new(text)
|
||||
.font(FontId::new(13.0, fonts::regular()))
|
||||
.color(t.surface_text_dim),
|
||||
);
|
||||
}
|
||||
|
||||
/// A settings row: label + subtitle on the left, an on/off switch on the right.
|
||||
/// Returns `Some(new_value)` on the frame it is toggled.
|
||||
fn settings_row_toggle(ui: &mut egui::Ui, label: &str, sub: &str, on: bool) -> Option<bool> {
|
||||
|
||||
@@ -75,7 +75,9 @@ impl Default for OnboardingContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
step: Step::Intro,
|
||||
integrated: true,
|
||||
// Default to the Instant path (connect to a public node) so a new
|
||||
// user is online immediately, with no chain-sync wait.
|
||||
integrated: false,
|
||||
ext_url: "https://grincoin.org".to_string(),
|
||||
restore: false,
|
||||
name: "Main wallet".to_string(),
|
||||
@@ -293,16 +295,8 @@ impl OnboardingContent {
|
||||
&t!("goblin.onboarding.node.title"),
|
||||
Step::Intro,
|
||||
);
|
||||
if Self::node_card(
|
||||
ui,
|
||||
self.integrated,
|
||||
&t!("goblin.onboarding.node.own_title"),
|
||||
&t!("goblin.onboarding.node.own_badge"),
|
||||
&t!("goblin.onboarding.node.own_body"),
|
||||
) {
|
||||
self.integrated = true;
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
// Instant (connect to a public node) leads — most people want to be
|
||||
// online immediately, with no chain-sync wait.
|
||||
if Self::node_card(
|
||||
ui,
|
||||
!self.integrated,
|
||||
@@ -323,6 +317,16 @@ impl OnboardingContent {
|
||||
.ui(ui, &mut self.ext_url, cb);
|
||||
});
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
if Self::node_card(
|
||||
ui,
|
||||
self.integrated,
|
||||
&t!("goblin.onboarding.node.own_title"),
|
||||
&t!("goblin.onboarding.node.own_badge"),
|
||||
&t!("goblin.onboarding.node.own_body"),
|
||||
) {
|
||||
self.integrated = true;
|
||||
}
|
||||
ui.add_space(8.0);
|
||||
ui.label(
|
||||
RichText::new(t!("goblin.onboarding.node.changeable"))
|
||||
|
||||
@@ -382,6 +382,43 @@ pub fn big_action_on_card_ink(ui: &mut Ui, label: &str, ink: Color32) -> Respons
|
||||
resp
|
||||
}
|
||||
|
||||
/// A full-width outlined action with an icon to the left of its label, bordered
|
||||
/// in a tint of `ink` (so it reads "around the same color" as the text). Used
|
||||
/// for the wallet-management cluster at the foot of Settings — switch / lock /
|
||||
/// advanced — where each action stands on its own rather than in a card.
|
||||
pub fn outlined_icon_action(ui: &mut Ui, icon: &str, label: &str, ink: Color32) -> Response {
|
||||
let desired = Vec2::new(ui.available_width(), 50.0);
|
||||
let (rect, resp) = ui.allocate_exact_size(desired, Sense::click());
|
||||
let border = ink.gamma_multiply(if resp.hovered() { 0.9 } else { 0.55 });
|
||||
let fill = if resp.hovered() {
|
||||
ink.gamma_multiply(0.10)
|
||||
} else {
|
||||
Color32::TRANSPARENT
|
||||
};
|
||||
ui.painter().rect(
|
||||
rect,
|
||||
CornerRadius::same(14),
|
||||
fill,
|
||||
Stroke::new(1.5, border),
|
||||
egui::StrokeKind::Inside,
|
||||
);
|
||||
ui.painter().text(
|
||||
rect.left_center() + Vec2::new(18.0, 0.0),
|
||||
egui::Align2::LEFT_CENTER,
|
||||
icon,
|
||||
FontId::new(18.0, fonts::regular()),
|
||||
ink,
|
||||
);
|
||||
ui.painter().text(
|
||||
rect.left_center() + Vec2::new(46.0, 0.0),
|
||||
egui::Align2::LEFT_CENTER,
|
||||
label,
|
||||
FontId::new(15.0, fonts::semibold()),
|
||||
ink,
|
||||
);
|
||||
resp
|
||||
}
|
||||
|
||||
/// A pill/chip; returns the click response. `active` paints it inverted.
|
||||
pub fn chip(ui: &mut Ui, label: &str, active: bool) -> Response {
|
||||
let t = theme::tokens();
|
||||
|
||||
@@ -28,7 +28,6 @@ pub struct SettingsContent {
|
||||
interface_settings: InterfaceSettingsContent,
|
||||
/// Network communication settings.
|
||||
network_settings: NetworkSettingsContent,
|
||||
// tor_settings: TorSettingsContent,
|
||||
}
|
||||
|
||||
impl Default for SettingsContent {
|
||||
@@ -36,7 +35,6 @@ impl Default for SettingsContent {
|
||||
Self {
|
||||
interface_settings: InterfaceSettingsContent::default(),
|
||||
network_settings: NetworkSettingsContent::default(),
|
||||
//tor_settings: TorSettingsContent::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,21 +108,5 @@ impl SettingsContent {
|
||||
}
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Do not show Tor settings on Android.
|
||||
// let os = OperatingSystem::from_target_os();
|
||||
// let show_tor = os != OperatingSystem::Android;
|
||||
// if show_tor {
|
||||
// View::horizontal_line(ui, Colors::stroke());
|
||||
// ui.add_space(6.0);
|
||||
//
|
||||
// View::sub_title(ui, format!("{} {}", CIRCLE_HALF, t!("transport.tor_network")));
|
||||
// View::horizontal_line(ui, Colors::stroke());
|
||||
// ui.add_space(6.0);
|
||||
//
|
||||
// // Show Tor settings.
|
||||
// self.tor_settings.ui(ui, cb);
|
||||
// ui.add_space(8.0);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{
|
||||
ARROW_LEFT, BOOKMARKS, CALENDAR_CHECK, CLOUD_ARROW_DOWN, COMPUTER_TOWER, GEAR, GEAR_FINE,
|
||||
GLOBE, GLOBE_SIMPLE, LOCK_KEY, NOTEPAD, PLUS, SIDEBAR_SIMPLE, SUITCASE,
|
||||
GLOBE_SIMPLE, LOCK_KEY, NOTEPAD, PLUS, SIDEBAR_SIMPLE, SUITCASE,
|
||||
};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::goblin::onboarding::OnboardingContent;
|
||||
@@ -210,11 +210,12 @@ 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,
|
||||
// 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 {
|
||||
// Show the title panel everywhere except the full-bleed Goblin wallet
|
||||
// surface and onboarding (which carry their own headers). The wallet
|
||||
// list keeps GRIM's title bar — it puts the app-settings gear within
|
||||
// reach at the top-right and gives the list a proper header, painted in
|
||||
// the Pay-screen accent yellow.
|
||||
if !showing_wallet && !onboarding_active {
|
||||
self.title_ui(ui, dual_panel, cb);
|
||||
}
|
||||
|
||||
@@ -236,6 +237,13 @@ impl ContentContainer for WalletsContent {
|
||||
}
|
||||
});
|
||||
|
||||
// "Switch wallet" in the goblin settings asks to return to the chooser
|
||||
// without locking the current wallet (it stays open, so re-picking it is
|
||||
// instant). Locking is a separate, explicit action.
|
||||
if self.wallet_content.take_switch_request() {
|
||||
self.wallets.select(None);
|
||||
}
|
||||
|
||||
// Show wallet list tabs.
|
||||
let side_padding = View::TAB_ITEMS_PADDING + if View::is_desktop() { 0.0 } else { 4.0 };
|
||||
let tabs_margin = Margin {
|
||||
@@ -552,10 +560,6 @@ impl WalletsContent {
|
||||
View::title_button_big(ui, list_icon, |_| {
|
||||
AppConfig::toggle_show_wallets_at_dual_panel();
|
||||
});
|
||||
} else if !Content::is_dual_panel_mode(ui.ctx()) {
|
||||
View::title_button_big(ui, GLOBE, |_| {
|
||||
Content::toggle_network_panel();
|
||||
});
|
||||
}
|
||||
},
|
||||
|ui| {
|
||||
@@ -574,35 +578,6 @@ impl WalletsContent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Slim header for the wallet-list surface: just the app-settings gear,
|
||||
/// right-aligned. The integrated node moved into the gear's settings — out
|
||||
/// of the list, every node feature still intact.
|
||||
fn wallet_list_header_ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
// 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()
|
||||
@@ -611,11 +586,8 @@ 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);
|
||||
// The app-settings gear now lives in the restored title bar
|
||||
// above; the list starts straight into the app logo.
|
||||
ui.add_space(8.0);
|
||||
|
||||
// Show application logo and name.
|
||||
|
||||
@@ -310,6 +310,12 @@ impl WalletContent {
|
||||
self.goblin.overlay_active() || self.account_content.can_back()
|
||||
}
|
||||
|
||||
/// Take the pending "switch wallet" request from the goblin settings, so the
|
||||
/// host can deselect this wallet (return to the chooser) without locking it.
|
||||
pub fn take_switch_request(&mut self) -> bool {
|
||||
self.goblin.take_switch_request()
|
||||
}
|
||||
|
||||
/// Navigate back on navigation stack. Returns true if not consumed.
|
||||
pub fn back(&mut self, cb: &dyn PlatformCallbacks) -> bool {
|
||||
if self.goblin.overlay_active() {
|
||||
|
||||
@@ -324,7 +324,7 @@ impl SendRequestContent {
|
||||
if self.amount_edit.is_empty() {
|
||||
return;
|
||||
}
|
||||
// Check address to send over Tor if enabled.
|
||||
// Validate the recipient slatepack address.
|
||||
let addr_str = self.address_edit.as_str();
|
||||
if let Ok(r) = SlatepackAddress::try_from(addr_str.trim()) {
|
||||
if let Ok(a) = amount_from_hr_string(self.amount_edit.as_str()) {
|
||||
|
||||
+20
-5
@@ -557,7 +557,13 @@ impl NostrService {
|
||||
/// Ensure a contact entry exists for a sender (auto-added as unknown).
|
||||
fn ensure_contact(&self, sender_hex: &str) {
|
||||
if self.store.contact(sender_hex).is_none() {
|
||||
let hue = u8::from_str_radix(&sender_hex[..2], 16).unwrap_or(0) % 7;
|
||||
// Guard the byte slice: callers pass 64-char hex today, but this is a
|
||||
// general helper and a short/non-ASCII key must not panic.
|
||||
let hue = sender_hex
|
||||
.get(..2)
|
||||
.and_then(|s| u8::from_str_radix(s, 16).ok())
|
||||
.unwrap_or(0)
|
||||
% 7;
|
||||
self.store.save_contact(&Contact {
|
||||
ver: 1,
|
||||
npub: sender_hex.to_string(),
|
||||
@@ -1200,6 +1206,10 @@ async fn handle_wrap(svc: &Arc<NostrService>, wallet: &Wallet, client: &Client,
|
||||
status: RequestStatus::Pending,
|
||||
});
|
||||
svc.has_new_requests.store(true, Ordering::Relaxed);
|
||||
// The request is durably saved — safe to mark this wrap processed.
|
||||
svc.store.mark_processed(&wrap_id);
|
||||
svc.store.mark_processed(&rumor_id);
|
||||
svc.store.mark_processed(&slate_marker);
|
||||
}
|
||||
IngestDecision::FinalizePost => match wallet.nostr_finalize_post(&slate) {
|
||||
Ok(()) => {
|
||||
@@ -1224,12 +1234,17 @@ async fn handle_wrap(svc: &Arc<NostrService>, wallet: &Wallet, client: &Client,
|
||||
},
|
||||
IngestDecision::Drop(reason) => {
|
||||
info!("nostr: dropped slate {}: {}", slate.id, reason);
|
||||
// A dropped slate is a permanent decision — don't re-evaluate it.
|
||||
svc.store.mark_processed(&wrap_id);
|
||||
svc.store.mark_processed(&rumor_id);
|
||||
svc.store.mark_processed(&slate_marker);
|
||||
}
|
||||
}
|
||||
|
||||
svc.store.mark_processed(&wrap_id);
|
||||
svc.store.mark_processed(&rumor_id);
|
||||
svc.store.mark_processed(&slate_marker);
|
||||
// NOTE: AutoReceive and FinalizePost mark the wrap processed only inside their
|
||||
// success arms. On a transient failure they deliberately leave it UNMARKED so
|
||||
// the next catch-up fetch retries — otherwise an incoming payment could be
|
||||
// silently lost on a momentary wallet/node hiccup. decide() + grin's
|
||||
// already-received / re-post guards keep a retried success idempotent.
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -39,19 +39,27 @@ pub struct ExternalConnection {
|
||||
}
|
||||
|
||||
/// Default external node URLs for main network. grincoin.org leads (main.gri.mw
|
||||
/// has intermittent issues); main.us-ea.st is the Goblin-run node.
|
||||
const DEFAULT_MAIN_URLS: [&'static str; 4] = [
|
||||
/// has intermittent issues); main.us-ea.st is the Goblin-run node. The rest are
|
||||
/// independent public nodes (healthy on grin.fail) so a single operator going
|
||||
/// down never strands the wallet.
|
||||
const DEFAULT_MAIN_URLS: [&'static str; 6] = [
|
||||
"https://grincoin.org",
|
||||
"https://main.us-ea.st",
|
||||
"https://main.gri.mw",
|
||||
"https://mainnet.grinffindor.org",
|
||||
"https://api.grin.money",
|
||||
"https://main.grin.raubritter.org",
|
||||
];
|
||||
|
||||
/// Default external node URL for main network.
|
||||
const DEFAULT_TEST_URLS: [&'static str; 3] = [
|
||||
/// Default external node URLs for the test network — the testnet counterparts of
|
||||
/// the same public operators, so testers get the same redundancy.
|
||||
const DEFAULT_TEST_URLS: [&'static str; 6] = [
|
||||
"https://test.gri.mw",
|
||||
"https://testnet.grincoin.org",
|
||||
"https://testnet.grinffindor.org",
|
||||
"https://test.us-ea.st",
|
||||
"https://test.grin.raubritter.org",
|
||||
"https://testapi.grin.money",
|
||||
];
|
||||
|
||||
impl ExternalConnection {
|
||||
|
||||
+14
-2
@@ -472,7 +472,7 @@ impl Wallet {
|
||||
/// Rotate the nostr identity to a brand-new RANDOM key (no derivation
|
||||
/// chain: a future seed compromise cannot reach it, and the old key
|
||||
/// shares nothing with it), atomically moving the registered username
|
||||
/// (if any) to the new key via the name server. Blocking (Tor HTTP):
|
||||
/// (if any) to the new key via the name server. Blocking (network I/O):
|
||||
/// call from a worker thread. Returns the new bech32 npub.
|
||||
pub fn rotate_nostr_identity(&self, password: String) -> Result<String, String> {
|
||||
let svc = self
|
||||
@@ -1265,7 +1265,19 @@ impl Wallet {
|
||||
let tx = self
|
||||
.retrieve_tx_by_id(None, Some(slate.id))
|
||||
.ok_or_else(|| Error::GenericError("transaction not found".to_string()))?;
|
||||
let finalized = self.finalize(slate, tx.id)?;
|
||||
// A prior attempt may have finalized but then failed to post (a transient
|
||||
// node outage). Re-finalizing errors on the already-finalized tx, so when
|
||||
// the finalized (Standard3) slatepack is already on disk we parse and
|
||||
// re-post it instead of finalizing again — a post failure then recovers on
|
||||
// the next retry rather than getting permanently stuck.
|
||||
let finalized = match self.read_slatepack_text(slate.id, &SlateState::Standard3) {
|
||||
Some(text) => {
|
||||
self.parse_slatepack(&text)
|
||||
.map_err(|e| Error::GenericError(format!("reload finalized slate: {e}")))?
|
||||
.0
|
||||
}
|
||||
None => self.finalize(slate, tx.id)?,
|
||||
};
|
||||
self.post(&finalized, Some(tx.id))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user