image_collage/tui/
explorer.rs1use anyhow::Result;
2use std::{env, fs, path::PathBuf};
3
4use crate::utils::is_image_file;
5
6pub struct FileExplorer {
8 current_dir: PathBuf,
9 entries: Vec<PathBuf>,
10 selected_index: usize,
11 selected_images: Vec<PathBuf>,
12}
13
14impl FileExplorer {
15 pub fn new() -> Result<Self> {
17 let current_dir = env::current_dir()?;
18 let mut explorer = FileExplorer {
19 current_dir: current_dir.clone(),
20 entries: Vec::new(),
21 selected_index: 0,
22 selected_images: Vec::new(),
23 };
24 explorer.refresh_entries()?;
25 Ok(explorer)
26 }
27
28 fn refresh_entries(&mut self) -> Result<()> {
33 let mut entries = Vec::new();
34
35 if let Some(parent) = self.current_dir.parent() {
36 entries.push(parent.to_path_buf());
37 }
38
39 for entry in fs::read_dir(&self.current_dir)? {
40 let entry = entry?;
41 let path = entry.path();
42
43 if path.is_dir() || is_image_file(&path) {
44 entries.push(path);
45 }
46 }
47
48 entries.sort_by(|a, b| {
49 let a_is_dir = a.is_dir();
50 let b_is_dir = b.is_dir();
51 match (a_is_dir, b_is_dir) {
52 (true, false) => std::cmp::Ordering::Less,
53 (false, true) => std::cmp::Ordering::Greater,
54 _ => a.file_name().cmp(&b.file_name()),
55 }
56 });
57
58 self.entries = entries;
59 self.selected_index = 0;
60 Ok(())
61 }
62
63 pub fn move_up(&mut self) {
65 if self.selected_index > 0 {
66 self.selected_index -= 1;
67 }
68 }
69
70 pub fn move_down(&mut self) {
72 if self.selected_index < self.entries.len().saturating_sub(1) {
73 self.selected_index += 1;
74 }
75 }
76
77 pub fn enter_selected(&mut self) -> Result<()> {
83 if let Some(path) = self.entries.get(self.selected_index) {
84 if path.is_dir() {
85 self.current_dir = path.clone();
86 self.refresh_entries()?;
87 } else if is_image_file(path) {
88 if let Some(pos) = self.selected_images.iter().position(|p| p == path) {
89 self.selected_images.remove(pos);
90 } else if self.selected_images.len() < 4 {
91 self.selected_images.push(path.clone());
92 }
93 }
94 }
95 Ok(())
96 }
97
98 pub fn go_up(&mut self) -> Result<()> {
100 if let Some(parent) = self.current_dir.parent() {
101 self.current_dir = parent.to_path_buf();
102 self.refresh_entries()?;
103 }
104 Ok(())
105 }
106
107 pub fn current_dir(&self) -> &PathBuf {
109 &self.current_dir
110 }
111
112 pub fn entries(&self) -> &[PathBuf] {
114 &self.entries
115 }
116
117 pub fn selected_index(&self) -> usize {
119 self.selected_index
120 }
121
122 pub fn selected_images(&self) -> &[PathBuf] {
124 &self.selected_images
125 }
126}