feat(bluetooth): add discoverable & pairable toggles + fix bug where the receiver for bluetooth events is accidentally dropped

This commit is contained in:
Ashley Wulber 2023-02-10 13:08:29 -05:00 • committed by Ashley Wulber
parent c068343c4d
commit b1a5468547
3 changed files with 48 additions and 30 deletions

View file

@ -7,4 +7,6 @@ confirm = Confirm
cancel = Cancel cancel = Cancel
unsuccessful = Pairing Unsuccessful unsuccessful = Pairing Unsuccessful
check-device = Make sure {$deviceName} is turned on, in range, and is ready to pair. check-device = Make sure {$deviceName} is turned on, in range, and is ready to pair.
try-again = Try Again try-again = Try Again
discoverable = Discoverable
pairable = Pairable

View file

@ -34,19 +34,6 @@ pub fn run() -> cosmic::iced::Result {
CosmicBluetoothApplet::run(helper.window_settings()) CosmicBluetoothApplet::run(helper.window_settings())
} }
// impl Into<()> for NewConnectionState {
// fn into(self) -> AccessPoint {
// match self {
// NewConnectionState::EnterPassword {
// access_point,
// password,
// } => access_point,
// NewConnectionState::Waiting(access_point) => access_point,
// NewConnectionState::Failure(access_point) => access_point,
// }
// }
// }
#[derive(Default)] #[derive(Default)]
struct CosmicBluetoothApplet { struct CosmicBluetoothApplet {
icon_name: String, icon_name: String,
@ -151,9 +138,6 @@ impl Application for CosmicBluetoothApplet {
BluerRequest::StateUpdate BluerRequest::StateUpdate
if self.popup.is_some() && self.bluer_sender.is_some() => if self.popup.is_some() && self.bluer_sender.is_some() =>
{ {
for device in &self.bluer_state.devices {
dbg!((&device.name, &device.status));
}
let tx = self.bluer_sender.as_ref().cloned().unwrap(); let tx = self.bluer_sender.as_ref().cloned().unwrap();
return Command::perform( return Command::perform(
async move { async move {
@ -172,9 +156,6 @@ impl Application for CosmicBluetoothApplet {
self.bluer_state = state; self.bluer_state = state;
} }
BluerEvent::DevicesChanged { state } => { BluerEvent::DevicesChanged { state } => {
for device in &state.devices {
dbg!(&device.name);
}
self.bluer_state = state; self.bluer_state = state;
} }
BluerEvent::Finished => { BluerEvent::Finished => {
@ -372,12 +353,22 @@ impl Application for CosmicBluetoothApplet {
} }
let mut content = column![ let mut content = column![
container( column![
toggler(fl!("bluetooth"), self.bluer_state.bluetooth_enabled, |m| { toggler(fl!("bluetooth"), self.bluer_state.bluetooth_enabled, |m| {
Message::Request(BluerRequest::SetBluetoothEnabled(m)) Message::Request(BluerRequest::SetBluetoothEnabled(m))
},) },)
.width(Length::Fill),
// these are not in the UX mockup, but they are useful imo
toggler(fl!("discoverable"), self.bluer_state.discoverable, |m| {
Message::Request(BluerRequest::SetDiscoverable(m))
},)
.width(Length::Fill),
toggler(fl!("pairable"), self.bluer_state.pairable, |m| {
Message::Request(BluerRequest::SetPairable(m))
},)
.width(Length::Fill) .width(Length::Fill)
) ]
.spacing(8)
.padding([0, 12]), .padding([0, 12]),
divider::horizontal::light(), divider::horizontal::light(),
known_bluetooth, known_bluetooth,

View file

@ -67,10 +67,7 @@ async fn start_listening<I: Copy + Debug>(id: I, state: State) -> (Option<(I, Bl
let event = if let Some(event) = session_rx.recv().await { let event = if let Some(event) = session_rx.recv().await {
match event { match event {
BluerSessionEvent::ChangesProcessed(state) => { BluerSessionEvent::ChangesProcessed(state) => {
return ( Some((id, BluerEvent::DevicesChanged { state }))
Some((id, BluerEvent::DevicesChanged { state })),
State::Waiting { session_state },
);
} }
BluerSessionEvent::RequestResponse { BluerSessionEvent::RequestResponse {
req, req,
@ -90,7 +87,6 @@ async fn start_listening<I: Copy + Debug>(id: I, state: State) -> (Option<(I, Bl
} else { } else {
return (None, State::Finished); return (None, State::Finished);
}; };
session_state.rx = Some(session_rx); session_state.rx = Some(session_rx);
(event, State::Waiting { session_state }) (event, State::Waiting { session_state })
} }
@ -101,6 +97,8 @@ async fn start_listening<I: Copy + Debug>(id: I, state: State) -> (Option<(I, Bl
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum BluerRequest { pub enum BluerRequest {
SetBluetoothEnabled(bool), SetBluetoothEnabled(bool),
SetPairable(bool),
SetDiscoverable(bool),
PairDevice(Address), PairDevice(Address),
ConnectDevice(Address), ConnectDevice(Address),
DisconnectDevice(Address), DisconnectDevice(Address),
@ -130,6 +128,8 @@ pub enum BluerEvent {
pub struct BluerState { pub struct BluerState {
pub devices: Vec<BluerDevice>, pub devices: Vec<BluerDevice>,
pub bluetooth_enabled: bool, pub bluetooth_enabled: bool,
pub discoverable: bool,
pub pairable: bool,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -178,6 +178,7 @@ impl BluerDevice {
} }
} }
#[derive(Debug, Clone)]
pub enum BluerSessionEvent { pub enum BluerSessionEvent {
RequestResponse { RequestResponse {
req: BluerRequest, req: BluerRequest,
@ -334,7 +335,6 @@ impl BluerSessionState {
)) ))
.await; .await;
let res = rx.recv().await; let res = rx.recv().await;
dbg!(res);
match res { match res {
Some(res) if res => Ok(()), Some(res) if res => Ok(()),
_ => Err(bluer::agent::ReqError::Rejected), _ => Err(bluer::agent::ReqError::Rejected),
@ -404,8 +404,9 @@ impl BluerSessionState {
tx, tx,
active_requests: Arc::new(Mutex::new(HashMap::new())), active_requests: Arc::new(Mutex::new(HashMap::new())),
}; };
self_.process_changes();
self_.process_requests(request_rx); self_.process_requests(request_rx);
self_.process_changes();
Ok(self_) Ok(self_)
} }
@ -433,7 +434,15 @@ impl BluerSessionState {
let _ = tx let _ = tx
.send(BluerSessionEvent::ChangesProcessed(BluerState { .send(BluerSessionEvent::ChangesProcessed(BluerState {
devices: build_device_list(&adapter_clone).await, devices: build_device_list(&adapter_clone).await,
bluetooth_enabled: true, bluetooth_enabled: adapter_clone
.is_powered()
.await
.unwrap_or_default(),
discoverable: adapter_clone
.is_discoverable()
.await
.unwrap_or_default(),
pairable: adapter_clone.is_pairable().await.unwrap_or_default(),
})) }))
.await; .await;
// reset timeout // reset timeout
@ -518,11 +527,25 @@ impl BluerSessionState {
} }
} }
BluerRequest::StateUpdate => {} BluerRequest::StateUpdate => {}
BluerRequest::SetPairable(enabled) => {
let res = adapter_clone.set_pairable(*enabled).await;
if let Err(e) = res {
err_msg = Some(e.to_string());
}
}
BluerRequest::SetDiscoverable(enabled) => {
let res = adapter_clone.set_discoverable(*enabled).await;
if let Err(e) = res {
err_msg = Some(e.to_string());
}
}
}; };
let state = BluerState { let state = BluerState {
devices: build_device_list(&adapter_clone).await, devices: build_device_list(&adapter_clone).await,
bluetooth_enabled: adapter_clone.is_powered().await.unwrap_or_default(), bluetooth_enabled: adapter_clone.is_powered().await.unwrap_or_default(),
discoverable: adapter_clone.is_discoverable().await.unwrap_or_default(),
pairable: adapter_clone.is_pairable().await.unwrap_or_default(),
}; };
let _ = tx_clone let _ = tx_clone
@ -550,6 +573,8 @@ impl BluerSessionState {
devices: build_device_list(&self.adapter).await, devices: build_device_list(&self.adapter).await,
// TODO is this a proper way of checking if bluetooth is enabled? // TODO is this a proper way of checking if bluetooth is enabled?
bluetooth_enabled: self.adapter.is_powered().await.unwrap_or_default(), bluetooth_enabled: self.adapter.is_powered().await.unwrap_or_default(),
discoverable: self.adapter.is_discoverable().await.unwrap_or_default(),
pairable: self.adapter.is_pairable().await.unwrap_or_default(),
} }
} }
} }