fix: wallpaper discovery
Allows settings to show installed wallpapers. - Modified `load_each_from_path` to recursively discover wallpapers, limited depth to 3 for performance.
This commit is contained in:
parent
1b2aba0107
commit
8ca65bafe4
4 changed files with 34 additions and 49 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1844,6 +1844,7 @@ dependencies = [
|
||||||
"jxl-oxide",
|
"jxl-oxide",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -1178,11 +1178,6 @@ pub async fn change_folder(current_folder: PathBuf) -> Context {
|
||||||
let mut update = Context::default();
|
let mut update = Context::default();
|
||||||
let mut streams = Vec::with_capacity(2);
|
let mut streams = Vec::with_capacity(2);
|
||||||
|
|
||||||
// Include the cosmic background folder when loading the system wallpapers.
|
|
||||||
if current_folder == Config::default_folder() {
|
|
||||||
streams.push(wallpaper::load_each_from_path(Config::default_folder().join("cosmic")).await);
|
|
||||||
}
|
|
||||||
|
|
||||||
streams.push(wallpaper::load_each_from_path(current_folder).await);
|
streams.push(wallpaper::load_each_from_path(current_folder).await);
|
||||||
|
|
||||||
for mut wallpapers in streams {
|
for mut wallpapers in streams {
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,4 @@ infer = "0.16.0"
|
||||||
jxl-oxide = "0.11.3"
|
jxl-oxide = "0.11.3"
|
||||||
tokio = { version = "1.44.1", features = ["sync"] }
|
tokio = { version = "1.44.1", features = ["sync"] }
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
|
walkdir = "=2.5.0"
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,20 @@ pub use cosmic_bg_config::{Color, Config, Entry, Gradient, ScalingMode, Source};
|
||||||
use eyre::{eyre, OptionExt};
|
use eyre::{eyre, OptionExt};
|
||||||
use fast_image_resize::SrcCropping;
|
use fast_image_resize::SrcCropping;
|
||||||
use futures_lite::Stream;
|
use futures_lite::Stream;
|
||||||
|
use futures_util::StreamExt;
|
||||||
use image::imageops::FilterType;
|
use image::imageops::FilterType;
|
||||||
use image::{DynamicImage, ImageBuffer, Rgba, RgbaImage};
|
use image::{DynamicImage, ImageBuffer, Rgba, RgbaImage};
|
||||||
use jxl_oxide::{EnumColourEncoding, JxlImage, PixelFormat};
|
use jxl_oxide::{EnumColourEncoding, JxlImage, PixelFormat};
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::{hash_map::DefaultHasher, BTreeSet, HashMap},
|
collections::{hash_map::DefaultHasher, HashMap},
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
io::Read,
|
io::Read,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
};
|
};
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
pub const DEFAULT_COLORS: &[Color] = &[
|
pub const DEFAULT_COLORS: &[Color] = &[
|
||||||
Color::Single([0.580, 0.922, 0.922]),
|
Color::Single([0.580, 0.922, 0.922]),
|
||||||
|
|
@ -99,54 +101,40 @@ pub fn cache_dir() -> Option<PathBuf> {
|
||||||
pub async fn load_each_from_path(
|
pub async fn load_each_from_path(
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
) -> Pin<Box<dyn Send + Stream<Item = (PathBuf, RgbaImage, RgbaImage)>>> {
|
) -> Pin<Box<dyn Send + Stream<Item = (PathBuf, RgbaImage, RgbaImage)>>> {
|
||||||
let wallpapers = tokio::task::spawn_blocking(move || {
|
let candidate_paths: Vec<_> = WalkDir::new(path)
|
||||||
// Discovered image files that will be loaded as wallpapers.
|
.max_depth(3)
|
||||||
let mut wallpapers = BTreeSet::new();
|
.into_iter()
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.filter(|entry| entry.file_type().is_file())
|
||||||
|
.map(|entry| entry.path().to_path_buf())
|
||||||
|
.collect();
|
||||||
|
|
||||||
if let Ok(dir) = path.read_dir() {
|
let future = futures_util::stream::iter(candidate_paths)
|
||||||
for entry in dir.filter_map(Result::ok) {
|
.map(|path| {
|
||||||
let Ok(file_type) = entry.file_type() else {
|
tokio::task::spawn_blocking(move || {
|
||||||
continue;
|
let is_jxl = path.extension().map(|ext| ext == "jxl").unwrap_or_default();
|
||||||
|
let is_image = if !is_jxl {
|
||||||
|
if let Ok(Some(kind)) = infer::get_from_path(&path) {
|
||||||
|
infer::MatcherType::Image == kind.matcher_type()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = entry.path();
|
if is_jxl || is_image {
|
||||||
|
load_image_with_thumbnail(path)
|
||||||
if file_type.is_file() {
|
} else {
|
||||||
let path = if path.extension().map(|ext| ext == "jxl").unwrap_or_default() {
|
None
|
||||||
path
|
|
||||||
} else if let Ok(Some(kind)) = infer::get_from_path(&path) {
|
|
||||||
if infer::MatcherType::Image == kind.matcher_type() {
|
|
||||||
path
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
wallpapers.insert(path);
|
|
||||||
|
|
||||||
if wallpapers.len() > 99 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
|
.buffered(4)
|
||||||
|
.filter_map(|value| async { value.ok().flatten() })
|
||||||
|
.take(100);
|
||||||
|
|
||||||
wallpapers
|
Box::pin(future)
|
||||||
});
|
|
||||||
|
|
||||||
if let Ok(wallpapers) = wallpapers.await {
|
|
||||||
use futures_util::StreamExt;
|
|
||||||
let future = futures_util::stream::iter(wallpapers)
|
|
||||||
.map(|path| tokio::task::spawn_blocking(|| load_image_with_thumbnail(path)))
|
|
||||||
.buffered(4)
|
|
||||||
.filter_map(|value| async { value.ok()? });
|
|
||||||
|
|
||||||
Box::pin(future)
|
|
||||||
} else {
|
|
||||||
Box::pin(futures_lite::stream::empty())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue