pub mod core {
pub use flashkraft_core::commands;
pub use flashkraft_core::domain;
pub use flashkraft_core::flash_helper;
pub use flashkraft_core::utils;
}
pub use flashkraft_core::domain;
pub mod tui;
pub use flashkraft_core::flash_helper;
pub use tui::app::{App, AppScreen, FlashEvent, InputMode, UsbEntry};
pub use tui::events::handle_key;
pub use tui::ui::render;
pub use tui_file_explorer::{ExplorerOutcome, FileExplorer, FsEntry};
use std::io;
use std::panic;
use std::time::Duration;
use anyhow::Result;
use crossterm::{
event::{self, Event},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{backend::CrosstermBackend, Terminal};
pub async fn run() -> Result<()> {
let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |info| {
let _ = restore_terminal();
default_hook(info);
}));
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let run_result = run_app(&mut terminal).await;
restore_terminal()?;
terminal.show_cursor()?;
run_result
}
pub async fn run_app<B: ratatui::backend::Backend>(terminal: &mut Terminal<B>) -> Result<()>
where
B::Error: Send + Sync + 'static,
{
let mut app = App::new();
{
use flashkraft_core::commands::watch_usb_events;
use futures::StreamExt as _;
use tokio::sync::mpsc;
let (tx, rx) = mpsc::unbounded_channel::<()>();
app.hotplug_rx = Some(rx);
tokio::spawn(async move {
match watch_usb_events() {
Ok(mut stream) => {
while stream.next().await.is_some() {
if tx.send(()).is_err() {
break;
}
}
}
Err(e) => {
eprintln!("[hotplug] watch_usb_events failed: {e}");
}
}
});
}
loop {
app.tick_count = app.tick_count.wrapping_add(1);
app.poll_hotplug();
app.poll_drives();
app.poll_flash();
terminal.draw(|frame| render(&mut app, frame))?;
if event::poll(Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
handle_key(&mut app, key);
}
}
if app.should_quit {
break;
}
}
Ok(())
}
pub fn restore_terminal() -> Result<()> {
disable_raw_mode()?;
execute!(io::stdout(), LeaveAlternateScreen)?;
Ok(())
}