// Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only use cosmic::cosmic_config::{self, ConfigGet, ConfigSet}; use cosmic_settings_desktop::wallpaper; use std::collections::VecDeque; use std::path::{Path, PathBuf}; const NAME: &str = "com.system76.CosmicSettings.Wallpaper"; const VERSION: u64 = 1; const CURRENT_FOLDER: &str = "current-folder"; const CUSTOM_COLORS: &str = "custom-colors"; const CUSTOM_IMAGES: &str = "custom-images"; const RECENT_FOLDERS: &str = "recent-folders"; #[derive(Debug, Default)] pub struct Config { context: Option, current_folder: Option, custom_colors: Vec, custom_images: Vec, recent_folders: VecDeque, } impl Config { pub fn new() -> Self { let mut config = Self::default(); let context = match cosmic_config::Config::new(NAME, VERSION) { Ok(context) => context, Err(why) => { tracing::warn!(?why, "failed to get config"); return Self::default(); } }; if let Ok(path) = dbg!(context.get::(CURRENT_FOLDER)) { config.current_folder = Some(path); } if let Ok(colors) = context.get::>(CUSTOM_COLORS) { config.custom_colors = colors; } if let Ok(images) = context.get::>(CUSTOM_IMAGES) { config.custom_images = images; } if let Ok(folders) = dbg!(context.get::>(RECENT_FOLDERS)) { config.recent_folders = folders; } config.context = Some(context); config } #[must_use] pub fn current_folder(&self) -> &Path { self.current_folder .as_deref() .unwrap_or(Path::new("/usr/share/backgrounds/")) } /// Sets the current background folder /// /// # Errors /// /// Returns an error if the on-disk configuration could not be updated. pub fn set_current_folder(&mut self, folder: PathBuf) -> Result<(), cosmic_config::Error> { let result = self.update(CURRENT_FOLDER, &folder); self.current_folder = Some(folder); result } #[must_use] pub fn custom_colors(&self) -> &[wallpaper::Color] { &self.custom_colors } /// Adds a custom color /// /// # Errors /// /// Returns an error if the on-disk configuration could not be updated. pub fn add_custom_color( &mut self, color: wallpaper::Color, ) -> Result<(), cosmic_config::Error> { if !self.custom_colors.contains(&color) { self.custom_colors.push(color); return self.update_custom_colors(); } Ok(()) } /// Removes custom background colors. /// /// # Errors /// /// Returns an error if the on-disk configuration could not be updated. pub fn remove_custom_color( &mut self, color: &wallpaper::Color, ) -> Result<(), cosmic_config::Error> { if let Some(position) = self.custom_colors.iter().position(|c| c == color) { self.custom_colors.remove(position); return self.update_custom_colors(); } Ok(()) } #[must_use] pub fn custom_images(&self) -> &[PathBuf] { &self.custom_images } /// Adds a custom background image /// /// # Errors /// /// Returns an error if the on-disk configuration could not be updated. pub fn add_custom_image(&mut self, image: PathBuf) -> Result<(), cosmic_config::Error> { if !self.custom_images.contains(&image) { self.custom_images.push(image); return self.update_custom_images(); } Ok(()) } /// Removes custom background images. /// /// # Errors /// /// Returns an error if the on-disk configuration could not be updated. pub fn remove_custom_image(&mut self, image: &Path) -> Result<(), cosmic_config::Error> { if let Some(position) = self.custom_images.iter().position(|p| p == image) { self.custom_images.remove(position); return self.update_custom_images(); } Ok(()) } #[must_use] pub fn recent_folders(&self) -> &VecDeque { &self.recent_folders } /// Adds a folder to the recent folders list /// /// # Errors /// /// Returns an error if the on-disk configuration could not be updated. pub fn add_recent_folder(&mut self, folder: PathBuf) -> Result<(), cosmic_config::Error> { while self.recent_folders.len() > 4 { self.recent_folders.pop_front(); } if !self.recent_folders.contains(&folder) { self.recent_folders.push_back(folder); return self.update_recent_folders(); } Ok(()) } fn update( &self, key: &str, value: &V, ) -> Result<(), cosmic_config::Error> { if let Some(context) = self.context.as_ref() { context.set(key, value)?; } Ok(()) } fn update_custom_colors(&self) -> Result<(), cosmic_config::Error> { self.update(CUSTOM_COLORS, &self.custom_colors) } fn update_custom_images(&self) -> Result<(), cosmic_config::Error> { self.update(CUSTOM_IMAGES, &self.custom_images) } fn update_recent_folders(&self) -> Result<(), cosmic_config::Error> { self.update(RECENT_FOLDERS, &self.recent_folders) } }