v0.0.37: TUI call state UI, missed calls, inline keyboards in web
FC-P2-T4: TUI call state machine - CallInfo struct + CallPhase enum (Calling/Ringing/Active) - Header shows call indicator: yellow "Calling...", magenta "Incoming", green timer - /call sets Calling, /accept sets Active, /reject+/hangup clears - Incoming signals show contextual messages (Offer→prompt, Answer→connected, etc.) FC-P2-T5: Missed call display in TUI - WS Text frames parsed for missed_call + bot_message JSON - Missed calls: "📞 Missed call from X at HH:MM" + terminal bell - Bot messages rendered as @botname: text FC-P8-T5: Inline keyboard buttons in web - CSS styled keyboard buttons (.kbd-btn) - Bot messages with reply_markup render clickable button rows - Click sends callback_data back to bot as bot_message - Works in both WS text handler and handleIncomingMessage fallback Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -549,6 +549,12 @@ impl App {
|
||||
.map(|s| if s.len() > 16 { format!("{}...", &s[..16]) } else { s.to_string() })
|
||||
.unwrap_or_default();
|
||||
self.add_message(ChatLine { sender: "system".into(), text: format!("📞 Calling {}...", display), is_system: true, is_self: false, message_id: None, timestamp: Local::now() });
|
||||
self.call_state = Some(super::types::CallInfo {
|
||||
peer_fp: peer_fp_clean.clone(),
|
||||
peer_display: display.clone(),
|
||||
state: super::types::CallPhase::Calling,
|
||||
started_at: Local::now(),
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
self.add_message(ChatLine { sender: "system".into(), text: format!("Call failed: {}", e), is_system: true, is_self: false, message_id: None, timestamp: Local::now() });
|
||||
@@ -578,6 +584,12 @@ impl App {
|
||||
if let Ok(encoded) = bincode::serialize(&wire) {
|
||||
let _ = client.send_message(&normfp(&peer), Some(&self.our_fp), &encoded).await;
|
||||
self.add_message(ChatLine { sender: "system".into(), text: "✓ Call accepted".into(), is_system: true, is_self: false, message_id: None, timestamp: Local::now() });
|
||||
self.call_state = Some(super::types::CallInfo {
|
||||
peer_fp: normfp(&peer),
|
||||
peer_display: peer[..peer.len().min(16)].to_string(),
|
||||
state: super::types::CallPhase::Active,
|
||||
started_at: Local::now(),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -603,6 +615,7 @@ impl App {
|
||||
if let Ok(encoded) = bincode::serialize(&wire) {
|
||||
let _ = client.send_message(&normfp(&peer), Some(&self.our_fp), &encoded).await;
|
||||
self.add_message(ChatLine { sender: "system".into(), text: "✗ Call rejected".into(), is_system: true, is_self: false, message_id: None, timestamp: Local::now() });
|
||||
self.call_state = None;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -629,6 +642,7 @@ impl App {
|
||||
if let Ok(encoded) = bincode::serialize(&wire) {
|
||||
let _ = client.send_message(&normfp(&peer), Some(&self.our_fp), &encoded).await;
|
||||
self.add_message(ChatLine { sender: "system".into(), text: "Call ended".into(), is_system: true, is_self: false, message_id: None, timestamp: Local::now() });
|
||||
self.call_state = None;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user