use super::themes::Theme;
use crate::models::AliasEntry;
#[derive(Debug, Clone, Copy)]
pub enum ExitAction {
Execute,
Populate,
}
use super::state::{
EntryData, EntryFilter, FilterState, GroupMode, InputMode, InputState, NavigationState, Panel, ScrollManager,
SearchState, SortOrder, UiState,
};
pub struct App {
data: EntryData,
search: SearchState,
ui: UiState,
input: InputState,
navigation: NavigationState,
filter: FilterState,
theme: Theme,
pub should_quit: bool,
pub exit_action: Option<ExitAction>,
}
impl App {
pub fn new(
entries: Vec<AliasEntry>,
theme: Theme,
) -> Self {
let mut app = Self {
data: EntryData::new(entries),
search: SearchState::new(),
ui: UiState::default(),
input: InputState::default(),
navigation: NavigationState::default(),
filter: FilterState::default(),
theme,
should_quit: false,
exit_action: None,
};
app.update_visible_entries();
app
}
pub fn selected_entry(&self) -> Option<&AliasEntry> {
self.data.get_visible_entry(self.navigation.selected_index())
}
pub fn update_visible_entries(&mut self) {
self.filter.update_visible_entries(&mut self.data, self.search.query());
self.navigation.clamp(self.data.visible_count());
self.ui.reset_detail_scroll();
}
pub fn entries(&self) -> &[AliasEntry] {
self.data.entries()
}
pub fn visible_indices(&self) -> &[usize] {
self.data.visible_indices()
}
pub fn search_query(&self) -> &str {
self.search.query()
}
pub fn cursor_position(&self) -> usize {
self.search.cursor_position()
}
pub fn selected_index(&self) -> usize {
self.navigation.selected_index()
}
pub fn input_mode(&self) -> InputMode {
self.input.mode()
}
pub fn active_panel(&self) -> Panel {
self.ui.active_panel()
}
pub fn filter(&self) -> EntryFilter {
self.filter.filter()
}
pub fn list_scroll_offset(&self) -> usize {
self.ui.list_scroll_offset()
}
pub fn description_scroll_offset(&self) -> usize {
self.ui.description_scroll_offset()
}
pub fn description_max_scroll(&self) -> usize {
self.ui.description_max_scroll()
}
pub fn script_scroll_offset(&self) -> usize {
self.ui.script_scroll_offset()
}
pub fn script_max_scroll(&self) -> usize {
self.ui.script_max_scroll()
}
pub fn pending_key(&self) -> Option<char> {
self.input.pending_key()
}
pub fn pending_key_time(&self) -> Option<std::time::Instant> {
self.input.pending_key_time()
}
pub fn show_help(&self) -> bool {
self.ui.show_help()
}
pub fn help_scroll_offset(&self) -> usize {
self.ui.help_scroll_offset()
}
pub fn help_max_scroll(&self) -> usize {
self.ui.help_max_scroll()
}
pub fn group_mode(&self) -> GroupMode {
self.filter.group_mode()
}
pub fn sort_order(&self) -> SortOrder {
self.filter.sort_order()
}
pub fn move_up(&mut self) {
self.navigation.move_up();
self.ui.reset_detail_scroll();
}
pub fn move_down(&mut self) {
self.navigation.move_down(self.data.visible_count());
self.ui.reset_detail_scroll();
}
pub fn move_top(&mut self) {
ScrollManager::move_top(&mut self.ui, &mut self.navigation);
}
pub fn move_bottom(&mut self) {
ScrollManager::move_bottom(&mut self.ui, &mut self.navigation, self.data.visible_count());
}
pub fn scroll_up(
&mut self,
amount: usize,
) {
ScrollManager::scroll_up(&mut self.ui, &mut self.navigation, amount);
}
pub fn scroll_down(
&mut self,
amount: usize,
) {
ScrollManager::scroll_down(&mut self.ui, &mut self.navigation, amount, self.data.visible_count());
}
pub fn cycle_panel(&mut self) {
self.ui.cycle_panel();
}
pub fn cycle_panel_backward(&mut self) {
self.ui.cycle_panel_backward();
}
pub fn cycle_filter(&mut self) {
self.filter.cycle_filter();
self.update_visible_entries();
}
pub fn cycle_filter_backward(&mut self) {
self.filter.cycle_filter_backward();
self.update_visible_entries();
}
pub fn set_filter(
&mut self,
filter: EntryFilter,
) {
self.filter.set_filter(filter);
self.update_visible_entries();
}
pub fn enter_search_mode(&mut self) {
self.input.enter_search();
}
pub fn exit_search_keep_query(&mut self) {
self.input.exit_search();
}
pub fn exit_search_clear_query(&mut self) {
self.input.exit_search();
self.search.clear();
self.update_visible_entries();
}
pub fn clear_search(&mut self) {
self.search.clear();
self.update_visible_entries();
}
pub fn set_search_query(
&mut self,
query: String,
) {
self.search.set_query(query);
self.update_visible_entries();
}
pub fn search_insert_char(
&mut self,
c: char,
) {
self.search.insert_char(c);
self.update_visible_entries();
}
pub fn search_delete_char(&mut self) {
self.search.delete_char();
self.update_visible_entries();
}
pub fn search_cursor_left(&mut self) {
self.search.move_cursor_left();
}
pub fn search_cursor_right(&mut self) {
self.search.move_cursor_right();
}
pub fn toggle_help(&mut self) {
self.ui.toggle_help();
}
pub fn help_scroll_down(&mut self) {
ScrollManager::help_scroll_down(&mut self.ui);
}
pub fn help_scroll_up(&mut self) {
ScrollManager::help_scroll_up(&mut self.ui);
}
pub fn help_jump_top(&mut self) {
ScrollManager::help_jump_top(&mut self.ui);
}
pub fn help_jump_bottom(&mut self) {
ScrollManager::help_jump_bottom(&mut self.ui);
}
pub fn update_help_max_scroll(
&mut self,
total_lines: usize,
visible_lines: usize,
) {
self.ui.update_help_max_scroll(total_lines, visible_lines);
}
pub fn update_description_max_scroll(
&mut self,
total_lines: usize,
visible_lines: usize,
) {
self.ui.update_description_max_scroll(total_lines, visible_lines);
}
pub fn update_script_max_scroll(
&mut self,
total_lines: usize,
visible_lines: usize,
) {
self.ui.update_script_max_scroll(total_lines, visible_lines);
}
pub fn cycle_group_mode(&mut self) {
self.filter.cycle_group_mode();
self.update_visible_entries();
}
pub fn cycle_group_mode_backward(&mut self) {
self.filter.cycle_group_mode_backward();
self.update_visible_entries();
}
pub fn toggle_sort_order(&mut self) {
self.filter.toggle_sort_order();
self.update_visible_entries();
}
pub fn is_pending_key_expired(&self) -> bool {
self.input.is_pending_key_expired()
}
pub fn clear_pending_key(&mut self) {
self.input.clear_pending_key();
}
pub fn set_pending_key(
&mut self,
key: char,
) {
self.input.set_pending_key(key);
}
pub fn select_entry(
&mut self,
action: ExitAction,
) {
if self.selected_entry().is_some() {
self.exit_action = Some(action);
}
self.should_quit = true;
}
pub fn tick(&mut self) {
if self.input.is_pending_key_expired() {
self.input.clear_pending_key();
}
}
pub fn cycle_theme_next(&mut self) {
let themes = Theme::available_themes();
let current = themes.iter().position(|n| n == &self.theme.name).unwrap_or(0);
let next = (current + 1) % themes.len();
if let Some(t) = Theme::from_name(&themes[next]) {
self.theme = t;
}
}
pub fn cycle_theme_prev(&mut self) {
let themes = Theme::available_themes();
let current = themes.iter().position(|n| n == &self.theme.name).unwrap_or(0);
let prev = (current + themes.len() - 1) % themes.len();
if let Some(t) = Theme::from_name(&themes[prev]) {
self.theme = t;
}
}
pub fn theme(&self) -> &Theme {
&self.theme
}
}
#[cfg(test)]
#[path = "app_tests.rs"]
pub(crate) mod app_tests;