Skip to content

Commit

Permalink
refactor: creating a store to hold collection state
Browse files Browse the repository at this point in the history
  • Loading branch information
wllfaria committed Jun 2, 2024
1 parent 4630e86 commit 480d17f
Show file tree
Hide file tree
Showing 14 changed files with 649 additions and 460 deletions.
2 changes: 1 addition & 1 deletion hac-client/benches/collection_viewer_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::{Arc, RwLock};

use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
use hac_client::{
pages::{collection_viewer::CollectionViewer, Component, Eventful},
pages::{collection_viewer::CollectionViewer, Eventful, Page},
utils::build_syntax_highlighted_lines,
};
use hac_core::{
Expand Down
18 changes: 10 additions & 8 deletions hac-client/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
event_pool::{Event, EventPool},
pages::{Component, Eventful},
pages::{Eventful, Page},
screen_manager::ScreenManager,
};
use hac_core::{collection::Collection, command::Command};
Expand Down Expand Up @@ -49,6 +49,15 @@ impl<'app> App<'app> {
.register_command_handler(command_tx.clone())?;

loop {
{
while let Ok(command) = command_rx.try_recv() {
match command {
Command::Quit => self.should_quit = true,
_ => self.screen_manager.handle_command(command),
}
}
}

if let Some(event) = self.event_pool.next().await {
match event {
Event::Tick => self.screen_manager.handle_tick()?,
Expand All @@ -75,13 +84,6 @@ impl<'app> App<'app> {
};
}

while let Ok(command) = command_rx.try_recv() {
match command {
Command::Quit => self.should_quit = true,
_ => self.screen_manager.handle_command(command),
}
}

if self.should_quit {
break;
}
Expand Down
58 changes: 44 additions & 14 deletions hac-client/src/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod confirm_popup;
pub mod error_popup;
pub mod input;
mod overlay;
pub mod spinner;
mod spinner;
pub mod terminal_too_small;

use crate::event_pool::Event;
Expand All @@ -14,7 +14,7 @@ use ratatui::{layout::Rect, Frame};
use tokio::sync::mpsc::UnboundedSender;

/// A `Page` is anything that is a top level page and can be drawn to the screen
pub trait Component {
pub trait Page {
fn draw(&mut self, frame: &mut Frame, size: Rect) -> anyhow::Result<()>;

/// pages need to adapt to change of sizes on the application, this function is called
Expand All @@ -29,31 +29,61 @@ pub trait Component {
Ok(())
}

/// tick is a smaller interval than the one used by the render cycle, it is mainly used
/// for actions that rely on time, such as auto-syncing the edited request on the
/// CollectionViewer
/// tick is a bigger interval than the one used by the render cycle, it is mainly used
/// for actions that rely on time, such as syncing changes to disk
fn handle_tick(&mut self) -> anyhow::Result<()> {
Ok(())
}
}

/// An `Eventful` component is a component that can handle key events, and mouse events
/// An `Eventful` page is a page that can handle key events, and mouse events
/// when support for them gets added.
pub trait Eventful {
type Result;

/// the top level event loop doesnt differentiate between kinds of events, so this is what
/// delegate each kind of events to the responsible function
fn handle_event(&mut self, event: Option<Event>) -> anyhow::Result<Option<Command>> {
let action = match event {
Some(Event::Key(key_event)) => self.handle_key_event(key_event)?,
_ => None,
};

Ok(action)
fn handle_event(&mut self, event: Option<Event>) -> anyhow::Result<Option<Self::Result>> {
match event {
Some(Event::Key(key_event)) => self.handle_key_event(key_event),
_ => Ok(None),
}
}

/// when we get a key_event, this will be called for the eventful component to handle it
#[allow(unused_variables)]
fn handle_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Command>> {
fn handle_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Self::Result>> {
Ok(None)
}
}

/// An `EventfulWithContext` component is a component that can handle events but requires
/// additional information which can be specified by its implementer. Such as defining a
/// associate type required to re-render properly or information that it needs to decide
/// on how to behave
///
/// besides the contextful behavior, this is exactly as `Eventful`
pub trait EventfulWithContext {
type Result;
type Context;

fn handle_event(
&mut self,
event: Option<Event>,
context: Self::Context,
) -> anyhow::Result<Option<Self::Result>> {
match event {
Some(Event::Key(key_event)) => self.handle_key_event(key_event, context),
_ => Ok(None),
}
}

#[allow(unused_variables)]
fn handle_key_event(
&mut self,
key_event: KeyEvent,
context: Self::Context,
) -> anyhow::Result<Option<Self::Result>> {
Ok(None)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::pages::{
confirm_popup::ConfirmPopup,
error_popup::ErrorPopup,
overlay::draw_overlay,
Component, Eventful,
Eventful, Page,
};
use hac_core::{collection::types::Collection, command::Command};

Expand Down Expand Up @@ -520,7 +520,7 @@ impl<'a> CollectionDashboard<'a> {
}
}

impl Component for CollectionDashboard<'_> {
impl Page for CollectionDashboard<'_> {
fn draw(&mut self, frame: &mut Frame, size: Rect) -> anyhow::Result<()> {
self.draw_background(size, frame);
self.draw_title(frame)?;
Expand Down Expand Up @@ -558,6 +558,8 @@ impl Component for CollectionDashboard<'_> {
}

impl Eventful for CollectionDashboard<'_> {
type Result = Command;

fn handle_key_event(&mut self, key_event: KeyEvent) -> anyhow::Result<Option<Command>> {
if let (KeyCode::Char('c'), KeyModifiers::CONTROL) = (key_event.code, key_event.modifiers) {
return Ok(Some(Command::Quit));
Expand Down
Loading

0 comments on commit 480d17f

Please sign in to comment.