cadmus_core/settings/
preset.rs1use crate::frontlight::LightLevels;
2use crate::geom::circular_distances;
3use chrono::{Local, Timelike};
4use serde::{Deserialize, Serialize};
5
6const MINUTES_PER_DAY: u16 = 24 * 60;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(default, rename_all = "camelCase")]
10pub struct LightPreset {
11 pub timestamp: u16,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub lightsensor_level: Option<u16>,
14 pub frontlight_levels: LightLevels,
15}
16
17impl Default for LightPreset {
18 fn default() -> Self {
19 let now = Local::now();
20 LightPreset {
21 timestamp: (60 * now.hour() + now.minute()) as u16,
22 frontlight_levels: LightLevels::default(),
23 lightsensor_level: None,
24 }
25 }
26}
27
28impl LightPreset {
29 pub fn name(&self) -> String {
30 let hours = self.timestamp / 60;
31 let minutes = self.timestamp - hours * 60;
32 format!("{:02}:{:02}", hours, minutes)
33 }
34}
35
36pub fn guess_frontlight(
37 lightsensor_level: Option<u16>,
38 light_presets: &[LightPreset],
39) -> Option<LightLevels> {
40 if light_presets.len() < 2 {
41 return None;
42 }
43 let cur = LightPreset {
44 lightsensor_level,
45 ..Default::default()
46 };
47
48 let mut dmin = [u16::MAX; 2];
49 let mut index = [usize::MAX; 2];
50
51 if light_presets[0].lightsensor_level.is_some() {
52 let s = cur.lightsensor_level.unwrap_or_default();
53
54 for (i, lp) in light_presets.iter().enumerate() {
55 let p = lp.lightsensor_level.unwrap_or_default();
56 let d = if s >= p { s - p } else { p - s };
57
58 if p >= s && d < dmin[0] {
59 dmin[0] = d;
60 index[0] = i;
61 }
62
63 if p <= s && d < dmin[1] {
64 dmin[1] = d;
65 index[1] = i;
66 }
67 }
68 } else {
69 for (i, lp) in light_presets.iter().enumerate() {
70 let (d0, d1) = circular_distances(cur.timestamp, lp.timestamp, MINUTES_PER_DAY);
71
72 if d0 < dmin[0] {
73 dmin[0] = d0;
74 index[0] = i;
75 }
76
77 if d1 < dmin[1] {
78 dmin[1] = d1;
79 index[1] = i;
80 }
81 }
82 }
83
84 if dmin[0] == 0 || dmin[1] == u16::MAX {
85 return Some(light_presets[index[0]].frontlight_levels);
86 }
87
88 if dmin[1] == 0 || dmin[0] == u16::MAX {
89 return Some(light_presets[index[1]].frontlight_levels);
90 }
91
92 let fl0 = light_presets[index[0]].frontlight_levels;
93 let fl1 = light_presets[index[1]].frontlight_levels;
94 let t = dmin[0] as f32 / (dmin[0] + dmin[1]) as f32;
95
96 Some(fl0.interpolate(fl1, t))
97}