mod types; mod draw; mod commands; mod file_transfer; mod input; mod network; pub use types::App; use std::sync::Arc; use std::time::Duration; use anyhow::Result; use crossterm::event::{self, Event, KeyCode}; use warzone_protocol::identity::{IdentityKeyPair, Seed}; use crate::net::ServerClient; use crate::storage::LocalDb; /// Run the TUI event loop. pub async fn run_tui( our_fp: String, peer_fp: Option, server_url: String, identity: IdentityKeyPair, poll_seed: Seed, db: LocalDb, ) -> Result<()> { let mut terminal = ratatui::init(); let client = ServerClient::new(&server_url); let db = Arc::new(db); let mut app = App::new(our_fp.clone(), peer_fp, server_url); // Derive a second identity for the poll loop (can't clone IdentityKeyPair) let poll_identity = poll_seed.derive_identity(); let poll_messages = app.messages.clone(); let poll_receipts = app.receipts.clone(); let poll_pending_files = app.pending_files.clone(); let poll_last_dm = app.last_dm_peer.clone(); let poll_connected = app.connected.clone(); let poll_client = client.clone(); let poll_db = db.clone(); let poll_fp = our_fp.clone(); tokio::spawn(async move { network::poll_loop(poll_messages, poll_receipts, poll_pending_files, poll_fp, poll_identity, poll_db, poll_client, poll_last_dm, poll_connected).await; }); // Auto-join #ops if no peer set if app.peer_fp.is_none() { let join_url = format!("{}/v1/groups/ops/join", client.base_url); let fp_clean: String = our_fp.chars().filter(|c| c.is_ascii_hexdigit()).collect::().to_lowercase(); let _ = client.client.post(&join_url) .json(&serde_json::json!({"fingerprint": fp_clean})) .send().await; app.peer_fp = Some("#ops".to_string()); app.add_message(types::ChatLine { sender: "system".into(), text: "Welcome! You have been added to #ops".into(), is_system: true, is_self: false, message_id: None, timestamp: chrono::Local::now(), }); } loop { terminal.draw(|frame| app.draw(frame))?; if event::poll(Duration::from_millis(100))? { if let Event::Key(key) = event::read()? { if key.code == KeyCode::Enter { app.handle_send(&identity, &db, &client).await; app.scroll_offset = 0; } else { app.handle_key_event(key); } } } if app.should_quit { break; } } ratatui::restore(); Ok(()) }