use crate::config::ProviderConfig;
use crate::environment::EnvironmentManager;
use crate::tui::log_tui_error;
use crate::tui::screens::{
ConfirmDeleteScreen, CreateEnvironmentScreen, EnvironmentListScreen, EnvironmentSettingsScreen,
};
use anyhow::Result;
use crossterm::{
event::{self, Event, KeyEventKind},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{backend::CrosstermBackend, Terminal};
use std::io::stdout;
use std::time::Duration;
#[derive(Debug, Clone)]
pub enum AppScreen {
EnvironmentList,
CreateEnvironment,
EnvironmentSettings { env_key: String },
ConfirmDelete { env_key: String },
}
#[derive(Debug, Clone)]
pub enum Action {
None,
Quit,
Goto(AppScreen),
CreateEnv {
key: String,
name: String,
color: String,
provider: ProviderConfig,
},
DeleteEnv { key: String },
SetDefault { key: String },
UpdateEnv {
key: String,
name: String,
color: String,
provider: ProviderConfig,
},
}
pub struct App {
pub manager: EnvironmentManager,
pub current_screen: AppScreen,
pub should_quit: bool,
pub list_screen: EnvironmentListScreen,
pub create_screen: CreateEnvironmentScreen,
pub settings_screen: EnvironmentSettingsScreen,
pub delete_screen: ConfirmDeleteScreen,
}
impl App {
pub fn new() -> Result<Self> {
let manager = EnvironmentManager::new()?;
Ok(Self {
manager,
current_screen: AppScreen::EnvironmentList,
should_quit: false,
list_screen: EnvironmentListScreen::new(),
create_screen: CreateEnvironmentScreen::new(),
settings_screen: EnvironmentSettingsScreen::new(),
delete_screen: ConfirmDeleteScreen::new(),
})
}
pub fn goto(&mut self, screen: AppScreen) {
match &screen {
AppScreen::CreateEnvironment => {
self.create_screen.reset();
}
AppScreen::EnvironmentSettings { env_key } => {
if let Some(config) = self.manager.config().get_environment(env_key) {
self.settings_screen.load(env_key.clone(), config.clone());
}
}
AppScreen::ConfirmDelete { env_key } => {
self.delete_screen.set_env_key(env_key.clone());
}
_ => {}
}
self.current_screen = screen;
}
pub fn refresh_list(&mut self) {
self.list_screen.refresh(&self.manager);
}
fn handle_action(&mut self, action: Action) {
match action {
Action::None => {}
Action::Quit => {
self.should_quit = true;
}
Action::Goto(screen) => {
self.goto(screen);
}
Action::CreateEnv { key, name, color, provider } => {
match self.manager.create_environment(&key, name, Some(color)) {
Ok(()) => {
if let Some(config) = self.manager.config_mut().environments.get_mut(&key) {
config.provider = provider;
}
if let Err(err) = self.manager.save() {
log_tui_error("save_config_after_create", err.as_ref());
}
self.refresh_list();
self.goto(AppScreen::EnvironmentList);
}
Err(err) => {
log_tui_error("create_environment", err.as_ref());
}
}
}
Action::DeleteEnv { key } => {
if let Err(err) = self.manager.delete_environment(&key) {
log_tui_error("delete_environment", err.as_ref());
}
self.refresh_list();
self.goto(AppScreen::EnvironmentList);
}
Action::SetDefault { key } => {
if let Err(err) = self.manager.set_default(Some(&key)) {
log_tui_error("set_default", err.as_ref());
}
}
Action::UpdateEnv { key, name, color, provider } => {
if let Some(config) = self.manager.config_mut().environments.get_mut(&key) {
config.name = name;
config.border_color = color;
config.provider = provider;
}
if let Err(err) = self.manager.save() {
log_tui_error("update_environment", err.as_ref());
}
self.refresh_list();
self.goto(AppScreen::EnvironmentList);
}
}
}
}
pub fn run_config_tui() -> Result<()> {
enable_raw_mode()?;
let mut stdout = stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut app = App::new()?;
app.refresh_list();
let result = run_app_loop(&mut terminal, &mut app);
if let Err(ref err) = result {
log_tui_error("run_app_loop", err.as_ref());
}
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
result
}
fn run_app_loop(
terminal: &mut Terminal<CrosstermBackend<std::io::Stdout>>,
app: &mut App,
) -> Result<()> {
while !app.should_quit {
let current_screen = app.current_screen.clone();
let config = app.manager.config().clone();
terminal.draw(|frame| {
match ¤t_screen {
AppScreen::EnvironmentList => app.list_screen.render(frame, &config),
AppScreen::CreateEnvironment => app.create_screen.render(frame),
AppScreen::EnvironmentSettings { .. } => app.settings_screen.render(frame),
AppScreen::ConfirmDelete { .. } => app.delete_screen.render(frame, &config),
}
})?;
if event::poll(Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press {
let action = match ¤t_screen {
AppScreen::EnvironmentList => {
app.list_screen.handle_input(key.code)
}
AppScreen::CreateEnvironment => {
app.create_screen.handle_input(key.code)
}
AppScreen::EnvironmentSettings { .. } => {
app.settings_screen.handle_input(key.code)
}
AppScreen::ConfirmDelete { .. } => {
app.delete_screen.handle_input(key.code)
}
};
app.handle_action(action);
}
}
}
}
Ok(())
}