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:
@@ -302,6 +302,13 @@ public:
|
||||
wallet::LiteWalletController* liteWallet() { return lite_wallet_.get(); }
|
||||
// HushChat service (identity + in-memory message store); the Chat tab reads its store.
|
||||
chat::ChatService& chatService() { return chat_service_; }
|
||||
// Why the Chat tab has no identity yet, so it can show the right prompt instead of always
|
||||
// "unlock your wallet". Locked = encrypted & locked (seed unreadable); Preparing = unlocked and
|
||||
// deriving the identity (fetch in flight, or waiting on the node / address list); Unavailable =
|
||||
// no usable secret for this wallet (view-only, or a legacy wallet on a daemon without the needed
|
||||
// export RPC) — correctly latched, so the prompt points at Back up / Migrate instead.
|
||||
enum class ChatIdentityStatus { Ready, Locked, Preparing, Unavailable };
|
||||
ChatIdentityStatus chatIdentityStatus() const;
|
||||
// HushChat composing: construct, broadcast (broadcastChatMemos), and locally echo an outgoing
|
||||
// message (to a conversation whose peer key we know) / a new-conversation contact request.
|
||||
void sendChatMessage(const std::string& conversationId, const std::string& text);
|
||||
@@ -1044,6 +1051,12 @@ private:
|
||||
// submit (the count lags a spend by a cycle, but the wallet still picks a fresh note per send). Zeroed on
|
||||
// a transient-funds failure so we stop draining until the next refresh/scan restores the truth.
|
||||
int chat_verified_note_budget_ = 0;
|
||||
// Stuck-send notice: when a chat message sits queued ("Sending") because the wallet is offline or
|
||||
// has no shielded funds for the fee, tell the user WHY once (throttled) — the send stays queued and
|
||||
// goes out when the condition clears. cause: 0=none, 1=offline, 2=unfunded. See maybeNoticeStuckChatSend.
|
||||
int chat_stuck_cause_ = 0;
|
||||
double chat_stuck_since_ = 0.0; // ImGui::GetTime() when this cause began (dwell gate)
|
||||
double chat_stuck_notice_at_ = 0.0; // next time a repeat notice is allowed (throttle)
|
||||
int chat_pipeline_note_count_ = 0; // verified + maturing self-notes (drives shouldSplit)
|
||||
std::uint64_t chat_verified_shielded_zat_ = 0; // verified shielded balance (split affordability)
|
||||
bool chat_note_model_seen_ = false; // saw a refresh/scan carrying per-note visibility
|
||||
@@ -1132,6 +1145,8 @@ private:
|
||||
// variants); derives via deriveChatIdentityFromSecret and wipes the secret. No-op when the
|
||||
// feature is off, already provisioned, in flight, or unavailable.
|
||||
void maybeProvisionChatIdentity();
|
||||
// Surface (throttled) why an outgoing chat message is stuck "Sending" — offline or unfunded.
|
||||
void maybeNoticeStuckChatSend();
|
||||
// Drop the in-memory chat identity + decrypted message store, lock the chat DB, and re-arm
|
||||
// provisioning. MUST be called whenever the loaded wallet changes (switch / seed-migration adopt)
|
||||
// so wallet A's private chat can't surface — or be signed with A's keys — under wallet B.
|
||||
|
||||
Reference in New Issue
Block a user