use anyhow::Result;
use std::path::{Path, PathBuf};
use crate::{
app_state::AppState,
modes::ModeAction,
services::{DataProvider, FilesystemService, PreviewManager},
utils::DisplayItem,
};
pub struct FileListDataProvider;
impl DataProvider for FileListDataProvider {
fn get_preview_path(&self, state: &AppState) -> Option<PathBuf> {
if let Some(DisplayItem::File(file)) = state.get_selected_item() {
Some(file.path)
} else {
None
}
}
fn navigate_into_directory(&self, state: &mut AppState) -> Result<Option<ModeAction>> {
if let Some(file) = state.get_selected_item()
&& file.is_directory() {
self.save_position(state);
state.current_dir = file.get_path().to_path_buf();
self.on_directory_changed(state, &state.current_dir.clone())?;
return Ok(None); }
Ok(None)
}
fn navigate_to_parent(&self, state: &mut AppState) -> Result<Option<ModeAction>> {
if state.current_dir.to_string_lossy() == "DRIVES:" {
return Ok(None);
}
if let Some(parent) = state.current_dir.parent() {
let parent_path = parent.to_path_buf();
self.save_position(state);
state.current_dir = parent_path.clone();
self.on_directory_changed(state, &parent_path)?;
Ok(None) } else {
#[cfg(windows)]
{
if self.is_windows_drive_root(&state.current_dir) {
self.save_position(state);
state.current_dir = PathBuf::from("DRIVES:");
self.on_directory_changed(state, &state.current_dir.clone())?;
return Ok(None);
}
}
Ok(None)
}
}
fn load_data(&self, state: &mut AppState) -> Result<()> {
let files = FilesystemService::load_directory(&state.current_dir)?;
state.load_file_items(files);
state.apply_search_filter();
Ok(())
}
fn save_position(&self, state: &mut AppState) {
if let Some(selected) = state.file_list_state.selected() {
state
.dir_positions
.insert(state.current_dir.clone(), selected);
}
}
fn restore_position(&self, state: &mut AppState) {
if let Some(&saved_position) = state.dir_positions.get(&state.current_dir) {
if saved_position < state.filtered_files.len() {
state.file_list_state.select(Some(saved_position));
} else {
if !state.filtered_files.is_empty() {
state
.file_list_state
.select(Some(state.filtered_files.len() - 1));
} else {
state.file_list_state.select(None);
}
}
} else {
state.file_list_state.select(None);
}
}
fn on_directory_changed(&self, state: &mut AppState, _new_dir: &Path) -> Result<()> {
state.search_input.clear();
state.is_searching = false;
self.load_data(state)?;
self.restore_position(state);
PreviewManager::clear_preview(state);
Ok(())
}
}
impl FileListDataProvider {
#[cfg(windows)]
fn is_windows_drive_root(&self, path: &PathBuf) -> bool {
let path_str = path.to_string_lossy();
path_str.len() == 3
&& path_str.ends_with(":\\")
&& path_str.chars().next().unwrap().is_ascii_alphabetic()
}
}