prevent all lights having their state set on startup
+ some cleanup
This commit is contained in:
parent
c610f8b798
commit
c02ff988c1
5 changed files with 114 additions and 43 deletions
|
@ -23,13 +23,14 @@ pub enum HeaderBarMsg {
|
||||||
|
|
||||||
#[widget]
|
#[widget]
|
||||||
impl Widget for HeaderBar {
|
impl Widget for HeaderBar {
|
||||||
fn model(data: (UnboundedSender<RuntimeMsg>, Sender<Msg>, String, String)) -> HeaderBarModel {
|
fn model(data: (UnboundedSender<RuntimeMsg>, Sender<Msg>)) -> HeaderBarModel {
|
||||||
HeaderBarModel {
|
HeaderBarModel {
|
||||||
settings: relm::init::<Settings>((data.0.clone(), data.2, data.3))
|
settings: relm::init::<Settings>(data.0.clone())
|
||||||
.expect("failed to create settings window"),
|
.expect("failed to create settings window"),
|
||||||
rootwintx: data.1,
|
rootwintx: data.1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, msg: HeaderBarMsg) {
|
fn update(&mut self, msg: HeaderBarMsg) {
|
||||||
match msg {
|
match msg {
|
||||||
HeaderBarMsg::OpenSettings => {
|
HeaderBarMsg::OpenSettings => {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use relm::Relm;
|
||||||
use angular_units::Turns;
|
use angular_units::Turns;
|
||||||
use gtk::{prelude::*, Orientation};
|
use gtk::{prelude::*, Orientation};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use prisma::{Hsv, Rgb};
|
use prisma::{Hsv, Rgb};
|
||||||
use relm::Widget;
|
use relm::{Channel, Sender, Widget};
|
||||||
use relm_derive::{widget, Msg};
|
use relm_derive::{widget, Msg};
|
||||||
use rhue::{
|
use rhue::{
|
||||||
api::{Light, LightArchetype},
|
api::{Light, LightArchetype},
|
||||||
|
@ -14,6 +15,8 @@ use tokio::sync::mpsc::UnboundedSender;
|
||||||
use crate::runtime::RuntimeMsg;
|
use crate::runtime::RuntimeMsg;
|
||||||
|
|
||||||
pub struct LightEntryModel {
|
pub struct LightEntryModel {
|
||||||
|
_channel: Channel<LightEntryMsg>,
|
||||||
|
tx: Sender<LightEntryMsg>,
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
runtime: UnboundedSender<RuntimeMsg>,
|
runtime: UnboundedSender<RuntimeMsg>,
|
||||||
|
@ -21,12 +24,18 @@ pub struct LightEntryModel {
|
||||||
brightness: f64,
|
brightness: f64,
|
||||||
color: Rc<Cell<Rgb<f64>>>,
|
color: Rc<Cell<Rgb<f64>>>,
|
||||||
icon: String,
|
icon: String,
|
||||||
|
updates_active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Msg)]
|
#[derive(Clone, Msg)]
|
||||||
pub enum LightEntryMsg {
|
pub enum LightEntryMsg {
|
||||||
Update(StateUpdate),
|
Update(StateUpdate),
|
||||||
PropertyChanged(EntryLightProperty),
|
PropertyChanged(EntryLightProperty),
|
||||||
|
/// Changing the values of the light's GUI elements before this message is
|
||||||
|
/// sent has no effect. This is to prevent light update requests being
|
||||||
|
/// sent to the bridge while their values are being set programatically
|
||||||
|
/// in the widget's initialization
|
||||||
|
ActivateUpdates,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
@ -37,8 +46,16 @@ pub enum EntryLightProperty {
|
||||||
|
|
||||||
#[widget]
|
#[widget]
|
||||||
impl Widget for LightEntry {
|
impl Widget for LightEntry {
|
||||||
fn model(params: (String, Light, UnboundedSender<RuntimeMsg>)) -> LightEntryModel {
|
fn model(
|
||||||
|
relm: &Relm<Self>,
|
||||||
|
params: (String, Light, UnboundedSender<RuntimeMsg>),
|
||||||
|
) -> LightEntryModel {
|
||||||
|
let stream = relm.stream().clone();
|
||||||
|
let (ch, tx) = Channel::new(move |msg| stream.emit(msg));
|
||||||
|
|
||||||
LightEntryModel {
|
LightEntryModel {
|
||||||
|
_channel: ch,
|
||||||
|
tx,
|
||||||
id: params.0,
|
id: params.0,
|
||||||
name: params.1.name,
|
name: params.1.name,
|
||||||
runtime: params.2,
|
runtime: params.2,
|
||||||
|
@ -53,6 +70,7 @@ impl Widget for LightEntry {
|
||||||
.into(),
|
.into(),
|
||||||
)),
|
)),
|
||||||
icon: resource_of_archetype(params.1.config.archetype),
|
icon: resource_of_archetype(params.1.config.archetype),
|
||||||
|
updates_active: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,11 +98,13 @@ impl Widget for LightEntry {
|
||||||
self.model.on = on;
|
self.model.on = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.model.updates_active {
|
||||||
let _ = self
|
let _ = self
|
||||||
.model
|
.model
|
||||||
.runtime
|
.runtime
|
||||||
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LightEntryMsg::PropertyChanged(prop) => {
|
LightEntryMsg::PropertyChanged(prop) => {
|
||||||
debug!("updating light {}", &self.model.id);
|
debug!("updating light {}", &self.model.id);
|
||||||
|
@ -110,11 +130,15 @@ impl Widget for LightEntry {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if self.model.updates_active {
|
||||||
let _ = self
|
let _ = self
|
||||||
.model
|
.model
|
||||||
.runtime
|
.runtime
|
||||||
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LightEntryMsg::ActivateUpdates => self.model.updates_active = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +157,12 @@ impl Widget for LightEntry {
|
||||||
|
|
||||||
Inhibit(false)
|
Inhibit(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// we need to send this throught the channel, instead of just setting
|
||||||
|
// `self.model.updates_active`, since messages of the widget's stream
|
||||||
|
// are only handled once the view has been fully initialized.
|
||||||
|
// This would result in the updates being activated before the state is set.
|
||||||
|
let _ = self.model.tx.send(LightEntryMsg::ActivateUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl Widget for Win {
|
||||||
|
|
||||||
Model {
|
Model {
|
||||||
_channel: ch,
|
_channel: ch,
|
||||||
headerbar: relm::init::<HeaderBar>((params.0.clone(), tx.clone(), params.1, params.2))
|
headerbar: relm::init::<HeaderBar>((params.0.clone(), tx.clone()))
|
||||||
.expect("header init"),
|
.expect("header init"),
|
||||||
runtime: params.0,
|
runtime: params.0,
|
||||||
tx,
|
tx,
|
||||||
|
|
|
@ -23,28 +23,35 @@ pub enum SettingsMsg {
|
||||||
Discover,
|
Discover,
|
||||||
Register,
|
Register,
|
||||||
Save,
|
Save,
|
||||||
SetAddr(Option<String>),
|
SetAddr(SettingsDataResponse),
|
||||||
SetUsername(Result<String, String>),
|
SetUsername(SettingsDataResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum SettingsDataResponse {
|
||||||
|
FailedWithError(String),
|
||||||
|
FailedWithoutError,
|
||||||
|
Success(String),
|
||||||
|
Unset,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[widget]
|
#[widget]
|
||||||
impl Widget for Settings {
|
impl Widget for Settings {
|
||||||
fn model(
|
fn model(relm: &Relm<Settings>, runtime: UnboundedSender<RuntimeMsg>) -> SettingsModel {
|
||||||
relm: &Relm<Settings>,
|
|
||||||
params: (UnboundedSender<RuntimeMsg>, String, String),
|
|
||||||
) -> SettingsModel {
|
|
||||||
let stream = relm.stream().clone();
|
let stream = relm.stream().clone();
|
||||||
let (ch, tx) = Channel::new(move |msg| stream.emit(msg));
|
let (ch, tx) = Channel::new(move |msg| stream.emit(msg));
|
||||||
|
|
||||||
|
let _ = runtime.send(RuntimeMsg::RequestConfig(tx.clone()));
|
||||||
|
|
||||||
SettingsModel {
|
SettingsModel {
|
||||||
_channel: ch,
|
_channel: ch,
|
||||||
runtime: params.0,
|
runtime,
|
||||||
tx,
|
tx,
|
||||||
status: String::new(),
|
status: String::new(),
|
||||||
addr_spinning: false,
|
addr_spinning: false,
|
||||||
username_spinning: false,
|
username_spinning: false,
|
||||||
addr: params.1,
|
addr: String::new(),
|
||||||
username: params.2,
|
username: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,25 +88,31 @@ impl Widget for Settings {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
SettingsMsg::SetAddr(addr) => {
|
SettingsMsg::SetAddr(res) => {
|
||||||
self.model.addr_spinning = false;
|
self.model.addr_spinning = false;
|
||||||
if let Some(addr) = addr {
|
match res {
|
||||||
self.model.addr = addr;
|
SettingsDataResponse::FailedWithoutError => {
|
||||||
} else {
|
self.model.status = "Couldn't find a Bridge.".to_string()
|
||||||
self.model.status = "Couldn't find a Bridge.".to_string();
|
},
|
||||||
|
SettingsDataResponse::FailedWithError(e) => {
|
||||||
|
self.model.status = format!("Couldn't find a Bridge: {}", e)
|
||||||
|
},
|
||||||
|
SettingsDataResponse::Success(addr) => self.model.addr = addr,
|
||||||
|
SettingsDataResponse::Unset => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
SettingsMsg::SetUsername(username) => {
|
SettingsMsg::SetUsername(res) => {
|
||||||
self.model.username_spinning = false;
|
self.model.username_spinning = false;
|
||||||
match username {
|
match res {
|
||||||
Ok(u) => {
|
SettingsDataResponse::FailedWithoutError => {
|
||||||
self.model.username = u;
|
self.model.status = "Failed to register.".to_string()
|
||||||
},
|
},
|
||||||
|
SettingsDataResponse::FailedWithError(e) => {
|
||||||
Err(e) => {
|
self.model.status = format!("Failed to register: {}", e)
|
||||||
self.model.status = format!("Failed to register at bridge: {}", e);
|
|
||||||
},
|
},
|
||||||
|
SettingsDataResponse::Success(username) => self.model.username = username,
|
||||||
|
SettingsDataResponse::Unset => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,10 @@ use tokio::sync::{mpsc, RwLock};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, ConfigData},
|
config::{Config, ConfigData},
|
||||||
gui::{settings::SettingsMsg, Msg},
|
gui::{
|
||||||
|
settings::{SettingsDataResponse, SettingsMsg},
|
||||||
|
Msg,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use miette::{miette, Context, IntoDiagnostic};
|
use miette::{miette, Context, IntoDiagnostic};
|
||||||
|
@ -123,7 +126,10 @@ impl Runtime {
|
||||||
|
|
||||||
RuntimeMsg::DiscoverBridge(tx) => {
|
RuntimeMsg::DiscoverBridge(tx) => {
|
||||||
let addr = rhue::discover_bridge(Arc::clone(&http), Duration::from_secs(5)).await?;
|
let addr = rhue::discover_bridge(Arc::clone(&http), Duration::from_secs(5)).await?;
|
||||||
tx.send(SettingsMsg::SetAddr(addr.map(|u| u.to_string())))
|
tx.send(SettingsMsg::SetAddr(match addr {
|
||||||
|
Some(a) => SettingsDataResponse::Success(a.to_string()),
|
||||||
|
None => SettingsDataResponse::FailedWithoutError,
|
||||||
|
}))
|
||||||
.into_diagnostic()?;
|
.into_diagnostic()?;
|
||||||
},
|
},
|
||||||
RuntimeMsg::Register(url, tx) => {
|
RuntimeMsg::Register(url, tx) => {
|
||||||
|
@ -131,11 +137,15 @@ impl Runtime {
|
||||||
Ok(b) => {
|
Ok(b) => {
|
||||||
let username = b.username.clone();
|
let username = b.username.clone();
|
||||||
*bridge.write().await = Some(b);
|
*bridge.write().await = Some(b);
|
||||||
tx.send(SettingsMsg::SetUsername(Ok(username)))
|
tx.send(SettingsMsg::SetUsername(SettingsDataResponse::Success(
|
||||||
|
username,
|
||||||
|
)))
|
||||||
.into_diagnostic()?;
|
.into_diagnostic()?;
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tx.send(SettingsMsg::SetUsername(Err(e.description)))
|
tx.send(SettingsMsg::SetUsername(
|
||||||
|
SettingsDataResponse::FailedWithError(e.description),
|
||||||
|
))
|
||||||
.into_diagnostic()?;
|
.into_diagnostic()?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -146,6 +156,22 @@ impl Runtime {
|
||||||
bridge.update_light(&id, upd).await?;
|
bridge.update_light(&id, upd).await?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
RuntimeMsg::RequestConfig(tx) => {
|
||||||
|
let cfg = config.read().await;
|
||||||
|
|
||||||
|
tx.send(SettingsMsg::SetAddr(match &cfg.data.bridge_addr {
|
||||||
|
Some(a) => SettingsDataResponse::Success(a.to_string()),
|
||||||
|
None => SettingsDataResponse::Unset,
|
||||||
|
}))
|
||||||
|
.into_diagnostic()?;
|
||||||
|
|
||||||
|
tx.send(SettingsMsg::SetUsername(match &cfg.data.bridge_username {
|
||||||
|
Some(a) => SettingsDataResponse::Success(a.clone()),
|
||||||
|
None => SettingsDataResponse::Unset,
|
||||||
|
}))
|
||||||
|
.into_diagnostic()?;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
@ -159,4 +185,5 @@ pub enum RuntimeMsg {
|
||||||
DiscoverBridge(Sender<SettingsMsg>),
|
DiscoverBridge(Sender<SettingsMsg>),
|
||||||
Register(Url, Sender<SettingsMsg>),
|
Register(Url, Sender<SettingsMsg>),
|
||||||
UpdateLight(String, StateUpdate),
|
UpdateLight(String, StateUpdate),
|
||||||
|
RequestConfig(Sender<SettingsMsg>),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue