use std::collections::HashMap;
use std::path::PathBuf;
use log::info;
use ratatui::layout::Rect;
use super::state::{
App, AppMode, DescriptionState, FocusedPanel, HelpState, MultiSelectState, PreviewState,
SearchState, StatefulList,
};
use crate::ui::state::{ScriptItem, UiOptions};
use crate::ui::theme::Theme;
impl<'a> App<'a> {
pub fn new(options: &UiOptions) -> App<'a> {
let theme = match options.theme.as_str() {
"catppuccin-mocha" => Theme::catppuccin_mocha(),
"dracula" => Theme::dracula(),
"gruvbox" => Theme::gruvbox(),
"nord" => Theme::nord(),
"rose-pine" => Theme::rose_pine(),
_ => Theme::catppuccin_mocha(),
};
App {
mode: if options.is_root { AppMode::RootWarning } else { AppMode::Normal },
quit: false,
focused_panel: FocusedPanel::Categories,
log_mode: false,
modules_dir: PathBuf::new(),
theme,
theme_locked: options.theme_locked,
scripts: StatefulList::new(),
categories: StatefulList::new(),
all_scripts: HashMap::new(),
script_panel_area: Rect::default(),
preview: PreviewState::default(),
search: SearchState::default(),
multi_select: MultiSelectState::default(),
help: HelpState::default(),
description: DescriptionState::default(),
run_script_popup: None,
script_execution_queue: Vec::new(),
}
}
pub fn cycle_theme(&mut self) {
self.theme = match self.theme.name.as_str() {
"Catppuccin Mocha" => Theme::dracula(),
"Dracula" => Theme::gruvbox(),
"Gruvbox" => Theme::nord(),
"Nord" => Theme::rose_pine(),
"Rosé Pine" => Theme::catppuccin_mocha(),
_ => Theme::catppuccin_mocha(),
}
}
pub fn toggle_description_popup(&mut self) {
if self.mode == AppMode::Description {
self.mode = AppMode::Normal;
self.description.content = None;
if self.log_mode {
info!("Closed description popup");
}
} else if let Some(selected_script) = self.get_selected_script() {
let desc_path = self.modules_dir.join(&selected_script.category).join("desc.toml");
if self.log_mode {
info!(
"Attempting to show description for script: {}/{}",
selected_script.category, selected_script.name
);
info!("Description file path: {}", desc_path.display());
}
if desc_path.exists() {
if let Ok(content) = std::fs::read_to_string(&desc_path) {
if let Ok(table) = content.parse::<toml::Table>() {
let script_path = PathBuf::from(&selected_script.name);
let script_name_without_ext =
script_path.file_stem().and_then(|s| s.to_str());
if let Some(name) = script_name_without_ext {
if let Some(desc) = table
.get(name)
.and_then(|v| v.as_table())
.and_then(|t| t.get("description"))
.and_then(|v| v.as_str())
{
self.description.content = Some(desc.to_string());
self.mode = AppMode::Description;
if self.log_mode {
info!(
"Successfully loaded description and entered description mode."
);
}
} else if self.log_mode {
info!(
"No description found for script '{}' in desc.toml",
selected_script.name
);
}
}
} else if self.log_mode {
info!("Failed to parse desc.toml at {}", desc_path.display());
}
} else if self.log_mode {
info!("Failed to read desc.toml at {}", desc_path.display());
}
} else if self.log_mode {
info!("desc.toml not found at {}", desc_path.display());
}
}
}
pub fn get_selected_script(&self) -> Option<&ScriptItem> {
self.scripts.state.selected().map(|i| &self.scripts.items[i])
}
}