Skip to content

Commit

Permalink
refactor(app): integrate Tui into App
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
ShenMian committed Dec 11, 2024
1 parent 9cd765a commit c10cac7
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 60 deletions.
92 changes: 45 additions & 47 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::time::{Duration, Instant};

use anyhow::Result;
use anyhow::{Ok, Result};

This comment has been minimized.

Copy link
@ShenMian

ShenMian Dec 11, 2024

Author Owner

Remove Ok

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseEvent};
use ratatui::{
layout::{Constraint, Layout},
prelude::CrosstermBackend,
style::Color,
Frame, Terminal,
Terminal,
};

use crate::{
Expand All @@ -27,72 +27,70 @@ pub struct App {
pub world_map_state: WorldMapState,
pub satellites_state: SatellitesState,
pub object_information_state: ObjectInformationState,

tui: Tui<CrosstermBackend<std::io::Stdout>>,
}

impl Default for App {
fn default() -> Self {
Self {
impl App {
/// Constructs a new instance of [`App`].
pub fn new() -> Result<Self> {
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.
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ pub mod widgets;

#[tokio::main]
async fn main() -> Result<()> {
App::new().run().await
App::new()?.run().await
}
15 changes: 3 additions & 12 deletions src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -16,7 +16,7 @@ use crate::{app::App, event::EventHandler};
#[derive(Debug)]
pub struct Tui<B: Backend> {
/// Interface to the Terminal.
terminal: Terminal<B>,
pub terminal: Terminal<B>,
/// Terminal event handler.
pub events: EventHandler,
}
Expand Down Expand Up @@ -47,15 +47,6 @@ impl<B: Backend> Tui<B> {
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
Expand All @@ -69,7 +60,7 @@ impl<B: Backend> Tui<B> {
/// 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(())
Expand Down

0 comments on commit c10cac7

Please sign in to comment.