Party mode
This commit is contained in:
@ -1,13 +1,13 @@
|
||||
use crate::components::color_picker::{ColorPicker, ColorPickerMsg};
|
||||
use crate::css::C;
|
||||
use chrono::{NaiveTime, Weekday};
|
||||
use common::{BulbGroup, BulbGroupShape, BulbMap, ClientMessage, ServerMessage};
|
||||
use common::{BulbGroup, BulbGroupShape, BulbMap, BulbPrefs, ClientMessage, Param, ServerMessage};
|
||||
use lighter_lib::{BulbId, BulbMode};
|
||||
use seed::{attrs, button, div, h2, input, table, td, tr, C};
|
||||
use seed::{attrs, button, div, empty, h2, input, table, td, tr, C};
|
||||
use seed::{prelude::*, IF};
|
||||
use seed_router::Page;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::fmt::Write;
|
||||
use std::iter::repeat;
|
||||
|
||||
/// /lights page
|
||||
#[derive(Default)]
|
||||
@ -28,7 +28,7 @@ pub struct Model {
|
||||
#[derive(Default, Clone)]
|
||||
struct BulbState {
|
||||
mode: BulbMode,
|
||||
wake_schedule: HashMap<Weekday, NaiveTime>,
|
||||
prefs: BTreeMap<String, BulbPrefs>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -39,7 +39,13 @@ pub enum Msg {
|
||||
DeselectGroups,
|
||||
ColorPicker(ColorPickerMsg),
|
||||
SetBulbPower(bool),
|
||||
LightTime(String, Weekday),
|
||||
|
||||
/// Set a script parameter value for all selected bulbs.
|
||||
SetParam {
|
||||
script: String,
|
||||
name: String,
|
||||
value: Param,
|
||||
},
|
||||
}
|
||||
|
||||
impl Page for Model {
|
||||
@ -58,11 +64,11 @@ impl Page for Model {
|
||||
ServerMessage::BulbState {
|
||||
id,
|
||||
mode: new_mode,
|
||||
wake_schedule,
|
||||
prefs,
|
||||
} => {
|
||||
*self.bulb_states.entry(id).or_default() = BulbState {
|
||||
mode: new_mode,
|
||||
wake_schedule,
|
||||
prefs,
|
||||
};
|
||||
|
||||
//color_picker.set_color(mode.color);
|
||||
@ -124,26 +130,25 @@ impl Page for Model {
|
||||
orders.notify(message);
|
||||
});
|
||||
}
|
||||
Msg::LightTime(time, day) => {
|
||||
if time.is_empty() {
|
||||
self.for_selected_bulbs(|id, _| {
|
||||
let message = ClientMessage::SetBulbWakeTime {
|
||||
id: id.clone(),
|
||||
day,
|
||||
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);
|
||||
});
|
||||
}
|
||||
Msg::SetParam {
|
||||
script,
|
||||
name,
|
||||
value,
|
||||
} => {
|
||||
self.for_selected_bulbs(|id, bulb| {
|
||||
bulb.prefs
|
||||
.get_mut(&script)
|
||||
.unwrap() //TOD
|
||||
.kvs
|
||||
.insert(name.clone(), value.clone());
|
||||
let message = ClientMessage::SetBulbPref {
|
||||
bulb: id.clone(),
|
||||
script: script.clone(),
|
||||
name: name.clone(),
|
||||
value: value.clone(),
|
||||
};
|
||||
orders.notify(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -230,20 +235,44 @@ impl Page for Model {
|
||||
.and_then(|group| group.bulbs.first())
|
||||
.and_then(|id| self.bulb_states.get(id));
|
||||
|
||||
let calendar_day = |day: Weekday| {
|
||||
let time = selected_bulb
|
||||
.and_then(|b| b.wake_schedule.get(&day))
|
||||
.map(|t| t.to_string())
|
||||
.unwrap_or_default();
|
||||
tr![
|
||||
C![C.calendar_day],
|
||||
td![day.to_string()],
|
||||
td![input![
|
||||
C![C.calendar_time_input],
|
||||
attrs! {At::Placeholder => time},
|
||||
input_ev(Ev::Input, move |input| Msg::LightTime(input, day))
|
||||
]],
|
||||
]
|
||||
let script_param = |script: &str, name: &str, value: &Param| {
|
||||
let name = name.to_string();
|
||||
let script = script.to_string();
|
||||
|
||||
match value {
|
||||
Param::String(value) => tr![
|
||||
C![C.pref_line],
|
||||
td![&name],
|
||||
td![input![
|
||||
C![C.pref_input],
|
||||
attrs! {At::Placeholder => &script},
|
||||
attrs! {At::Value => value},
|
||||
input_ev(Ev::Input, move |input| Msg::SetParam {
|
||||
script,
|
||||
name,
|
||||
value: Param::String(input),
|
||||
})
|
||||
]]
|
||||
],
|
||||
&Param::Toggle(value) => {
|
||||
tr![
|
||||
C![C.pref_line],
|
||||
button![
|
||||
if value {
|
||||
C![C.pref_button_enabled]
|
||||
} else {
|
||||
C![C.pref_button]
|
||||
},
|
||||
&name,
|
||||
input_ev(Ev::Click, move |_| Msg::SetParam {
|
||||
script,
|
||||
name,
|
||||
value: Param::Toggle(!value),
|
||||
})
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
div![
|
||||
@ -278,30 +307,35 @@ impl Page for Model {
|
||||
],
|
||||
],
|
||||
div![
|
||||
C![C.calendar_box],
|
||||
C![C.prefs_box],
|
||||
IF!(selected_bulb.is_none() => C![C.cross_out]),
|
||||
h2!["Wake Schedule"],
|
||||
table![
|
||||
calendar_day(Weekday::Mon),
|
||||
calendar_day(Weekday::Tue),
|
||||
calendar_day(Weekday::Wed),
|
||||
calendar_day(Weekday::Thu),
|
||||
calendar_day(Weekday::Fri),
|
||||
calendar_day(Weekday::Sat),
|
||||
calendar_day(Weekday::Sun),
|
||||
],
|
||||
h2!["Settings"],
|
||||
if let Some(selected_bulb) = selected_bulb {
|
||||
table![selected_bulb
|
||||
.prefs
|
||||
.iter()
|
||||
.flat_map(|(script, prefs)| repeat(script).zip(prefs.kvs.iter()))
|
||||
.map(|(script, (name, value))| script_param(script, name, value))]
|
||||
} else {
|
||||
empty![]
|
||||
},
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn for_selected_bulbs(&self, mut f: impl FnMut(&BulbId, &BulbState)) {
|
||||
self.selected_groups
|
||||
.iter()
|
||||
.filter_map(|&index| self.bulb_map.groups.get(index))
|
||||
.flat_map(|group| group.bulbs.iter())
|
||||
.filter_map(|id| self.bulb_states.get(id).map(|bulb| (id, bulb)))
|
||||
.for_each(|(id, bulb)| f(id, bulb));
|
||||
fn for_selected_bulbs(&mut self, mut f: impl FnMut(&BulbId, &mut BulbState)) {
|
||||
for &index in &self.selected_groups {
|
||||
let Some(group) = self.bulb_map.groups.get(index) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for id in group.bulbs.iter() {
|
||||
if let Some(bulb) = self.bulb_states.get_mut(id) {
|
||||
f(id, bulb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,14 +304,16 @@ body {
|
||||
|
||||
transition: margin 0.1s ease-out;
|
||||
}
|
||||
.calendar_day {
|
||||
|
||||
|
||||
.pref_line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: .3em;
|
||||
}
|
||||
|
||||
.calendar_time_input {
|
||||
.pref_input {
|
||||
background: #453f4b;
|
||||
border: solid 0.35em #5b3f63;
|
||||
border-radius: .3em;
|
||||
@ -323,17 +325,49 @@ body {
|
||||
margin-left: .5em;
|
||||
}
|
||||
|
||||
.calendar_box {
|
||||
.pref_button {}
|
||||
.pref_button, .pref_button_enabled {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-shadow: 0.1rem 0.1rem 0.3rem black;
|
||||
|
||||
padding: 1rem;
|
||||
border: solid 0.35em #5b3f63;
|
||||
border-radius: 0.3em;
|
||||
background: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
.pref_button_enabled::before {
|
||||
content: "";
|
||||
z-index: -1;
|
||||
width: 20rem;
|
||||
height: 20rem;
|
||||
background-size: 100% 100%;
|
||||
background-image: url(/images/hsb.png);
|
||||
position: absolute;
|
||||
transform: translate(-8.5rem, -2.5rem);
|
||||
animation: infinite linear 3s button_rainbow;
|
||||
}
|
||||
@keyframes button_rainbow {
|
||||
from { transform: translate(-8.5rem, -2.5rem) rotate( 0deg); }
|
||||
to { transform: translate(-8.5rem, -2.5rem) rotate(360deg); }
|
||||
}
|
||||
|
||||
.prefs_box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.calendar_box > h2 {
|
||||
.prefs_box > h2 {
|
||||
writing-mode: sideways-lr;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
.calendar_box > * {
|
||||
.prefs_box > * {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user