use crate::{CacheEntry, Colors, FileInfo, SliceDisplay, State, WallSwitchResult};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path::PathBuf, str::FromStr};
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum SortCriteria {
Path,
Size,
SizeDesc,
Name,
Extension,
Width,
Height,
Area,
Ratio,
Time,
Processed, Unprocessed, Cache, }
impl FromStr for SortCriteria {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"path" => Ok(Self::Path),
"size" => Ok(Self::Size),
"sizedesc" => Ok(Self::SizeDesc),
"name" => Ok(Self::Name),
"extension" => Ok(Self::Extension),
"width" => Ok(Self::Width),
"height" => Ok(Self::Height),
"area" => Ok(Self::Area),
"ratio" => Ok(Self::Ratio),
"time" => Ok(Self::Time),
"processed" => Ok(Self::Processed),
"unprocessed" => Ok(Self::Unprocessed),
"cache" => Ok(Self::Cache),
_ => Err("Invalid criteria. \
Use: path, size, sizedesc, name, \
extension, width, height, area, ratio, \
time, processed, unprocessed, cache"
.to_string()),
}
}
}
pub fn list_json_cache(state: &State, criteria: SortCriteria) -> WallSwitchResult<()> {
let filtered: HashMap<&PathBuf, &CacheEntry> = state
.hashes
.iter()
.filter(|(_, entry)| match criteria {
SortCriteria::Processed => entry.dimension.is_some(),
SortCriteria::Unprocessed => entry.dimension.is_none(),
SortCriteria::Cache => true,
_ => false, })
.collect();
let json = serde_json::to_string_pretty(&filtered)?;
println!("{json}");
Ok(())
}
pub fn list_all_images(mut images: Vec<FileInfo>, criteria: SortCriteria) -> WallSwitchResult<()> {
let label = match criteria {
SortCriteria::Path => {
images.sort_by(|a, b| a.path.cmp(&b.path));
"PATH"
}
SortCriteria::Size => {
images.sort_by_key(|f| f.size);
"SIZE (ASC)"
}
SortCriteria::SizeDesc => {
images.sort_by_key(|b| std::cmp::Reverse(b.size));
"SIZE (DESC)"
}
SortCriteria::Name => {
images.sort_by(|a, b| a.path.file_name().cmp(&b.path.file_name()));
"FILE NAME"
}
SortCriteria::Extension => {
images.sort_by(|a, b| a.path.extension().cmp(&b.path.extension()));
"EXTENSION"
}
SortCriteria::Width => {
images.sort_by_key(|f| f.dimension.as_ref().map(|d| d.width).unwrap_or(0));
"WIDTH"
}
SortCriteria::Height => {
images.sort_by_key(|f| f.dimension.as_ref().map(|d| d.height).unwrap_or(0));
"HEIGHT"
}
SortCriteria::Area => {
images.sort_by_key(|f| {
f.dimension
.as_ref()
.map(|d| d.width * d.height)
.unwrap_or(0)
});
"AREA (TOTAL PIXELS)"
}
SortCriteria::Ratio => {
images.sort_by(|a, b| {
let r_a = a
.dimension
.as_ref()
.map(|d| d.width as f64 / d.height as f64)
.unwrap_or(0.0);
let r_b = b
.dimension
.as_ref()
.map(|d| d.width as f64 / d.height as f64)
.unwrap_or(0.0);
r_a.partial_cmp(&r_b).unwrap_or(std::cmp::Ordering::Equal)
});
"ASPECT RATIO"
}
SortCriteria::Time => {
images.sort_by_key(|f| f.mtime);
"MODIFICATION TIME (NEWEST LAST)"
}
_ => "CACHE STATE",
};
println!("Listing images sorted by {}:", label.yellow().bold());
let total = images.len();
for (i, img) in images.iter_mut().enumerate() {
img.number = i + 1;
img.total = total;
}
print!("{}", SliceDisplay(&images));
println!("\nTotal images found: {}", total.to_string().green().bold());
Ok(())
}