Merge pull request #66 from Xetibo/dashie

feat: Implement Bluetoothdevice changed and code cleanup
This commit is contained in:
takotori 2023-12-02 12:45:05 +01:00 committed by GitHub
commit 29eea9ce4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 423 additions and 315 deletions

View file

@ -6,7 +6,7 @@ description = "A wip universal Linux settings application."
[dependencies]
reset_daemon = "0.3.3"
ReSet-Lib = "0.5.4"
ReSet-Lib = "0.5.5"
adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] }
dbus = "0.9.7"
gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] }

View file

@ -5,8 +5,8 @@ use adw::glib::Object;
use adw::prelude::{ComboRowExt, PreferencesRowExt};
use dbus::blocking::Connection;
use dbus::Error;
use glib::{Cast, clone};
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast};
use gtk::{gio, StringList, StringObject};
use ReSet_Lib::audio::audio::Card;
@ -29,10 +29,9 @@ impl CardEntry {
let imp = entry.imp();
let mut map = imp.resetCardMap.borrow_mut();
entry.set_title(&card.name);
let mut i: u32 = 0;
let mut index: u32 = 0;
let list = StringList::new(&[]);
for profile in card.profiles.iter() {
for (i, profile) in (0_u32..).zip(card.profiles.iter()) {
if profile.name == card.active_profile {
index = i;
}
@ -41,23 +40,22 @@ impl CardEntry {
profile.description.clone(),
(card.index, profile.name.clone()),
);
i += 1;
}
entry.set_model(Some(&list));
entry.set_selected(index);
entry.set_use_subtitle(true);
entry.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected_item();
if selected.is_none() {
return;
}
let selected = selected.unwrap();
let selected = selected.downcast_ref::<StringObject>().unwrap();
let selected = selected.string().to_string();
let map = imp.resetCardMap.borrow();
let (device_index, profile_name) = map.get(&selected).unwrap();
set_card_profile_of_device(*device_index, profile_name.clone());
}));
let selected = dropdown.selected_item();
if selected.is_none() {
return;
}
let selected = selected.unwrap();
let selected = selected.downcast_ref::<StringObject>().unwrap();
let selected = selected.string().to_string();
let map = imp.resetCardMap.borrow();
let (device_index, profile_name) = map.get(&selected).unwrap();
set_card_profile_of_device(*device_index, profile_name.clone());
}));
entry.set_factory(Some(&createDropdownLabelFactory()));
}
entry

View file

@ -1,9 +1,9 @@
use std::cell::RefCell;
use std::collections::HashMap;
use adw::ComboRow;
use adw::subclass::action_row::ActionRowImpl;
use adw::subclass::preferences_row::PreferencesRowImpl;
use adw::subclass::prelude::ComboRowImpl;
use adw::ComboRow;
use std::cell::RefCell;
use std::collections::HashMap;
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate};

View file

@ -13,7 +13,12 @@ glib::wrapper! {
impl Popup {
pub fn new() -> Self {
let popup: Popup = Object::builder().build();
// popup.set_child(child);
popup
}
}
impl Default for Popup {
fn default() -> Self {
Self::new()
}
}

View file

@ -17,4 +17,3 @@ impl SettingBox {
entry
}
}

View file

@ -394,11 +394,11 @@ pub fn start_audio_listener(
let mut conn = start_dbus_audio_listener(conn);
if sink_box.is_some() {
conn = start_output_box_listener(conn, sink_box.unwrap());
if let Some(sink_box) = sink_box {
conn = start_output_box_listener(conn, sink_box);
}
if source_box.is_some() {
conn = start_input_box_listener(conn, source_box.unwrap());
if let Some(source_box) = source_box {
conn = start_input_box_listener(conn, source_box);
}
listeners.pulse_listener.store(true, Ordering::SeqCst);
@ -435,4 +435,3 @@ fn stop_dbus_audio_listener(conn: Connection) {
);
let _: Result<(), Error> = proxy.method_call("org.Xetibo.ReSetAudio", "StopAudioListener", ());
}

View file

@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
@ -12,15 +11,14 @@ use dbus::message::SignalArgs;
use dbus::{Error, Path};
use gtk::gio;
use gtk::glib::Variant;
use gtk::prelude::{ActionableExt, ListBoxRowExt};
use gtk::prelude::{ActionableExt, ListBoxRowExt, WidgetExt};
use ReSet_Lib::bluetooth::bluetooth::BluetoothDevice;
use ReSet_Lib::signals::{BluetoothDeviceAdded, BluetoothDeviceRemoved};
use ReSet_Lib::signals::{BluetoothDeviceAdded, BluetoothDeviceChanged, BluetoothDeviceRemoved};
use crate::components::base::listEntry::ListEntry;
use crate::components::base::utils::Listeners;
use crate::components::bluetooth::bluetoothBoxImpl;
use crate::components::bluetooth::bluetoothEntry::BluetoothEntry;
// use crate::components::bluetooth::bluetoothEntryImpl::DeviceTypes;
glib::wrapper! {
pub struct BluetoothBox(ObjectSubclass<bluetoothBoxImpl::BluetoothBox>)
@ -52,6 +50,12 @@ impl BluetoothBox {
}
}
impl Default for BluetoothBox {
fn default() -> Self {
Self::new()
}
}
pub fn populate_conntected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
gio::spawn_blocking(move || {
let ref_box = bluetooth_box.clone();
@ -63,11 +67,11 @@ pub fn populate_conntected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
for device in devices {
let path = device.path.clone();
let connected = device.connected;
let bluetooth_entry = Arc::new(BluetoothEntry::new(device));
let bluetooth_entry = Arc::new(BluetoothEntry::new(&device));
let entry = Arc::new(ListEntry::new(&*bluetooth_entry));
imp.availableDevices
.borrow_mut()
.insert(path, (bluetooth_entry.clone(), entry.clone()));
.insert(path, (bluetooth_entry.clone(), entry.clone(), device));
if connected {
imp.resetBluetoothConnectedDevices.append(&*entry);
} else {
@ -108,24 +112,31 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
Some(&Path::from("/org/Xetibo/ReSetDaemon")),
)
.static_clone();
let device_changed = BluetoothDeviceChanged::match_rule(
Some(&"org.Xetibo.ReSetDaemon".into()),
Some(&Path::from("/org/Xetibo/ReSetDaemon")),
)
.static_clone();
let device_added_box = bluetooth_box.clone();
let device_removed_box = bluetooth_box.clone();
let device_changed_box = bluetooth_box.clone();
let loop_box = bluetooth_box.clone();
// TODO handle device changed
let res = conn.add_match(device_added, move |ir: BluetoothDeviceAdded, _, _| {
let bluetooth_box = device_added_box.clone();
println!("added");
glib::spawn_future(async move {
glib::idle_add_once(move || {
println!("{}", ir.bluetooth_device.icon);
let imp = bluetooth_box.imp();
let path = ir.bluetooth_device.path.clone();
let connected = ir.bluetooth_device.connected;
let bluetooth_entry = Arc::new(BluetoothEntry::new(ir.bluetooth_device));
let bluetooth_entry = Arc::new(BluetoothEntry::new(&ir.bluetooth_device));
let entry = Arc::new(ListEntry::new(&*bluetooth_entry));
imp.availableDevices
.borrow_mut()
.insert(path, (bluetooth_entry.clone(), entry.clone()));
imp.availableDevices.borrow_mut().insert(
path,
(bluetooth_entry.clone(), entry.clone(), ir.bluetooth_device),
);
if connected {
imp.resetBluetoothConnectedDevices.append(&*entry);
} else {
@ -147,12 +158,43 @@ pub fn start_bluetooth_listener(listeners: Arc<Listeners>, bluetooth_box: Arc<Bl
glib::idle_add_once(move || {
let imp = bluetooth_box.imp();
let map = imp.availableDevices.borrow_mut();
let list_entry = map.get(&ir.bluetooth_device);
if list_entry.is_some() {
imp.resetBluetoothAvailableDevices
.remove(&*list_entry.unwrap().1);
imp.resetBluetoothConnectedDevices
.remove(&*list_entry.unwrap().1);
if let Some(list_entry) = map.get(&ir.bluetooth_device) {
imp.resetBluetoothAvailableDevices.remove(&*list_entry.1);
imp.resetBluetoothConnectedDevices.remove(&*list_entry.1);
}
});
});
true
});
if res.is_err() {
println!("fail on bluetooth device remove");
return;
}
let res = conn.add_match(device_changed, move |ir: BluetoothDeviceChanged, _, _| {
let bluetooth_box = device_changed_box.clone();
println!("removed");
glib::spawn_future(async move {
glib::idle_add_once(move || {
let imp = bluetooth_box.imp();
let map = imp.availableDevices.borrow_mut();
if let Some(list_entry) = map.get(&ir.bluetooth_device.path) {
if list_entry.2.connected != ir.bluetooth_device.connected {
if ir.bluetooth_device.connected {
imp.resetBluetoothConnectedDevices.append(&*list_entry.1);
imp.resetBluetoothAvailableDevices.remove(&*list_entry.1);
} else {
imp.resetBluetoothAvailableDevices.append(&*list_entry.1);
imp.resetBluetoothConnectedDevices.remove(&*list_entry.1);
}
}
if list_entry.2.paired != ir.bluetooth_device.paired {
if ir.bluetooth_device.paired {
list_entry.0.imp().resetBluetoothButton.set_sensitive(true);
} else {
list_entry.0.imp().resetBluetoothButton.set_sensitive(false);
}
}
}
});
});

View file

@ -1,3 +1,4 @@
use adw::ActionRow;
use dbus::Path;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
@ -5,12 +6,15 @@ use gtk::{glib, CompositeTemplate, ListBox, Switch};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Arc;
use adw::ActionRow;
use ReSet_Lib::bluetooth::bluetooth::BluetoothDevice;
use crate::components::base::listEntry::ListEntry;
use crate::components::bluetooth::bluetoothBox;
use crate::components::bluetooth::bluetoothEntry::BluetoothEntry;
type BluetoothMap =
RefCell<HashMap<Path<'static>, (Arc<BluetoothEntry>, Arc<ListEntry>, BluetoothDevice)>>;
#[allow(non_snake_case)]
#[derive(Default, CompositeTemplate)]
#[template(resource = "/org/Xetibo/ReSet/resetBluetooth.ui")]
@ -25,8 +29,8 @@ pub struct BluetoothBox {
pub resetVisibility: TemplateChild<ActionRow>,
#[template_child]
pub resetBluetoothMainTab: TemplateChild<ListEntry>,
pub availableDevices: RefCell<HashMap<Path<'static>, (Arc<BluetoothEntry>, Arc<ListEntry>)>>,
pub connectedDevices: RefCell<HashMap<Path<'static>, (Arc<BluetoothEntry>, Arc<ListEntry>)>>,
pub availableDevices: BluetoothMap,
pub connectedDevices: BluetoothMap,
}
#[glib::object_subclass]

View file

@ -1,15 +1,12 @@
use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
use crate::components::bluetooth::bluetoothEntryImpl;
// use crate::components::bluetooth::bluetoothEntryImpl::DeviceTypes;
use adw::glib;
use adw::glib::Object;
use adw::subclass::prelude::ObjectSubclassIsExt;
use dbus::blocking::Connection;
use dbus::{Error, Path};
use glib::clone;
use gtk::prelude::{ButtonExt, WidgetExt};
use gtk::{gio, GestureClick};
use ReSet_Lib::bluetooth::bluetooth::BluetoothDevice;
@ -20,22 +17,27 @@ glib::wrapper! {
@implements gtk::Accessible, gtk::Buildable, gtk::Actionable, gtk::ConstraintTarget;
}
unsafe impl Send for BluetoothEntry {}
unsafe impl Sync for BluetoothEntry {}
impl BluetoothEntry {
pub fn new(device: BluetoothDevice) -> Self {
pub fn new(device: &BluetoothDevice) -> Self {
let entry: BluetoothEntry = Object::builder().build();
let entryImp = entry.imp();
entryImp.resetBluetoothLabel.get().set_text(&device.name);
entryImp.resetBluetoothAddress.get().set_text(&device.alias);
// entryImp
// .resetBluetoothDeviceType
// .get()
// .set_from_icon_name(match deviceType {
// DeviceTypes::Mouse => Some("input-mouse-symbolic"),
// DeviceTypes::Keyboard => Some("input-keyboard-symbolic"),
// DeviceTypes::Headset => Some("output-headset-symbolic"),
// DeviceTypes::Controller => Some("input-gaming-symbolic"),
// DeviceTypes::None => Some("text-x-generic-symbolic"), // no generic bluetooth device icon found
// });
entryImp.resetBluetoothLabel.get().set_text(&device.alias);
entryImp
.resetBluetoothAddress
.get()
.set_text(&device.address);
if device.icon.is_empty() {
entryImp
.resetBluetoothDeviceType
.set_icon_name(Some("dialog-question-symbolic"));
} else {
entryImp
.resetBluetoothDeviceType
.set_icon_name(Some(&device.icon));
}
if device.paired {
entryImp.resetBluetoothButton.set_sensitive(true);
} else {
@ -47,17 +49,17 @@ impl BluetoothEntry {
});
let gesture = GestureClick::new();
let connected = device.connected;
entryImp.device.replace(device);
gesture.connect_released(clone!(@weak entryImp => move |_, _, _, _| {
let device = entryImp.device.borrow_mut();
let paired = device.paired;
let path = device.path.clone();
gesture.connect_released(move |_, _, _, _| {
if connected {
disconnect_from_device(device.path.clone());
} else if device.paired {
connect_to_device(device.path.clone());
disconnect_from_device(path.clone());
} else if paired {
connect_to_device(path.clone());
} else {
pair_with_device(device.path.clone());
pair_with_device(path.clone());
}
}));
});
entry.add_controller(gesture);
entry
}

View file

@ -2,17 +2,7 @@ use crate::components::bluetooth::bluetoothEntry;
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CompositeTemplate, Image, Label};
use std::cell::RefCell;
use ReSet_Lib::bluetooth::bluetooth::BluetoothDevice;
#[derive(Default, Copy, Clone)]
pub enum DeviceTypes {
Mouse,
Keyboard,
Headset,
Controller,
#[default]
None,
}
#[allow(non_snake_case)]
#[derive(Default, CompositeTemplate)]
#[template(resource = "/org/Xetibo/ReSet/resetBluetoothEntry.ui")]
@ -26,7 +16,6 @@ pub struct BluetoothEntry {
#[template_child]
pub resetBluetoothButton: TemplateChild<Button>,
pub deviceName: RefCell<String>,
pub device: RefCell<BluetoothDevice>,
}
#[glib::object_subclass]

View file

@ -3,4 +3,3 @@ pub mod bluetoothBox;
pub mod bluetoothBoxImpl;
pub mod bluetoothEntry;
pub mod bluetoothEntryImpl;

View file

@ -1,6 +1,7 @@
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use crate::components::utils::{createDropdownLabelFactory, setComboRowEllipsis};
use adw::glib;
use adw::glib::Object;
use adw::prelude::{ButtonExt, ComboRowExt, PreferencesRowExt, RangeExt};
@ -10,7 +11,6 @@ use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation};
use gtk::{gio, StringObject};
use ReSet_Lib::audio::audio::OutputStream;
use crate::components::utils::{createDropdownLabelFactory, setComboRowEllipsis};
use super::outputStreamEntryImpl;
use super::sourceBox::SourceBox;
@ -33,7 +33,8 @@ impl OutputStreamEntry {
let imp = obj.imp();
let name = stream.application_name.clone() + ": " + stream.name.as_str();
imp.resetSourceSelection.set_title(name.as_str());
imp.resetSourceSelection.set_factory(Some(&createDropdownLabelFactory()));
imp.resetSourceSelection
.set_factory(Some(&createDropdownLabelFactory()));
setComboRowEllipsis(imp.resetSourceSelection.get());
let volume = stream.volume.first().unwrap_or(&0_u32);
let fraction = (*volume as f64 / 655.36).round();
@ -68,16 +69,8 @@ impl OutputStreamEntry {
);
{
let list = box_imp.resetModelList.read().unwrap();
// while list.is_err() {
// list = box_imp.resetModelList.try_borrow();
// }
// let list = list.unwrap();
imp.resetSourceSelection.set_model(Some(&*list));
let map = box_imp.resetSourceMap.write().unwrap();
// while map.is_err() {
// map = box_imp.resetSourceMap.try_borrow();
// }
// let map = map.unwrap();
let mut name = box_imp.resetDefaultSource.try_borrow();
while name.is_err() {
name = box_imp.resetDefaultSource.try_borrow();
@ -85,8 +78,8 @@ impl OutputStreamEntry {
let name = name.unwrap();
let name = &name.alias;
let index = map.get(name);
if index.is_some() {
imp.resetSourceSelection.set_selected(index.unwrap().1);
if let Some(index) = index {
imp.resetSourceSelection.set_selected(index.1);
}
}
imp.resetSourceSelection.connect_selected_notify(
@ -166,8 +159,11 @@ fn toggle_output_stream_mute(index: u32, muted: bool) -> bool {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "SetOutputStreamMute", (index, muted));
let _: Result<(), Error> = proxy.method_call(
"org.Xetibo.ReSetAudio",
"SetOutputStreamMute",
(index, muted),
);
// if res.is_err() {
// return false;
// }

View file

@ -1,12 +1,12 @@
use adw::subclass::prelude::PreferencesGroupImpl;
use adw::{ComboRow, PreferencesGroup};
use std::cell::RefCell;
use std::sync::Arc;
use std::time::SystemTime;
use adw::{ComboRow, PreferencesGroup};
use adw::subclass::prelude::PreferencesGroupImpl;
use crate::components::input::outputStreamEntry;
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CompositeTemplate, DropDown, Label, ProgressBar, Scale};
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale};
use ReSet_Lib::audio::audio::OutputStream;
#[allow(non_snake_case)]

View file

@ -4,14 +4,16 @@ use std::time::{Duration, SystemTime};
use adw::glib;
use adw::glib::Object;
use adw::prelude::{BoxExt, ButtonExt, CheckButtonExt, ComboRowExt, ListBoxRowExt, PreferencesGroupExt, RangeExt};
use dbus::{Error, Path};
use adw::prelude::{
BoxExt, ButtonExt, CheckButtonExt, ComboRowExt, ListBoxRowExt, PreferencesGroupExt, RangeExt,
};
use dbus::blocking::Connection;
use dbus::message::SignalArgs;
use glib::{Cast, clone, Propagation, Variant};
use dbus::{Error, Path};
use glib::subclass::prelude::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation, Variant};
use gtk::prelude::ActionableExt;
use gtk::{gio, StringObject};
use gtk::prelude::{ActionableExt};
use ReSet_Lib::audio::audio::{Card, OutputStream, Source};
use crate::components::base::cardEntry::CardEntry;
@ -25,7 +27,7 @@ use crate::components::input::sourceEntry::set_source_volume;
use crate::components::utils::{createDropdownLabelFactory, setComboRowEllipsis};
use super::outputStreamEntry::OutputStreamEntry;
use super::sourceEntry::{set_default_source, SourceEntry, toggle_source_mute};
use super::sourceEntry::{set_default_source, toggle_source_mute, SourceEntry};
glib::wrapper! {
pub struct SourceBox(ObjectSubclass<sourceBoxImpl::SourceBox>)
@ -59,16 +61,28 @@ impl SourceBox {
.set_action_target_value(Some(&Variant::from("profileConfiguration")));
selfImp.resetOutputStreamButton.set_activatable(true);
selfImp.resetOutputStreamButton.set_action_name(Some("navigation.pop"));
selfImp
.resetOutputStreamButton
.set_action_name(Some("navigation.pop"));
selfImp.resetInputCardsBackButton.set_activatable(true);
selfImp.resetInputCardsBackButton.set_action_name(Some("navigation.pop"));
selfImp
.resetInputCardsBackButton
.set_action_name(Some("navigation.pop"));
selfImp.resetSourceDropdown.set_factory(Some(&createDropdownLabelFactory()));
selfImp
.resetSourceDropdown
.set_factory(Some(&createDropdownLabelFactory()));
setComboRowEllipsis(selfImp.resetSourceDropdown.get());
}
}
impl Default for SourceBox {
fn default() -> Self {
Self::new()
}
}
pub fn populate_sources(input_box: Arc<SourceBox>) {
gio::spawn_blocking(move || {
let output_box_imp = input_box.imp();
@ -77,11 +91,9 @@ pub fn populate_sources(input_box: Arc<SourceBox>) {
let list = output_box_imp.resetModelList.write().unwrap();
let mut map = output_box_imp.resetSourceMap.write().unwrap();
let mut model_index = output_box_imp.resetModelIndex.write().unwrap();
let mut i: u32 = 0;
for source in sources.iter() {
for (i, source) in (0_u32..).zip(sources.iter()) {
list.append(&source.alias);
map.insert(source.alias.clone(), (source.index, i, source.name.clone()));
i += 1;
*model_index += 1;
}
}
@ -93,7 +105,6 @@ pub fn populate_sources(input_box: Arc<SourceBox>) {
populate_cards(input_box.clone());
glib::spawn_future(async move {
glib::idle_add_once(move || {
// TODO handle events
let output_box_ref_slider = input_box.clone();
let output_box_ref_mute = input_box.clone();
let output_box_ref = input_box.clone();
@ -130,12 +141,8 @@ pub fn populate_sources(input_box: Arc<SourceBox>) {
output_box_imp.resetSourceDropdown.set_model(Some(&*list));
let map = output_box_imp.resetSourceMap.read().unwrap();
let name = output_box_imp.resetDefaultSource.borrow();
let name = &name.alias;
let index = map.get(name);
if index.is_some() {
output_box_imp
.resetSourceDropdown
.set_selected(index.unwrap().1);
if let Some(index) = map.get(&name.alias) {
output_box_imp.resetSourceDropdown.set_selected(index.1);
}
output_box_imp.resetSourceDropdown.connect_selected_notify(
clone!(@weak output_box_imp => move |dropdown| {
@ -206,7 +213,6 @@ pub fn populate_sources(input_box: Arc<SourceBox>) {
}
pub fn populate_outputstreams(input_box: Arc<SourceBox>) {
// TODO add listener
let input_box_ref = input_box.clone();
gio::spawn_blocking(move || {
@ -237,8 +243,7 @@ pub fn populate_cards(input_box: Arc<SourceBox>) {
glib::idle_add_once(move || {
let imp = output_box_ref.imp();
for card in cards {
imp.resetCards
.add(&CardEntry::new(card));
imp.resetCards.add(&CardEntry::new(card));
}
});
});
@ -282,7 +287,8 @@ fn get_cards() -> Vec<Card> {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let res: Result<(Vec<Card>,), Error> = proxy.method_call("org.Xetibo.ReSetAudio", "ListCards", ());
let res: Result<(Vec<Card>,), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "ListCards", ());
if res.is_err() {
return Vec::new();
}
@ -405,12 +411,12 @@ pub fn start_input_box_listener(conn: Connection, source_box: Arc<SourceBox>) ->
}
let mut map = output_box_imp.resetSourceMap.write().unwrap();
let entry_index = map.remove(&alias.unwrap().2);
if entry_index.is_some() {
if let Some(entry_index) = entry_index {
output_box_imp
.resetModelList
.write()
.unwrap()
.remove(entry_index.unwrap().1);
.remove(entry_index.1);
}
let mut index = output_box_imp.resetModelIndex.write().unwrap();
if *index != 0 {
@ -449,10 +455,10 @@ pub fn start_input_box_listener(conn: Connection, source_box: Arc<SourceBox>) ->
} else {
imp.resetSelectedSource.set_active(false);
}
imp.resetSourceName.set_title(ir.source.alias.clone().as_str());
imp.resetSourceName
.set_title(ir.source.alias.clone().as_str());
imp.resetVolumePercentage.set_text(&percentage);
imp.resetVolumeSlider.set_value(*volume as f64);
});
});
true
@ -492,9 +498,8 @@ pub fn start_input_box_listener(conn: Connection, source_box: Arc<SourceBox>) ->
let alias: String;
{
let source_list = imp.resetSourceList.read().unwrap();
let alias_opt = source_list.get(&ir.stream.source_index);
if alias_opt.is_some() {
alias = alias_opt.unwrap().2.clone();
if let Some(alias_opt) = source_list.get(&ir.stream.source_index) {
alias = alias_opt.2.clone();
} else {
alias = String::from("");
}
@ -529,9 +534,8 @@ pub fn start_input_box_listener(conn: Connection, source_box: Arc<SourceBox>) ->
imp.resetVolumePercentage.set_text(&percentage);
imp.resetVolumeSlider.set_value(*volume as f64);
let map = output_box_imp.resetSourceMap.read().unwrap();
let index = map.get(&alias);
if index.is_some() {
imp.resetSourceSelection.set_selected(index.unwrap().1);
if let Some(index) = map.get(&alias) {
imp.resetSourceSelection.set_selected(index.1);
}
});
});
@ -554,7 +558,6 @@ pub fn start_input_box_listener(conn: Connection, source_box: Arc<SourceBox>) ->
let mut list = output_box_imp.resetOutputStreamList.write().unwrap();
let entry = list.remove(&ir.index);
if entry.is_none() {
println!("tried to remove nonexistant?? wat");
return;
}
output_box_imp.resetOutputStreams.remove(&*entry.unwrap().0);

View file

@ -1,8 +1,8 @@
use adw::{ActionRow, ComboRow, PreferencesGroup};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::time::SystemTime;
use adw::{ActionRow, ComboRow, PreferencesGroup};
use crate::components::base::listEntry::ListEntry;
use crate::components::input::sourceBox;
@ -14,6 +14,10 @@ use ReSet_Lib::audio::audio::Source;
use super::outputStreamEntry::OutputStreamEntry;
use super::sourceEntry::SourceEntry;
type SourceEntryMap = Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<SourceEntry>, String)>>>;
type OutputStreamEntryMap = Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<OutputStreamEntry>)>>>;
type SourceMap = Arc<RwLock<HashMap<String, (u32, u32, String)>>>;
#[allow(non_snake_case)]
#[derive(Default, CompositeTemplate)]
#[template(resource = "/org/Xetibo/ReSet/resetAudioInput.ui")]
@ -44,13 +48,13 @@ pub struct SourceBox {
pub resetCards: TemplateChild<PreferencesGroup>,
pub resetDefaultCheckButton: Arc<CheckButton>,
pub resetDefaultSource: Arc<RefCell<Source>>,
pub resetSourceList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<SourceEntry>, String)>>>,
pub resetOutputStreamList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<OutputStreamEntry>)>>>,
pub resetSourceList: SourceEntryMap,
pub resetOutputStreamList: OutputStreamEntryMap,
pub resetModelList: Arc<RwLock<StringList>>,
pub resetModelIndex: Arc<RwLock<u32>>,
// first u32 is the index of the source, the second the index in the model list and the third is
// the full name
pub resetSourceMap: Arc<RwLock<HashMap<String, (u32, u32, String)>>>,
pub resetSourceMap: SourceMap,
pub volumeTimeStamp: RefCell<Option<SystemTime>>,
}

View file

@ -1,8 +1,8 @@
use adw::subclass::prelude::PreferencesGroupImpl;
use adw::{ActionRow, PreferencesGroup};
use std::cell::RefCell;
use std::sync::Arc;
use std::time::SystemTime;
use adw::{ActionRow, PreferencesGroup};
use adw::subclass::prelude::PreferencesGroupImpl;
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CheckButton, CompositeTemplate, Label, ProgressBar, Scale};

View file

@ -2,7 +2,6 @@ mod base;
pub mod bluetooth;
mod input;
pub mod output;
pub mod utils;
pub mod wifi;
pub mod window;
pub mod utils;

View file

@ -1,6 +1,7 @@
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use crate::components::utils::{createDropdownLabelFactory, setComboRowEllipsis};
use adw::glib;
use adw::glib::Object;
use adw::prelude::{ButtonExt, ComboRowExt, PreferencesRowExt, RangeExt};
@ -10,7 +11,6 @@ use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation};
use gtk::{gio, StringObject};
use ReSet_Lib::audio::audio::InputStream;
use crate::components::utils::{createDropdownLabelFactory, setComboRowEllipsis};
use super::inputStreamEntryImpl;
use super::sinkBox::SinkBox;
@ -21,6 +21,9 @@ glib::wrapper! {
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
}
unsafe impl Send for InputStreamEntry {}
unsafe impl Sync for InputStreamEntry {}
impl InputStreamEntry {
pub fn new(sink_box: Arc<SinkBox>, stream: InputStream) -> Self {
let obj: Self = Object::builder().build();
@ -38,7 +41,8 @@ impl InputStreamEntry {
}
let name = stream.application_name.clone() + ": " + stream.name.as_str();
imp.resetSinkSelection.set_title(name.as_str());
imp.resetSinkSelection.set_factory(Some(&createDropdownLabelFactory()));
imp.resetSinkSelection
.set_factory(Some(&createDropdownLabelFactory()));
setComboRowEllipsis(imp.resetSinkSelection.get());
let volume = stream.volume.first().unwrap_or(&0_u32);
let fraction = (*volume as f64 / 655.36).round();
@ -83,11 +87,11 @@ impl InputStreamEntry {
let map = box_imp.resetSinkMap.read().unwrap();
let sink_list = box_imp.resetSinkList.read().unwrap();
let name = sink_list.get(&index);
if name.is_some() {
let name = &name.unwrap().2;
if let Some(name) = name {
let name = &name.2;
let index = map.get(name);
if index.is_some() {
imp.resetSinkSelection.set_selected(index.unwrap().1);
if let Some(index) = index {
imp.resetSinkSelection.set_selected(index.1);
}
} else {
let mut name = box_imp.resetDefaultSink.try_borrow();
@ -96,8 +100,8 @@ impl InputStreamEntry {
}
let name = &name.unwrap().alias;
let index = map.get(name);
if index.is_some() {
imp.resetSinkSelection.set_selected(index.unwrap().1);
if let Some(index) = index {
imp.resetSinkSelection.set_selected(index.1);
}
}
}
@ -182,8 +186,11 @@ fn toggle_input_stream_mute(index: u32, muted: bool) -> bool {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "SetInputStreamMute", (index, muted));
let _: Result<(), Error> = proxy.method_call(
"org.Xetibo.ReSetAudio",
"SetInputStreamMute",
(index, muted),
);
// if res.is_err() {
// return false;
// }
@ -200,8 +207,11 @@ fn set_sink_of_input_stream(stream: u32, sink: u32) -> bool {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let _: Result<(), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "SetSinkOfInputStream", (stream, sink));
let _: Result<(), Error> = proxy.method_call(
"org.Xetibo.ReSetAudio",
"SetSinkOfInputStream",
(stream, sink),
);
// if res.is_err() {
// return false;
// }

View file

@ -1,8 +1,8 @@
use adw::subclass::prelude::PreferencesGroupImpl;
use adw::{ComboRow, PreferencesGroup};
use std::cell::RefCell;
use std::sync::Arc;
use std::time::SystemTime;
use adw::{ComboRow, PreferencesGroup};
use adw::subclass::prelude::PreferencesGroupImpl;
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale};

View file

@ -1,18 +1,18 @@
use adw::prelude::PreferencesRowExt;
use adw::prelude::PreferencesGroupExt;
use adw::prelude::PreferencesRowExt;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use adw::{glib, prelude::ListBoxRowExt};
use adw::glib::Object;
use adw::prelude::{BoxExt, ButtonExt, CheckButtonExt, ComboRowExt, RangeExt};
use dbus::{Error, Path};
use adw::{glib, prelude::ListBoxRowExt};
use dbus::blocking::Connection;
use dbus::message::SignalArgs;
use glib::{Cast, clone, Propagation, Variant};
use dbus::{Error, Path};
use glib::subclass::prelude::ObjectSubclassIsExt;
use gtk::{gio, StringObject};
use glib::{clone, Cast, Propagation, Variant};
use gtk::prelude::ActionableExt;
use gtk::{gio, StringObject};
use ReSet_Lib::audio::audio::{Card, InputStream, Sink};
use crate::components::base::cardEntry::CardEntry;
@ -25,7 +25,7 @@ use crate::components::utils::{createDropdownLabelFactory, setComboRowEllipsis};
use super::inputStreamEntry::InputStreamEntry;
use super::sinkBoxImpl;
use super::sinkEntry::{set_default_sink, SinkEntry, toggle_sink_mute};
use super::sinkEntry::{set_default_sink, toggle_sink_mute, SinkEntry};
glib::wrapper! {
pub struct SinkBox(ObjectSubclass<sinkBoxImpl::SinkBox>)
@ -66,12 +66,18 @@ impl SinkBox {
selfImp.resetCardsRow.connect_action_name_notify(|_| {});
selfImp.resetInputStreamButton.set_activatable(true);
selfImp.resetInputStreamButton.set_action_name(Some("navigation.pop"));
selfImp
.resetInputStreamButton
.set_action_name(Some("navigation.pop"));
selfImp.resetInputCardsBackButton.set_activatable(true);
selfImp.resetInputCardsBackButton.set_action_name(Some("navigation.pop"));
selfImp
.resetInputCardsBackButton
.set_action_name(Some("navigation.pop"));
selfImp.resetSinkDropdown.set_factory(Some(&createDropdownLabelFactory()));
selfImp
.resetSinkDropdown
.set_factory(Some(&createDropdownLabelFactory()));
setComboRowEllipsis(selfImp.resetSinkDropdown.get());
}
}
@ -92,11 +98,9 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
let list = output_box_imp.resetModelList.write().unwrap();
let mut model_index = output_box_imp.resetModelIndex.write().unwrap();
output_box_imp.resetDefaultSink.replace(get_default_sink());
let mut i: u32 = 0;
for sink in sinks.iter() {
for (i, sink) in (0_u32..).zip(sinks.iter()) {
list.append(&sink.alias);
map.insert(sink.alias.clone(), (sink.index, i, sink.name.clone()));
i += 1;
*model_index += 1;
}
}
@ -130,7 +134,7 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
sink,
));
let sink_clone = sink_entry.clone();
let entry = Arc::new(ListEntry::new(&*sink_entry, ));
let entry = Arc::new(ListEntry::new(&*sink_entry));
entry.set_activatable(false);
list.insert(index, (entry.clone(), sink_clone, alias));
output_box_imp.resetSinks.append(&*entry);
@ -141,10 +145,8 @@ pub fn populate_sinks(output_box: Arc<SinkBox>) {
let name = output_box_imp.resetDefaultSink.borrow();
let name = &name.alias;
let index = map.get(name);
if index.is_some() {
output_box_imp
.resetSinkDropdown
.set_selected(index.unwrap().1);
if let Some(index) = index {
output_box_imp.resetSinkDropdown.set_selected(index.1);
}
output_box_imp.resetSinkDropdown.connect_selected_notify(
clone!(@weak output_box_imp => move |dropdown| {
@ -225,7 +227,7 @@ pub fn populate_inputstreams(output_box: Arc<SinkBox>) {
for stream in streams {
let index = stream.index;
let input_stream = Arc::new(InputStreamEntry::new(output_box.clone(), stream));
let entry = Arc::new(ListEntry::new(&*input_stream, ));
let entry = Arc::new(ListEntry::new(&*input_stream));
entry.set_activatable(false);
list.insert(index, (entry.clone(), input_stream.clone()));
output_box_imp.resetInputStreams.append(&*entry);
@ -243,8 +245,7 @@ pub fn populate_cards(output_box: Arc<SinkBox>) {
glib::idle_add_once(move || {
let imp = output_box_ref.imp();
for card in cards {
imp.resetCards
.add(&CardEntry::new(card));
imp.resetCards.add(&CardEntry::new(card));
}
});
});
@ -273,7 +274,8 @@ fn get_sinks() -> Vec<Sink> {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let res: Result<(Vec<Sink>,), Error> = proxy.method_call("org.Xetibo.ReSetAudio", "ListSinks", ());
let res: Result<(Vec<Sink>,), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "ListSinks", ());
if res.is_err() {
return Vec::new();
}
@ -287,7 +289,8 @@ fn get_default_sink() -> Sink {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let res: Result<(Sink,), Error> = proxy.method_call("org.Xetibo.ReSetAudio", "GetDefaultSink", ());
let res: Result<(Sink,), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "GetDefaultSink", ());
if res.is_err() {
return Sink::default();
}
@ -301,7 +304,8 @@ fn get_cards() -> Vec<Card> {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let res: Result<(Vec<Card>,), Error> = proxy.method_call("org.Xetibo.ReSetAudio", "ListCards", ());
let res: Result<(Vec<Card>,), Error> =
proxy.method_call("org.Xetibo.ReSetAudio", "ListCards", ());
if res.is_err() {
return Vec::new();
}
@ -367,7 +371,7 @@ pub fn start_output_box_listener(conn: Connection, sink_box: Arc<SinkBox>) -> Co
ir.sink,
));
let sink_clone = sink_entry.clone();
let entry = Arc::new(ListEntry::new(&*sink_entry, ));
let entry = Arc::new(ListEntry::new(&*sink_entry));
entry.set_activatable(false);
list.insert(sink_index, (entry.clone(), sink_clone, alias.clone()));
output_box_imp.resetSinks.append(&*entry);
@ -407,12 +411,12 @@ pub fn start_output_box_listener(conn: Connection, sink_box: Arc<SinkBox>) -> Co
}
let mut map = output_box_imp.resetSinkMap.write().unwrap();
let entry_index = map.remove(&alias.unwrap().2);
if entry_index.is_some() {
if let Some(entry_index) = entry_index {
output_box_imp
.resetModelList
.write()
.unwrap()
.remove(entry_index.unwrap().1);
.remove(entry_index.1);
}
let mut index = output_box_imp.resetModelIndex.write().unwrap();
if *index != 0 {
@ -473,7 +477,7 @@ pub fn start_output_box_listener(conn: Connection, sink_box: Arc<SinkBox>) -> Co
let mut list = output_box_imp.resetInputStreamList.write().unwrap();
let index = ir.stream.index;
let input_stream = Arc::new(InputStreamEntry::new(output_box.clone(), ir.stream));
let entry = Arc::new(ListEntry::new(&*input_stream, ));
let entry = Arc::new(ListEntry::new(&*input_stream));
entry.set_activatable(false);
list.insert(index, (entry.clone(), input_stream.clone()));
output_box_imp.resetInputStreams.append(&*entry);
@ -492,8 +496,8 @@ pub fn start_output_box_listener(conn: Connection, sink_box: Arc<SinkBox>) -> Co
{
let sink_list = imp.resetSinkList.read().unwrap();
let alias_opt = sink_list.get(&ir.stream.sink_index);
if alias_opt.is_some() {
alias = alias_opt.unwrap().2.clone();
if let Some(alias_opt) = alias_opt {
alias = alias_opt.2.clone();
} else {
alias = String::from("");
}
@ -529,8 +533,8 @@ pub fn start_output_box_listener(conn: Connection, sink_box: Arc<SinkBox>) -> Co
imp.resetVolumeSlider.set_value(*volume as f64);
let map = output_box_imp.resetSinkMap.read().unwrap();
let index = map.get(&alias);
if index.is_some() {
imp.resetSinkSelection.set_selected(index.unwrap().1);
if let Some(index) = index {
imp.resetSinkSelection.set_selected(index.1);
}
});
});

View file

@ -1,21 +1,23 @@
use adw::{ActionRow, ComboRow, PreferencesGroup};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::time::SystemTime;
use adw::{ActionRow, ComboRow, PreferencesGroup};
use crate::components::base::listEntry::ListEntry;
use crate::components::output::inputStreamEntry::InputStreamEntry;
use gtk::subclass::prelude::*;
use gtk::{
glib, Box, Button, CheckButton, CompositeTemplate, Label, StringList, TemplateChild,
};
use gtk::{glib, Box, Button, CheckButton, CompositeTemplate, Label, StringList, TemplateChild};
use gtk::{prelude::*, ProgressBar, Scale};
use ReSet_Lib::audio::audio::Sink;
use super::sinkBox;
use super::sinkEntry::SinkEntry;
type SinkEntryMap = Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<SinkEntry>, String)>>>;
type InputStreamEntryMap = Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<InputStreamEntry>)>>>;
type SinkMap = Arc<RwLock<HashMap<String, (u32, u32, String)>>>;
#[allow(non_snake_case)]
#[derive(Default, CompositeTemplate)]
#[template(resource = "/org/Xetibo/ReSet/resetAudioOutput.ui")]
@ -46,14 +48,13 @@ pub struct SinkBox {
pub resetCards: TemplateChild<PreferencesGroup>,
pub resetDefaultCheckButton: Arc<CheckButton>,
pub resetDefaultSink: Arc<RefCell<Sink>>,
pub resetSinkList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<SinkEntry>, String)>>>,
pub resetInputStreamList: Arc<RwLock<HashMap<u32, (Arc<ListEntry>, Arc<InputStreamEntry>)>>>,
pub resetSinkList: SinkEntryMap,
pub resetInputStreamList: InputStreamEntryMap,
pub resetModelList: Arc<RwLock<StringList>>,
pub resetModelIndex: Arc<RwLock<u32>>,
// first u32 is the index of the sink, the second the index in the model list and the third is
// the full name
pub resetSinkMap: Arc<RwLock<HashMap<String, (u32, u32, String)>>>,
// pub : Arc<Mutex<Vec<ListEntry>>>,
pub resetSinkMap: SinkMap,
pub volumeTimeStamp: RefCell<Option<SystemTime>>,
}

View file

@ -19,11 +19,13 @@ glib::wrapper! {
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
}
unsafe impl Send for SinkEntry {}
unsafe impl Sync for SinkEntry {}
impl SinkEntry {
pub fn new(is_default: bool, check_group: Arc<CheckButton>, stream: Sink) -> Self {
let obj: Self = Object::builder().build();
// TODO use event callback for progress bar -> this is the "im speaking" indicator
// TODO handle events
{
let imp = obj.imp();
imp.resetSinkName.set_title(stream.alias.clone().as_str());

View file

@ -1,8 +1,8 @@
use adw::subclass::prelude::PreferencesGroupImpl;
use adw::{ActionRow, PreferencesGroup};
use std::cell::RefCell;
use std::sync::Arc;
use std::time::SystemTime;
use adw::{ActionRow, PreferencesGroup};
use adw::subclass::prelude::PreferencesGroupImpl;
use crate::components::output::sinkEntry;
use gtk::subclass::prelude::*;

View file

@ -1,9 +1,6 @@
use std::time::Duration;
use adw::gdk::pango::EllipsizeMode;
use adw::prelude::ListModelExtManual;
use adw::ComboRow;
use dbus::blocking::{Connection, Proxy};
use glib::{Cast, Object};
use gtk::prelude::{GObjectPropertyExpressionExt, ListBoxRowExt, ListItemExt, WidgetExt};
use gtk::{Align, SignalListItemFactory, StringObject};

View file

@ -1,14 +1,15 @@
#![allow(non_snake_case)]
pub mod savedWifiEntry;
pub mod savedWifiEntryImpl;
pub mod utils;
pub mod wifiAddressEntry;
pub mod wifiAddressEntryImpl;
pub mod wifiBox;
pub mod wifiBoxImpl;
pub mod wifiEntry;
pub mod wifiEntryImpl;
pub mod wifiOptions;
pub mod wifiOptionsImpl;
pub mod wifiAddressEntry;
pub mod wifiAddressEntryImpl;
pub mod wifiRouteEntry;
pub mod wifiRouteEntryImpl;
pub mod utils;

View file

@ -1,6 +1,7 @@
use std::time::Duration;
use crate::components::wifi::savedWifiEntryImpl;
use crate::components::wifi::wifiBoxImpl::WifiBox;
use adw::glib;
use adw::glib::Object;
use adw::prelude::{ButtonExt, WidgetExt};
@ -10,7 +11,6 @@ use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, PropertySet};
use gtk::gio;
use gtk::prelude::ListBoxRowExt;
use crate::components::wifi::wifiBoxImpl::WifiBox;
glib::wrapper! {
pub struct SavedWifiEntry(ObjectSubclass<savedWifiEntryImpl::SavedWifiEntry>)
@ -19,16 +19,18 @@ glib::wrapper! {
}
impl SavedWifiEntry {
pub fn new(name: &String, path: Path<'static>, wifiBox: &WifiBox) -> Self {
pub fn new(name: &str, path: Path<'static>, wifiBox: &WifiBox) -> Self {
let entry: SavedWifiEntry = Object::builder().build();
entry.set_activatable(false);
let entryImp = entry.imp();
entryImp.resetEditSavedWifiButton.connect_clicked(clone!(@ weak entryImp, @ weak wifiBox => move |_| {
// TODO accesspoint has to be saved somewhere i guess
// let _option = getConnectionSettings(entryImp.accessPoint.borrow().associated_connection.clone());
// wifiBox.resetWifiNavigation.push(&*WifiOptions::new(_option));
}));
entryImp.resetEditSavedWifiButton.connect_clicked(
clone!(@ weak entryImp, @ weak wifiBox => move |_| {
// TODO accesspoint has to be saved somewhere i guess
// let _option = getConnectionSettings(entryImp.accessPoint.borrow().associated_connection.clone());
// wifiBox.resetWifiNavigation.push(&*WifiOptions::new(_option));
}),
);
entryImp.resetSavedWifiLabel.set_text(name);
entryImp.resetConnectionPath.set(path);

View file

@ -1,7 +1,7 @@
use std::cell::RefCell;
use adw::ActionRow;
use adw::subclass::preferences_row::PreferencesRowImpl;
use adw::subclass::prelude::ActionRowImpl;
use adw::ActionRow;
use std::cell::RefCell;
use dbus::Path;
use gtk::subclass::prelude::*;

View file

@ -1,11 +1,14 @@
use std::collections::HashMap;
use std::time::Duration;
use dbus::arg::{RefArg};
use dbus::arg::RefArg;
use dbus::blocking::Connection;
use dbus::Error;
use dbus::Path;
use std::collections::HashMap;
use std::time::Duration;
use ReSet_Lib::network::connection::Connection as ResetConnection;
type ResultType =
Result<(HashMap<String, HashMap<String, dbus::arg::Variant<Box<dyn RefArg>>>>,), Error>;
pub fn getConnectionSettings(path: Path<'static>) -> ResetConnection {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(
@ -13,10 +16,8 @@ pub fn getConnectionSettings(path: Path<'static>) -> ResetConnection {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let res: Result<
(HashMap<String, HashMap<String, dbus::arg::Variant<Box<dyn RefArg>>>>,),
Error,
> = proxy.method_call("org.xetibo.ReSetWireless", "GetConnectionSettings", (path,));
let res: ResultType =
proxy.method_call("org.xetibo.ReSetWireless", "GetConnectionSettings", (path,));
if res.is_err() {
ResetConnection::default();
}

View file

@ -27,7 +27,9 @@ impl WifiAddressEntry {
entryImp.resetAddressAddress.set_text(&addr);
entryImp.resetAddressNetmask.set_text(&prefix);
entryImp.resetAddressRow.set_title(&format!("{}, {}", addr, prefix));
entryImp
.resetAddressRow
.set_title(&format!("{}, {}", addr, prefix));
}
entry
}

View file

@ -1,7 +1,7 @@
use crate::components::wifi::wifiAddressEntry;
use adw::{EntryRow, ExpanderRow};
use crate::components::wifi::{wifiAddressEntry};
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate, Button};
use gtk::{glib, Button, CompositeTemplate};
#[allow(non_snake_case)]
#[derive(Default, CompositeTemplate)]

View file

@ -4,39 +4,37 @@ use std::sync::Arc;
use std::time::Duration;
use crate::components::base::utils::Listeners;
use crate::components::utils::setComboRowEllipsis;
use adw::glib;
use adw::glib::Object;
use adw::prelude::{ListBoxRowExt, PreferencesGroupExt};
use adw::subclass::prelude::ObjectSubclassIsExt;
use dbus::arg::{RefArg};
use dbus::blocking::Connection;
use dbus::message::SignalArgs;
use dbus::Error;
use dbus::Path;
use glib::{ObjectExt, PropertySet};
use glib::PropertySet;
use gtk::gio;
use gtk::glib::Variant;
use gtk::prelude::{ActionableExt, WidgetExt};
use ReSet_Lib::network::network::{AccessPoint, WifiStrength};
use ReSet_Lib::signals::{AccessPointAdded};
use ReSet_Lib::signals::AccessPointAdded;
use ReSet_Lib::signals::{AccessPointChanged, AccessPointRemoved};
use crate::components::utils::setComboRowEllipsis;
use crate::components::wifi::wifiBoxImpl;
use crate::components::wifi::wifiEntry::WifiEntry;
use super::savedWifiEntry::SavedWifiEntry;
glib::wrapper! {
pub struct WifiBox(ObjectSubclass<wifiBoxImpl::WifiBox>)
@extends gtk::Box, gtk::Widget,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
}
type ResultMap = Result<(Vec<(Path<'static>, Vec<u8>)>,), Error>;
unsafe impl Send for WifiBox {}
unsafe impl Sync for WifiBox {}
@ -56,11 +54,19 @@ impl WifiBox {
.set_action_target_value(Some(&Variant::from("saved")));
selfImp.resetAvailableNetworks.set_activatable(true);
selfImp.resetAvailableNetworks.set_action_name(Some("navigation.pop"));
selfImp
.resetAvailableNetworks
.set_action_name(Some("navigation.pop"));
setComboRowEllipsis(selfImp.resetWiFiDevice.get());
}
}
impl Default for WifiBox {
fn default() -> Self {
Self::new()
}
}
pub fn scanForWifi(_listeners: Arc<Listeners>, wifiBox: Arc<WifiBox>) {
let wifibox_ref = wifiBox.clone();
let _wifibox_ref_listener = wifiBox.clone();
@ -116,7 +122,8 @@ pub fn dbus_start_network_events() {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let _: Result<(), Error> = proxy.method_call("org.Xetibo.ReSetWireless", "StartNetworkListener", ());
let _: Result<(), Error> =
proxy.method_call("org.Xetibo.ReSetWireless", "StartNetworkListener", ());
}
pub fn get_access_points() -> Vec<AccessPoint> {
@ -142,8 +149,7 @@ pub fn get_stored_connections() -> Vec<(Path<'static>, Vec<u8>)> {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(1000),
);
let res: Result<(Vec<(Path<'static>, Vec<u8>)>,), Error> =
proxy.method_call("org.Xetibo.ReSetWireless", "ListStoredConnections", ());
let res: ResultMap = proxy.method_call("org.Xetibo.ReSetWireless", "ListStoredConnections", ());
if res.is_err() {
println!("we got error...");
return Vec::new();
@ -162,7 +168,7 @@ pub fn start_event_listener(listeners: Arc<Listeners>, wifi_box: Arc<WifiBox>) {
let conn = Connection::new_session().unwrap();
let added_ref = wifi_box.clone();
let removed_ref = wifi_box.clone();
let changed_ref = wifi_box.clone(); // TODO implement changed
let changed_ref = wifi_box.clone();
let access_point_added = AccessPointAdded::match_rule(
Some(&"org.Xetibo.ReSetDaemon".into()),
Some(&Path::from("/org/Xetibo/ReSetDaemon")),

View file

@ -2,6 +2,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::time::Duration;
use crate::components::wifi::utils::getConnectionSettings;
use adw::glib;
use adw::glib::{Object, PropertySet};
use adw::prelude::{ActionRowExt, ButtonExt, EditableExt, PopoverExt};
@ -12,7 +13,6 @@ use glib::clone;
use gtk::gio;
use gtk::prelude::{ListBoxRowExt, WidgetExt};
use ReSet_Lib::network::network::{AccessPoint, WifiStrength};
use crate::components::wifi::utils::getConnectionSettings;
use crate::components::wifi::wifiBoxImpl::WifiBox;
use crate::components::wifi::wifiEntryImpl;
@ -99,8 +99,11 @@ pub fn click_disconnect(entry: Arc<WifiEntry>) {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(10000),
);
let res: Result<(bool,), Error> =
proxy.method_call("org.Xetibo.ReSetWireless", "DisconnectFromCurrentAccessPoint", ());
let res: Result<(bool,), Error> = proxy.method_call(
"org.Xetibo.ReSetWireless",
"DisconnectFromCurrentAccessPoint",
(),
);
if res.is_err() {
println!("res of disconnect was error bro");
return;

View file

@ -1,11 +1,11 @@
use crate::components::base::popup::Popup;
use crate::components::wifi::wifiEntry;
use adw::subclass::preferences_row::PreferencesRowImpl;
use adw::subclass::prelude::ActionRowImpl;
use adw::ActionRow;
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CompositeTemplate, Image, Label};
use std::cell::RefCell;
use adw::ActionRow;
use adw::subclass::preferences_row::PreferencesRowImpl;
use adw::subclass::prelude::ActionRowImpl;
use ReSet_Lib::network::network::{AccessPoint, WifiStrength};
#[allow(non_snake_case)]

View file

@ -20,6 +20,9 @@ glib::wrapper! {
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}
unsafe impl Send for WifiOptions {}
unsafe impl Sync for WifiOptions {}
impl WifiOptions {
pub fn new(connection: Connection) -> Arc<Self> {
let wifiOption: Arc<WifiOptions> = Arc::new(Object::builder().build());
@ -34,8 +37,12 @@ impl WifiOptions {
let conn = selfImp.connection.borrow();
// General
selfImp.resetWifiName.set_subtitle(&conn.settings.name);
selfImp.resetWifiAutoConnect.set_active(conn.settings.autoconnect);
selfImp.resetWifiMetered.set_active(conn.settings.metered != -1);
selfImp
.resetWifiAutoConnect
.set_active(conn.settings.autoconnect);
selfImp
.resetWifiMetered
.set_active(conn.settings.metered != -1);
match &conn.device {
TypeSettings::WIFI(wifi) => {
selfImp.resetWifiLinkSpeed.set_visible(false);
@ -44,7 +51,7 @@ impl WifiOptions {
selfImp.resetWifiDNS.set_visible(false);
selfImp.resetWifiGateway.set_visible(false);
selfImp.resetWifiLastUsed.set_visible(true);
selfImp.resetWifiMac.set_subtitle(&*wifi.cloned_mac_address);
selfImp.resetWifiMac.set_subtitle(&wifi.cloned_mac_address);
}
TypeSettings::ETHERNET(ethernet) => {
selfImp.resetWifiLinkSpeed.set_visible(true);
@ -53,17 +60,26 @@ impl WifiOptions {
selfImp.resetWifiDNS.set_visible(true);
selfImp.resetWifiGateway.set_visible(true);
selfImp.resetWifiLastUsed.set_visible(false);
selfImp.resetWifiMac.set_subtitle(&*ethernet.cloned_mac_address);
selfImp.resetWifiLinkSpeed.set_subtitle(&*ethernet.speed.to_string());
selfImp
.resetWifiMac
.set_subtitle(&ethernet.cloned_mac_address);
selfImp
.resetWifiLinkSpeed
.set_subtitle(&ethernet.speed.to_string());
}
TypeSettings::VPN(_vpn) => {}
TypeSettings::None => {}
};
// IPv4
selfImp.resetIP4Method.set_selected(conn.ipv4.dns_method.to_i32() as u32);
selfImp
.resetIP4Method
.set_selected(conn.ipv4.dns_method.to_i32() as u32);
self.setIP4Visibility(conn.ipv4.dns_method.to_i32() as u32);
let ipv4Dns: Vec<String> = conn.ipv4.dns.iter()
let ipv4Dns: Vec<String> = conn
.ipv4
.dns
.iter()
.map(|addr| {
addr.iter()
.map(|octet| octet.to_string())
@ -75,10 +91,14 @@ impl WifiOptions {
selfImp.resetIP4Gateway.set_text(&conn.ipv4.gateway);
if conn.ipv4.address_data.is_empty() {
selfImp.resetIP4AddressGroup.add(&WifiAddressEntry::new(None))
selfImp
.resetIP4AddressGroup
.add(&WifiAddressEntry::new(None))
} else {
for address in conn.ipv4.address_data.iter() {
selfImp.resetIP4AddressGroup.add(&WifiAddressEntry::new(Some(address)))
selfImp
.resetIP4AddressGroup
.add(&WifiAddressEntry::new(Some(address)))
}
}
@ -86,14 +106,21 @@ impl WifiOptions {
selfImp.resetIP4RoutesGroup.add(&WifiRouteEntry::new(None))
} else {
for address in conn.ipv4.route_data.iter() {
selfImp.resetIP4RoutesGroup.add(&WifiRouteEntry::new(Some(address)))
selfImp
.resetIP4RoutesGroup
.add(&WifiRouteEntry::new(Some(address)))
}
}
// IPv6
selfImp.resetIP6Method.set_selected(conn.ipv6.dns_method.to_i32() as u32);
selfImp
.resetIP6Method
.set_selected(conn.ipv6.dns_method.to_i32() as u32);
self.setIP6Visibility(conn.ipv6.dns_method.to_i32() as u32);
let ipv6Dns: Vec<String> = conn.ipv6.dns.iter()
let ipv6Dns: Vec<String> = conn
.ipv6
.dns
.iter()
.map(|addr| {
addr.iter()
.map(|octet| octet.to_string())
@ -105,10 +132,14 @@ impl WifiOptions {
selfImp.resetIP6Gateway.set_text(&conn.ipv6.gateway);
if conn.ipv6.address_data.is_empty() {
selfImp.resetIP6AddressGroup.add(&WifiAddressEntry::new(None))
selfImp
.resetIP6AddressGroup
.add(&WifiAddressEntry::new(None))
} else {
for address in conn.ipv6.address_data.iter() {
selfImp.resetIP6AddressGroup.add(&WifiAddressEntry::new(Some(address)))
selfImp
.resetIP6AddressGroup
.add(&WifiAddressEntry::new(Some(address)))
}
}
@ -116,7 +147,9 @@ impl WifiOptions {
selfImp.resetIP6RoutesGroup.add(&WifiRouteEntry::new(None))
} else {
for address in conn.ipv6.route_data.iter() {
selfImp.resetIP6RoutesGroup.add(&WifiRouteEntry::new(Some(address)))
selfImp
.resetIP6RoutesGroup
.add(&WifiRouteEntry::new(Some(address)))
}
}
// Security
@ -126,12 +159,14 @@ impl WifiOptions {
pub fn setIP4Visibility(&self, method: u32) {
let selfImp = self.imp();
match method {
0 => { // auto
0 => {
// auto
selfImp.resetIP4AddressGroup.set_visible(false);
selfImp.resetIP4RoutesGroup.set_visible(true);
selfImp.resetIP4Gateway.set_visible(false);
}
1 => { // manual
1 => {
// manual
selfImp.resetIP4AddressGroup.set_visible(true);
selfImp.resetIP4RoutesGroup.set_visible(true);
selfImp.resetIP4Gateway.set_visible(true);
@ -147,12 +182,14 @@ impl WifiOptions {
pub fn setIP6Visibility(&self, method: u32) {
let selfImp = self.imp();
match method {
0 | 1 => { // auto, dhcp
0 | 1 => {
// auto, dhcp
selfImp.resetIP6AddressGroup.set_visible(false);
selfImp.resetIP6RoutesGroup.set_visible(true);
selfImp.resetIP6Gateway.set_visible(false);
}
2 => { // manual
2 => {
// manual
selfImp.resetIP6AddressGroup.set_visible(true);
selfImp.resetIP6RoutesGroup.set_visible(true);
selfImp.resetIP6Gateway.set_visible(true);
@ -170,55 +207,57 @@ fn setupCallbacks(wifiOptions: &Arc<WifiOptions>) {
let imp = wifiOptions.imp();
// General
imp.resetWifiAutoConnect.connect_active_notify(clone!(@weak imp => move |x| {
imp.connection.borrow_mut().settings.autoconnect = x.is_active();
}));
imp.resetWifiMetered.connect_active_notify(clone!(@weak imp => move |x| {
imp.connection.borrow_mut().settings.metered = if x.is_active() { 1 } else { 2 };
}));
imp.resetWifiAutoConnect
.connect_active_notify(clone!(@weak imp => move |x| {
imp.connection.borrow_mut().settings.autoconnect = x.is_active();
}));
imp.resetWifiMetered
.connect_active_notify(clone!(@weak imp => move |x| {
imp.connection.borrow_mut().settings.metered = if x.is_active() { 1 } else { 2 };
}));
// IPv4
let wifiOptionsIP4 = wifiOptions.clone();
imp.resetIP4Method.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
wifiOptionsIP4.setIP4Visibility(selected);
}));
imp.resetIP4Method
.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
wifiOptionsIP4.setIP4Visibility(selected);
}));
let dnsRegex = Regex::new(r"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$").unwrap();
imp.resetIP4DNS.connect_changed(clone!(@weak imp => move |entry| {
let dnsInput = entry.text();
let mut conn = imp.connection.borrow_mut();
conn.ipv4.dns.clear();
if dnsInput.as_str().is_empty() {
imp.resetIP4DNS.remove_css_class("error");
return;
}
for dnsEntry in dnsInput.as_str().split(',').collect::<Vec<&str>>() {
if dnsRegex.is_match(dnsEntry) {
imp.resetIP4DNS
.connect_changed(clone!(@weak imp => move |entry| {
let dnsInput = entry.text();
let mut conn = imp.connection.borrow_mut();
conn.ipv4.dns.clear();
if dnsInput.as_str().is_empty() {
imp.resetIP4DNS.remove_css_class("error");
let dnsParts = dnsEntry.split('.')
.map(|s| s.parse::<u8>().unwrap())
.collect::<Vec<u8>>();
conn.ipv4.dns.push(dnsParts);
} else {
imp.resetIP4DNS.add_css_class("error");
return;
}
}
}));
for dnsEntry in dnsInput.as_str().split(',').collect::<Vec<&str>>() {
if dnsRegex.is_match(dnsEntry) {
imp.resetIP4DNS.remove_css_class("error");
let dnsParts = dnsEntry.split('.')
.map(|s| s.parse::<u8>().unwrap())
.collect::<Vec<u8>>();
conn.ipv4.dns.push(dnsParts);
} else {
imp.resetIP4DNS.add_css_class("error");
}
}
}));
// IPv6
let wifiOptionsIP6 = wifiOptions.clone();
imp.resetIP6Method.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
wifiOptionsIP6.setIP6Visibility(selected);
}));
imp.resetIP6Method
.connect_selected_notify(clone!(@weak imp => move |dropdown| {
let selected = dropdown.selected();
wifiOptionsIP6.setIP6Visibility(selected);
}));
// Security
}
pub fn getValueFromKey(map: &PropMap, key: &str) -> String {
map.get(key)
.map_or_else(|| "".to_string(),
|value| value.0
.as_str()
.unwrap_or_default()
.trim()
.to_string())
map.get(key).map_or_else(
|| "".to_string(),
|value| value.0.as_str().unwrap_or_default().trim().to_string(),
)
}

View file

@ -1,10 +1,10 @@
use crate::components::wifi::wifiOptions;
use adw::subclass::prelude::NavigationPageImpl;
use adw::{ActionRow, ComboRow, EntryRow, NavigationPage, PreferencesGroup, SwitchRow};
use gtk::subclass::prelude::*;
use gtk::{glib, Button, CompositeTemplate};
use std::cell::RefCell;
use std::rc::Rc;
use adw::{ActionRow, ComboRow, EntryRow, NavigationPage, PreferencesGroup, SwitchRow};
use adw::subclass::prelude::NavigationPageImpl;
use crate::components::wifi::{wifiOptions};
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate, Button};
use ReSet_Lib::network::connection::Connection;
#[allow(non_snake_case)]
@ -58,7 +58,7 @@ pub struct WifiOptions {
// Misc
#[template_child]
pub wifiOptionsApplyButton: TemplateChild<Button>,
pub connection: Rc<RefCell<Connection>>
pub connection: Rc<RefCell<Connection>>,
}
#[glib::object_subclass]

View file

@ -1,10 +1,10 @@
use crate::components::wifi::wifiOptions::getValueFromKey;
use adw::glib;
use adw::glib::Object;
use adw::prelude::PreferencesRowExt;
use glib::subclass::prelude::ObjectSubclassIsExt;
use gtk::prelude::EditableExt;
use ReSet_Lib::network::connection::Address;
use crate::components::wifi::wifiOptions::getValueFromKey;
use crate::components::wifi::wifiRouteEntryImpl;
@ -22,17 +22,18 @@ impl WifiRouteEntry {
let map = address.to_map();
let addr = getValueFromKey(&map, "address");
let prefix = getValueFromKey(&map, "prefix-length");
let gateway = getValueFromKey(&map, "gateway");
let metric = getValueFromKey(&map, "metric");
let prefix = getValueFromKey(&map, "prefix-length");
let gateway = getValueFromKey(&map, "gateway");
let metric = getValueFromKey(&map, "metric");
entryImp.resetRouteAddress.set_text(&addr);
entryImp.resetRouteNetmask.set_text(&prefix);
entryImp.resetRouteGateway.set_text(&gateway);
entryImp.resetRouteMetric.set_text(&metric);
entryImp.resetRouteRow.set_title(&format!("{}, {}, {}, {}", addr, prefix, gateway, metric));
entryImp
.resetRouteRow
.set_title(&format!("{}, {}, {}, {}", addr, prefix, gateway, metric));
}
entry
}
}

View file

@ -1,7 +1,7 @@
use adw::{EntryRow, ExpanderRow};
use crate::components::wifi::wifiRouteEntry;
use adw::{EntryRow, ExpanderRow};
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate, Button};
use gtk::{glib, Button, CompositeTemplate};
#[allow(non_snake_case)]
#[derive(Default, CompositeTemplate)]

View file

@ -18,8 +18,6 @@ const APP_ID: &str = "org.Xetibo.ReSet";
#[tokio::main]
async fn main() {
// TODO is this the best way to handle this??
tokio::task::spawn(daemon_check());
gio::resources_register_include!("src.templates.gresource")
.expect("Failed to register resources.");
@ -63,7 +61,8 @@ fn shutdown(_: &Application) {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(100),
);
let res: Result<(), Error> = proxy.method_call("org.Xetibo.ReSetDaemon", "UnregisterClient", ("ReSet",));
let res: Result<(), Error> =
proxy.method_call("org.Xetibo.ReSetDaemon", "UnregisterClient", ("ReSet",));
res
});
}
@ -76,7 +75,8 @@ async fn daemon_check() {
"/org/Xetibo/ReSetDaemon",
Duration::from_millis(100),
);
let res: Result<(), Error> = proxy.method_call("org.Xetibo.ReSetDaemon", "RegisterClient", ("ReSet",));
let res: Result<(), Error> =
proxy.method_call("org.Xetibo.ReSetDaemon", "RegisterClient", ("ReSet",));
res
});
let res = handle.join();