The fiat subline now fetches the CURRENT rate over Tor only while the
balance is actually on screen, and never paints a stale number as if it
were live. No disk cache, no background timer: an idle or payment-
listening wallet never polls (battery).
- price.rs: in-session rate held for a 3-minute freshness window; viewing
a stale/missing rate kicks a live refetch. New RateState (Fresh/Loading/
Unavailable) replaces the Option<f64>; failures are tracked so the line
says "unavailable" instead of spinning or showing an old value. Removed
the disk seed and the persisted-rate write.
- config.rs: dropped the dead last_rate/last_rate_vs/last_rate_at fields
and their read/write paths. Old configs still load (serde ignores the
unknown keys); the fields are simply not written back.
- lib.rs: dropped the cold-start seed_from_disk call.
- GUI: balance hero fiat line renders a subtle "≈ …" while loading and a
localized "rate unavailable" on failure, requesting a bounded repaint
while a fetch is pending so the rate pops in on-screen. Pay/send amount
preview shows nothing until a fresh rate lands.
- New goblin.home.fiat_unavailable string across all six locales.
- Tests: freshness-window bounds, is_fresh boundary, classify state
machine (fresh/loading/unavailable), and config compat for the removed
fields.
Cold connect gets a fast path: the last-known-good entry gateway and IPR
are persisted (choices only, keys stay ephemeral) and tried first on the
next launch - measured 4.4s to tunnel-ready vs 5.6s cold, and no dead-
random-gateway lottery. Cached hints self-clear on failure and fall back
to auto-select.
The price appears instantly: the last fetched rate (under 48h) paints on
the first frame and a live fetch fires the moment the tunnel is ready
instead of waiting for the balance screen. The eager fetch doubles as an
end-to-end probe: if the first reads all fail while the tunnel claims
ready, the exit is condemned and reselected in seconds instead of
minutes. warm_up now runs first at startup.
Money path (streamexit.rs, transport.rs) untouched; ponytail sweep
verified all fallback paths and gates green.
- Lower-left sidebar cards are now individual shortcuts: tapping the
identity chip opens identity settings, tapping the node card jumps
straight to the Node menu (was: both opened generic settings).
- Pay screen gains a scan-to-pay QR puck top-right that opens the camera
and prefills the recipient while keeping the typed amount (reuses the
Home scan + SendFlow::request_scan/prefill_amount path).
- Replace the USD-only "fiat preview" with a configurable "Pairing":
Off / USD / EUR / GBP / JPY / CNY / Bitcoin / Sats (default USD). price.rs
now fetches GRIN against any vs_currency (sats price vs btc, ×1e8) and
caches per code; a Settings → Pairing sub-page picks it; the Pay, send,
and balance previews all route through one pairing_preview() helper.
- Hide the Yellow theme from the picker (cycle is Dark ↔ Light now); the
ThemeKind::Yellow tokens stay defined — it's beta, not removed.
Verified live on :2 (Default wallet): node card → Node menu; identity chip
→ identity settings; QR puck renders top-right of Pay; Pairing → Sats shows
"≈ 1,912 sats" for 50ツ over a live BTC rate, resets to USD; theme cycles
Dark↔Light, never Yellow. 34 lib tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New src/gui/views/goblin/ module rendered as the primary surface for an open
wallet: bottom tab bar (Wallet/Activity/Scan/Me), balance hero in ツ, Send/
Receive, recent peers, activity feed (wallet txs joined with nostr metadata
by slate id), pending payment requests with approve/decline, receive screen
with nostr-handle QR, settings/Me tab. Full send flow (recipient resolve via
npub/NIP-05 over Tor -> numpad amount -> review -> hold-to-send -> success)
dispatching WalletTask::NostrSend. Widgets library, fiat preview over Tor.
Fixed a font-binding panic: weight families are referenced only at widget
call sites, not in default text styles (set_fonts applies a pass later).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>