Set scaling mode from args and configs

This commit is contained in:
Candifloss 2025-12-18 13:38:02 +05:30
parent 84186d3d66
commit 7fc8c0051f
3 changed files with 61 additions and 15 deletions

View File

@ -7,7 +7,7 @@ use std::path::PathBuf;
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pub background_image: String,
pub mode: Option<String>, // Unused now, deal with it later
pub mode: Option<String>,
}
impl Config {

View File

@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{Context, Result};
use std::path::PathBuf;
use crate::{args, config, wallpaper};
@ -12,6 +12,13 @@ pub fn resolve_wallpaper(
args: &args::Args,
config: Option<config::Config>,
) -> Result<WallpaperSettings> {
// Borrow the config once as `Option<&Config>`.
//
// Avoids moving `config`, allows to:
// - read values multiple times
// - decide later whether we need to write a new config
let cfg_ref = config.as_ref();
// Resolve wallpaper image path by precedence:
// 1. args (`--set`, `--update`): Use path from args.
// 2. config: Use path from config.
@ -21,10 +28,16 @@ pub fn resolve_wallpaper(
// Case: arg `--update`. Persist wallpaper path to config (create if missing), then apply it.
(None, Some(path)) => {
let cfg = config.unwrap_or_else(|| config::Config {
background_image: String::new(),
mode: None,
});
// Use existing config if present.
// Otherwise, create a minimal temporary config only for writing.
// Avoids moving or cloning the original config, keeps ownership simple.
let cfg = match cfg_ref {
Some(cfg) => cfg,
None => &config::Config {
background_image: String::new(),
mode: None,
},
};
// Write to config.
cfg.update_background_image(
@ -37,21 +50,42 @@ pub fn resolve_wallpaper(
// Case: No args. Fallback to config file.
(None, None) => {
let cfg = config.ok_or_else(|| {
let cfg = cfg_ref.ok_or_else(|| {
// No CLI args and no valid config.
anyhow::anyhow!("No or invalid image path specified in config or args.")
})?;
// Successfully loaded.
cfg.background_image.into()
cfg.background_image.clone().into()
}
// Case: Both args `--set` & `--update`. This case is already rejected during argument parsing.
_ => unreachable!(),
};
//let mode = wallpaper::ScalingMode::Stretch; //
let mode = wallpaper::ScalingMode::Fill; // Default
// Resolve scaling mode by precedence:
// 1. CLI argument (`--mode`) if provided
// 2. Config file value if present
// 3. Default to Fill
let mode = if let Some(mode_arg) = &args.mode {
// CLI has highest priority
mode_arg
.parse::<wallpaper::ScalingMode>()
.with_context(|| "Invalid wallpaper mode in CLI")?
} else if let Some(cfg) = cfg_ref {
if let Some(mode_str) = &cfg.mode {
// Config-specified mode
mode_str
.parse::<wallpaper::ScalingMode>()
.with_context(|| "Invalid wallpaper mode in config")?
} else {
// Config exists, but mode not specified
wallpaper::ScalingMode::Fill
}
} else {
// No CLI and no config → default
wallpaper::ScalingMode::Fill
};
Ok(WallpaperSettings { path, mode })
}

View File

@ -1,15 +1,26 @@
use anyhow::{Context, Result};
use image::{RgbaImage, imageops};
use std::path::Path;
use std::{path::Path, str::FromStr};
/// Supported wallpaper scaling modes.
///
/// Others are defined so the public API does not need to change later.
#[derive(Debug, Clone, Copy)]
pub enum ScalingMode {
Stretch,
Fill,
// Fit,
}
impl FromStr for ScalingMode {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
// Accept human-friendly strings from CLI / config.
// Case-insensitive to reduce user friction.
match s.to_lowercase().as_str() {
"fill" => Ok(ScalingMode::Fill),
"stretch" => Ok(ScalingMode::Stretch),
_ => Err(anyhow::anyhow!("Invalid wallpaper mode: {s}")),
}
}
}
/// Result of preparing a wallpaper image for the screen.
@ -116,9 +127,10 @@ pub fn prepare_wallpaper(
.with_context(|| format!("Failed to open image: {}", image_path.display()))?
.to_rgba8();
// Scaling mode
let prepared = match mode {
ScalingMode::Fill => prepare_fill(&img, screen_width, screen_height), // Default
ScalingMode::Stretch => prepare_stretch(&img, screen_width, screen_height),
ScalingMode::Fill => prepare_fill(&img, screen_width, screen_height),
};
Ok(prepared)