ferrite_navigation/
manager.rs1use crate::error::{NavigationError, Result};
2use ferrite_image::SupportedFormats;
3use std::{
4 fs,
5 path::{Path, PathBuf},
6};
7use tracing::{info, instrument};
8
9pub struct NavigationManager {
10 directory_images: Vec<PathBuf>,
11 current_index: usize,
12}
13
14impl NavigationManager {
15 pub fn new() -> Self {
16 Self {
17 directory_images: Vec::new(), current_index: 0
18 }
19 }
20
21 #[instrument(skip(self, image_path), fields(path = ?image_path))]
22 pub fn load_current_directory(&mut self, image_path: &Path) -> Result<()> {
23 let absolute_path = fs::canonicalize(image_path)
24 .map_err(NavigationError::DirectoryAccess)?;
25
26 let parent_dir = absolute_path.parent().ok_or_else(|| {
27 NavigationError::InvalidPath(image_path.to_path_buf())
28 })?;
29
30 info!("Loading images from directory: {}", parent_dir.display());
31
32 self.directory_images = fs::read_dir(parent_dir)
34 .map_err(NavigationError::DirectoryAccess)?
35 .filter_map(|entry| {
36 entry.ok().and_then(|e| {
37 let path = e.path();
38 if path.is_file()
39 && SupportedFormats::is_supported(path.extension())
40 {
41 Some(path)
42 } else {
43 None
44 }
45 })
46 })
47 .collect();
48
49 self.directory_images.sort();
50
51 self.current_index = self
52 .directory_images
53 .iter()
54 .position(|p| p == &absolute_path)
55 .unwrap_or(0);
56
57 info!(
58 "Found {} images in directory, current image at index {}",
59 self.directory_images.len(),
60 self.current_index
61 );
62
63 Ok(())
64 }
65
66 pub fn get_nearby_paths(
67 &self,
68 count: usize,
69 ) -> (Vec<PathBuf>, Vec<PathBuf>) {
70 if self.directory_images.is_empty() {
71 return (Vec::new(), Vec::new());
72 }
73
74 let total_images = self.directory_images.len();
75 let mut next_paths = Vec::with_capacity(count);
76 let mut prev_paths = Vec::with_capacity(count);
77
78 for i in 1..=count {
79 let next_index = (self.current_index + i) % total_images;
81 if next_index != self.current_index {
82 next_paths.push(self.directory_images[next_index].clone());
83 }
84
85 let prev_index = if i <= self.current_index {
87 self.current_index - i
88 } else {
89 total_images - (i - self.current_index)
90 };
91 if prev_index < total_images && prev_index != self.current_index {
92 prev_paths.push(self.directory_images[prev_index].clone());
93 }
94 }
95
96 (prev_paths, next_paths)
97 }
98
99 pub fn next_image(&mut self) -> Option<PathBuf> {
100 if self.directory_images.is_empty() {
101 return None;
102 }
103 self.current_index =
104 (self.current_index + 1) % self.directory_images.len();
105 Some(self.directory_images[self.current_index].clone())
106 }
107
108 pub fn previous_image(&mut self) -> Option<PathBuf> {
109 if self.directory_images.is_empty() {
110 return None;
111 }
112 self.current_index = if self.current_index == 0 {
113 self.directory_images.len() - 1
114 } else {
115 self.current_index - 1
116 };
117 Some(self.directory_images[self.current_index].clone())
118 }
119}