From c10cac706bd1187aa54eef7f4124515a8f37e3cb Mon Sep 17 00:00:00 2001 From: ShenMian Date: Tue, 10 Dec 2024 23:59:15 +0000 Subject: [PATCH] refactor(app): integrate Tui into App - Move Tui initialization into App struct - Refactor render method to be part of App - Update run method to use new rendering approach - Rename exit method to deinit for better naming convention --- src/app.rs | 92 ++++++++++++++++++++++++++--------------------------- src/main.rs | 2 +- src/tui.rs | 15 ++------- 3 files changed, 49 insertions(+), 60 deletions(-) diff --git a/src/app.rs b/src/app.rs index b2ed14d..3605f5c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,12 +1,12 @@ use std::time::{Duration, Instant}; -use anyhow::Result; +use anyhow::{Ok, Result}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent}; use ratatui::{ layout::{Constraint, Layout}, prelude::CrosstermBackend, style::Color, - Frame, Terminal, + Terminal, }; use crate::{ @@ -27,72 +27,70 @@ pub struct App { pub world_map_state: WorldMapState, pub satellites_state: SatellitesState, pub object_information_state: ObjectInformationState, + + tui: Tui>, } -impl Default for App { - fn default() -> Self { - Self { +impl App { + /// Constructs a new instance of [`App`]. + pub fn new() -> Result { + let backend = CrosstermBackend::new(std::io::stdout()); + let terminal = Terminal::new(backend)?; + let events = EventHandler::new(); + let tui = Tui::new(terminal, events); + Ok(Self { running: true, world_map_state: Default::default(), satellites_state: Default::default(), object_information_state: Default::default(), - } - } -} - -impl App { - /// Constructs a new instance of [`App`]. - pub fn new() -> Self { - Self::default() + tui, + }) } pub async fn run(&mut self) -> Result<()> { - // Initialize the terminal user interface. - let backend = CrosstermBackend::new(std::io::stdout()); - let terminal = Terminal::new(backend)?; - let events = EventHandler::new(); - let mut tui = Tui::new(terminal, events); - tui.init()?; + self.tui.init()?; // Start the main loop. while self.running { // Handle events. - match tui.events.next().await? { + match self.tui.events.next().await? { Event::Update => self.update().await, - Event::Render => tui.render(self)?, + Event::Render => self.render()?, Event::Key(event) => handle_key_events(event, self).await?, Event::Mouse(event) => handle_mouse_events(event, self).await?, } } - // Exit the user interface. - tui.exit() + self.tui.deinit() } - pub fn render(&mut self, frame: &mut Frame) { - let horizontal = Layout::horizontal([Constraint::Percentage(80), Constraint::Min(25)]); - let [left, right] = horizontal.areas(frame.area()); - let vertical = Layout::vertical([Constraint::Percentage(60), Constraint::Fill(1)]); - let [top_right, bottom_right] = vertical.areas(right); - - let world_map = WorldMap { - satellites_state: &self.satellites_state, - satellit_symbol: "+".to_string(), - trajectory_color: Color::LightBlue, - }; - frame.render_stateful_widget(world_map, left, &mut self.world_map_state); - - let object_information = ObjectInformation { - satellites_state: &self.satellites_state, - world_map_state: &self.world_map_state, - }; - frame.render_stateful_widget( - object_information, - top_right, - &mut self.object_information_state, - ); - - frame.render_stateful_widget(Satellites, bottom_right, &mut self.satellites_state); + pub fn render(&mut self) -> Result<()> { + self.tui.terminal.draw(|frame| { + let horizontal = Layout::horizontal([Constraint::Percentage(80), Constraint::Min(25)]); + let [left, right] = horizontal.areas(frame.area()); + let vertical = Layout::vertical([Constraint::Percentage(60), Constraint::Fill(1)]); + let [top_right, bottom_right] = vertical.areas(right); + + let world_map = WorldMap { + satellites_state: &self.satellites_state, + satellit_symbol: "+".to_string(), + trajectory_color: Color::LightBlue, + }; + frame.render_stateful_widget(world_map, left, &mut self.world_map_state); + + let object_information = ObjectInformation { + satellites_state: &self.satellites_state, + world_map_state: &self.world_map_state, + }; + frame.render_stateful_widget( + object_information, + top_right, + &mut self.object_information_state, + ); + + frame.render_stateful_widget(Satellites, bottom_right, &mut self.satellites_state); + })?; + Ok(()) } /// Handles the tick event of the terminal. diff --git a/src/main.rs b/src/main.rs index 795f495..c3c5777 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,5 +11,5 @@ pub mod widgets; #[tokio::main] async fn main() -> Result<()> { - App::new().run().await + App::new()?.run().await } diff --git a/src/tui.rs b/src/tui.rs index 9dceaa3..d008bc3 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -7,7 +7,7 @@ use crossterm::{ }; use ratatui::{backend::Backend, Terminal}; -use crate::{app::App, event::EventHandler}; +use crate::event::EventHandler; /// Representation of a terminal user interface. /// @@ -16,7 +16,7 @@ use crate::{app::App, event::EventHandler}; #[derive(Debug)] pub struct Tui { /// Interface to the Terminal. - terminal: Terminal, + pub terminal: Terminal, /// Terminal event handler. pub events: EventHandler, } @@ -47,15 +47,6 @@ impl Tui { Ok(()) } - /// [`Draw`] the terminal interface by [`rendering`] the widgets. - /// - /// [`Draw`]: ratatui::Terminal::draw - /// [`rendering`]: crate::App::render - pub fn render(&mut self, app: &mut App) -> Result<()> { - self.terminal.draw(|frame| app.render(frame))?; - Ok(()) - } - /// Resets the terminal interface. /// /// This function is also used for the panic hook to revert @@ -69,7 +60,7 @@ impl Tui { /// Exits the terminal interface. /// /// It disables the raw mode and reverts back the terminal properties. - pub fn exit(&mut self) -> Result<()> { + pub fn deinit(&mut self) -> Result<()> { Self::reset()?; self.terminal.show_cursor()?; Ok(())