From 940fb5ceda601892e71195aa5c15e52a61d73419 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Mon, 6 Nov 2023 22:28:56 +0100 Subject: [PATCH] wip bulb list --- frontend/src/page/lights.rs | 154 +++++++++++++++++++---------- frontend/static/styles/common.scss | 37 +++++++ 2 files changed, 141 insertions(+), 50 deletions(-) diff --git a/frontend/src/page/lights.rs b/frontend/src/page/lights.rs index cbacb75..823bd69 100644 --- a/frontend/src/page/lights.rs +++ b/frontend/src/page/lights.rs @@ -3,7 +3,7 @@ use crate::css::C; use chrono::{NaiveTime, Weekday}; use common::{BulbGroup, BulbGroupShape, BulbMap, ClientMessage, ServerMessage}; use lighter_lib::{BulbId, BulbMode}; -use seed::{attrs, button, div, h2, input, table, td, tr, C}; +use seed::{attrs, button, div, h2, h3, input, label, span, table, td, tr, C}; use seed::{prelude::*, IF}; use seed_router::Page; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -14,11 +14,18 @@ use std::fmt::Write; pub struct Model { bulb_states: BTreeMap, + select_mode: SelectMode, + + bulb_groups: BTreeMap>, + bulb_map: BulbMap, - /// the currently selected bulb map groups + /// the currently selected bulbs on the map selected_groups: HashSet, + /// the currently selected bulbs on the list + selected_bulbs: HashSet, + /// whether the currently selected map groups have been interacted with groups_interacted: bool, @@ -37,9 +44,21 @@ pub enum Msg { SelectGroup(usize), DeselectGroups, + + SelectBulb(BulbId), + ColorPicker(ColorPickerMsg), SetBulbPower(bool), LightTime(String, Weekday), + SetSelectMode(SelectMode), +} + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub enum SelectMode { + //#[default] + Map, + #[default] + List, } impl Page for Model { @@ -64,8 +83,6 @@ impl Page for Model { mode: new_mode, wake_schedule, }; - - //color_picker.set_color(mode.color); } ServerMessage::BulbMap(bulb_map) => { self.bulb_map = bulb_map; @@ -100,6 +117,11 @@ impl Page for Model { } } } + Msg::SelectBulb(bulb) => { + if !self.selected_bulbs.remove(&bulb) { + self.selected_bulbs.insert(bulb); + } + } Msg::ColorPicker(ColorPickerMsg::SetColor(color)) => { self.groups_interacted = true; self.for_selected_bulbs(|id, _| { @@ -145,36 +167,13 @@ impl Page for Model { }); } } + Msg::SetSelectMode(mode) => { + self.select_mode = mode; + } } } fn view(&self) -> Node { - //let view_bulb = |(id, (mode, color_picker)): (&BulbId, &(BulbMode, ColorPicker))| { - // div![ - // C![C.bulb_box], - // h1![id], - // div![ - // C![C.bulb_controls], - // { - // let id = id.clone(); - // color_picker.view().map_msg(|msg| Msg::ColorPicker(id, msg)) - // }, - // button![ - // if mode.power { - // C![C.bulb_power_button, C.bulb_power_button_on] - // } else { - // C![C.bulb_power_button] - // }, - // { - // let id = id.clone(); - // let power = !mode.power; - // ev(Ev::Click, move |_| Msg::SetBulbPower(id, power)) - // }, - // ], - // ], - // ] - //}; - let bulb_map_width = self .bulb_map .groups @@ -191,7 +190,7 @@ impl Page for Model { .max() .unwrap_or(0); - let view_bulb_group = |(i, group): (usize, &BulbGroup)| { + let bulb_group_map = |(i, group): (usize, &BulbGroup)| { let (w, h) = (group.shape.width(), group.shape.height()); let mut style = String::new(); write!( @@ -222,13 +221,39 @@ impl Page for Model { ] }; - 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)); + let bulb_group_list = |(i, group): (usize, &BulbGroup)| { + div![ + h3![&group.name[..1]], + group.bulbs.iter().map(|bulb| { + div![ + input![ + attrs! { At::Type => "checkbox" }, + IF!(self.selected_bulbs.contains(bulb) => attrs! { At::Checked => true }), + { + let bulb = bulb.clone(); + ev(Ev::Change, |_| Msg::SelectBulb(bulb)) + }, + ], + span![bulb], + ] + }), + ] + }; + + // pick one (arbitrary) selected bulb to pull values for the controls from + let selected_bulb = if let SelectMode::Map = self.select_mode { + 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)) + } else { + self.selected_bulbs + .iter() + .next() + .and_then(|id| self.bulb_states.get(id)) + }; let calendar_day = |day: Weekday| { let time = selected_bulb @@ -249,13 +274,35 @@ impl Page for Model { div![ C![C.bulb_box], div![ - C![C.bulb_map], - attrs! { - At::Style => format!("min-width: {}rem; height: {}rem;", bulb_map_width, bulb_map_height), - }, - ev(Ev::Click, |_| Msg::DeselectGroups), - self.bulb_map.groups.iter().enumerate().map(view_bulb_group), + C![C.selector_selector], + div![ + C![C.selector_selector_highlight], + IF!(self.select_mode == SelectMode::List => + attrs! { At::Style => "margin-left: 10rem;"}), + ], + button![ + "Map", + ev(Ev::Click, move |_| Msg::SetSelectMode(SelectMode::Map)) + ], + button![ + "List", + ev(Ev::Click, move |_| Msg::SetSelectMode(SelectMode::List)) + ], ], + match self.select_mode { + SelectMode::Map => div![ + C![C.bulb_map], + attrs! { + At::Style => format!("min-width: {}rem; height: {}rem;", bulb_map_width, bulb_map_height), + }, + ev(Ev::Click, |_| Msg::DeselectGroups), + self.bulb_map.groups.iter().enumerate().map(bulb_group_map), + ], + SelectMode::List => div![ + C![C.bulb_list], + self.bulb_map.groups.iter().enumerate().map(bulb_group_list), + ], + }, div![ C![C.bulb_controls], IF!(selected_bulb.is_none() => C![C.cross_out]), @@ -297,11 +344,18 @@ impl Page for Model { 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)); + if let SelectMode::Map = self.select_mode { + 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)); + } else { + self.selected_bulbs + .iter() + .filter_map(|id| self.bulb_states.get(id).map(|bulb| (id, bulb))) + .for_each(|(id, bulb)| f(id, bulb)); + } } } diff --git a/frontend/static/styles/common.scss b/frontend/static/styles/common.scss index fef7729..49263ce 100644 --- a/frontend/static/styles/common.scss +++ b/frontend/static/styles/common.scss @@ -102,6 +102,32 @@ body { margin-bottom: 1.5rem; } +/* lol i'm so funny */ +.selector_selector { + margin-bottom: 0; + display: flex; + border: solid 0.1rem wheat; + justify-content: center; + background: #534f44; +} +.selector_selector > button { + width: 10rem; + border: unset; + background: unset; + color: white; + font-size: 1.5rem; + border-left: solid white 0.1rem; + border-right: solid white 0.1rem; +} +.selector_selector_highlight { + position: absolute; + width: 10rem; + height: 2rem; + background: #ffd70069; + margin-left: -10rem; + transition: margin-left 0.3s ease-out; +} + .bulb_controls { display: flex; flex-direction: row; @@ -150,6 +176,17 @@ body { } @keyframes to_width_90 { to { width: 90%; } } +.bulb_list { + color: green; +} + +.bulb_list_checked { + color: green; +} +.bulb_list_unchecked { + color: green; +} + .bulb_map { background: url(images/blueprint_bg.png); background-size: auto;