diff --git a/src/gui/views/input/edit.rs b/src/gui/views/input/edit.rs index f2c0619..9e949c2 100644 --- a/src/gui/views/input/edit.rs +++ b/src/gui/views/input/edit.rs @@ -78,7 +78,13 @@ impl TextEdit { scan_pressed: false, enter_pressed: false, numeric: false, - no_soft_keyboard: is_android(), + // Goblin uses each platform's NATIVE input everywhere: the Android + // soft keyboard via JNI on Android, the physical keyboard on desktop. + // Upstream Grim only suppresses its own on-screen keyboard on Android + // (`is_android()`) and pops it on desktop — which looked out of place + // in Goblin's wallet flows and competed with physical typing. Suppress + // it on every platform; native text entry still works. + no_soft_keyboard: true, hint: None, text_color: None, body_font: false, diff --git a/src/nostr/client.rs b/src/nostr/client.rs index 2c0519e..c114cb4 100644 --- a/src/nostr/client.rs +++ b/src/nostr/client.rs @@ -517,6 +517,24 @@ async fn run_service(svc: Arc, wallet: Wallet) { warn!("nostr: add relay {relay} failed: {e}"); } } + // Wait for the bundled Nym sidecar to be listening before dialing relays. + // `warm_up()` starts it at launch, but a fast wallet-open can beat the cold + // mixnet bootstrap — and dialing relays before :1080 is up makes every relay + // fail and drop into nostr-sdk's (backing-off) reconnect, so the wallet sits + // on "Connecting…" long after the mixnet is actually ready. Once the sidecar + // is warm this returns immediately. + for i in 0..60u32 { + if nym_socks_ready().await { + if i > 0 { + info!( + "nostr: Nym sidecar ready after ~{}ms, dialing relays", + i * 500 + ); + } + break; + } + tokio::time::sleep(Duration::from_millis(500)).await; + } client.connect().await; { let mut w_client = svc.client.write(); @@ -612,6 +630,19 @@ async fn run_service(svc: Arc, wallet: Wallet) { client.disconnect().await; } +/// Quick, non-blocking check that the Nym SOCKS5 sidecar is accepting +/// connections on its loopback port (i.e. the mixnet is ready to carry traffic). +async fn nym_socks_ready() -> bool { + matches!( + tokio::time::timeout( + Duration::from_millis(500), + tokio::net::TcpStream::connect(crate::nym::socks5_addr()), + ) + .await, + Ok(Ok(_)) + ) +} + /// True when at least one relay has completed its handshake. async fn relays_connected(client: &Client) -> bool { client