1#![allow(
5 clippy::cast_possible_truncation,
6 clippy::cast_possible_wrap,
7 clippy::cast_precision_loss,
8 clippy::cast_sign_loss
9)]
10use anyhow::{Context, Result};
11
12use super::{App, ImageMeta};
13
14pub fn is_image_name(name: &str) -> bool {
17 let ext = std::path::Path::new(name)
18 .extension()
19 .map(|e| e.to_string_lossy().to_ascii_lowercase())
20 .unwrap_or_default();
21 matches!(
22 ext.as_str(),
23 "png" | "jpg" | "jpeg" | "gif" | "webp" | "bmp" | "ico" | "tiff" | "tif" | "avif" | "svg"
24 )
25}
26
27impl App {
28 pub fn refresh_images(&mut self) {
32 let dir = self.space.files_dir(&self.active_space.name);
33 let _ = std::fs::create_dir_all(&dir);
34 self.images_cache = match std::fs::read_dir(&dir) {
35 Err(_) => Vec::new(),
36 Ok(entries) => entries
37 .flatten()
38 .filter(|e| e.path().is_file())
39 .filter(|e| is_image_name(&e.file_name().to_string_lossy()))
40 .filter_map(|e| {
41 let meta = e.metadata().ok()?;
42 let modified = meta
43 .modified()
44 .ok()
45 .and_then(|t| {
46 chrono::DateTime::from_timestamp(
47 t.duration_since(std::time::UNIX_EPOCH).ok()?.as_secs() as i64,
48 0,
49 )
50 })
51 .map(|dt| dt.to_rfc3339())
52 .unwrap_or_default();
53 Some(ImageMeta {
54 name: e.file_name().to_string_lossy().to_string(),
55 size: meta.len(),
56 modified,
57 })
58 })
59 .collect(),
60 };
61 self.images_cache.sort_by(|a, b| a.name.cmp(&b.name));
62 }
63
64 pub fn delete_image_file(&mut self, name: &str) -> Result<bool> {
68 let dir = self.space.files_dir(&self.active_space.name);
69 let path = dir.join(name);
70 if path.exists() {
71 std::fs::remove_file(&path).with_context(|| format!("removing {}", path.display()))?;
72 self.push_status(format!("removed {name}"));
73 self.refresh_images();
74 Ok(true)
75 } else {
76 Ok(false)
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::is_image_name;
84
85 #[test]
86 fn image_names_match_only_raster_formats() {
87 assert!(is_image_name("paste.png"));
88 assert!(is_image_name("photo.JPG"));
89 assert!(is_image_name("a.b.webp"));
90 assert!(is_image_name("diagram.svg"));
91 assert!(!is_image_name("notes.md"));
92 assert!(!is_image_name("script.py"));
93 assert!(!is_image_name("archive.tar.gz"));
94 assert!(!is_image_name("README"));
95 assert!(!is_image_name(".hidden"));
96 }
97}