From e117d0ba4b064928a0c5e47fef96283686989684 Mon Sep 17 00:00:00 2001 From: Hamed Zaghaghi Date: Mon, 4 Mar 2024 18:51:18 +0100 Subject: [PATCH] refactor: :necktie: added Page and Pane traits, removed Component trait --- src/app.rs | 25 +++++---- src/component.rs | 121 ----------------------------------------- src/components.rs | 66 ++++++++++++++++++++++ src/components/home.rs | 24 +++----- src/main.rs | 1 - 5 files changed, 89 insertions(+), 148 deletions(-) delete mode 100644 src/component.rs diff --git a/src/app.rs b/src/app.rs index 4f8fcc8..1b83460 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,7 +4,12 @@ use ratatui::prelude::Rect; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc; -use crate::{action::Action, component::Component, components::home::Home, config::Config, tui}; +use crate::{ + action::Action, + components::{home::Home, Page}, + config::Config, + tui, +}; #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Mode { @@ -14,7 +19,7 @@ pub enum Mode { pub struct App { pub config: Config, - pub components: Vec>, + pub pages: Vec>, pub should_quit: bool, pub should_suspend: bool, pub mode: Mode, @@ -27,7 +32,7 @@ impl App { let config = Config::new()?; let mode = Mode::Home; Ok(Self { - components: vec![Box::new(home)], + pages: vec![Box::new(home)], should_quit: false, should_suspend: false, config, @@ -42,22 +47,22 @@ impl App { let mut tui = tui::Tui::new()?; tui.enter()?; - for component in self.components.iter_mut() { + for component in self.pages.iter_mut() { component.register_action_handler(action_tx.clone())?; } - for component in self.components.iter_mut() { + for component in self.pages.iter_mut() { component.register_config_handler(self.config.clone())?; } - for component in self.components.iter_mut() { + for component in self.pages.iter_mut() { component.init()?; } loop { if let Some(e) = tui.next().await { let mut stop_event_propagation = false; - for component in self.components.iter_mut() { + for component in self.pages.iter_mut() { if let Some(response) = component.handle_events(Some(e.clone()))? { match response { tui::EventResponse::Continue(action) => { @@ -114,7 +119,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.pages.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(); @@ -124,7 +129,7 @@ impl App { }, Action::Render => { tui.draw(|f| { - for component in self.components.iter_mut() { + for component in self.pages.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(); @@ -134,7 +139,7 @@ impl App { }, _ => {}, } - for component in self.components.iter_mut() { + for component in self.pages.iter_mut() { if let Some(action) = component.update(action.clone())? { action_tx.send(action)? }; diff --git a/src/component.rs b/src/component.rs deleted file mode 100644 index 05b43b7..0000000 --- a/src/component.rs +++ /dev/null @@ -1,121 +0,0 @@ -use color_eyre::eyre::Result; -use crossterm::event::{KeyEvent, MouseEvent}; -use ratatui::layout::Rect; -use tokio::sync::mpsc::UnboundedSender; - -use crate::{ - action::Action, - config::Config, - tui::{Event, EventResponse, Frame}, -}; - -/// `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, -/// update state, and be rendered on the screen. -pub trait Component { - /// Register an action handler that can send actions for processing if necessary. - /// - /// # Arguments - /// - /// * `tx` - An unbounded sender that can send actions. - /// - /// # Returns - /// - /// * `Result<()>` - An Ok result or an error. - #[allow(unused_variables)] - fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { - Ok(()) - } - /// Register a configuration handler that provides configuration settings if necessary. - /// - /// # Arguments - /// - /// * `config` - Configuration settings. - /// - /// # Returns - /// - /// * `Result<()>` - An Ok result or an error. - #[allow(unused_variables)] - fn register_config_handler(&mut self, config: Config) -> Result<()> { - Ok(()) - } - /// Initialize the component with a specified area if necessary. - /// - /// # Arguments - /// - /// * `area` - Rectangular area to initialize the component within. - /// - /// # Returns - /// - /// * `Result<()>` - An Ok result or an error. - fn init(&mut self) -> Result<()> { - Ok(()) - } - /// Handle incoming events and produce actions if necessary. - /// - /// # Arguments - /// - /// * `event` - An optional event to be processed. - /// - /// # Returns - /// - /// * `Result>` - An action to be processed or none. - fn handle_events(&mut self, event: Option) -> Result>> { - let r = match event { - Some(Event::Key(key_event)) => self.handle_key_events(key_event)?, - Some(Event::Mouse(mouse_event)) => self.handle_mouse_events(mouse_event)?, - _ => None, - }; - Ok(r) - } - /// Handle key events and produce actions if necessary. - /// - /// # Arguments - /// - /// * `key` - A key event to be processed. - /// - /// # Returns - /// - /// * `Result>` - An action to be processed or none. - #[allow(unused_variables)] - fn handle_key_events(&mut self, key: KeyEvent) -> Result>> { - Ok(None) - } - /// Handle mouse events and produce actions if necessary. - /// - /// # Arguments - /// - /// * `mouse` - A mouse event to be processed. - /// - /// # Returns - /// - /// * `Result>` - An action to be processed or none. - #[allow(unused_variables)] - fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Result>> { - Ok(None) - } - /// Update the state of the component based on a received action. (REQUIRED) - /// - /// # Arguments - /// - /// * `action` - An action that may modify the state of the component. - /// - /// # Returns - /// - /// * `Result>` - An action to be processed or none. - #[allow(unused_variables)] - fn update(&mut self, action: Action) -> Result> { - Ok(None) - } - /// Render the component on the screen. (REQUIRED) - /// - /// # Arguments - /// - /// * `f` - A frame used for rendering. - /// * `area` - The area in which the component should be drawn. - /// - /// # Returns - /// - /// * `Result<()>` - An Ok result or an error. - fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()>; -} diff --git a/src/components.rs b/src/components.rs index 9b86bcf..a7cede2 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1 +1,67 @@ +use color_eyre::eyre::Result; +use crossterm::event::{KeyEvent, MouseEvent}; +use ratatui::layout::Rect; +use tokio::sync::mpsc::UnboundedSender; + +use crate::{ + action::Action, + config::Config, + tui::{Event, EventResponse, Frame}, +}; + pub mod home; + +pub trait Page { + #[allow(unused_variables)] + fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { + Ok(()) + } + + #[allow(unused_variables)] + fn register_config_handler(&mut self, config: Config) -> Result<()> { + Ok(()) + } + + fn init(&mut self) -> Result<()> { + Ok(()) + } + + fn handle_events(&mut self, event: Option) -> Result>> { + let r = match event { + Some(Event::Key(key_event)) => self.handle_key_events(key_event)?, + Some(Event::Mouse(mouse_event)) => self.handle_mouse_events(mouse_event)?, + _ => None, + }; + Ok(r) + } + + #[allow(unused_variables)] + fn handle_key_events(&mut self, key: KeyEvent) -> Result>> { + Ok(None) + } + + #[allow(unused_variables)] + fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Result>> { + Ok(None) + } + + #[allow(unused_variables)] + fn update(&mut self, action: Action) -> Result> { + Ok(None) + } + + fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()>; +} + +pub trait Pane { + fn init(&mut self) -> Result<()> { + Ok(()) + } + + #[allow(unused_variables)] + fn update(&mut self, action: Action) -> Result> { + Ok(None) + } + + fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()>; +} diff --git a/src/components/home.rs b/src/components/home.rs index 1c2f188..a9deeb6 100644 --- a/src/components/home.rs +++ b/src/components/home.rs @@ -10,7 +10,7 @@ use ratatui::{ use serde::{Deserialize, Serialize}; use tokio::sync::mpsc::UnboundedSender; -use crate::{action::Action, component::Component, config::Config, tui::EventResponse}; +use crate::{action::Action, components::Page, config::Config, tui::EventResponse}; #[derive(Default, Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] pub enum Pane { @@ -135,25 +135,17 @@ impl Home { } fn method_color(method: &str) -> Color { - // method.0 is private, so matching - if method == "GET" { - return Color::LightCyan; + match method { + "GET" => Color::LightCyan, + "POST" => Color::LightBlue, + "PUT" => Color::LightYellow, + "DELETE" => Color::LightRed, + _ => Color::Gray, } - if method == "POST" { - return Color::LightBlue; - } - if method == "PUT" { - return Color::LightYellow; - } - if method == "DELETE" { - return Color::LightRed; - } - - Color::Gray } } -impl Component for Home { +impl Page for Home { fn init(&mut self) -> Result<()> { self.openapi_spec = Some(oas3::from_path(self.openapi_path.clone())?); self.openapi_spec_operations_len = match &self.openapi_spec { diff --git a/src/main.rs b/src/main.rs index 7b88d4e..e15d54d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ pub mod action; pub mod app; pub mod cli; -pub mod component; pub mod components; pub mod config; pub mod tui;