Make configuration file optional
This commit is contained in:
		
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,6 +2,20 @@ | ||||
|  | ||||
| This is a Rust implementation of cinnamon’s [Seasonal Hours Clock](https://github.com/cinnamon-bun/seasonal-hours-clock), running as a native Wayland application. | ||||
|  | ||||
| ## Configuration | ||||
|  | ||||
| Create a file `$XDG_CONFIG_HOME/seasonal-clock.toml` (where `$XDG_CONFIG_HOME` is `~/.config` on Linux systems) with the following content: | ||||
|  | ||||
| ``` | ||||
| [seasonal-clock] | ||||
| latitude = 47.655 | ||||
| longitude = 19.286 | ||||
| ``` | ||||
|  | ||||
| (this is a location around Hungary; you may want to change these.) | ||||
|  | ||||
| If you don’t provide a configuration file, the day parts (day/night time and the golden/blue hours) won’t be visible on the clock face. | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| ### Seasonal hours! | ||||
|   | ||||
							
								
								
									
										295
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										295
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -48,7 +48,7 @@ impl fmt::Display for Season { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Deserialize)] | ||||
| #[derive(Deserialize, Copy, Clone)] | ||||
| struct Config { | ||||
|     latitude: f64, | ||||
|     longitude: f64, | ||||
| @@ -256,7 +256,7 @@ fn get_moon_path(image_width: u32, radius: f32, moon_phase: f64) -> Path { | ||||
|     Path::new().set("class", "moon").set("d", path_data) | ||||
| } | ||||
|  | ||||
| fn gen_svg(config: &Config) -> Document { | ||||
| fn gen_svg(config: &Option<Config>) -> Document { | ||||
|     let local_timestamp = Local::now(); | ||||
|     let utc_hour = local_timestamp.with_timezone(&Utc).time().hour(); | ||||
|     let local_hour = local_timestamp.time().hour(); | ||||
| @@ -276,40 +276,6 @@ fn gen_svg(config: &Config) -> Document { | ||||
|     let moon_radius = image_width as f32 * 0.071428571; | ||||
|     let moon_phase = moon_illumination.phase * 28.0; | ||||
|  | ||||
|     let sun_times = suncalc::get_times(unixtime, config.latitude, config.longitude, None); | ||||
|     let noon = Utc | ||||
|         .timestamp_millis(sun_times.solar_noon.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let midnight = Utc | ||||
|         .timestamp_millis(sun_times.nadir.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let morning_golden_end = Utc | ||||
|         .timestamp_millis(sun_times.golden_hour_end.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let evening_golden_start = Utc | ||||
|         .timestamp_millis(sun_times.golden_hour.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let sunrise = Utc | ||||
|         .timestamp_millis(sun_times.sunrise.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let sunset = Utc | ||||
|         .timestamp_millis(sun_times.sunset.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let dawn = Utc | ||||
|         .timestamp_millis(sun_times.dawn.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|     let dusk = Utc | ||||
|         .timestamp_millis(sun_times.dusk.0) | ||||
|         .time() | ||||
|         .num_seconds_from_midnight() as i32; | ||||
|  | ||||
|     let local_hour_font_size = image_width as f32 * 0.02357; | ||||
|     let hour_name_font_size = image_width as f32 * 0.019109; | ||||
|     let utc_hour_font_size = image_width as f32 * 0.021462; | ||||
| @@ -406,102 +372,147 @@ fn gen_svg(config: &Config) -> Document { | ||||
|         .set("cy", image_width / 2) | ||||
|         .set("r", marker_radius); | ||||
|  | ||||
|     let golden_hour_path = get_range_path( | ||||
|         image_width, | ||||
|         marker_radius, | ||||
|         "golden-hour", | ||||
|         morning_golden_end, | ||||
|         evening_golden_start, | ||||
|     ); | ||||
|     let day_parts_group: Option<Group> = if config.is_some() { | ||||
|         let sun_times = suncalc::get_times( | ||||
|             unixtime, | ||||
|             config.unwrap().latitude, | ||||
|             config.unwrap().longitude, | ||||
|             None, | ||||
|         ); | ||||
|         let noon = Utc | ||||
|             .timestamp_millis(sun_times.solar_noon.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let midnight = Utc | ||||
|             .timestamp_millis(sun_times.nadir.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let morning_golden_end = Utc | ||||
|             .timestamp_millis(sun_times.golden_hour_end.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let evening_golden_start = Utc | ||||
|             .timestamp_millis(sun_times.golden_hour.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let sunrise = Utc | ||||
|             .timestamp_millis(sun_times.sunrise.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let sunset = Utc | ||||
|             .timestamp_millis(sun_times.sunset.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let dawn = Utc | ||||
|             .timestamp_millis(sun_times.dawn.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|         let dusk = Utc | ||||
|             .timestamp_millis(sun_times.dusk.0) | ||||
|             .time() | ||||
|             .num_seconds_from_midnight() as i32; | ||||
|  | ||||
|     let sun_disc = Circle::new() | ||||
|         .set("class", "sun") | ||||
|         .set("cx", image_width / 2) | ||||
|         .set("cy", image_width as f32 / 2.0 + outer_r / 2.0 + sun_radius) | ||||
|         .set("r", sun_radius) | ||||
|         .set( | ||||
|             "transform", | ||||
|             format!( | ||||
|                 "rotate({}, {}, {})", | ||||
|                 time_to_degrees(local_time) - utc_rotation, | ||||
|                 image_width / 2, | ||||
|                 image_width / 2 | ||||
|             ), | ||||
|         let golden_hour_path = get_range_path( | ||||
|             image_width, | ||||
|             marker_radius, | ||||
|             "golden-hour", | ||||
|             morning_golden_end, | ||||
|             evening_golden_start, | ||||
|         ); | ||||
|  | ||||
|     let blue_hour_path = get_range_path( | ||||
|         image_width, | ||||
|         marker_radius, | ||||
|         "blue-hour", | ||||
|         sunrise, // morning_blue_end | ||||
|         sunset,  // evening_blue_start | ||||
|     ); | ||||
|         let sun_disc = Circle::new() | ||||
|             .set("class", "sun") | ||||
|             .set("cx", image_width / 2) | ||||
|             .set("cy", image_width as f32 / 2.0 + outer_r / 2.0 + sun_radius) | ||||
|             .set("r", sun_radius) | ||||
|             .set( | ||||
|                 "transform", | ||||
|                 format!( | ||||
|                     "rotate({}, {}, {})", | ||||
|                     time_to_degrees(local_time) - utc_rotation, | ||||
|                     image_width / 2, | ||||
|                     image_width / 2 | ||||
|                 ), | ||||
|             ); | ||||
|  | ||||
|     let nighttime_path = get_range_path(image_width, marker_radius, "night-time", dawn, dusk); | ||||
|         let blue_hour_path = get_range_path( | ||||
|             image_width, | ||||
|             marker_radius, | ||||
|             "blue-hour", | ||||
|             sunrise, // morning_blue_end | ||||
|             sunset,  // evening_blue_start | ||||
|         ); | ||||
|  | ||||
|     let marker_circle = Circle::new() | ||||
|         .set("class", "marker") | ||||
|         .set("cx", image_width / 2) | ||||
|         .set("cy", image_width / 2) | ||||
|         .set("r", marker_radius); | ||||
|         let nighttime_path = get_range_path(image_width, marker_radius, "night-time", dawn, dusk); | ||||
|  | ||||
|     let noon_marker = Line::new() | ||||
|         .set("class", "mid-marker") | ||||
|         .set( | ||||
|             "transform", | ||||
|             format!( | ||||
|                 "rotate({}, {}, {})", | ||||
|                 time_to_degrees(noon), | ||||
|                 image_width / 2, | ||||
|                 image_width / 2 | ||||
|             ), | ||||
|         ) | ||||
|         .set("x1", image_width / 2) | ||||
|         .set( | ||||
|             "y1", | ||||
|             image_width as f32 / 2.0 + marker_radius - sun_radius as f32, | ||||
|         ) | ||||
|         .set("x2", image_width / 2) | ||||
|         .set("y2", image_width as f32 / 2.0 + marker_radius); | ||||
|         let marker_circle = Circle::new() | ||||
|             .set("class", "marker") | ||||
|             .set("cx", image_width / 2) | ||||
|             .set("cy", image_width / 2) | ||||
|             .set("r", marker_radius); | ||||
|  | ||||
|     let midnight_marker = Line::new() | ||||
|         .set("class", "mid-marker") | ||||
|         .set( | ||||
|             "transform", | ||||
|             format!( | ||||
|                 "rotate({}, {}, {})", | ||||
|                 time_to_degrees(midnight), | ||||
|                 image_width / 2, | ||||
|                 image_width / 2 | ||||
|             ), | ||||
|         ) | ||||
|         .set("x1", image_width / 2) | ||||
|         .set( | ||||
|             "y1", | ||||
|             image_width as f32 / 2.0 + marker_radius - sun_radius as f32, | ||||
|         ) | ||||
|         .set("x2", image_width / 2) | ||||
|         .set("y2", image_width as f32 / 2.0 + marker_radius); | ||||
|         let noon_marker = Line::new() | ||||
|             .set("class", "mid-marker") | ||||
|             .set( | ||||
|                 "transform", | ||||
|                 format!( | ||||
|                     "rotate({}, {}, {})", | ||||
|                     time_to_degrees(noon), | ||||
|                     image_width / 2, | ||||
|                     image_width / 2 | ||||
|                 ), | ||||
|             ) | ||||
|             .set("x1", image_width / 2) | ||||
|             .set( | ||||
|                 "y1", | ||||
|                 image_width as f32 / 2.0 + marker_radius - sun_radius as f32, | ||||
|             ) | ||||
|             .set("x2", image_width / 2) | ||||
|             .set("y2", image_width as f32 / 2.0 + marker_radius); | ||||
|  | ||||
|     let day_parts_group = Group::new() | ||||
|         .set("id", "day-parts") | ||||
|         .set( | ||||
|             "transform", | ||||
|             format!( | ||||
|                 "rotate({}, {}, {})", | ||||
|                 utc_rotation, | ||||
|                 image_width / 2, | ||||
|                 image_width / 2 | ||||
|             ), | ||||
|         let midnight_marker = Line::new() | ||||
|             .set("class", "mid-marker") | ||||
|             .set( | ||||
|                 "transform", | ||||
|                 format!( | ||||
|                     "rotate({}, {}, {})", | ||||
|                     time_to_degrees(midnight), | ||||
|                     image_width / 2, | ||||
|                     image_width / 2 | ||||
|                 ), | ||||
|             ) | ||||
|             .set("x1", image_width / 2) | ||||
|             .set( | ||||
|                 "y1", | ||||
|                 image_width as f32 / 2.0 + marker_radius - sun_radius as f32, | ||||
|             ) | ||||
|             .set("x2", image_width / 2) | ||||
|             .set("y2", image_width as f32 / 2.0 + marker_radius); | ||||
|  | ||||
|         Some( | ||||
|             Group::new() | ||||
|                 .set("id", "day-parts") | ||||
|                 .set( | ||||
|                     "transform", | ||||
|                     format!( | ||||
|                         "rotate({}, {}, {})", | ||||
|                         utc_rotation, | ||||
|                         image_width / 2, | ||||
|                         image_width / 2 | ||||
|                     ), | ||||
|                 ) | ||||
|                 .add(daytime_circle) | ||||
|                 .add(golden_hour_path) | ||||
|                 .add(sun_disc) | ||||
|                 .add(blue_hour_path) | ||||
|                 .add(nighttime_path) | ||||
|                 .add(marker_circle) | ||||
|                 .add(noon_marker) | ||||
|                 .add(midnight_marker), | ||||
|         ) | ||||
|         .add(daytime_circle) | ||||
|         .add(golden_hour_path) | ||||
|         .add(sun_disc) | ||||
|         .add(blue_hour_path) | ||||
|         .add(nighttime_path) | ||||
|         .add(marker_circle) | ||||
|         .add(noon_marker) | ||||
|         .add(midnight_marker); | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
|  | ||||
|     let moon_circle = Circle::new() | ||||
|         .set("class", "moon-background") | ||||
| @@ -588,7 +599,7 @@ fn gen_svg(config: &Config) -> Document { | ||||
|         .add(current_hour_name) | ||||
|         .add(current_time_text); | ||||
|  | ||||
|     Document::new() | ||||
|     let mut document = Document::new() | ||||
|         .set("viewBox", (0i32, 0i32, 700i32, 700i32)) | ||||
|         .set("width", 700i32) | ||||
|         .set("height", 700i32) | ||||
| @@ -596,8 +607,13 @@ fn gen_svg(config: &Config) -> Document { | ||||
|         .add(stylesheet) | ||||
|         .add(definitions) | ||||
|         .add(border) | ||||
|         .add(local_clock) | ||||
|         .add(day_parts_group) | ||||
|         .add(local_clock); | ||||
|  | ||||
|     if let Some(..) = day_parts_group { | ||||
|         document = document.add(day_parts_group.unwrap()); | ||||
|     } | ||||
|  | ||||
|     document | ||||
|         .add(seasonal_clock) | ||||
|         .add(moon_group) | ||||
|         .add(dial) | ||||
| @@ -609,8 +625,13 @@ fn main() { | ||||
|     let config_path = xdg_dirs | ||||
|         .place_config_file("seasonal-clock.toml") | ||||
|         .expect("cannot create configuration directory"); | ||||
|     let data = fs::read_to_string(config_path).expect("Unable to read file"); | ||||
|     let config: CompleteConfig = toml::from_str(&data).unwrap(); | ||||
|     let data: std::io::Result<String> = fs::read_to_string(config_path); | ||||
|     let config: Option<Config> = if let Ok(..) = data { | ||||
|         let complete_config: CompleteConfig = toml::from_str(&data.unwrap()).unwrap(); | ||||
|         Some(complete_config.seasonal_clock) | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
|  | ||||
|     let (env, display, mut queue) = sctk::new_default_environment!(SeasonalClock, desktop) | ||||
|         .expect("Unable to connect to a Wayland compositor"); | ||||
| @@ -654,13 +675,7 @@ fn main() { | ||||
|     let mut dimensions = (700, 700); | ||||
|  | ||||
|     if !env.get_shell().unwrap().needs_configure() { | ||||
|         redraw( | ||||
|             &mut pool, | ||||
|             window.surface(), | ||||
|             dimensions, | ||||
|             &config.seasonal_clock, | ||||
|         ) | ||||
|         .expect("Failed to draw"); | ||||
|         redraw(&mut pool, window.surface(), dimensions, &config).expect("Failed to draw"); | ||||
|         window.refresh() | ||||
|     } | ||||
|  | ||||
| @@ -708,13 +723,7 @@ fn main() { | ||||
|         if need_redraw { | ||||
|             need_redraw = false; | ||||
|  | ||||
|             redraw( | ||||
|                 &mut pool, | ||||
|                 window.surface(), | ||||
|                 dimensions, | ||||
|                 &config.seasonal_clock, | ||||
|             ) | ||||
|             .expect("Failed to draw") | ||||
|             redraw(&mut pool, window.surface(), dimensions, &config).expect("Failed to draw") | ||||
|         } | ||||
|  | ||||
|         if let Err(e) = display.flush() { | ||||
| @@ -744,7 +753,7 @@ fn redraw( | ||||
|     pool: &mut AutoMemPool, | ||||
|     surface: &wl_surface::WlSurface, | ||||
|     (buf_x, buf_y): (u32, u32), | ||||
|     config: &Config, | ||||
|     config: &Option<Config>, | ||||
| ) -> Result<(), ::std::io::Error> { | ||||
|     let document = gen_svg(config); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user