use chrono::{DateTime, Local, NaiveTime, Utc};
use directories_next::BaseDirs;
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
use wallpaper_rs::{Desktop, DesktopEnvt};
mod solar;
pub fn match_dir(dir: Option<&str>) -> Result<(), Box<dyn Error>> {
match dir {
None => (),
Some(dir) => match generate_config(Path::new(dir)) {
Ok(_) => println!("Generated config file"),
Err(e) => eprintln!("Error generating config file: {}", e),
},
}
Ok(())
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
pub times: Vec<String>,
pub walls: Vec<String>,
}
pub fn get_config() -> Result<Config, Box<dyn Error>> {
let config_path = get_config_path()?;
let toml_file = std::fs::read_to_string(&config_path)?;
let toml_data: Config = toml::from_str(&toml_file)?;
Ok(toml_data)
}
pub fn get_dir(path: &Path, solar_filter: &str) -> Result<Vec<String>, Box<dyn Error>> {
let mut files: Vec<String> = std::fs::read_dir(path)?
.into_iter()
.map(|x| x.unwrap().path().display().to_string())
.filter(|y| y.contains(solar_filter))
.collect();
if cfg!(target_os = "linux") {
files = files
.into_iter()
.map(|y| "file://".to_string() + &y)
.filter(|y| y.contains(solar_filter))
.collect();
}
if cfg!(target_os = "macos") {
files = files.into_iter()
.filter(|y| y.contains(solar_filter))
.collect();
}
files.sort();
Ok(files)
}
pub fn generate_config_solar(path: &Path, lat: f64, long: f64) -> Result<(), Box<dyn Error>> {
println!("<---- Solar Mode ---->");
println!("Lat: {} Long: {}", &lat, &long);
let mut day_walls = get_dir(path, "DAY")?;
let night_walls = get_dir(path, "NIGHT")?;
let unixtime = DateTime::timestamp(&Utc::now()) as f64;
let tt = solar::Timetable::new(unixtime, lat, long);
let (sunrise, sunset) = tt.get_sunrise_sunset();
let day_len = (sunset - sunrise) % 86400;
let night_len = (86400 - day_len) % 86400;
let day_div = day_len / (day_walls.len()) as i64;
let night_div = night_len / (night_walls.len()) as i64;
let mut times = Vec::new();
for i in 0..day_walls.len() {
let absolute = sunrise + (day_div * (i as i64));
let time_str: String = solar::unix_to_local(absolute).format("%H:%M").to_string();
times.push(time_str);
}
for i in 0..night_walls.len() {
let absolute = sunset + (night_div * (i as i64));
let time_str: String = solar::unix_to_local(absolute).format("%H:%M").to_string();
times.push(time_str);
}
day_walls.extend(night_walls);
let config = Config {
times,
walls: day_walls,
};
let toml_string = toml::to_string(&config)?;
std::fs::write(&get_config_path()?, toml_string)?;
Ok(())
}
pub fn generate_config(path: &Path) -> Result<(), Box<dyn Error>> {
println!("<---- Normal Mode ---->");
let walls = get_dir(path, "")?;
let div = 86400 / walls.len();
let mut times = Vec::new();
for i in 0..walls.len() {
let offset = div * i;
times.push(format!("{:02}:{:02}", offset / 3600, (offset / 60) % 60));
}
let config = Config { times, walls };
let toml_string = toml::to_string(&config)?;
std::fs::write(&get_config_path()?, toml_string)?;
Ok(())
}
pub fn get_config_dir() -> Result<PathBuf, Box<dyn Error>> {
let base_dirs = BaseDirs::new().expect("Couldn't get base directory for the config file");
let mut config_file = base_dirs.config_dir().to_path_buf();
config_file.push("flowy");
std::fs::create_dir_all(&config_file)?;
Ok(config_file)
}
fn get_config_path() -> Result<PathBuf, Box<dyn Error>> {
let mut config_file = get_config_dir()?;
config_file.push("config.toml");
Ok(config_file)
}
pub fn set_times(config: Config) -> Result<(), Box<dyn Error>> {
let walls = config.walls;
let times = config.times;
println!("Times - {:#?}", ×);
println!("Paths - {:#?}", &walls);
let desktop_envt = DesktopEnvt::new().expect("Desktop envt could not be determined");
let mut last_index = None;
println!("<--- Daemon Listening --->");
loop {
let current_index = get_current_wallpaper_idx(×)?;
if Some(current_index) != last_index {
last_index = Some(current_index);
desktop_envt.set_wallpaper(&walls[current_index])?;
}
let t = 60;
thread::sleep(Duration::from_secs(t));
}
}
fn get_current_wallpaper_idx(wall_times: &[String]) -> Result<usize, Box<dyn Error>> {
if wall_times.is_empty() {
panic!("Array of times can't be empty");
}
let curr_time = Local::now().time();
let mut index = 0;
for time in wall_times {
let time = NaiveTime::parse_from_str(&time, "%H:%M")?;
if time > curr_time {
break;
}
index += 1;
}
if index == 0 {
index = wall_times.len() - 1;
return Ok(index);
}
Ok(index - 1)
}