feat(send): usable-while-syncing form, calmer validation, honest clear/memo/source

Send-tab UX pass (presentation/validation only — the z_sendmany submit path, its
amounts, fee, recipients and memo bytes are unchanged, and the Review button plus
the confirm-time live re-check still block any send until the wallet is synced):
- The form is now editable while syncing (so the recipient/amount/memo can be
  pre-filled); only Review/Send stays gated, with an "available once synced" note.
- The recipient's red "Invalid address" no longer flashes from the first
  keystroke — it waits until the field loses focus.
- The memo field stays visible (text preserved) with a "requires a shielded
  recipient" explainer for transparent recipients, instead of vanishing + silently
  dropping what was typed.
- "Cancel" (which only cleared the form) is relabeled "Clear form", disabled when
  empty, and drops its redundant confirm (the timed Undo already covers it).
- The source picker shows address labels, and warns when the chosen source is
  transparent (non-private on this chain).

Also adds the string keys used here and by the next commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 22:50:30 -05:00
co-authored by Claude Opus 4.8
parent ee6e99965c
commit f2d9590058
2 changed files with 74 additions and 45 deletions
+8
View File
@@ -1151,6 +1151,8 @@ void I18n::loadBuiltinEnglish()
strings_["recent_sends"] = "RECENT SENDS";
strings_["recipient"] = "RECIPIENT";
strings_["memo_optional"] = "MEMO (OPTIONAL)";
strings_["send_memo_requires_shielded"] = "Memos require a shielded (z) recipient address.";
strings_["send_memo_will_not_be_sent"] = "This memo will not be sent: memos only work with shielded (z) recipients.";
strings_["no_recent_sends"] = "No recent sends";
strings_["network_fee"] = "NETWORK FEE";
strings_["amount_details"] = "AMOUNT DETAILS";
@@ -2575,6 +2577,8 @@ void I18n::loadBuiltinEnglish()
strings_["request_payment_uri"] = "Payment URI:";
strings_["request_receive_address"] = "Receive Address:";
strings_["request_select_address"] = "Select address...";
strings_["request_no_shielded"] = "You don't have a shielded address yet. Create one to receive payments.";
strings_["request_create_shielded"] = "Create a shielded address";
strings_["request_shielded_addrs"] = "-- Shielded Addresses --";
strings_["request_title"] = "Request Payment";
strings_["request_uri_copied"] = "Payment URI copied to clipboard";
@@ -2584,6 +2588,8 @@ void I18n::loadBuiltinEnglish()
strings_["send_amount_details"] = "AMOUNT DETAILS";
strings_["send_amount_upper"] = "AMOUNT";
strings_["send_clear_fields"] = "Clear all form fields?";
strings_["send_clear_form"] = "Clear form";
strings_["send_clear_form_tip"] = "Clear the recipient, amount and memo. You can undo for a few seconds.";
strings_["send_copy_error"] = "Copy Error";
strings_["send_dismiss"] = "Dismiss";
strings_["send_error_copied"] = "Error copied to clipboard";
@@ -2600,6 +2606,7 @@ void I18n::loadBuiltinEnglish()
strings_["send_network_fee_label"] = "Network fee:";
strings_["send_total_label"] = "Total:";
strings_["send_no_balance"] = "No balance";
strings_["send_transparent_source_warn"] = "Sending from a transparent address is not private: the sender, amount and recipient are visible on-chain. Use a shielded (Z) address for privacy.";
strings_["send_no_recent"] = "No recent sends";
strings_["send_recent_sends"] = "RECENT SENDS";
strings_["send_recipient"] = "RECIPIENT";
@@ -2615,6 +2622,7 @@ void I18n::loadBuiltinEnglish()
strings_["send_tooltip_not_connected"] = "Not connected to daemon";
strings_["send_tooltip_select_source"] = "Select a source address first";
strings_["send_tooltip_syncing"] = "Wait for blockchain to sync";
strings_["send_available_when_synced"] = "You can fill in the details now. Sending is available once the wallet is fully synced.";
strings_["send_tooltip_view_only"] = "View-only address — no spending key, cannot send";
strings_["send_total"] = "Total";
strings_["send_tx_failed"] = "Transaction failed";