feat: Implement error popup for bluetooth and network

This commit is contained in:
Fabio Lenherr / DashieTM 2024-03-11 18:56:53 +01:00
parent 16a30a7bdd
commit 75050c840a
11 changed files with 220 additions and 86 deletions

View file

@ -58,6 +58,7 @@ pub fn show_error<T: ReSetErrorImpl + Send + Sync + 'static>(
parent: Arc<T>, parent: Arc<T>,
message: &'static str, message: &'static str,
) { ) {
// TODO: Add error to log
glib::spawn_future(async move { glib::spawn_future(async move {
glib::idle_add_once(move || { glib::idle_add_once(move || {
let mut error = parent.error(); let mut error = parent.error();

View file

@ -16,6 +16,7 @@ use gtk::{gio, StringObject};
use re_set_lib::bluetooth::bluetooth_structures::{BluetoothAdapter, BluetoothDevice}; use re_set_lib::bluetooth::bluetooth_structures::{BluetoothAdapter, BluetoothDevice};
use re_set_lib::signals::{BluetoothDeviceAdded, BluetoothDeviceChanged, BluetoothDeviceRemoved}; use re_set_lib::signals::{BluetoothDeviceAdded, BluetoothDeviceChanged, BluetoothDeviceRemoved};
use crate::components::base::error_impl::{show_error, ReSetErrorImpl};
use crate::components::base::utils::Listeners; use crate::components::base::utils::Listeners;
use crate::components::bluetooth::bluetooth_box_impl; use crate::components::bluetooth::bluetooth_box_impl;
use crate::components::bluetooth::bluetooth_entry::BluetoothEntry; use crate::components::bluetooth::bluetooth_entry::BluetoothEntry;
@ -30,6 +31,14 @@ glib::wrapper! {
unsafe impl Send for BluetoothBox {} unsafe impl Send for BluetoothBox {}
unsafe impl Sync for BluetoothBox {} unsafe impl Sync for BluetoothBox {}
impl ReSetErrorImpl for BluetoothBox {
fn error(
&self,
) -> &gtk::subclass::prelude::TemplateChild<crate::components::base::error::ReSetError> {
&self.imp().error
}
}
impl BluetoothBox { impl BluetoothBox {
pub fn new(listeners: Arc<Listeners>) -> Arc<Self> { pub fn new(listeners: Arc<Listeners>) -> Arc<Self> {
let obj: Arc<Self> = Arc::new(Object::builder().build()); let obj: Arc<Self> = Arc::new(Object::builder().build());
@ -68,14 +77,24 @@ fn setup_callbacks(
.store(true, Ordering::SeqCst); .store(true, Ordering::SeqCst);
}); });
let bluetooth_box_discover = bluetooth_box.clone();
imp.reset_bluetooth_discoverable_switch imp.reset_bluetooth_discoverable_switch
.connect_active_notify(clone!(@weak imp => move |state| { .connect_active_notify(clone!(@weak imp => move |state| {
set_bluetooth_adapter_visibility(imp.reset_current_bluetooth_adapter.borrow().path.clone(), state.is_active()); set_bluetooth_adapter_visibility(
imp.reset_current_bluetooth_adapter.borrow().path.clone(),
state.is_active(),
bluetooth_box_discover.clone()
);
})); }));
let bluetooth_box_pairable = bluetooth_box.clone();
imp.reset_bluetooth_pairable_switch imp.reset_bluetooth_pairable_switch
.connect_active_notify(clone!(@weak imp => move |state| { .connect_active_notify(clone!(@weak imp => move |state| {
set_bluetooth_adapter_pairability(imp.reset_current_bluetooth_adapter.borrow().path.clone(), state.is_active()); set_bluetooth_adapter_pairability(
imp.reset_current_bluetooth_adapter.borrow().path.clone(),
state.is_active(),
bluetooth_box_pairable.clone()
);
})); }));
imp.reset_bluetooth_switch.connect_state_set( imp.reset_bluetooth_switch.connect_state_set(
@ -110,6 +129,7 @@ fn setup_callbacks(
let res = set_adapter_enabled( let res = set_adapter_enabled(
current_adapter.path.clone(), current_adapter.path.clone(),
false, false,
bluetooth_box_ref.clone()
); );
if res { if res {
current_adapter.powered = false; current_adapter.powered = false;
@ -129,6 +149,7 @@ fn setup_callbacks(
.path .path
.clone(), .clone(),
true, true,
restart_ref.clone()
) { ) {
current_adapter.powered = true; current_adapter.powered = true;
start_bluetooth_listener(restart_listener_ref.clone(), restart_ref.clone()); start_bluetooth_listener(restart_listener_ref.clone(), restart_ref.clone());
@ -145,8 +166,8 @@ pub fn populate_conntected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
// TODO handle saved devices -> they also exist // TODO handle saved devices -> they also exist
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let ref_box = bluetooth_box.clone(); let ref_box = bluetooth_box.clone();
let devices = get_connected_devices(); let devices = get_connected_devices(ref_box.clone());
let adapters = get_bluetooth_adapters(); let adapters = get_bluetooth_adapters(ref_box.clone());
{ {
let imp = bluetooth_box.imp(); let imp = bluetooth_box.imp();
let list = imp.reset_model_list.write().unwrap(); let list = imp.reset_model_list.write().unwrap();
@ -165,6 +186,7 @@ pub fn populate_conntected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
} }
glib::spawn_future(async move { glib::spawn_future(async move {
glib::idle_add_once(move || { glib::idle_add_once(move || {
let new_adapter_ref = ref_box.clone();
let imp = ref_box.imp(); let imp = ref_box.imp();
let list = imp.reset_model_list.read().unwrap(); let list = imp.reset_model_list.read().unwrap();
@ -202,14 +224,14 @@ pub fn populate_conntected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
if device.is_none() { if device.is_none() {
return; return;
} }
set_bluetooth_adapter(device.unwrap().0.path.clone()); set_bluetooth_adapter(device.unwrap().0.path.clone(), new_adapter_ref.clone());
}), }),
); );
for device in devices { for device in devices {
let path = device.path.clone(); let path = device.path.clone();
let connected = device.connected; let connected = device.connected;
let bluetooth_entry = BluetoothEntry::new(device); let bluetooth_entry = BluetoothEntry::new(device, ref_box.clone());
imp.available_devices imp.available_devices
.borrow_mut() .borrow_mut()
.insert(path, bluetooth_entry.clone()); .insert(path, bluetooth_entry.clone());
@ -242,7 +264,10 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call(BLUETOOTH, "StartBluetoothListener", ()); let res: Result<(), Error> = proxy.method_call(BLUETOOTH, "StartBluetoothListener", ());
if res.is_err() {
show_error::<BluetoothBox>(bluetooth_box.clone(), "Failed to start bluetooth listener");
}
imp.reset_bluetooth_available_devices imp.reset_bluetooth_available_devices
.set_description(Some("Scanning...")); .set_description(Some("Scanning..."));
let device_added = let device_added =
@ -262,7 +287,8 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
let imp = bluetooth_box.imp(); let imp = bluetooth_box.imp();
let path = ir.bluetooth_device.path.clone(); let path = ir.bluetooth_device.path.clone();
let connected = ir.bluetooth_device.connected; let connected = ir.bluetooth_device.connected;
let bluetooth_entry = BluetoothEntry::new(ir.bluetooth_device); let bluetooth_entry =
BluetoothEntry::new(ir.bluetooth_device, bluetooth_box.clone());
imp.available_devices imp.available_devices
.borrow_mut() .borrow_mut()
.insert(path, bluetooth_entry.clone()); .insert(path, bluetooth_entry.clone());
@ -353,8 +379,14 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
loop { loop {
let _ = conn.process(Duration::from_millis(1000)); let _ = conn.process(Duration::from_millis(1000));
if !listeners.bluetooth_listener.load(Ordering::SeqCst) { if !listeners.bluetooth_listener.load(Ordering::SeqCst) {
let _: Result<(), Error> = let res: Result<(), Error> =
proxy.method_call(BLUETOOTH, "StopBluetoothListener", ()); proxy.method_call(BLUETOOTH, "StopBluetoothListener", ());
if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to stop bluetooth listener",
);
}
loop_box loop_box
.imp() .imp()
.reset_bluetooth_available_devices .reset_bluetooth_available_devices
@ -372,7 +404,13 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
.set_sensitive(true); .set_sensitive(true);
}); });
}); });
let _: Result<(), Error> = proxy.method_call(BLUETOOTH, "StopBluetoothScan", ()); let res: Result<(), Error> = proxy.method_call(BLUETOOTH, "StopBluetoothScan", ());
if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to stop bluetooth listener",
);
}
loop_box loop_box
.imp() .imp()
.reset_bluetooth_available_devices .reset_bluetooth_available_devices
@ -383,8 +421,14 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
.bluetooth_scan_requested .bluetooth_scan_requested
.store(false, Ordering::SeqCst); .store(false, Ordering::SeqCst);
listener_active = true; listener_active = true;
let _: Result<(), Error> = let res: Result<(), Error> =
proxy.method_call(BLUETOOTH, "StartBluetoothListener", ()); proxy.method_call(BLUETOOTH, "StartBluetoothListener", ());
if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to start bluetooth listener",
);
}
loop_box loop_box
.imp() .imp()
.reset_bluetooth_available_devices .reset_bluetooth_available_devices
@ -395,58 +439,91 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
}); });
} }
fn get_connected_devices() -> Vec<BluetoothDevice> { fn get_connected_devices(bluetooth_box: Arc<BluetoothBox>) -> Vec<BluetoothDevice> {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(Vec<BluetoothDevice>,), Error> = let res: Result<(Vec<BluetoothDevice>,), Error> =
proxy.method_call(BLUETOOTH, "GetConnectedBluetoothDevices", ()); proxy.method_call(BLUETOOTH, "GetConnectedBluetoothDevices", ());
if res.is_err() { if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to get connected bluetooth devices",
);
return Vec::new(); return Vec::new();
} }
res.unwrap().0 res.unwrap().0
} }
fn get_bluetooth_adapters() -> Vec<BluetoothAdapter> { fn get_bluetooth_adapters(bluetooth_box: Arc<BluetoothBox>) -> Vec<BluetoothAdapter> {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(Vec<BluetoothAdapter>,), Error> = let res: Result<(Vec<BluetoothAdapter>,), Error> =
proxy.method_call(BLUETOOTH, "GetBluetoothAdapters", ()); proxy.method_call(BLUETOOTH, "GetBluetoothAdapters", ());
if res.is_err() { if res.is_err() {
show_error::<BluetoothBox>(bluetooth_box.clone(), "Failed to get bluetooth adapters");
return Vec::new(); return Vec::new();
} }
res.unwrap().0 res.unwrap().0
} }
fn set_bluetooth_adapter(path: Path<'static>) { fn set_bluetooth_adapter(path: Path<'static>, bluetooth_box: Arc<BluetoothBox>) {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(Path<'static>,), Error> = let res: Result<(Path<'static>,), Error> =
proxy.method_call(BLUETOOTH, "SetBluetoothAdapter", (path,)); proxy.method_call(BLUETOOTH, "SetBluetoothAdapter", (path,));
if res.is_err() {
show_error::<BluetoothBox>(bluetooth_box.clone(), "Failed to set bluetooth adapter");
}
} }
fn set_bluetooth_adapter_visibility(path: Path<'static>, visible: bool) { fn set_bluetooth_adapter_visibility(
path: Path<'static>,
visible: bool,
bluetooth_box: Arc<BluetoothBox>,
) {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(bool,), Error> = proxy.method_call( let res: Result<(bool,), Error> = proxy.method_call(
BLUETOOTH, BLUETOOTH,
"SetBluetoothAdapterDiscoverability", "SetBluetoothAdapterDiscoverability",
(path, visible), (path, visible),
); );
if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to set bluetooth adapter visibility",
);
}
} }
fn set_bluetooth_adapter_pairability(path: Path<'static>, visible: bool) { fn set_bluetooth_adapter_pairability(
path: Path<'static>,
visible: bool,
bluetooth_box: Arc<BluetoothBox>,
) {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(bool,), Error> = let res: Result<(bool,), Error> =
proxy.method_call(BLUETOOTH, "SetBluetoothAdapterPairability", (path, visible)); proxy.method_call(BLUETOOTH, "SetBluetoothAdapterPairability", (path, visible));
if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to set bluetooth adapter pairability",
);
}
} }
fn set_adapter_enabled(path: Path<'static>, enabled: bool) -> bool { fn set_adapter_enabled(
path: Path<'static>,
enabled: bool,
bluetooth_box: Arc<BluetoothBox>,
) -> bool {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let result: Result<(bool,), Error> = let result: Result<(bool,), Error> =
proxy.method_call(BLUETOOTH, "SetBluetoothAdapterEnabled", (path, enabled)); proxy.method_call(BLUETOOTH, "SetBluetoothAdapterEnabled", (path, enabled));
if result.is_err() { if result.is_err() {
show_error::<BluetoothBox>(bluetooth_box.clone(), "Failed to enable bluetooth adapter");
return false; return false;
} }
result.unwrap().0 result.unwrap().0

View file

@ -9,6 +9,7 @@ use std::collections::HashMap;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use crate::components::base::error::ReSetError;
use crate::components::base::list_entry::ListEntry; use crate::components::base::list_entry::ListEntry;
use crate::components::bluetooth::bluetooth_box; use crate::components::bluetooth::bluetooth_box;
use crate::components::bluetooth::bluetooth_entry::BluetoothEntry; use crate::components::bluetooth::bluetooth_entry::BluetoothEntry;
@ -36,6 +37,8 @@ pub struct BluetoothBox {
pub reset_bluetooth_discoverable_switch: TemplateChild<SwitchRow>, pub reset_bluetooth_discoverable_switch: TemplateChild<SwitchRow>,
#[template_child] #[template_child]
pub reset_bluetooth_pairable_switch: TemplateChild<SwitchRow>, pub reset_bluetooth_pairable_switch: TemplateChild<SwitchRow>,
#[template_child]
pub error: TemplateChild<ReSetError>,
pub available_devices: BluetoothMap, pub available_devices: BluetoothMap,
pub connected_devices: BluetoothMap, pub connected_devices: BluetoothMap,
pub reset_bluetooth_adapters: Arc<RwLock<HashMap<String, (BluetoothAdapter, u32)>>>, pub reset_bluetooth_adapters: Arc<RwLock<HashMap<String, (BluetoothAdapter, u32)>>>,

View file

@ -2,8 +2,10 @@ use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use crate::components::base::error_impl::show_error;
use crate::components::bluetooth::bluetooth_entry_impl; use crate::components::bluetooth::bluetooth_entry_impl;
use crate::components::utils::{BASE, BLUETOOTH, DBUS_PATH}; use crate::components::utils::{BASE, BLUETOOTH, DBUS_PATH};
use crate::components::wifi::wifi_box_impl::WifiBox;
use adw::glib::Object; use adw::glib::Object;
use adw::prelude::{ActionRowExt, PreferencesRowExt}; use adw::prelude::{ActionRowExt, PreferencesRowExt};
use adw::{glib, ActionRow}; use adw::{glib, ActionRow};
@ -14,6 +16,8 @@ use gtk::prelude::{ButtonExt, ListBoxRowExt, WidgetExt};
use gtk::{gio, Align, Button, GestureClick, Image, Label}; use gtk::{gio, Align, Button, GestureClick, Image, Label};
use re_set_lib::bluetooth::bluetooth_structures::BluetoothDevice; use re_set_lib::bluetooth::bluetooth_structures::BluetoothDevice;
use super::bluetooth_box::BluetoothBox;
glib::wrapper! { glib::wrapper! {
pub struct BluetoothEntry(ObjectSubclass<bluetooth_entry_impl::BluetoothEntry>) pub struct BluetoothEntry(ObjectSubclass<bluetooth_entry_impl::BluetoothEntry>)
@extends ActionRow, gtk::Widget, @extends ActionRow, gtk::Widget,
@ -24,7 +28,7 @@ unsafe impl Send for BluetoothEntry {}
unsafe impl Sync for BluetoothEntry {} unsafe impl Sync for BluetoothEntry {}
impl BluetoothEntry { impl BluetoothEntry {
pub fn new(device: BluetoothDevice) -> Arc<Self> { pub fn new(device: BluetoothDevice, bluetooth_box: Arc<BluetoothBox>) -> Arc<Self> {
let entry: Arc<BluetoothEntry> = Arc::new(Object::builder().build()); let entry: Arc<BluetoothEntry> = Arc::new(Object::builder().build());
let entry_imp = entry.imp(); let entry_imp = entry.imp();
let entry_ref = entry.clone(); let entry_ref = entry.clone();
@ -60,7 +64,7 @@ impl BluetoothEntry {
.borrow() .borrow()
.connect_clicked(move |_| { .connect_clicked(move |_| {
let imp = entry_ref_remove.imp(); let imp = entry_ref_remove.imp();
remove_device_pairing(imp.bluetooth_device.borrow().path.clone()); remove_device_pairing(imp.bluetooth_device.borrow().path.clone(), bluetooth_box.clone());
}); });
let gesture = GestureClick::new(); let gesture = GestureClick::new();
// paired is not what we think // paired is not what we think
@ -147,11 +151,14 @@ fn disconnect_from_device(entry: Arc<BluetoothEntry>, path: Path<'static>) {
}); });
} }
fn remove_device_pairing(path: Path<'static>) { fn remove_device_pairing(path: Path<'static>, wifi_box: Arc<BluetoothBox>) {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(bool,), Error> = let res: Result<(bool,), Error> =
proxy.method_call(BLUETOOTH, "RemoveDevicePairing", (path,)); proxy.method_call(BLUETOOTH, "RemoveDevicePairing", (path,));
if res.is_err() {
show_error::<BluetoothBox>(wifi_box.clone(), "Failed to remove device pairing");
}
}); });
} }

View file

@ -1,6 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use crate::components::base::error_impl::show_error;
use crate::components::utils::{ use crate::components::utils::{
create_dropdown_label_factory, set_combo_row_ellipsis, AUDIO, BASE, DBUS_PATH, create_dropdown_label_factory, set_combo_row_ellipsis, AUDIO, BASE, DBUS_PATH,
}; };
@ -30,6 +31,9 @@ impl OutputStreamEntry {
pub fn new(source_box: Arc<SourceBox>, stream: OutputStream) -> Self { pub fn new(source_box: Arc<SourceBox>, stream: OutputStream) -> Self {
let obj: Self = Object::builder().build(); let obj: Self = Object::builder().build();
// TODO use event callback for progress bar -> this is the "im speaking" indicator // TODO use event callback for progress bar -> this is the "im speaking" indicator
let output_box_volume_ref = source_box.clone();
let output_box_mute_ref = source_box.clone();
let output_box_source_ref = source_box.clone();
{ {
let index = stream.index; let index = stream.index;
let box_imp = source_box.imp(); let box_imp = source_box.imp();
@ -66,7 +70,7 @@ impl OutputStreamEntry {
} }
*time = Some(SystemTime::now()); *time = Some(SystemTime::now());
} }
set_outputstream_volume(value, index, channels); set_outputstream_volume(value, index, channels, output_box_volume_ref.clone());
Propagation::Proceed Propagation::Proceed
}), }),
); );
@ -118,7 +122,7 @@ impl OutputStreamEntry {
} }
let stream = stream.unwrap(); let stream = stream.unwrap();
let source = source.unwrap().0; let source = source.unwrap().0;
set_source_of_output_stream(stream.index, source); set_source_of_output_stream(stream.index, source, output_box_source_ref.clone());
}), }),
); );
imp.reset_source_mute imp.reset_source_mute
@ -139,53 +143,56 @@ impl OutputStreamEntry {
imp.reset_source_mute imp.reset_source_mute
.set_icon_name("audio-input-microphone-symbolic"); .set_icon_name("audio-input-microphone-symbolic");
} }
toggle_output_stream_mute(index, muted); toggle_output_stream_mute(index, muted, output_box_mute_ref.clone());
})); }));
} }
obj obj
} }
} }
fn set_outputstream_volume(value: f64, index: u32, channels: u16) -> bool { fn set_outputstream_volume(
value: f64,
index: u32,
channels: u16,
input_box: Arc<SourceBox>,
) -> bool {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call( let res: Result<(), Error> = proxy.method_call(
AUDIO, AUDIO,
"SetOutputStreamVolume", "SetOutputStreamVolume",
(index, channels, value as u32), (index, channels, value as u32),
); );
// if res.is_err() { if res.is_err() {
// return false; show_error::<SourceBox>(input_box.clone(), "Failed to set output stream volume");
// } }
// res.unwrap().0
}); });
true true
} }
fn toggle_output_stream_mute(index: u32, muted: bool) -> bool { fn toggle_output_stream_mute(index: u32, muted: bool, input_box: Arc<SourceBox>) -> bool {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call(AUDIO, "SetOutputStreamMute", (index, muted)); let res: Result<(), Error> =
// if res.is_err() { proxy.method_call(AUDIO, "SetOutputStreamMute", (index, muted));
// return false; if res.is_err() {
// } show_error::<SourceBox>(input_box.clone(), "Failed to mute output stream");
// res.unwrap().0 }
}); });
true true
} }
fn set_source_of_output_stream(stream: u32, source: u32) -> bool { fn set_source_of_output_stream(stream: u32, source: u32, input_box: Arc<SourceBox>) -> bool {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(bool,), Error> = let res: Result<(bool,), Error> =
proxy.method_call(AUDIO, "SetSourceOfOutputStream", (stream, source)); proxy.method_call(AUDIO, "SetSourceOfOutputStream", (stream, source));
// if res.is_err() { if res.is_err() {
// return false; show_error::<SourceBox>(input_box.clone(), "Failed to set source of output stream");
// } }
// res.unwrap().0
}); });
true true
} }

View file

@ -1,6 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use crate::components::base::error_impl::show_error;
use crate::components::utils::{ use crate::components::utils::{
create_dropdown_label_factory, set_combo_row_ellipsis, AUDIO, BASE, DBUS_PATH, create_dropdown_label_factory, set_combo_row_ellipsis, AUDIO, BASE, DBUS_PATH,
}; };
@ -30,6 +31,9 @@ impl InputStreamEntry {
pub fn new(sink_box: Arc<SinkBox>, stream: InputStream) -> Self { pub fn new(sink_box: Arc<SinkBox>, stream: InputStream) -> Self {
let obj: Self = Object::builder().build(); let obj: Self = Object::builder().build();
// TODO use event callback for progress bar -> this is the "im speaking" indicator // TODO use event callback for progress bar -> this is the "im speaking" indicator
let output_box_mute_ref = sink_box.clone();
let output_box_volume_ref = sink_box.clone();
let output_box_sink_ref = sink_box.clone();
{ {
let index = stream.sink_index; let index = stream.sink_index;
let box_imp = sink_box.imp(); let box_imp = sink_box.imp();
@ -75,7 +79,7 @@ impl InputStreamEntry {
} }
*time = Some(SystemTime::now()); *time = Some(SystemTime::now());
} }
set_inputstream_volume(value, index, channels); set_inputstream_volume(value, index, channels, output_box_volume_ref.clone());
Propagation::Proceed Propagation::Proceed
}), }),
); );
@ -131,7 +135,7 @@ impl InputStreamEntry {
} }
let stream = stream.unwrap(); let stream = stream.unwrap();
let sink = sink.unwrap().0; let sink = sink.unwrap().0;
set_sink_of_input_stream(stream.index, sink); set_sink_of_input_stream(stream.index, sink, output_box_sink_ref.clone());
}), }),
); );
imp.reset_sink_mute imp.reset_sink_mute
@ -152,54 +156,55 @@ impl InputStreamEntry {
imp.reset_sink_mute imp.reset_sink_mute
.set_icon_name("audio-volume-high-symbolic"); .set_icon_name("audio-volume-high-symbolic");
} }
toggle_input_stream_mute(index, muted); toggle_input_stream_mute(index, muted, output_box_mute_ref.clone());
})); }));
} }
obj obj
} }
} }
fn set_inputstream_volume(value: f64, index: u32, channels: u16) -> bool { fn set_inputstream_volume(
value: f64,
index: u32,
channels: u16,
output_box: Arc<SinkBox>,
) -> bool {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call( let res: Result<(), Error> = proxy.method_call(
AUDIO, AUDIO,
"SetInputStreamVolume", "SetInputStreamVolume",
(index, channels, value as u32), (index, channels, value as u32),
); );
// if res.is_err() { if res.is_err() {
// return false; show_error::<SinkBox>(output_box.clone(), "Failed to set input stream volume");
// } }
// res.unwrap().0
}); });
true true
} }
fn toggle_input_stream_mute(index: u32, muted: bool) -> bool { fn toggle_input_stream_mute(index: u32, muted: bool, output_box: Arc<SinkBox>) -> bool {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call(AUDIO, "SetInputStreamMute", (index, muted)); let res: Result<(), Error> = proxy.method_call(AUDIO, "SetInputStreamMute", (index, muted));
// if res.is_err() { if res.is_err() {
// return false; show_error::<SinkBox>(output_box.clone(), "Failed to mute input stream");
// } }
// res.unwrap().0
}); });
true true
} }
fn set_sink_of_input_stream(stream: u32, sink: u32) -> bool { fn set_sink_of_input_stream(stream: u32, sink: u32, output_box: Arc<SinkBox>) -> bool {
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call(AUDIO, "SetSinkOfInputStream", (stream, sink)); let res: Result<(), Error> =
// if res.is_err() { proxy.method_call(AUDIO, "SetSinkOfInputStream", (stream, sink));
// return false; if res.is_err() {
// } show_error::<SinkBox>(output_box.clone(), "Failed to set sink of input stream");
// res.unwrap().0 }
}); });
true true
} }
// TODO propagate error from dbus

View file

@ -4,6 +4,7 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use crate::components::base::error_impl::{show_error, ReSetErrorImpl};
use crate::components::base::utils::Listeners; use crate::components::base::utils::Listeners;
use crate::components::utils::{set_combo_row_ellipsis, BASE, DBUS_PATH, WIRELESS}; use crate::components::utils::{set_combo_row_ellipsis, BASE, DBUS_PATH, WIRELESS};
use adw::glib; use adw::glib;
@ -38,6 +39,14 @@ type ResultMap = Result<(Vec<(Path<'static>, Vec<u8>)>,), Error>;
unsafe impl Send for WifiBox {} unsafe impl Send for WifiBox {}
unsafe impl Sync for WifiBox {} unsafe impl Sync for WifiBox {}
impl ReSetErrorImpl for WifiBox {
fn error(
&self,
) -> &gtk::subclass::prelude::TemplateChild<crate::components::base::error::ReSetError> {
&self.imp().error
}
}
impl WifiBox { impl WifiBox {
pub fn new(listeners: Arc<Listeners>) -> Arc<Self> { pub fn new(listeners: Arc<Listeners>) -> Arc<Self> {
let obj: Arc<WifiBox> = Arc::new(Object::builder().build()); let obj: Arc<WifiBox> = Arc::new(Object::builder().build());
@ -50,6 +59,7 @@ impl WifiBox {
fn setup_callbacks(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) -> Arc<WifiBox> { fn setup_callbacks(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) -> Arc<WifiBox> {
let imp = wifi_box.imp(); let imp = wifi_box.imp();
let wifibox_ref = wifi_box.clone(); let wifibox_ref = wifi_box.clone();
let wifibox_ref_switch = wifi_box.clone();
imp.reset_switch_initial.set(true); imp.reset_switch_initial.set(true);
imp.reset_saved_networks.set_activatable(true); imp.reset_saved_networks.set_activatable(true);
imp.reset_saved_networks imp.reset_saved_networks
@ -66,7 +76,7 @@ fn setup_callbacks(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) -> Arc<Wif
if imp.reset_switch_initial.load(Ordering::SeqCst) { if imp.reset_switch_initial.load(Ordering::SeqCst) {
return glib::Propagation::Proceed; return glib::Propagation::Proceed;
} }
set_wifi_enabled(value); set_wifi_enabled(value, wifibox_ref_switch.clone());
if !value { if !value {
imp.reset_wifi_devices.write().unwrap().clear(); imp.reset_wifi_devices.write().unwrap().clear();
*imp.reset_model_list.write().unwrap() = StringList::new(&[]); *imp.reset_model_list.write().unwrap() = StringList::new(&[]);
@ -92,17 +102,16 @@ fn setup_callbacks(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) -> Arc<Wif
pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) { pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) {
let wifibox_ref = wifi_box.clone(); let wifibox_ref = wifi_box.clone();
let _wifibox_ref_listener = wifi_box.clone();
let wifi_entries = wifi_box.imp().wifi_entries.clone(); let wifi_entries = wifi_box.imp().wifi_entries.clone();
let wifi_entries_path = wifi_box.imp().wifi_entries_path.clone(); let wifi_entries_path = wifi_box.imp().wifi_entries_path.clone();
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let wifi_status = get_wifi_status(); let wifi_status = get_wifi_status(wifibox_ref.clone());
let devices = get_wifi_devices(); let devices = get_wifi_devices(wifibox_ref.clone());
if devices.is_empty() { if devices.is_empty() {
return; return;
} }
let access_points = get_access_points(); let access_points = get_access_points(wifibox_ref.clone());
{ {
let imp = wifibox_ref.imp(); let imp = wifibox_ref.imp();
let list = imp.reset_model_list.write().unwrap(); let list = imp.reset_model_list.write().unwrap();
@ -118,7 +127,7 @@ pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) {
} }
let wifi_entries = wifi_entries.clone(); let wifi_entries = wifi_entries.clone();
let wifi_entries_path = wifi_entries_path.clone(); let wifi_entries_path = wifi_entries_path.clone();
dbus_start_network_events(); dbus_start_network_events(wifibox_ref.clone());
glib::spawn_future(async move { glib::spawn_future(async move {
glib::idle_add_once(move || { glib::idle_add_once(move || {
let mut wifi_entries = wifi_entries.write().unwrap(); let mut wifi_entries = wifi_entries.write().unwrap();
@ -139,6 +148,7 @@ pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) {
} }
} }
let device_changed_ref = wifibox_ref.clone();
imp.reset_wifi_device.connect_selected_notify( imp.reset_wifi_device.connect_selected_notify(
clone!(@weak imp => move |dropdown| { clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected_item(); let selected = dropdown.selected_item();
@ -154,7 +164,7 @@ pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) {
if device.is_none() { if device.is_none() {
return; return;
} }
set_wifi_device(device.unwrap().0.path.clone()); set_wifi_device(device.unwrap().0.path.clone(), device_changed_ref.clone());
}), }),
); );
for access_point in access_points { for access_point in access_points {
@ -178,7 +188,7 @@ pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) {
pub fn show_stored_connections(wifi_box: Arc<WifiBox>) { pub fn show_stored_connections(wifi_box: Arc<WifiBox>) {
let wifibox_ref = wifi_box.clone(); let wifibox_ref = wifi_box.clone();
gio::spawn_blocking(move || { gio::spawn_blocking(move || {
let connections = get_stored_connections(); let connections = get_stored_connections(wifi_box.clone());
glib::spawn_future(async move { glib::spawn_future(async move {
glib::idle_add_once(move || { glib::idle_add_once(move || {
let self_imp = wifibox_ref.imp(); let self_imp = wifibox_ref.imp();
@ -194,67 +204,80 @@ pub fn show_stored_connections(wifi_box: Arc<WifiBox>) {
}); });
} }
pub fn dbus_start_network_events() { pub fn dbus_start_network_events(wifi_box: Arc<WifiBox>) {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(), Error> = proxy.method_call(WIRELESS, "StartNetworkListener", ()); let res: Result<(), Error> = proxy.method_call(WIRELESS, "StartNetworkListener", ());
if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to start Network listener");
}
} }
pub fn get_access_points() -> Vec<AccessPoint> { pub fn get_access_points(wifi_box: Arc<WifiBox>) -> Vec<AccessPoint> {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(Vec<AccessPoint>,), Error> = let res: Result<(Vec<AccessPoint>,), Error> =
proxy.method_call(WIRELESS, "ListAccessPoints", ()); proxy.method_call(WIRELESS, "ListAccessPoints", ());
if res.is_err() { if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to list access points");
return Vec::new(); return Vec::new();
} }
let (access_points,) = res.unwrap(); let (access_points,) = res.unwrap();
access_points access_points
} }
pub fn set_wifi_device(path: Path<'static>) { pub fn set_wifi_device(path: Path<'static>, wifi_box: Arc<WifiBox>) {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(bool,), Error> = proxy.method_call(WIRELESS, "SetWifiDevice", (path,)); let res: Result<(bool,), Error> = proxy.method_call(WIRELESS, "SetWifiDevice", (path,));
if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to set WiFi devices");
}
} }
pub fn get_wifi_devices() -> Vec<WifiDevice> { pub fn get_wifi_devices(wifi_box: Arc<WifiBox>) -> Vec<WifiDevice> {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(Vec<WifiDevice>,), Error> = let res: Result<(Vec<WifiDevice>,), Error> =
proxy.method_call(WIRELESS, "GetAllWifiDevices", ()); proxy.method_call(WIRELESS, "GetAllWifiDevices", ());
if res.is_err() { if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to get WiFi devices");
return Vec::new(); return Vec::new();
} }
let (devices,) = res.unwrap(); let (devices,) = res.unwrap();
devices devices
} }
pub fn get_wifi_status() -> bool { pub fn get_wifi_status(wifi_box: Arc<WifiBox>) -> bool {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(bool,), Error> = proxy.method_call(WIRELESS, "GetWifiStatus", ()); let res: Result<(bool,), Error> = proxy.method_call(WIRELESS, "GetWifiStatus", ());
if res.is_err() { if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to get WiFi status");
return false; return false;
} }
res.unwrap().0 res.unwrap().0
} }
pub fn get_stored_connections() -> Vec<(Path<'static>, Vec<u8>)> { pub fn get_stored_connections(wifi_box: Arc<WifiBox>) -> Vec<(Path<'static>, Vec<u8>)> {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: ResultMap = proxy.method_call(WIRELESS, "ListStoredConnections", ()); let res: ResultMap = proxy.method_call(WIRELESS, "ListStoredConnections", ());
if res.is_err() { if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to list stored connections");
return Vec::new(); return Vec::new();
} }
let (connections,) = res.unwrap(); let (connections,) = res.unwrap();
connections connections
} }
pub fn set_wifi_enabled(enabled: bool) { pub fn set_wifi_enabled(enabled: bool, wifi_box: Arc<WifiBox>) {
let conn = Connection::new_session().unwrap(); let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000)); let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let _: Result<(bool,), Error> = proxy.method_call(WIRELESS, "SetWifiEnabled", (enabled,)); let res: Result<(bool,), Error> = proxy.method_call(WIRELESS, "SetWifiEnabled", (enabled,));
if res.is_err() {
show_error::<WifiBox>(wifi_box.clone(), "Failed to enable WiFi");
}
} }
pub fn start_event_listener(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) { pub fn start_event_listener(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) {

View file

@ -1,3 +1,4 @@
use crate::components::base::error::ReSetError;
use crate::components::wifi::wifi_box; use crate::components::wifi::wifi_box;
use adw::{ActionRow, ComboRow, NavigationView, PreferencesGroup}; use adw::{ActionRow, ComboRow, NavigationView, PreferencesGroup};
use dbus::Path; use dbus::Path;
@ -32,6 +33,8 @@ pub struct WifiBox {
pub reset_stored_wifi_list: TemplateChild<PreferencesGroup>, pub reset_stored_wifi_list: TemplateChild<PreferencesGroup>,
#[template_child] #[template_child]
pub reset_available_networks: TemplateChild<ActionRow>, pub reset_available_networks: TemplateChild<ActionRow>,
#[template_child]
pub error: TemplateChild<ReSetError>,
pub wifi_entries: Arc<RwLock<HashMap<Vec<u8>, Arc<WifiEntry>>>>, pub wifi_entries: Arc<RwLock<HashMap<Vec<u8>, Arc<WifiEntry>>>>,
pub wifi_entries_path: Arc<RwLock<HashMap<Path<'static>, Arc<WifiEntry>>>>, pub wifi_entries_path: Arc<RwLock<HashMap<Path<'static>, Arc<WifiEntry>>>>,
pub reset_wifi_devices: Arc<RwLock<HashMap<String, (WifiDevice, u32)>>>, pub reset_wifi_devices: Arc<RwLock<HashMap<String, (WifiDevice, u32)>>>,

View file

@ -144,5 +144,8 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="resetError" id="error"/>
</child>
</template> </template>
</interface> </interface>

View file

@ -77,6 +77,7 @@
(4,206,"AdwActionRow","reset_available_networks",205,None,None,None,-1,None), (4,206,"AdwActionRow","reset_available_networks",205,None,None,None,-1,None),
(4,207,"GtkImage",None,206,None,None,None,None,None), (4,207,"GtkImage",None,206,None,None,None,None,None),
(4,208,"AdwPreferencesGroup","reset_wifi_list",154,None,None,None,1,None), (4,208,"AdwPreferencesGroup","reset_wifi_list",154,None,None,None,1,None),
(4,209,"resetError","error",7,None,None,None,2,None),
(5,12,"AdwActionRow","resetWifiEntry",None,None,None,None,-1,None), (5,12,"AdwActionRow","resetWifiEntry",None,None,None,None,-1,None),
(5,13,"resetPopup","reset_wifi_popup",12,None,None,None,None,None), (5,13,"resetPopup","reset_wifi_popup",12,None,None,None,None,None),
(6,1,"GtkListBoxRow","resetSidebarEntry",None,None,None,None,None,None), (6,1,"GtkListBoxRow","resetSidebarEntry",None,None,None,None,None,None),
@ -150,6 +151,7 @@
(10,211,"AdwSwitchRow","reset_bluetooth_discoverable_switch",209,None,None,None,-1,None), (10,211,"AdwSwitchRow","reset_bluetooth_discoverable_switch",209,None,None,None,-1,None),
(10,212,"AdwActionRow","reset_bluetooth_main_tab",208,None,None,None,None,None), (10,212,"AdwActionRow","reset_bluetooth_main_tab",208,None,None,None,None,None),
(10,213,"GtkImage",None,212,None,None,None,None,None), (10,213,"GtkImage",None,212,None,None,None,None,None),
(10,214,"resetError","error",1,None,None,None,2,None),
(11,1,"AdwActionRow","resetBluetoothEntry",None,None,None,None,None,None), (11,1,"AdwActionRow","resetBluetoothEntry",None,None,None,None,None,None),
(12,11,"GtkBox","resetAudioInput",None,None,None,None,None,None), (12,11,"GtkBox","resetAudioInput",None,None,None,None,None,None),
(12,12,"GtkLabel",None,11,None,None,None,None,None), (12,12,"GtkLabel",None,11,None,None,None,None,None),

View file

@ -120,5 +120,8 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="resetError" id="error"/>
</child>
</template> </template>
</interface> </interface>