prevent all lights having their state set on startup
+ some cleanup
This commit is contained in:
parent
c610f8b798
commit
c02ff988c1
|
@ -23,13 +23,14 @@ pub enum HeaderBarMsg {
|
|||
|
||||
#[widget]
|
||||
impl Widget for HeaderBar {
|
||||
fn model(data: (UnboundedSender<RuntimeMsg>, Sender<Msg>, String, String)) -> HeaderBarModel {
|
||||
fn model(data: (UnboundedSender<RuntimeMsg>, Sender<Msg>)) -> 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"),
|
||||
rootwintx: data.1,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: HeaderBarMsg) {
|
||||
match msg {
|
||||
HeaderBarMsg::OpenSettings => {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use relm::Relm;
|
||||
use angular_units::Turns;
|
||||
use gtk::{prelude::*, Orientation};
|
||||
use log::debug;
|
||||
use prisma::{Hsv, Rgb};
|
||||
use relm::Widget;
|
||||
use relm::{Channel, Sender, Widget};
|
||||
use relm_derive::{widget, Msg};
|
||||
use rhue::{
|
||||
api::{Light, LightArchetype},
|
||||
|
@ -14,6 +15,8 @@ use tokio::sync::mpsc::UnboundedSender;
|
|||
use crate::runtime::RuntimeMsg;
|
||||
|
||||
pub struct LightEntryModel {
|
||||
_channel: Channel<LightEntryMsg>,
|
||||
tx: Sender<LightEntryMsg>,
|
||||
id: String,
|
||||
name: String,
|
||||
runtime: UnboundedSender<RuntimeMsg>,
|
||||
|
@ -21,12 +24,18 @@ pub struct LightEntryModel {
|
|||
brightness: f64,
|
||||
color: Rc<Cell<Rgb<f64>>>,
|
||||
icon: String,
|
||||
updates_active: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Msg)]
|
||||
pub enum LightEntryMsg {
|
||||
Update(StateUpdate),
|
||||
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)]
|
||||
|
@ -37,8 +46,16 @@ pub enum EntryLightProperty {
|
|||
|
||||
#[widget]
|
||||
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 {
|
||||
_channel: ch,
|
||||
tx,
|
||||
id: params.0,
|
||||
name: params.1.name,
|
||||
runtime: params.2,
|
||||
|
@ -53,6 +70,7 @@ impl Widget for LightEntry {
|
|||
.into(),
|
||||
)),
|
||||
icon: resource_of_archetype(params.1.config.archetype),
|
||||
updates_active: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,11 +98,13 @@ impl Widget for LightEntry {
|
|||
self.model.on = on;
|
||||
}
|
||||
|
||||
let _ = self
|
||||
.model
|
||||
.runtime
|
||||
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
||||
},
|
||||
if self.model.updates_active {
|
||||
let _ = self
|
||||
.model
|
||||
.runtime
|
||||
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
||||
}
|
||||
}
|
||||
|
||||
LightEntryMsg::PropertyChanged(prop) => {
|
||||
debug!("updating light {}", &self.model.id);
|
||||
|
@ -110,11 +130,15 @@ impl Widget for LightEntry {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let _ = self
|
||||
.model
|
||||
.runtime
|
||||
.send(RuntimeMsg::UpdateLight(self.model.id.clone(), upd));
|
||||
},
|
||||
if self.model.updates_active {
|
||||
let _ = self
|
||||
.model
|
||||
.runtime
|
||||
.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)
|
||||
});
|
||||
|
||||
// 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! {
|
||||
|
|
|
@ -52,7 +52,7 @@ impl Widget for Win {
|
|||
|
||||
Model {
|
||||
_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"),
|
||||
runtime: params.0,
|
||||
tx,
|
||||
|
|
|
@ -23,28 +23,35 @@ pub enum SettingsMsg {
|
|||
Discover,
|
||||
Register,
|
||||
Save,
|
||||
SetAddr(Option<String>),
|
||||
SetUsername(Result<String, String>),
|
||||
SetAddr(SettingsDataResponse),
|
||||
SetUsername(SettingsDataResponse),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SettingsDataResponse {
|
||||
FailedWithError(String),
|
||||
FailedWithoutError,
|
||||
Success(String),
|
||||
Unset,
|
||||
}
|
||||
|
||||
#[widget]
|
||||
impl Widget for Settings {
|
||||
fn model(
|
||||
relm: &Relm<Settings>,
|
||||
params: (UnboundedSender<RuntimeMsg>, String, String),
|
||||
) -> SettingsModel {
|
||||
fn model(relm: &Relm<Settings>, runtime: UnboundedSender<RuntimeMsg>) -> SettingsModel {
|
||||
let stream = relm.stream().clone();
|
||||
let (ch, tx) = Channel::new(move |msg| stream.emit(msg));
|
||||
|
||||
let _ = runtime.send(RuntimeMsg::RequestConfig(tx.clone()));
|
||||
|
||||
SettingsModel {
|
||||
_channel: ch,
|
||||
runtime: params.0,
|
||||
runtime,
|
||||
tx,
|
||||
status: String::new(),
|
||||
addr_spinning: false,
|
||||
username_spinning: false,
|
||||
addr: params.1,
|
||||
username: params.2,
|
||||
addr: String::new(),
|
||||
username: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,25 +88,31 @@ impl Widget for Settings {
|
|||
}
|
||||
},
|
||||
|
||||
SettingsMsg::SetAddr(addr) => {
|
||||
SettingsMsg::SetAddr(res) => {
|
||||
self.model.addr_spinning = false;
|
||||
if let Some(addr) = addr {
|
||||
self.model.addr = addr;
|
||||
} else {
|
||||
self.model.status = "Couldn't find a Bridge.".to_string();
|
||||
match res {
|
||||
SettingsDataResponse::FailedWithoutError => {
|
||||
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;
|
||||
match username {
|
||||
Ok(u) => {
|
||||
self.model.username = u;
|
||||
match res {
|
||||
SettingsDataResponse::FailedWithoutError => {
|
||||
self.model.status = "Failed to register.".to_string()
|
||||
},
|
||||
|
||||
Err(e) => {
|
||||
self.model.status = format!("Failed to register at bridge: {}", e);
|
||||
SettingsDataResponse::FailedWithError(e) => {
|
||||
self.model.status = format!("Failed to register: {}", e)
|
||||
},
|
||||
SettingsDataResponse::Success(username) => self.model.username = username,
|
||||
SettingsDataResponse::Unset => {},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ use tokio::sync::{mpsc, RwLock};
|
|||
|
||||
use crate::{
|
||||
config::{Config, ConfigData},
|
||||
gui::{settings::SettingsMsg, Msg},
|
||||
gui::{
|
||||
settings::{SettingsDataResponse, SettingsMsg},
|
||||
Msg,
|
||||
},
|
||||
};
|
||||
use log::{error, info};
|
||||
use miette::{miette, Context, IntoDiagnostic};
|
||||
|
@ -123,20 +126,27 @@ impl Runtime {
|
|||
|
||||
RuntimeMsg::DiscoverBridge(tx) => {
|
||||
let addr = rhue::discover_bridge(Arc::clone(&http), Duration::from_secs(5)).await?;
|
||||
tx.send(SettingsMsg::SetAddr(addr.map(|u| u.to_string())))
|
||||
.into_diagnostic()?;
|
||||
tx.send(SettingsMsg::SetAddr(match addr {
|
||||
Some(a) => SettingsDataResponse::Success(a.to_string()),
|
||||
None => SettingsDataResponse::FailedWithoutError,
|
||||
}))
|
||||
.into_diagnostic()?;
|
||||
},
|
||||
RuntimeMsg::Register(url, tx) => {
|
||||
match Bridge::register(http, "GUE", url).await?.to_result() {
|
||||
Ok(b) => {
|
||||
let username = b.username.clone();
|
||||
*bridge.write().await = Some(b);
|
||||
tx.send(SettingsMsg::SetUsername(Ok(username)))
|
||||
.into_diagnostic()?;
|
||||
tx.send(SettingsMsg::SetUsername(SettingsDataResponse::Success(
|
||||
username,
|
||||
)))
|
||||
.into_diagnostic()?;
|
||||
},
|
||||
Err(e) => {
|
||||
tx.send(SettingsMsg::SetUsername(Err(e.description)))
|
||||
.into_diagnostic()?;
|
||||
tx.send(SettingsMsg::SetUsername(
|
||||
SettingsDataResponse::FailedWithError(e.description),
|
||||
))
|
||||
.into_diagnostic()?;
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -146,6 +156,22 @@ impl Runtime {
|
|||
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)
|
||||
|
@ -159,4 +185,5 @@ pub enum RuntimeMsg {
|
|||
DiscoverBridge(Sender<SettingsMsg>),
|
||||
Register(Url, Sender<SettingsMsg>),
|
||||
UpdateLight(String, StateUpdate),
|
||||
RequestConfig(Sender<SettingsMsg>),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue