chore: remove tui module

This commit is contained in:
Kristofers Solo 2025-11-24 08:45:56 +02:00
parent 262c7decfe
commit bfa93c095a
Signed by: kristoferssolo
GPG Key ID: 74FF8144483D82C8
6 changed files with 1 additions and 293 deletions

View File

@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["aes", "cipher-core", "cli", "des", "tui"]
members = ["aes", "cipher-core", "cli", "des"]
[workspace.dependencies]
aes = { path = "aes" }

View File

@ -1,17 +0,0 @@
[package]
name = "tui"
version = "0.1.0"
authors = ["Kristofers Solo <dev@kristofers.xyz>"]
edition = "2024"
[dependencies]
aes.workspace = true
cipher-core.workspace = true
color-eyre.workspace = true
crossterm = "0.28"
des.workspace = true
ratatui = "0.29"
thiserror.workspace = true
[lints]
workspace = true

View File

@ -1,96 +0,0 @@
use crate::event::{AppEvent, Event, EventHandler};
use color_eyre::Result;
use ratatui::{
DefaultTerminal,
crossterm::event::{KeyCode, KeyEvent, KeyModifiers},
};
/// Application.
#[derive(Debug)]
pub struct App {
/// Is the application running?
pub running: bool,
/// Counter.
pub counter: u8,
/// Event handler.
pub events: EventHandler,
}
impl Default for App {
fn default() -> Self {
Self {
running: true,
counter: 0,
events: EventHandler::new(),
}
}
}
impl App {
/// Constructs a new instance of [`App`].
pub fn new() -> Self {
Self::default()
}
/// Run the application's main loop.
pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
while self.running {
terminal.draw(|frame| frame.render_widget(&self, frame.area()))?;
self.handle_events()?;
}
Ok(())
}
pub fn handle_events(&mut self) -> Result<()> {
match self.events.next()? {
Event::Tick => self.tick(),
Event::Crossterm(event) => match event {
crossterm::event::Event::Key(key_event)
if key_event.kind == crossterm::event::KeyEventKind::Press =>
{
self.handle_key_event(key_event);
}
_ => {}
},
Event::App(app_event) => match app_event {
AppEvent::Increment => self.increment_counter(),
AppEvent::Decrement => self.decrement_counter(),
AppEvent::Quit => self.quit(),
},
}
Ok(())
}
/// Handles the key events and updates the state of [`App`].
pub fn handle_key_event(&self, key_event: KeyEvent) {
match key_event.code {
KeyCode::Esc | KeyCode::Char('q') => self.events.send(AppEvent::Quit),
KeyCode::Char('c' | 'C') if key_event.modifiers == KeyModifiers::CONTROL => {
self.events.send(AppEvent::Quit);
}
KeyCode::Right => self.events.send(AppEvent::Increment),
KeyCode::Left => self.events.send(AppEvent::Decrement),
// Other handlers you could add here.
_ => {}
}
}
/// Handles the tick event of the terminal.
///
/// The tick event is where you can update the state of your application with any logic that
/// needs to be updated at a fixed frame rate. E.g. polling a server, updating an animation.
pub const fn tick(&self) {}
/// Set running to false to quit the application.
pub const fn quit(&mut self) {
self.running = false;
}
pub const fn increment_counter(&mut self) {
self.counter = self.counter.saturating_add(1);
}
pub const fn decrement_counter(&mut self) {
self.counter = self.counter.saturating_sub(1);
}
}

View File

@ -1,131 +0,0 @@
use color_eyre::eyre::WrapErr;
use ratatui::crossterm::event::{self, Event as CrosstermEvent};
use std::{
sync::mpsc,
thread,
time::{Duration, Instant},
};
/// The frequency at which tick events are emitted.
const TICK_FPS: f64 = 30.0;
/// Representation of all possible events.
#[derive(Clone, Debug)]
pub enum Event {
/// An event that is emitted on a regular schedule.
///
/// Use this event to run any code which has to run outside of being a direct response to a user
/// event. e.g. polling exernal systems, updating animations, or rendering the UI based on a
/// fixed frame rate.
Tick,
/// Crossterm events.
///
/// These events are emitted by the terminal.
Crossterm(CrosstermEvent),
/// Application events.
///
/// Use this event to emit custom events that are specific to your application.
App(AppEvent),
}
/// Application events.
///
/// You can extend this enum with your own custom events.
#[derive(Clone, Debug)]
pub enum AppEvent {
/// Increment the counter.
Increment,
/// Decrement the counter.
Decrement,
/// Quit the application.
Quit,
}
/// Terminal event handler.
#[derive(Debug)]
pub struct EventHandler {
/// Event sender channel.
sender: mpsc::Sender<Event>,
/// Event receiver channel.
receiver: mpsc::Receiver<Event>,
}
impl EventHandler {
/// Constructs a new instance of [`EventHandler`] and spawns a new thread to handle events.
pub fn new() -> Self {
let (sender, receiver) = mpsc::channel();
let actor = EventThread::new(sender.clone());
thread::spawn(|| actor.run());
Self { sender, receiver }
}
/// Receives an event from the sender.
///
/// This function blocks until an event is received.
///
/// # Errors
///
/// This function returns an error if the sender channel is disconnected. This can happen if an
/// error occurs in the event thread. In practice, this should not happen unless there is a
/// problem with the underlying terminal.
pub fn next(&self) -> color_eyre::Result<Event> {
Ok(self.receiver.recv()?)
}
/// Queue an app event to be sent to the event receiver.
///
/// This is useful for sending events to the event handler which will be processed by the next
/// iteration of the application's event loop.
pub fn send(&self, app_event: AppEvent) {
// Ignore the result as the reciever cannot be dropped while this struct still has a
// reference to it
let _ = self.sender.send(Event::App(app_event));
}
}
/// A thread that handles reading crossterm events and emitting tick events on a regular schedule.
struct EventThread {
/// Event sender channel.
sender: mpsc::Sender<Event>,
}
impl EventThread {
/// Constructs a new instance of [`EventThread`].
const fn new(sender: mpsc::Sender<Event>) -> Self {
Self { sender }
}
/// Runs the event thread.
///
/// This function emits tick events at a fixed rate and polls for crossterm events in between.
fn run(self) -> color_eyre::Result<()> {
let tick_interval = Duration::from_secs_f64(1.0 / TICK_FPS);
let mut last_tick = Instant::now();
loop {
// emit tick events at a fixed rate
let timeout = tick_interval.saturating_sub(last_tick.elapsed());
if timeout == Duration::ZERO {
last_tick = Instant::now();
self.send(Event::Tick);
}
// poll for crossterm events, ensuring that we don't block the tick interval
if event::poll(timeout).wrap_err("failed to poll for crossterm events")? {
let event = event::read().wrap_err("failed to read crossterm event")?;
self.send(Event::Crossterm(event));
}
}
}
/// Sends an event to the receiver.
fn send(&self, event: Event) {
// Ignores the result because shutting down the app drops the receiver, which causes the send
// operation to fail. This is expected behavior and should not panic.
let _ = self.sender.send(event);
}
}
impl Default for EventHandler {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,13 +0,0 @@
use crate::app::App;
mod app;
mod event;
mod ui;
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
let terminal = ratatui::init();
let result = App::new().run(terminal);
ratatui::restore();
result
}

View File

@ -1,35 +0,0 @@
use ratatui::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Color, Stylize},
widgets::{Block, BorderType, Paragraph, Widget},
};
use crate::app::App;
impl Widget for &App {
/// Renders the user interface widgets.
///
// This is where you add new widgets.
// See the following resources:
// - https://docs.rs/ratatui/latest/ratatui/widgets/index.html
// - https://github.com/ratatui/ratatui/tree/master/examples
fn render(self, area: Rect, buf: &mut Buffer) {
let block = Block::bordered()
.title("event-driven-generated")
.title_alignment(Alignment::Center)
.border_type(BorderType::Rounded);
let text = format!(
"This is a tui template.\n\
Press `Esc`, `Ctrl-C` or `q` to stop running.\n\
Press left and right to increment and decrement the counter respectively.\n\
Counter: {}",
self.counter
);
let paragraph = Paragraph::new(text).block(block).fg(Color::Cyan).centered();
paragraph.render(area, buf);
}
}