use std::{
path::{Path, PathBuf},
sync::{
Arc, Mutex,
atomic::{AtomicUsize, Ordering},
},
thread,
};
use lexical_sort::PathSort;
use winit::event_loop::EventLoopProxy;
use super::op_queue::{LoadingInfo, prefetch};
use crate::{
app::cache::Cache,
util::{UserEvent, extensions::*},
};
type List = Arc<Mutex<Option<Vec<PathBuf>>>>;
pub struct ImageList {
list: List,
index: Arc<AtomicUsize>,
path: Option<PathBuf>,
cache: Arc<Cache>,
proxy: EventLoopProxy<UserEvent>,
loading_info: Arc<Mutex<LoadingInfo>>,
}
impl ImageList {
pub fn new(
cache: Arc<Cache>,
proxy: EventLoopProxy<UserEvent>,
loading_info: Arc<Mutex<LoadingInfo>>,
) -> Self {
Self {
list: Arc::new(Mutex::new(None)),
index: Arc::new(AtomicUsize::new(0)),
path: None,
proxy,
cache,
loading_info,
}
}
pub fn clear(&mut self) {
*self.list.lock().unwrap() = None;
self.path = None;
self.index.store(0, Ordering::SeqCst)
}
pub fn change_dir(&mut self, path: impl AsRef<Path>) {
let path_buf = path.as_ref().to_path_buf();
let mut dir_path = path_buf.clone();
dir_path.pop();
if dir_path == Path::new("") {
dir_path = PathBuf::from(".");
}
if let Some(ref p) = self.path
&& *p == dir_path
&& self.list.lock().unwrap().is_some()
{
let lock = self.list.lock().unwrap();
if let Some(ref dirs) = *lock {
for (index, path) in dirs.iter().enumerate() {
if *path == path_buf {
self.index.store(index, Ordering::SeqCst);
}
}
}
return;
}
self.path = Some(dir_path.clone());
let t_list = self.list.clone();
let t_index = self.index.clone();
let proxy = self.proxy.clone();
let cache = self.cache.clone();
let loading_info = self.loading_info.clone();
let mut list = vec![path_buf.clone()];
thread::spawn(move || {
let dirs = std::fs::read_dir(dir_path).unwrap();
for dir in dirs.flatten() {
if let Ok(file_type) = dir.file_type()
&& file_type.is_file()
{
let path = dir.path();
match dir.path().extension() {
Some(ext)
if EXTENSIONS
.contains(&&*ext.to_string_lossy().to_ascii_lowercase()) =>
{
list.push(path)
}
_ => (),
}
}
}
list.path_sort(lexical_sort::natural_lexical_cmp);
list.dedup();
for (index, path) in list.iter().enumerate() {
if *path == path_buf {
t_index.store(index, Ordering::SeqCst);
}
}
let next = list[next_index(t_index.load(Ordering::SeqCst), list.len())].clone();
prefetch(next, cache.clone(), proxy.clone(), loading_info.clone());
let prev = list[prev_index(t_index.load(Ordering::SeqCst), list.len())].clone();
prefetch(prev, cache.clone(), proxy.clone(), loading_info.clone());
*t_list.lock().unwrap() = Some(list);
});
}
pub fn next(&mut self) -> Option<PathBuf> {
let lock = self.list.lock().unwrap();
if let Some(ref list) = *lock {
self.index.fetch_add(1, Ordering::SeqCst);
if list.len() <= self.index.load(Ordering::SeqCst) {
self.index.store(0, Ordering::SeqCst);
}
prefetch(
list[next_index(self.index.load(Ordering::SeqCst), list.len())].clone(),
self.cache.clone(),
self.proxy.clone(),
self.loading_info.clone(),
);
Some(list[self.index.load(Ordering::SeqCst)].clone())
} else {
None
}
}
pub fn prev(&mut self) -> Option<PathBuf> {
let lock = self.list.lock().unwrap();
if let Some(ref list) = *lock {
if self.index.load(Ordering::SeqCst) == 0 {
self.index.store(list.len() - 1, Ordering::SeqCst);
} else {
self.index.fetch_sub(1, Ordering::SeqCst);
}
prefetch(
list[prev_index(self.index.load(Ordering::SeqCst), list.len())].clone(),
self.cache.clone(),
self.proxy.clone(),
self.loading_info.clone(),
);
Some(list[self.index.load(Ordering::SeqCst)].clone())
} else {
None
}
}
pub fn trash(&mut self, path: &PathBuf) -> Option<PathBuf> {
self.cache.pop(path);
let mut lock = self.list.lock().unwrap();
if let Some(ref mut list) = *lock {
let index = self.index.load(Ordering::SeqCst);
let p = list[index].clone();
if p == *path {
list.remove(index);
return list.get(index).cloned();
}
}
None
}
}
fn next_index(index: usize, len: usize) -> usize {
let next = index + 1;
if len <= next { 0 } else { next }
}
fn prev_index(index: usize, len: usize) -> usize {
let current = index;
if current == 0 { len - 1 } else { current - 1 }
}