Init Commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
target
|
||||
.idea
|
||||
1233
Cargo.lock
generated
Normal file
1233
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "sus-manager"
|
||||
version = "0.1.0"
|
||||
description = "An example generated using the hello-world template"
|
||||
authors = ["fromost"]
|
||||
license = "MIT"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
color-eyre = "0.6.3"
|
||||
ratatui = "0.29.0"
|
||||
|
||||
crossterm = { version = "0.29.0", features = ["event-stream"] }
|
||||
futures = "0.3.28"
|
||||
tokio = { version = "1.47.1", features = ["full"] }
|
||||
tokio-util = "0.7.9"
|
||||
tokio-utils = "0.1.2"
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) fromost
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
14
README.md
Normal file
14
README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# sus-manager
|
||||
|
||||
This is a [Ratatui] app generated by the [Hello World template].
|
||||
|
||||
[Ratatui]: https://ratatui.rs
|
||||
[Hello World Template]: https://github.com/ratatui/templates/tree/main/hello-world
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) fromost
|
||||
|
||||
This project is licensed under the MIT license ([LICENSE] or <http://opensource.org/licenses/MIT>)
|
||||
|
||||
[LICENSE]: ./LICENSE
|
||||
55
src/app.rs
Normal file
55
src/app.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use crate::event::{Event, EventHandler};
|
||||
use ratatui::widgets::Block;
|
||||
use ratatui::{DefaultTerminal, Frame};
|
||||
use std::time::Duration;
|
||||
use color_eyre::Result;
|
||||
use crossterm::event::KeyCode::Char;
|
||||
use ratatui::layout::Alignment;
|
||||
|
||||
pub(crate) struct App {
|
||||
running: bool,
|
||||
events: EventHandler,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> App {
|
||||
App {
|
||||
running: true,
|
||||
events: EventHandler::new(Duration::from_millis(250)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(&mut self, mut terminal: DefaultTerminal) -> Result<()> {
|
||||
loop {
|
||||
terminal.draw(|frame| App::render(self, frame))?;
|
||||
let event = self.events.next().await?;
|
||||
self.update(event)?;
|
||||
if !self.running {
|
||||
break Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, event: Event) -> Result<()> {
|
||||
if let Event::Key(key) = event {
|
||||
match key.code {
|
||||
Char('q') => self.quit(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn quit(&mut self) {
|
||||
self.running = false;
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &mut Frame) {
|
||||
frame.render_widget(
|
||||
Block::bordered()
|
||||
.title("Sus Manager")
|
||||
.title_alignment(Alignment::Center),
|
||||
frame.area()
|
||||
);
|
||||
}
|
||||
}
|
||||
62
src/event.rs
Normal file
62
src/event.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use color_eyre::eyre::{Result, eyre};
|
||||
use crossterm;
|
||||
use crossterm::event;
|
||||
use futures::FutureExt;
|
||||
use futures::StreamExt;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
pub(crate) enum Event {
|
||||
Error,
|
||||
Tick,
|
||||
Key(event::KeyEvent),
|
||||
}
|
||||
|
||||
pub(crate) struct EventHandler {
|
||||
_tx: UnboundedSender<Event>,
|
||||
rx: tokio::sync::mpsc::UnboundedReceiver<Event>,
|
||||
task: Option<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl EventHandler {
|
||||
pub fn new(tick_rate: Duration) -> Self {
|
||||
let mut interval = tokio::time::interval(tick_rate);
|
||||
let mut event_reader = crossterm::event::EventStream::new();
|
||||
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
let _tx = tx.clone();
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
loop {
|
||||
let delay = interval.tick();
|
||||
let crossterm_event = event_reader.next().fuse();
|
||||
tokio::select! {
|
||||
maybe_event = crossterm_event => {
|
||||
if let Some(Err(_)) = maybe_event {
|
||||
tx.send(Event::Error).unwrap()
|
||||
}
|
||||
else if let Some(Ok(event)) = maybe_event &&
|
||||
let event::Event::Key(key) = event &&
|
||||
key.kind == event::KeyEventKind::Press
|
||||
{
|
||||
tx.send(Event::Key(key)).unwrap()
|
||||
}
|
||||
}
|
||||
_ = delay => {
|
||||
tx.send(Event::Tick).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Self {
|
||||
_tx,
|
||||
rx,
|
||||
task: Some(task),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn next(&mut self) -> Result<Event> {
|
||||
self.rx.recv().await.ok_or(eyre!("Unable to get event"))
|
||||
}
|
||||
}
|
||||
15
src/main.rs
Normal file
15
src/main.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
mod app;
|
||||
mod event;
|
||||
|
||||
use color_eyre::Result;
|
||||
use tokio;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let terminal = ratatui::init();
|
||||
let mut app = app::App::new();
|
||||
let result = app.run(terminal).await;
|
||||
ratatui::restore();
|
||||
result
|
||||
}
|
||||
Reference in New Issue
Block a user