diff --git a/backend/src/tasks/lights.rs b/backend/src/tasks/lights.rs index 0b59323..d06a3ee 100644 --- a/backend/src/tasks/lights.rs +++ b/backend/src/tasks/lights.rs @@ -101,11 +101,17 @@ pub async fn lights_task(state: &State) { ClientMessage::SetBulbWakeTime { id, day, time } => { if let Err(e) = lights_state.update(|lights_state| { let schedule = lights_state.wake_schedule.entry(id.clone()).or_default(); - schedule.insert(day, time); + if let Some(time) = time { + schedule.insert(day, time); + } + else { + schedule.remove(&day); + } }).await { error!("Failed to save wake schedule: {e}"); }; - + + if let Some(time) = time { let handle = spawn(wake_task( state.client_message.subscribe(), cmd.clone(), @@ -113,8 +119,13 @@ pub async fn lights_task(state: &State) { day, time, )); + if let Some(old_handle) = wake_tasks.insert((id, day), handle) { old_handle.abort(); + }} else { + if let Some(old_handle) = wake_tasks.remove(&(id, day)) { + old_handle.abort(); + } } } _ => {} diff --git a/common/src/lib.rs b/common/src/lib.rs index 4d5f129..ea4200b 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -38,7 +38,7 @@ pub enum ClientMessage { SetBulbWakeTime { id: BulbId, day: Weekday, - time: NaiveTime, + time: Option, }, } diff --git a/frontend/src/page/lights.rs b/frontend/src/page/lights.rs index 93b65ac..32b26b2 100644 --- a/frontend/src/page/lights.rs +++ b/frontend/src/page/lights.rs @@ -6,23 +6,30 @@ use lighter_lib::{BulbId, BulbMode}; use seed::prelude::*; use seed::{attrs, button, div, input, C}; use seed_router::Page; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::fmt::Write; /// /lights page #[derive(Default)] pub struct Model { - bulb_states: BTreeMap, + bulb_states: BTreeMap, bulb_map: BulbMap, - /// The currently selected bulb map groups + /// the currently selected bulb map groups selected_groups: HashSet, - /// Whether the currently selected map groups have been interacted with + /// whether the currently selected map groups have been interacted with groups_interacted: bool, color_picker: ColorPicker, + +} + +#[derive(Default, Clone)] +struct BulbState { + mode: BulbMode, + wake_schedule: HashMap, } #[derive(Debug)] @@ -50,7 +57,11 @@ impl Page for Model { match msg { Msg::ServerMessage(msg) => match msg { ServerMessage::BulbState { id, mode: new_mode, wake_schedule } => { - *self.bulb_states.entry(id).or_default() = new_mode + *self.bulb_states.entry(id).or_default() = BulbState { + mode: new_mode, + wake_schedule, + }; + //color_picker.set_color(mode.color); } ServerMessage::BulbMap(bulb_map) => { @@ -82,7 +93,7 @@ impl Page for Model { .and_then(|id| self.bulb_states.get(id)); if let Some(bulb) = bulb { - self.color_picker.set_color(bulb.color); + self.color_picker.set_color(bulb.mode.color); } } } @@ -111,12 +122,22 @@ impl Page for Model { }); } Msg::LightTime(time, day) => { - if let Ok(time) = NaiveTime::parse_from_str(&time, "%H:%M") { + if time == "" { self.for_selected_bulbs(|id, _| { let message = ClientMessage::SetBulbWakeTime { id: id.clone(), day, - time, + time: None, + }; + orders.notify(message); + }); + } + else if let Ok(time) = NaiveTime::parse_from_str(&time, "%H:%M") { + self.for_selected_bulbs(|id, _| { + let message = ClientMessage::SetBulbWakeTime { + id: id.clone(), + day, + time: Some(time), }; orders.notify(message); }); @@ -200,27 +221,29 @@ fn view(&self) -> Node { ] }; - let calendar_day = |day: Weekday| { - div![ - C![C.calendar_day], - day.to_string(), - input![ - C![C.calendar_time_input], - attrs! {At::Placeholder => "7:30"}, - input_ev(Ev::Input, move |input| Msg::LightTime(input, day)) - ], - ] - }; - - let (_color, power) = self + let selected_bulb = self .selected_groups .iter() .next() .and_then(|&index| self.bulb_map.groups.get(index)) .and_then(|group| group.bulbs.first()) .and_then(|id| self.bulb_states.get(id)) - .map(|bulb| (bulb.color, bulb.power)) + .cloned() // TODO: remove clone .unwrap_or_default(); + + let calendar_day = |day: Weekday| { + let time = selected_bulb.wake_schedule.get(&day).map(|t| t.to_string()).unwrap_or_default(); + div![ + C![C.calendar_day], + day.to_string(), + input![ + C![C.calendar_time_input], + attrs! {At::Placeholder => time}, + input_ev(Ev::Input, move |input| Msg::LightTime(input, day)) + ], + ] + }; + div![ C![C.bulb_box], @@ -238,12 +261,12 @@ fn view(&self) -> Node { .view() .map_msg(|msg| Msg::ColorPicker(msg)), button![ - if power { + if selected_bulb.mode.power { C![C.bulb_power_button, C.bulb_power_button_on] } else { C![C.bulb_power_button] }, - ev(Ev::Click, move |_| Msg::SetBulbPower(!power)), + ev(Ev::Click, move |_| Msg::SetBulbPower(!selected_bulb.mode.power)), div![attrs! { At::Id => "switch_socket" }], div![attrs! { At::Id => "off_label" }, "Off"], div![attrs! { At::Id => "on_label" }, "On"], @@ -266,7 +289,7 @@ fn view(&self) -> Node { } impl Model { - fn for_selected_bulbs(&self, mut f: impl FnMut(&BulbId, &BulbMode)) { + fn for_selected_bulbs(&self, mut f: impl FnMut(&BulbId, &BulbState)) { self.selected_groups .iter() .filter_map(|&index| self.bulb_map.groups.get(index))