use envision::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq)]
enum Screen {
Home,
Settings,
Profile,
About,
}
struct RouterApp;
#[derive(Clone)]
struct State {
router: RouterState<Screen>,
}
#[derive(Clone, Debug)]
enum Msg {
Navigate(Screen),
Back,
Reset,
Quit,
}
impl App for RouterApp {
type State = State;
type Message = Msg;
fn init() -> (State, Command<Msg>) {
let router = RouterState::new(Screen::Home).with_max_history(10);
(State { router }, Command::none())
}
fn update(state: &mut State, msg: Msg) -> Command<Msg> {
match msg {
Msg::Navigate(screen) => {
Router::update(&mut state.router, RouterMessage::Navigate(screen));
}
Msg::Back => {
Router::update(&mut state.router, RouterMessage::Back);
}
Msg::Reset => {
Router::update(&mut state.router, RouterMessage::Reset(Screen::Home));
}
Msg::Quit => return Command::quit(),
}
Command::none()
}
fn view(state: &State, frame: &mut Frame) {
let area = frame.area();
let chunks = Layout::vertical([Constraint::Min(0), Constraint::Length(1)]).split(area);
let (title, body) = match state.router.current() {
Screen::Home => (
"Home",
"Welcome home!\n\n\
Press 's' for Settings\n\
Press 'p' for Profile\n\
Press 'a' for About",
),
Screen::Settings => (
"Settings",
"Application Settings\n\n\
Theme: Dark\n\
Language: English\n\
Notifications: On\n\n\
Press Backspace to go back",
),
Screen::Profile => (
"Profile",
"User Profile\n\n\
Name: Alice\n\
Email: alice@example.com\n\
Role: Administrator\n\n\
Press Backspace to go back",
),
Screen::About => (
"About",
"Envision Framework v0.1.0\n\n\
A modern TUI framework\n\
built with Rust.\n\n\
Press Backspace to go back",
),
};
let widget = ratatui::widgets::Paragraph::new(body).block(
ratatui::widgets::Block::default()
.borders(ratatui::widgets::Borders::ALL)
.title(title),
);
frame.render_widget(widget, chunks[0]);
let history_len = state.router.history_len();
let can_back = state.router.can_go_back();
let status = format!(
" Screen: {:?} | History: {} | Back: {}",
state.router.current(),
history_len,
can_back
);
frame.render_widget(
ratatui::widgets::Paragraph::new(status).style(Style::default().fg(Color::DarkGray)),
chunks[1],
);
}
fn handle_event(event: &Event) -> Option<Msg> {
if let Some(key) = event.as_key() {
match key.code {
Key::Char('q') | Key::Esc => Some(Msg::Quit),
Key::Char('s') => Some(Msg::Navigate(Screen::Settings)),
Key::Char('p') => Some(Msg::Navigate(Screen::Profile)),
Key::Char('a') => Some(Msg::Navigate(Screen::About)),
Key::Backspace => Some(Msg::Back),
Key::Char('r') => Some(Msg::Reset),
_ => None,
}
} else {
None
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut vt = Runtime::<RouterApp, _>::virtual_builder(50, 14).build()?;
println!("=== Router Example ===\n");
vt.tick()?;
println!("Home screen:");
println!("{}\n", vt.display());
vt.dispatch(Msg::Navigate(Screen::Settings));
vt.tick()?;
println!("After navigating to Settings:");
println!("{}\n", vt.display());
vt.dispatch(Msg::Navigate(Screen::Profile));
vt.tick()?;
println!("After navigating to Profile:");
println!("{}\n", vt.display());
vt.dispatch(Msg::Back);
vt.tick()?;
println!("After going back (to Settings):");
println!("{}\n", vt.display());
vt.dispatch(Msg::Back);
vt.tick()?;
println!("After going back again (to Home):");
println!("{}\n", vt.display());
Ok(())
}