Private
Public Access
1
0

kptui: organize client code into kordophoned-client

This commit is contained in:
2025-12-14 18:06:14 -08:00
parent 68bb94aa0b
commit fc69c387c5
13 changed files with 661 additions and 609 deletions

View File

@@ -1,4 +1,4 @@
mod daemon;
use kordophoned_client as daemon;
use anyhow::Result;
use crossterm::event::{Event as CEvent, KeyCode, KeyEventKind, KeyModifiers};
@@ -25,6 +25,7 @@ enum Focus {
struct AppState {
conversations: Vec<daemon::ConversationSummary>,
selected_idx: usize,
selected_conversation_id: Option<String>,
messages: Vec<daemon::ChatMessage>,
active_conversation_id: Option<String>,
active_conversation_title: String,
@@ -42,6 +43,7 @@ impl AppState {
Self {
conversations: Vec::new(),
selected_idx: 0,
selected_conversation_id: None,
messages: Vec::new(),
active_conversation_id: None,
active_conversation_title: String::new(),
@@ -58,23 +60,34 @@ impl AppState {
fn select_next(&mut self) {
if self.conversations.is_empty() {
self.selected_idx = 0;
self.selected_conversation_id = None;
return;
}
self.selected_idx = (self.selected_idx + 1).min(self.conversations.len() - 1);
self.selected_conversation_id = self
.conversations
.get(self.selected_idx)
.map(|c| c.id.clone());
}
fn select_prev(&mut self) {
if self.conversations.is_empty() {
self.selected_idx = 0;
self.selected_conversation_id = None;
return;
}
self.selected_idx = self.selected_idx.saturating_sub(1);
self.selected_conversation_id = self
.conversations
.get(self.selected_idx)
.map(|c| c.id.clone());
}
fn open_selected_conversation(&mut self) {
if let Some(conv) = self.conversations.get(self.selected_idx) {
self.active_conversation_id = Some(conv.id.clone());
self.active_conversation_title = conv.title.clone();
self.selected_conversation_id = Some(conv.id.clone());
self.messages.clear();
self.transcript_scroll = 0;
self.pinned_to_bottom = true;
@@ -331,14 +344,31 @@ fn run_app(terminal: &mut ratatui::Terminal<ratatui::backend::CrosstermBackend<s
while let Ok(evt) = event_rx.try_recv() {
match evt {
daemon::Event::Conversations(convs) => {
let keep_selected_id = app
.selected_conversation_id
.clone()
.or_else(|| app.active_conversation_id.clone());
app.refresh_conversations_in_flight = false;
app.status.clear();
app.conversations = convs;
if app.selected_idx >= app.conversations.len() {
app.selected_idx = app.conversations.len().saturating_sub(1);
}
if app.active_conversation_id.is_none() && !app.conversations.is_empty() {
if app.conversations.is_empty() {
app.selected_idx = 0;
app.selected_conversation_id = None;
} else if let Some(id) = keep_selected_id {
if let Some(idx) = app.conversations.iter().position(|c| c.id == id) {
app.selected_idx = idx;
app.selected_conversation_id = Some(id);
} else {
app.selected_idx = 0;
app.selected_conversation_id =
Some(app.conversations[0].id.clone());
}
} else {
app.selected_idx = app.selected_idx.min(app.conversations.len() - 1);
app.selected_conversation_id = Some(
app.conversations[app.selected_idx].id.clone(),
);
}
}
daemon::Event::Messages {
@@ -477,7 +507,7 @@ fn run_app(terminal: &mut ratatui::Terminal<ratatui::backend::CrosstermBackend<s
requested_view = ViewMode::List;
app.focus = Focus::Navigation;
}
KeyCode::Char('i') => app.focus = Focus::Input,
KeyCode::Char('i') if app.focus != Focus::Input => app.focus = Focus::Input,
_ => {
handle_chat_keys(&mut app, &request_tx, key.code, max_scroll);
}
@@ -490,7 +520,7 @@ fn run_app(terminal: &mut ratatui::Terminal<ratatui::backend::CrosstermBackend<s
}
}
KeyCode::Esc => app.focus = Focus::Navigation,
KeyCode::Char('i') => app.focus = Focus::Input,
KeyCode::Char('i') if app.focus != Focus::Input => app.focus = Focus::Input,
KeyCode::Up => {
if app.focus == Focus::Navigation {
app.select_prev()