Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
achristmascarl committed Jun 1, 2024
1 parent b510880 commit bfe73b7
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 47 deletions.
74 changes: 53 additions & 21 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,64 @@
use std::sync::Arc;

use color_eyre::eyre::Result;
use crossterm::event::KeyEvent;
use ratatui::prelude::Rect;
use ratatui::{
layout::{Constraint, Direction, Layout},
prelude::Rect,
widgets::{Block, Borders, Paragraph},
};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;

use crate::{
action::Action,
components::{fps::FpsCounter, home::Home, Component},
components::{data::Data, ide::IDE, menu::Menu, Component},
config::Config,
mode::Mode,
tui,
};

pub struct AppState {
pub connection_string: String,
}

pub struct Components {
pub menu: Box<dyn Component>,
pub ide: Box<dyn Component>,
pub data: Box<dyn Component>,
}

impl Components {
pub fn to_array(&mut self) -> [&mut Box<dyn Component>; 3] {
[&mut self.menu, &mut self.ide, &mut self.data]
}
}

pub struct App {
pub config: Config,
pub tick_rate: f64,
pub frame_rate: f64,
pub components: Vec<Box<dyn Component>>,
pub tick_rate: Option<f64>,
pub frame_rate: Option<f64>,
pub components: Components,
pub should_quit: bool,
pub should_suspend: bool,
pub mode: Mode,
pub last_tick_key_events: Vec<KeyEvent>,
pub state: Arc<AppState>,
}

impl App {
pub fn new(tick_rate: f64, frame_rate: f64) -> Result<Self> {
let home = Home::new();
let fps = FpsCounter::default();
pub fn new(connection_string: String, tick_rate: Option<f64>, frame_rate: Option<f64>) -> Result<Self> {
let state = Arc::new(AppState { connection_string });
let menu = Menu::new(Arc::clone(&state));
let ide = IDE::new(Arc::clone(&state));
let data = Data::new(Arc::clone(&state));
let config = Config::new()?;
let mode = Mode::Home;
Ok(Self {
state: Arc::clone(&state),
tick_rate,
frame_rate,
components: vec![Box::new(home), Box::new(fps)],
components: Components { menu: Box::new(menu), ide: Box::new(ide), data: Box::new(data) },
should_quit: false,
should_suspend: false,
config,
Expand All @@ -48,15 +74,15 @@ impl App {
// tui.mouse(true);
tui.enter()?;

for component in self.components.iter_mut() {
for component in self.components.to_array().iter_mut() {
component.register_action_handler(action_tx.clone())?;
}

for component in self.components.iter_mut() {
for component in self.components.to_array().iter_mut() {
component.register_config_handler(self.config.clone())?;
}

for component in self.components.iter_mut() {
for component in self.components.to_array().iter_mut() {
component.init(tui.size()?)?;
}

Expand Down Expand Up @@ -87,7 +113,7 @@ impl App {
},
_ => {},
}
for component in self.components.iter_mut() {
for component in self.components.to_array().iter_mut() {
if let Some(action) = component.handle_events(Some(e.clone()))? {
action_tx.send(action)?;
}
Expand All @@ -108,7 +134,7 @@ impl App {
Action::Resize(w, h) => {
tui.resize(Rect::new(0, 0, w, h))?;
tui.draw(|f| {
for component in self.components.iter_mut() {
for component in self.components.to_array().iter_mut() {
let r = component.draw(f, f.size());
if let Err(e) = r {
action_tx.send(Action::Error(format!("Failed to draw: {:?}", e))).unwrap();
Expand All @@ -118,17 +144,23 @@ impl App {
},
Action::Render => {
tui.draw(|f| {
for component in self.components.iter_mut() {
let r = component.draw(f, f.size());
if let Err(e) = r {
action_tx.send(Action::Error(format!("Failed to draw: {:?}", e))).unwrap();
}
}
let root_layout = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(25), Constraint::Percentage(75)])
.split(f.size());
let right_layout = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(root_layout[1]);

self.components.menu.draw(f, root_layout[0]).unwrap();
self.components.ide.draw(f, right_layout[0]).unwrap();
self.components.data.draw(f, right_layout[1]).unwrap();
})?;
},
_ => {},
}
for component in self.components.iter_mut() {
for component in self.components.to_array().iter_mut() {
if let Some(action) = component.update(action.clone())? {
action_tx.send(action)?
};
Expand Down
18 changes: 10 additions & 8 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ use crate::utils::version;
#[derive(Parser, Debug)]
#[command(author, version = version(), about)]
pub struct Cli {
#[arg(short, long, value_name = "FLOAT", help = "Tick rate, i.e. number of ticks per second", default_value_t = 1.0)]
pub tick_rate: f64,
#[arg(short, long, value_name = "FLOAT", help = "Tick rate, i.e. number of ticks per second")]
pub tick_rate: Option<f64>,

#[arg(short, long, value_name = "FLOAT", help = "Frame rate, i.e. number of frames per second")]
pub frame_rate: Option<f64>,

#[arg(
short,
long,
value_name = "FLOAT",
help = "Frame rate, i.e. number of frames per second",
default_value_t = 4.0
short = 'u',
long = "url",
value_name = "URL",
help = "Connection URL for the database, e.g. postgres://username::password@localhost:5432/dbname"
)]
pub frame_rate: f64,
pub connection_url: String,
}
5 changes: 3 additions & 2 deletions src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use crate::{
tui::{Event, Frame},
};

pub mod fps;
pub mod home;
pub mod data;
pub mod ide;
pub mod menu;

/// `Component` is a trait that represents a visual and interactive element of the user interface.
/// Implementors of this trait can be registered with the main application loop and will be able to receive events,
Expand Down
53 changes: 53 additions & 0 deletions src/components/data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::{collections::HashMap, sync::Arc, time::Duration};

use color_eyre::eyre::Result;
use crossterm::event::{KeyCode, KeyEvent};
use ratatui::{prelude::*, widgets::*};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::UnboundedSender;

use super::{Component, Frame};
use crate::{
action::Action,
app::{App, AppState},
config::{Config, KeyBindings},
};

pub struct Data {
command_tx: Option<UnboundedSender<Action>>,
config: Config,
state: Arc<AppState>,
}

impl Data {
pub fn new(state: Arc<AppState>) -> Self {
Data { command_tx: None, config: Config::default(), state }
}
}

impl Component for Data {
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.command_tx = Some(tx);
Ok(())
}

fn register_config_handler(&mut self, config: Config) -> Result<()> {
self.config = config;
Ok(())
}

fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::Tick => {},
_ => {},
}

Ok(None)
}

fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
let state = self.state.clone();
f.render_widget(Block::default().title("bottom").borders(Borders::ALL), area);
Ok(())
}
}
23 changes: 12 additions & 11 deletions src/components/home.rs → src/components/ide.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, time::Duration};
use std::{collections::HashMap, sync::Arc, time::Duration};

use color_eyre::eyre::Result;
use crossterm::event::{KeyCode, KeyEvent};
Expand All @@ -9,22 +9,23 @@ use tokio::sync::mpsc::UnboundedSender;
use super::{Component, Frame};
use crate::{
action::Action,
app::{App, AppState},
config::{Config, KeyBindings},
};

#[derive(Default)]
pub struct Home {
pub struct IDE {
command_tx: Option<UnboundedSender<Action>>,
config: Config,
state: Arc<AppState>,
}

impl Home {
pub fn new() -> Self {
Self::default()
impl IDE {
pub fn new(state: Arc<AppState>) -> Self {
IDE { command_tx: None, config: Config::default(), state }
}
}

impl Component for Home {
impl Component for IDE {
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.command_tx = Some(tx);
Ok(())
Expand All @@ -37,16 +38,16 @@ impl Component for Home {

fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::Tick => {
},
Action::Tick => {},
_ => {},
}

Ok(None)
}

fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
f.render_widget(Paragraph::new("hello world"), area);
let state = self.state.clone();
f.render_widget(Block::default().title("top").borders(Borders::ALL), area);
Ok(())
}
}

53 changes: 53 additions & 0 deletions src/components/menu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::{collections::HashMap, sync::Arc, time::Duration};

use color_eyre::eyre::Result;
use crossterm::event::{KeyCode, KeyEvent};
use ratatui::{prelude::*, widgets::*};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::UnboundedSender;

use super::{Component, Frame};
use crate::{
action::Action,
app::{App, AppState},
config::{Config, KeyBindings},
};

pub struct Menu {
command_tx: Option<UnboundedSender<Action>>,
config: Config,
state: Arc<AppState>,
}

impl Menu {
pub fn new(state: Arc<AppState>) -> Self {
Menu { command_tx: None, config: Config::default(), state }
}
}

impl Component for Menu {
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.command_tx = Some(tx);
Ok(())
}

fn register_config_handler(&mut self, config: Config) -> Result<()> {
self.config = config;
Ok(())
}

fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::Tick => {},
_ => {},
}
Ok(None)
}

fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
let state = self.state.clone();

f.render_widget(Block::default().title(state.connection_string.to_string()).borders(Borders::ALL), area);
Ok(())
}
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async fn tokio_main() -> Result<()> {
initialize_panic_handler()?;

let args = Cli::parse();
let mut app = App::new(args.tick_rate, args.frame_rate)?;
let mut app = App::new(args.connection_url, args.tick_rate, args.frame_rate)?;
app.run().await?;

Ok(())
Expand Down
12 changes: 8 additions & 4 deletions src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,17 @@ impl Tui {
Ok(Self { terminal, task, cancellation_token, event_rx, event_tx, frame_rate, tick_rate, mouse, paste })
}

pub fn tick_rate(mut self, tick_rate: f64) -> Self {
self.tick_rate = tick_rate;
pub fn tick_rate(mut self, tick_rate: Option<f64>) -> Self {
if tick_rate.is_some() {
self.tick_rate = tick_rate.unwrap()
};
self
}

pub fn frame_rate(mut self, frame_rate: f64) -> Self {
self.frame_rate = frame_rate;
pub fn frame_rate(mut self, frame_rate: Option<f64>) -> Self {
if frame_rate.is_some() {
self.frame_rate = frame_rate.unwrap();
}
self
}

Expand Down

0 comments on commit bfe73b7

Please sign in to comment.