129 lines
4.5 KiB
Rust
129 lines
4.5 KiB
Rust
use color_eyre::Report;
|
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
|
use ratatui::{prelude::CrosstermBackend, widgets::ListState, DefaultTerminal, Terminal};
|
|
use ratatui_form::{Email, Form};
|
|
use std::{io, path::Path};
|
|
|
|
use crate::{
|
|
event::{AppEvent, Event, EventHandler},
|
|
form::FormState,
|
|
manifest::{load_manifest, Manifest},
|
|
};
|
|
|
|
// #[derive(Debug)]
|
|
pub struct App {
|
|
pub running: bool,
|
|
pub list_state: ListState,
|
|
pub events: EventHandler,
|
|
pub isloadingmanifest: bool,
|
|
pub manifest: Option<Manifest>,
|
|
}
|
|
|
|
impl App {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
running: true,
|
|
list_state: ListState::default().with_selected(Some(0)),
|
|
events: EventHandler::new(),
|
|
isloadingmanifest: false,
|
|
manifest: None,
|
|
}
|
|
}
|
|
|
|
pub async fn run(
|
|
mut self,
|
|
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
|
|
) -> color_eyre::Result<()> {
|
|
let project_root = Path::new("/home/nikkuss/dotfiles-new");
|
|
self.events.send(AppEvent::LoadManifest);
|
|
|
|
while self.running {
|
|
terminal.draw(|frame| frame.render_widget(&mut self, frame.area()))?;
|
|
match self.events.next().await? {
|
|
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_events(key_event)?
|
|
}
|
|
_ => {}
|
|
},
|
|
Event::App(app_event) => match app_event {
|
|
AppEvent::LoadManifest => {
|
|
if !self.isloadingmanifest {
|
|
let tx = self.events.clone_sender();
|
|
tokio::spawn(async move {
|
|
let result = load_manifest(&project_root).await;
|
|
let _ = tx.send(Event::App(AppEvent::ManifestLoaded(result)));
|
|
});
|
|
}
|
|
}
|
|
AppEvent::ManifestLoaded(manifest) => {
|
|
self.isloadingmanifest = false;
|
|
match manifest {
|
|
Ok(m) => {
|
|
self.manifest = Some(m);
|
|
}
|
|
Err(e) => {
|
|
self.display_error(e);
|
|
}
|
|
}
|
|
}
|
|
AppEvent::SelectionUp => self.selection_up(),
|
|
AppEvent::SelectionDown => self.selection_down(),
|
|
AppEvent::Quit => self.quit(),
|
|
},
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Handles the key events and updates the state of [`App`].
|
|
pub fn handle_key_events(&mut self, key_event: KeyEvent) -> color_eyre::Result<()> {
|
|
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::Up => self.events.send(AppEvent::SelectionUp),
|
|
KeyCode::Down => self.events.send(AppEvent::SelectionDown),
|
|
KeyCode::Char('a') => self.create_secret(),
|
|
// Other handlers you could add here.
|
|
_ => {}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn selected_secret_name(&self) -> Option<String> {
|
|
let selected = self.list_state.selected()?;
|
|
if let Some(manifest) = &self.manifest {
|
|
return manifest.secrets.keys().nth(selected).cloned();
|
|
}
|
|
None
|
|
}
|
|
|
|
/// 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 fn tick(&self) {}
|
|
|
|
/// Set running to false to quit the application.
|
|
pub fn quit(&mut self) {
|
|
self.running = false;
|
|
}
|
|
|
|
pub fn selection_down(&mut self) {
|
|
self.list_state.select_next();
|
|
}
|
|
|
|
pub fn selection_up(&mut self) {
|
|
self.list_state.select_previous();
|
|
}
|
|
pub fn display_error(&mut self, display_error: Report) {
|
|
// somehow display the error?
|
|
}
|
|
pub fn create_secret(&mut self) {}
|
|
}
|