feat(chat): explain the no-identity state and why a send is stuck

- Chat tab no longer shows "Unlock your wallet" for every missing-identity
  case. A new App::chatIdentityStatus() distinguishes Locked (real),
  Preparing (unlocked, deriving the identity) and Unavailable (view-only or a
  legacy wallet with no exportable secret — correctly latched). Each gets its
  own icon + message, and the Unavailable prompt points at Back up / Migrate
  instead of telling the user to unlock an already-unlocked wallet.
- A chat message that sits queued ("Sending") because the wallet is offline or
  has no shielded funds for the fee now surfaces the reason (throttled, after a
  short dwell), wiring the ready-made chat_toast_not_connected /
  chat_toast_need_funds strings that were never shown. The send stays queued
  and goes out when the condition clears.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 16:41:30 -05:00
co-authored by Claude Opus 4.8
parent 6efe3c0f5c
commit e27d88eca4
4 changed files with 73 additions and 3 deletions
+14 -2
View File
@@ -748,9 +748,21 @@ void RenderChatTab(App* app)
const auto& store = service.store();
auto& book = app->addressBook();
// Not unlocked / identity not derived yet → nothing to show.
// No identity yet → show WHY, not a blanket "unlock your wallet" (which is wrong for an unlocked
// view-only/legacy wallet that simply can't derive a chat identity, and left it stuck forever).
if (!service.hasIdentity()) {
centeredEmptyState(ICON_MD_LOCK, TR("chat_locked_hint"), nullptr);
switch (app->chatIdentityStatus()) {
case App::ChatIdentityStatus::Preparing:
centeredEmptyState(ICON_MD_HOURGLASS_EMPTY, TR("chat_preparing_hint"), nullptr);
break;
case App::ChatIdentityStatus::Unavailable:
centeredEmptyState(ICON_MD_INFO_OUTLINE, TR("chat_unavailable_hint"), TR("chat_unavailable_sub"));
break;
case App::ChatIdentityStatus::Locked:
default:
centeredEmptyState(ICON_MD_LOCK, TR("chat_locked_hint"), nullptr);
break;
}
return;
}