Merge pull request #100 from Xetibo/dashie

feat: Dynamic sidebars
This commit is contained in:
takotori 2024-04-11 09:55:11 +02:00 committed by GitHub
commit ee31829897
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 370 additions and 210 deletions

View file

@ -15,7 +15,7 @@ pub const INTERFACE: &str = "org.Xetibo.ReSet.TestPlugin";
#[allow(improper_ctypes_definitions)]
pub extern "C" fn capabilities() -> PluginCapabilities {
println!("frontend capabilities called");
PluginCapabilities::new(vec!["frontend test"], PluginImplementation::Frontend)
PluginCapabilities::new(vec!["test"], PluginImplementation::Frontend)
}
#[no_mangle]
@ -81,4 +81,4 @@ pub struct LabelWrapper {
unsafe impl Send for LabelWrapper {}
unsafe impl Sync for LabelWrapper {}
unsafe impl Sync for LabelWrapper {}

View file

@ -535,14 +535,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/glib/glib-0.18.4.crate",
"sha256": "951bbd7fdc5c044ede9f05170f05a3ae9479239c3afdfe2d22d537a3add15c4e",
"dest": "cargo/vendor/glib-0.18.4"
"url": "https://static.crates.io/crates/glib/glib-0.18.3.crate",
"sha256": "58cf801b6f7829fa76db37449ab67c9c98a2b1bf21076d9113225621e61a0fa6",
"dest": "cargo/vendor/glib-0.18.3"
},
{
"type": "inline",
"contents": "{\"package\": \"951bbd7fdc5c044ede9f05170f05a3ae9479239c3afdfe2d22d537a3add15c4e\", \"files\": {}}",
"dest": "cargo/vendor/glib-0.18.4",
"contents": "{\"package\": \"58cf801b6f7829fa76db37449ab67c9c98a2b1bf21076d9113225621e61a0fa6\", \"files\": {}}",
"dest": "cargo/vendor/glib-0.18.3",
"dest-filename": ".cargo-checksum.json"
},
{
@ -886,14 +886,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/mio/mio-0.8.9.crate",
"sha256": "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0",
"dest": "cargo/vendor/mio-0.8.9"
"url": "https://static.crates.io/crates/mio/mio-0.8.10.crate",
"sha256": "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09",
"dest": "cargo/vendor/mio-0.8.10"
},
{
"type": "inline",
"contents": "{\"package\": \"3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0\", \"files\": {}}",
"dest": "cargo/vendor/mio-0.8.9",
"contents": "{\"package\": \"8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09\", \"files\": {}}",
"dest": "cargo/vendor/mio-0.8.10",
"dest-filename": ".cargo-checksum.json"
},
{
@ -951,14 +951,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/once_cell/once_cell-1.18.0.crate",
"sha256": "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d",
"dest": "cargo/vendor/once_cell-1.18.0"
"url": "https://static.crates.io/crates/once_cell/once_cell-1.19.0.crate",
"sha256": "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92",
"dest": "cargo/vendor/once_cell-1.19.0"
},
{
"type": "inline",
"contents": "{\"package\": \"dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d\", \"files\": {}}",
"dest": "cargo/vendor/once_cell-1.18.0",
"contents": "{\"package\": \"3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92\", \"files\": {}}",
"dest": "cargo/vendor/once_cell-1.19.0",
"dest-filename": ".cargo-checksum.json"
},
{
@ -1042,14 +1042,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/proc-macro-crate/proc-macro-crate-2.0.0.crate",
"sha256": "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8",
"dest": "cargo/vendor/proc-macro-crate-2.0.0"
"url": "https://static.crates.io/crates/proc-macro-crate/proc-macro-crate-2.0.1.crate",
"sha256": "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a",
"dest": "cargo/vendor/proc-macro-crate-2.0.1"
},
{
"type": "inline",
"contents": "{\"package\": \"7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8\", \"files\": {}}",
"dest": "cargo/vendor/proc-macro-crate-2.0.0",
"contents": "{\"package\": \"97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a\", \"files\": {}}",
"dest": "cargo/vendor/proc-macro-crate-2.0.1",
"dest-filename": ".cargo-checksum.json"
},
{
@ -1146,14 +1146,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/reset_daemon/reset_daemon-1.0.0.crate",
"sha256": "4ac44390e711dd73b2a2c365890d28f0ceec5c3e9f760deafbab2ad7410e90ed",
"dest": "cargo/vendor/reset_daemon-1.0.0"
"url": "https://static.crates.io/crates/reset_daemon/reset_daemon-1.0.1.crate",
"sha256": "eedc50550fb0c1b1a6d09c0c9e8025678d50833805ddf09e3aa39a66ff391cc4",
"dest": "cargo/vendor/reset_daemon-1.0.1"
},
{
"type": "inline",
"contents": "{\"package\": \"4ac44390e711dd73b2a2c365890d28f0ceec5c3e9f760deafbab2ad7410e90ed\", \"files\": {}}",
"dest": "cargo/vendor/reset_daemon-1.0.0",
"contents": "{\"package\": \"eedc50550fb0c1b1a6d09c0c9e8025678d50833805ddf09e3aa39a66ff391cc4\", \"files\": {}}",
"dest": "cargo/vendor/reset_daemon-1.0.1",
"dest-filename": ".cargo-checksum.json"
},
{
@ -1380,27 +1380,27 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/toml/toml-0.8.8.crate",
"sha256": "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35",
"dest": "cargo/vendor/toml-0.8.8"
"url": "https://static.crates.io/crates/toml/toml-0.8.2.crate",
"sha256": "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d",
"dest": "cargo/vendor/toml-0.8.2"
},
{
"type": "inline",
"contents": "{\"package\": \"a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35\", \"files\": {}}",
"dest": "cargo/vendor/toml-0.8.8",
"contents": "{\"package\": \"185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d\", \"files\": {}}",
"dest": "cargo/vendor/toml-0.8.2",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/toml_datetime/toml_datetime-0.6.5.crate",
"sha256": "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1",
"dest": "cargo/vendor/toml_datetime-0.6.5"
"url": "https://static.crates.io/crates/toml_datetime/toml_datetime-0.6.3.crate",
"sha256": "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b",
"dest": "cargo/vendor/toml_datetime-0.6.3"
},
{
"type": "inline",
"contents": "{\"package\": \"3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1\", \"files\": {}}",
"dest": "cargo/vendor/toml_datetime-0.6.5",
"contents": "{\"package\": \"7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b\", \"files\": {}}",
"dest": "cargo/vendor/toml_datetime-0.6.3",
"dest-filename": ".cargo-checksum.json"
},
{
@ -1419,27 +1419,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/toml_edit/toml_edit-0.20.7.crate",
"sha256": "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81",
"dest": "cargo/vendor/toml_edit-0.20.7"
"url": "https://static.crates.io/crates/toml_edit/toml_edit-0.20.2.crate",
"sha256": "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338",
"dest": "cargo/vendor/toml_edit-0.20.2"
},
{
"type": "inline",
"contents": "{\"package\": \"70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81\", \"files\": {}}",
"dest": "cargo/vendor/toml_edit-0.20.7",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/toml_edit/toml_edit-0.21.0.crate",
"sha256": "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03",
"dest": "cargo/vendor/toml_edit-0.21.0"
},
{
"type": "inline",
"contents": "{\"package\": \"d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03\", \"files\": {}}",
"dest": "cargo/vendor/toml_edit-0.21.0",
"contents": "{\"package\": \"396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338\", \"files\": {}}",
"dest": "cargo/vendor/toml_edit-0.20.2",
"dest-filename": ".cargo-checksum.json"
},
{
@ -1653,14 +1640,14 @@
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/winnow/winnow-0.5.19.crate",
"sha256": "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b",
"dest": "cargo/vendor/winnow-0.5.19"
"url": "https://static.crates.io/crates/winnow/winnow-0.5.26.crate",
"sha256": "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff",
"dest": "cargo/vendor/winnow-0.5.26"
},
{
"type": "inline",
"contents": "{\"package\": \"829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b\", \"files\": {}}",
"dest": "cargo/vendor/winnow-0.5.19",
"contents": "{\"package\": \"b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff\", \"files\": {}}",
"dest": "cargo/vendor/winnow-0.5.26",
"dest-filename": ".cargo-checksum.json"
},
{

View file

@ -6,7 +6,8 @@ use std::{
use adw::prelude::{ComboRowExt, PreferencesRowExt};
use dbus::arg::{Arg, Get};
use glib::{
object::{Cast, IsA},
object::{Cast, IsA, ObjectExt},
property::PropertyGet,
ControlFlow, Propagation,
};
use gtk::{
@ -171,8 +172,8 @@ pub fn populate_audio_objects<
default_audio_object_function: &'static DBusFunction,
set_default_audio_object_function: &'static DBusFunction,
get_audio_streams_function: &'static DBusFunction,
set_audio_object_mute_function: &'static DBusFunction,
set_audio_object_volume_function: &'static DBusFunction,
set_audio_object_mute_function: &'static DBusFunction,
) {
gio::spawn_blocking(move || {
let sources = audio_dbus_call::<AudioBox, (Vec<AudioObject>,), ()>(
@ -264,6 +265,7 @@ pub fn object_added_handler<
>(
audio_box: Arc<AudioBox>,
ir: Event,
dummy_name: &'static str,
) -> bool {
glib::spawn_future(async move {
glib::idle_add_once(move || {
@ -305,8 +307,7 @@ pub fn object_added_handler<
let mut index = index.write().unwrap();
let model_list = source_box_imp.model_list();
let model_list = model_list.write().unwrap();
// TODO: make this work generic!
if model_list.string(*index - 1) == Some("Monitor of Dummy Output".into()) {
if model_list.string(*index - 1) == Some(dummy_name.into()) {
model_list.append(&alias);
model_list.remove(*index - 1);
map.insert(alias, (object_index, name));
@ -314,8 +315,7 @@ pub fn object_added_handler<
} else {
model_list.append(&alias);
map.insert(alias.clone(), (object_index, name));
// TODO: make this work generic!
if alias == "Monitor of Dummy Output" {
if alias == dummy_name {
source_box_imp.audio_object_dropdown().set_selected(0);
}
*index += 1;
@ -406,6 +406,7 @@ pub fn object_removed_handler<
>(
audio_box: Arc<AudioBox>,
ir: Event,
dummy_name: &'static str,
) -> bool {
glib::spawn_future(async move {
glib::idle_add_once(move || {
@ -431,8 +432,7 @@ pub fn object_removed_handler<
let model_list = model_list.write().unwrap();
if *index == 1 {
// TODO: ensure dummy output and input are mentioned
model_list.append("Dummy");
model_list.append(dummy_name);
}
for entry in 0..*index {
if model_list.string(entry) == Some(alias.clone().into()) {

View file

@ -328,6 +328,7 @@ pub fn start_audio_box_listener<
conn: Connection,
source_box: Arc<AudioBox>,
get_default_name_function: &'static DBusFunction,
dummy_name: &'static str,
) -> Connection {
// TODO: make the failed logs generically sound -> deynamic output for both
let object_added =
@ -361,7 +362,7 @@ pub fn start_audio_box_listener<
AudioBox,
AudioBoxImpl,
ObjectAdded,
>(object_added_box.clone(), ir)
>(object_added_box.clone(), ir, dummy_name)
});
if res.is_err() {
// TODO: handle this with the log/error macro
@ -370,7 +371,6 @@ pub fn start_audio_box_listener<
}
let res = conn.add_match(object_changed, move |ir: ObjectChanged, _, _| {
// source_changed_handler(source_changed_box.clone(), ir)
object_changed_handler::<
AudioObject,
StreamObject,
@ -389,7 +389,6 @@ pub fn start_audio_box_listener<
}
let res = conn.add_match(object_removed, move |ir: ObjectRemoved, _, _| {
// source_removed_handler(source_removed_box.clone(), ir)
object_removed_handler::<
AudioObject,
StreamObject,
@ -400,7 +399,7 @@ pub fn start_audio_box_listener<
AudioBox,
AudioBoxImpl,
ObjectRemoved,
>(object_removed_box.clone(), ir)
>(object_removed_box.clone(), ir, dummy_name)
});
if res.is_err() {
println!("fail on source remove event");

View file

@ -20,7 +20,7 @@ use crate::components::base::error_impl::ReSetErrorImpl;
use super::output_stream_entry::OutputStreamEntry;
use super::source_const::{
GETDEFAULT, GETDEFAULTNAME, GETOBJECTS, GETSTREAMS, SETDEFAULT, SETMUTE, SETVOLUME,
DUMMY, GETDEFAULT, GETDEFAULTNAME, GETOBJECTS, GETSTREAMS, SETDEFAULT, SETMUTE, SETVOLUME
};
use super::source_entry::SourceEntry;
@ -110,5 +110,5 @@ pub fn start_source_box_listener(conn: Connection, source_box: Arc<SourceBox>) -
OutputStreamAdded,
OutputStreamChanged,
OutputStreamRemoved,
>(conn, source_box, &GETDEFAULTNAME)
>(conn, source_box, &GETDEFAULTNAME, DUMMY)
}

View file

@ -54,3 +54,5 @@ pub const SETSTREAMOBJECT: DBusFunction = DBusFunction {
function: "SetSourceOfOutputStream",
error: "Failed to set source of output stream",
};
pub const DUMMY: &str = "Monitor of Dummy Output";

View file

@ -20,13 +20,10 @@ use crate::components::base::error_impl::ReSetErrorImpl;
use super::input_stream_entry::InputStreamEntry;
use super::sink_box_impl;
use super::sink_const::GETDEFAULT;
use super::sink_const::GETDEFAULTNAME;
use super::sink_const::GETOBJECTS;
use super::sink_const::GETSTREAMS;
use super::sink_const::SETDEFAULT;
use super::sink_const::SETMUTE;
use super::sink_const::SETVOLUME;
use super::sink_const::DUMMY;
use super::sink_const::{
GETDEFAULT, GETDEFAULTNAME, GETOBJECTS, GETSTREAMS, SETDEFAULT, SETMUTE, SETVOLUME,
};
use super::sink_entry::SinkEntry;
glib::wrapper! {
@ -117,5 +114,5 @@ pub fn start_sink_box_listener(conn: Connection, sink_box: Arc<SinkBox>) -> Conn
InputStreamAdded,
InputStreamChanged,
InputStreamRemoved,
>(conn, sink_box, &GETDEFAULTNAME)
>(conn, sink_box, &GETDEFAULTNAME, DUMMY)
}

View file

@ -54,3 +54,5 @@ pub const SETSTREAMOBJECT: DBusFunction = DBusFunction {
function: "SetSinkOfInputStream",
error: "Failed to set sink of input stream",
};
pub const DUMMY: &str = "Dummy Input";

View file

@ -175,12 +175,15 @@ fn bluetooth_enabled_switch_handler(
glib::Propagation::Proceed
}
pub fn populate_connected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
pub fn populate_connected_bluetooth_devices(
listeners: Arc<Listeners>,
bluetooth_box: Arc<BluetoothBox>,
) {
// TODO handle saved devices -> they also exist
gio::spawn_blocking(move || {
let ref_box = bluetooth_box.clone();
let devices = get_connected_devices(ref_box.clone());
let adapters = get_bluetooth_adapters(ref_box.clone());
let devices = get_bluetooth_devices(ref_box.clone());
{
let imp = bluetooth_box.imp();
let list = imp.reset_model_list.write().unwrap();
@ -197,6 +200,7 @@ pub fn populate_connected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
*model_index += 1;
}
}
start_bluetooth_listener(listeners, ref_box.clone());
glib::spawn_future(async move {
glib::idle_add_once(move || {
let new_adapter_ref = ref_box.clone();
@ -230,14 +234,23 @@ pub fn populate_connected_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) {
for device in devices {
let path = device.path.clone();
let connected = device.connected;
let rssi = device.rssi;
let bluetooth_entry = BluetoothEntry::new(device, ref_box.clone());
imp.available_devices
.borrow_mut()
.insert(path, bluetooth_entry.clone());
if connected {
imp.reset_bluetooth_connected_devices.add(&*bluetooth_entry);
imp.connected_devices
.borrow_mut()
.insert(path, bluetooth_entry.clone());
} else if rssi == -1 {
imp.reset_bluetooth_saved_devices.add(&*bluetooth_entry);
imp.saved_devices
.borrow_mut()
.insert(path, bluetooth_entry.clone());
} else {
imp.reset_bluetooth_available_devices.add(&*bluetooth_entry);
imp.available_devices
.borrow_mut()
.insert(path, bluetooth_entry.clone());
}
}
});
@ -410,16 +423,13 @@ fn bluetooth_listener_loop(
}
}
fn get_connected_devices(bluetooth_box: Arc<BluetoothBox>) -> Vec<BluetoothDevice> {
fn get_bluetooth_devices(bluetooth_box: Arc<BluetoothBox>) -> Vec<BluetoothDevice> {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(Vec<BluetoothDevice>,), Error> =
proxy.method_call(BLUETOOTH, "GetConnectedBluetoothDevices", ());
proxy.method_call(BLUETOOTH, "GetBluetoothDevices", ());
if res.is_err() {
show_error::<BluetoothBox>(
bluetooth_box.clone(),
"Failed to get connected bluetooth devices",
);
show_error::<BluetoothBox>(bluetooth_box.clone(), "Failed to get bluetooth devices");
return Vec::new();
}
res.unwrap().0

View file

@ -24,6 +24,8 @@ pub struct BluetoothBox {
#[template_child]
pub reset_bluetooth_available_devices: TemplateChild<PreferencesGroup>,
#[template_child]
pub reset_bluetooth_saved_devices: TemplateChild<PreferencesGroup>,
#[template_child]
pub reset_bluetooth_refresh_button: TemplateChild<Button>,
#[template_child]
pub reset_bluetooth_adapter: TemplateChild<ComboRow>,
@ -41,6 +43,7 @@ pub struct BluetoothBox {
pub error: TemplateChild<ReSetError>,
pub available_devices: BluetoothMap,
pub connected_devices: BluetoothMap,
pub saved_devices: BluetoothMap,
pub reset_bluetooth_adapters: Arc<RwLock<HashMap<String, (BluetoothAdapter, u32)>>>,
pub reset_current_bluetooth_adapter: Arc<RefCell<BluetoothAdapter>>,
pub reset_model_list: Arc<RwLock<StringList>>,

View file

@ -15,15 +15,22 @@ pub fn device_changed_handler(
glib::spawn_future(async move {
glib::idle_add_once(move || {
let imp = bluetooth_box.imp();
let rssi = ir.bluetooth_device.rssi;
let mut map = imp.available_devices.borrow_mut();
if let Some(list_entry) = map.get_mut(&ir.bluetooth_device.path) {
let mut existing_bluetooth_device = list_entry.imp().bluetooth_device.borrow_mut();
if existing_bluetooth_device.connected != ir.bluetooth_device.connected {
if ir.bluetooth_device.connected {
imp.reset_bluetooth_available_devices.remove(&**list_entry);
imp.reset_bluetooth_saved_devices.remove(&**list_entry);
imp.reset_bluetooth_connected_devices.add(&**list_entry);
} else if rssi == -1 {
imp.reset_bluetooth_connected_devices.remove(&**list_entry);
imp.reset_bluetooth_saved_devices.add(&**list_entry);
imp.reset_bluetooth_available_devices.remove(&**list_entry);
} else {
imp.reset_bluetooth_connected_devices.remove(&**list_entry);
imp.reset_bluetooth_saved_devices.remove(&**list_entry);
imp.reset_bluetooth_available_devices.add(&**list_entry);
}
}
@ -62,7 +69,9 @@ pub fn device_removed_handler(
if list_entry.imp().bluetooth_device.borrow().connected {
imp.reset_bluetooth_connected_devices.remove(&*list_entry);
} else {
// TODO: is there a better way for this?
imp.reset_bluetooth_available_devices.remove(&*list_entry);
imp.reset_bluetooth_saved_devices.remove(&*list_entry);
}
}
});
@ -76,6 +85,7 @@ pub fn device_added_handler(device_added_box: Arc<BluetoothBox>, ir: BluetoothDe
glib::idle_add_once(move || {
let imp = bluetooth_box.imp();
let path = ir.bluetooth_device.path.clone();
let rssi = ir.bluetooth_device.rssi;
let connected = ir.bluetooth_device.connected;
let bluetooth_entry = BluetoothEntry::new(ir.bluetooth_device, bluetooth_box.clone());
imp.available_devices
@ -83,6 +93,8 @@ pub fn device_added_handler(device_added_box: Arc<BluetoothBox>, ir: BluetoothDe
.insert(path, bluetooth_entry.clone());
if connected {
imp.reset_bluetooth_connected_devices.add(&*bluetooth_entry);
} else if rssi == -1 {
imp.reset_bluetooth_saved_devices.add(&*bluetooth_entry);
} else {
imp.reset_bluetooth_available_devices.add(&*bluetooth_entry);
}

View file

@ -4,7 +4,7 @@ use std::sync::Arc;
use gtk::FlowBox;
use crate::components::base::utils::{Listeners, Position};
use crate::components::{base::utils::{Listeners, Position}, utils::Capabilities};
// extern "C" {
// pub fn startup() -> SidebarInfo;
@ -12,7 +12,7 @@ use crate::components::base::utils::{Listeners, Position};
// pub fn run_test();
// }
pub type RegularClickEvent = fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>);
pub type RegularClickEvent = fn(&Capabilities, Arc<Listeners>, FlowBox, Rc<RefCell<Position>>);
pub type PluginClickEvent = Rc<dyn Fn(FlowBox, Rc<RefCell<Position>>, Vec<gtk::Box>)>;
pub trait TSideBarInfo {
@ -28,7 +28,9 @@ pub struct ReSetSidebarInfo {
pub name: &'static str,
pub icon_name: &'static str,
pub parent: Option<&'static str>,
// pub pre_click:
pub click_event: RegularClickEvent,
// pub post_click:
}
impl TSideBarInfo for ReSetSidebarInfo {

View file

@ -1,17 +1,37 @@
use std::cell::Cell;
use std::time::Duration;
use adw::gdk::pango::EllipsizeMode;
use adw::prelude::ListModelExtManual;
use adw::{ActionRow, ComboRow};
use dbus::blocking::Connection;
use dbus::Error;
use glib::prelude::Cast;
use glib::Object;
use gtk::prelude::{GObjectPropertyExpressionExt, ListBoxRowExt, ListItemExt, WidgetExt};
use gtk::{Align, SignalListItemFactory, StringObject};
pub const DBUS_PATH: &str = "/org/Xetibo/ReSet/Daemon";
pub const WIRELESS: &str = "org.Xetibo.ReSet.Wireless";
pub const WIRELESS: &str = "org.Xetibo.ReSet.Network";
pub const BLUETOOTH: &str = "org.Xetibo.ReSet.Bluetooth";
pub const AUDIO: &str = "org.Xetibo.ReSet.Audio";
pub const BASE: &str = "org.Xetibo.ReSet.Daemon";
#[derive(Default)]
pub struct Capabilities {
pub wifi: Cell<bool>,
pub bluetooth: Cell<bool>,
pub audio: Cell<bool>,
}
impl Capabilities {
pub fn set(&self, wifi: bool, bluetooth: bool, audio: bool) {
self.wifi.set(wifi);
self.bluetooth.set(bluetooth);
self.audio.set(audio);
}
}
pub fn create_dropdown_label_factory() -> SignalListItemFactory {
let factory = SignalListItemFactory::new();
factory.connect_setup(|_, item| {
@ -68,3 +88,10 @@ pub fn set_action_row_ellipsis(element: ActionRow) {
}
}
}
pub fn get_capabilities() -> Vec<String> {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(Vec<String>,), Error> = proxy.method_call(BASE, "GetCapabilities", ());
res.unwrap().0
}

View file

@ -116,7 +116,7 @@ pub fn scan_for_wifi(wifi_box: Arc<WifiBox>) {
if devices.is_empty() {
return;
}
let access_points = get_access_points(wifibox_ref.clone());
let access_points = get_access_points(wifi_box.clone());
{
let imp = wifibox_ref.imp();
let list = imp.reset_model_list.write().unwrap();

View file

@ -0,0 +1,48 @@
use crate::components::plugin::function::ReSetSidebarInfo;
use super::handle_sidebar_click::{
HANDLE_AUDIO_CLICK, HANDLE_BLUETOOTH_CLICK, HANDLE_CONNECTIVITY_CLICK, HANDLE_MICROPHONE_CLICK,
HANDLE_VOLUME_CLICK, HANDLE_WIFI_CLICK,
};
pub const CONNECTIVITY_SIDEBAR: ReSetSidebarInfo = ReSetSidebarInfo {
name: "Connectivity",
icon_name: "network-wired-symbolic",
parent: None,
click_event: HANDLE_CONNECTIVITY_CLICK,
};
pub const WIFI_SIDEBAR: ReSetSidebarInfo = ReSetSidebarInfo {
name: "WiFi",
icon_name: "network-wireless-symbolic",
parent: Some("Connectivity"),
click_event: HANDLE_WIFI_CLICK,
};
pub const BLUETOOTH_SIDEBAR: ReSetSidebarInfo = ReSetSidebarInfo {
name: "Bluetooth",
icon_name: "bluetooth-symbolic",
parent: Some("Connectivity"),
click_event: HANDLE_BLUETOOTH_CLICK,
};
pub const AUDIO_SIDEBAR: ReSetSidebarInfo = ReSetSidebarInfo {
name: "Audio",
icon_name: "audio-headset-symbolic",
parent: None,
click_event: HANDLE_AUDIO_CLICK,
};
pub const SINK_SIDEBAR: ReSetSidebarInfo = ReSetSidebarInfo {
name: "Output",
icon_name: "audio-volume-high-symbolic",
parent: Some("Audio"),
click_event: HANDLE_VOLUME_CLICK,
};
pub const SOURCE_SIDEBAR: ReSetSidebarInfo = ReSetSidebarInfo {
name: "Input",
icon_name: "audio-input-microphone-symbolic",
parent: Some("Audio"),
click_event: HANDLE_MICROPHONE_CLICK,
};

View file

@ -10,65 +10,98 @@ use crate::components::audio::output::sink_box::{populate_sinks, SinkBox};
use crate::components::base::setting_box::SettingBox;
use crate::components::base::utils::{start_audio_listener, Listeners, Position};
use crate::components::bluetooth::bluetooth_box::{
populate_connected_bluetooth_devices, start_bluetooth_listener, BluetoothBox,
populate_connected_bluetooth_devices, BluetoothBox,
};
use crate::components::utils::Capabilities;
use crate::components::wifi::wifi_box::{
scan_for_wifi, show_stored_connections, start_event_listener, WifiBox,
};
use gtk::prelude::WidgetExt;
use gtk::{Align, FlowBox, FlowBoxChild, Frame};
pub const HANDLE_CONNECTIVITY_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::Connectivity) {
return;
}
pub const HANDLE_CONNECTIVITY_CLICK: fn(
&Capabilities,
Arc<Listeners>,
FlowBox,
Rc<RefCell<Position>>,
) = |capabilities: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::Connectivity) {
return;
}
reset_main.remove_all();
let mut count = 0;
if capabilities.wifi.get() {
let wifi_box = WifiBox::new(listeners.clone());
start_event_listener(listeners.clone(), wifi_box.clone());
show_stored_connections(wifi_box.clone());
scan_for_wifi(wifi_box.clone());
let wifi_frame = wrap_in_flow_box_child(SettingBox::new(&*wifi_box));
let bluetooth_box = BluetoothBox::new(listeners.clone());
populate_connected_bluetooth_devices(bluetooth_box.clone());
start_bluetooth_listener(listeners, bluetooth_box.clone());
let bluetooth_frame = wrap_in_flow_box_child(SettingBox::new(&*bluetooth_box));
reset_main.remove_all();
reset_main.insert(&wifi_frame, -1);
reset_main.insert(&bluetooth_frame, -1);
reset_main.set_max_children_per_line(2);
};
count += 1;
}
pub const HANDLE_WIFI_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
if capabilities.bluetooth.get() {
let bluetooth_box = BluetoothBox::new(listeners.clone());
populate_connected_bluetooth_devices(listeners, bluetooth_box.clone());
let bluetooth_frame = wrap_in_flow_box_child(SettingBox::new(&*bluetooth_box));
reset_main.insert(&bluetooth_frame, -1);
count += 1;
}
reset_main.set_max_children_per_line(count);
};
pub const HANDLE_WIFI_CLICK: fn(&Capabilities, Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|_: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::Wifi) {
return;
}
reset_main.remove_all();
let wifi_box = WifiBox::new(listeners.clone());
start_event_listener(listeners, wifi_box.clone());
show_stored_connections(wifi_box.clone());
scan_for_wifi(wifi_box.clone());
let wifi_frame = wrap_in_flow_box_child(SettingBox::new(&*wifi_box));
reset_main.remove_all();
reset_main.insert(&wifi_frame, -1);
reset_main.set_max_children_per_line(1);
};
pub const HANDLE_BLUETOOTH_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::Bluetooth) {
return;
}
let bluetooth_box = BluetoothBox::new(listeners.clone());
start_bluetooth_listener(listeners, bluetooth_box.clone());
populate_connected_bluetooth_devices(bluetooth_box.clone());
let bluetooth_frame = wrap_in_flow_box_child(SettingBox::new(&*bluetooth_box));
reset_main.remove_all();
reset_main.insert(&bluetooth_frame, -1);
reset_main.set_max_children_per_line(1);
};
pub const HANDLE_BLUETOOTH_CLICK: fn(
&Capabilities,
Arc<Listeners>,
FlowBox,
Rc<RefCell<Position>>,
) = |_: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::Bluetooth) {
return;
}
let bluetooth_box = BluetoothBox::new(listeners.clone());
populate_connected_bluetooth_devices(listeners, bluetooth_box.clone());
// start_bluetooth_listener(listeners, bluetooth_box.clone());
let bluetooth_frame = wrap_in_flow_box_child(SettingBox::new(&*bluetooth_box));
reset_main.remove_all();
reset_main.insert(&bluetooth_frame, -1);
reset_main.set_max_children_per_line(1);
};
pub const HANDLE_AUDIO_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
pub const HANDLE_AUDIO_CLICK: fn(&Capabilities, Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|_: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::Audio) {
return;
}
@ -92,8 +125,11 @@ pub const HANDLE_AUDIO_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>)
reset_main.set_max_children_per_line(2);
};
pub const HANDLE_VOLUME_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
pub const HANDLE_VOLUME_CLICK: fn(&Capabilities, Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|_: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::AudioOutput) {
return;
}
@ -109,25 +145,35 @@ pub const HANDLE_VOLUME_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>
reset_main.set_max_children_per_line(1);
};
pub const HANDLE_MICROPHONE_CLICK: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::AudioInput) {
return;
}
let audio_input = Arc::new(SourceBox::new());
start_audio_listener(listeners.clone(), None, Some(audio_input.clone()));
if !listeners.pulse_listener.load(Ordering::SeqCst) {
spin_loop();
}
populate_sources(audio_input.clone());
let source_frame = wrap_in_flow_box_child(SettingBox::new(&*audio_input));
reset_main.remove_all();
reset_main.insert(&source_frame, -1);
reset_main.set_max_children_per_line(1);
};
pub const HANDLE_MICROPHONE_CLICK: fn(
&Capabilities,
Arc<Listeners>,
FlowBox,
Rc<RefCell<Position>>,
) = |_: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners.clone(), position, Position::AudioInput) {
return;
}
let audio_input = Arc::new(SourceBox::new());
start_audio_listener(listeners.clone(), None, Some(audio_input.clone()));
if !listeners.pulse_listener.load(Ordering::SeqCst) {
spin_loop();
}
populate_sources(audio_input.clone());
let source_frame = wrap_in_flow_box_child(SettingBox::new(&*audio_input));
reset_main.remove_all();
reset_main.insert(&source_frame, -1);
reset_main.set_max_children_per_line(1);
};
pub const HANDLE_HOME: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|listeners: Arc<Listeners>, reset_main: FlowBox, position: Rc<RefCell<Position>>| {
pub const HANDLE_HOME: fn(&Capabilities, Arc<Listeners>, FlowBox, Rc<RefCell<Position>>) =
|_: &Capabilities,
listeners: Arc<Listeners>,
reset_main: FlowBox,
position: Rc<RefCell<Position>>| {
if handle_init(listeners, position, Position::Home) {
return;
}

View file

@ -3,3 +3,4 @@ pub mod reset_window;
pub mod reset_window_impl;
pub mod sidebar_entry;
pub mod sidebar_entry_impl;
pub mod consts;

View file

@ -16,11 +16,17 @@ use re_set_lib::utils::plugin_setup::FRONTEND_PLUGINS;
use crate::components::base::setting_box::SettingBox;
use crate::components::base::utils::{Listeners, Position};
use crate::components::plugin::function::{PluginSidebarInfo, ReSetSidebarInfo};
use crate::components::plugin::function::PluginSidebarInfo;
use crate::components::utils::get_capabilities;
use crate::components::window::handle_sidebar_click::*;
use crate::components::window::reset_window_impl;
use crate::components::window::sidebar_entry::SidebarEntry;
use super::consts::{
AUDIO_SIDEBAR, BLUETOOTH_SIDEBAR, CONNECTIVITY_SIDEBAR, SINK_SIDEBAR, SOURCE_SIDEBAR,
WIFI_SIDEBAR,
};
glib::wrapper! {
pub struct ReSetWindow(ObjectSubclass<reset_window_impl::ReSetWindow>)
@extends adw::ApplicationWindow, gtk::Window, gtk::Widget,
@ -112,53 +118,52 @@ impl ReSetWindow {
pub fn setup_sidebar_entries(&self) {
let self_imp = self.imp();
let capabilities = get_capabilities();
let wifi = capabilities.contains(&"WiFi".to_string());
let bluetooth = capabilities.contains(&"Bluetooth".to_string());
let audio = capabilities.contains(&"Audio".to_string());
self_imp.capabilities.set(wifi, bluetooth, audio);
let sidebar_list = vec![
ReSetSidebarInfo {
name: "Connectivity",
icon_name: "network-wired-symbolic",
parent: None,
click_event: HANDLE_CONNECTIVITY_CLICK,
},
ReSetSidebarInfo {
name: "WiFi",
icon_name: "network-wireless-symbolic",
parent: Some("Connectivity"),
click_event: HANDLE_WIFI_CLICK,
},
ReSetSidebarInfo {
name: "Bluetooth",
icon_name: "bluetooth-symbolic",
parent: Some("Connectivity"),
click_event: HANDLE_BLUETOOTH_CLICK,
},
ReSetSidebarInfo {
name: "Audio",
icon_name: "audio-headset-symbolic",
parent: None,
click_event: HANDLE_AUDIO_CLICK,
},
ReSetSidebarInfo {
name: "Output",
icon_name: "audio-volume-high-symbolic",
parent: Some("Audio"),
click_event: HANDLE_VOLUME_CLICK,
},
ReSetSidebarInfo {
name: "Input",
icon_name: "audio-input-microphone-symbolic",
parent: Some("Audio"),
click_event: HANDLE_MICROPHONE_CLICK,
},
];
let mut sidebar_list = Vec::new();
if wifi || bluetooth {
sidebar_list.push(CONNECTIVITY_SIDEBAR);
}
if wifi {
sidebar_list.push(WIFI_SIDEBAR);
};
if bluetooth {
sidebar_list.push(BLUETOOTH_SIDEBAR);
};
if audio {
sidebar_list.push(AUDIO_SIDEBAR);
sidebar_list.push(SINK_SIDEBAR);
sidebar_list.push(SOURCE_SIDEBAR);
}
let mut plugin_sidebar_list = vec![];
unsafe {
for plugin in FRONTEND_PLUGINS.iter() {
let plugin_capabilities = &plugin.capabilities;
(plugin.frontend_startup)();
let (sidebar_info, plugin_boxes) = (plugin.frontend_data)();
let listeners = self_imp.listeners.clone();
if plugin_capabilities.1 {
let mut found = false;
for capability in plugin_capabilities.0.iter() {
if capabilities.contains(&capability.to_string()) {
found = true;
break;
}
}
if !found {
continue;
}
}
let event = Rc::new(
move |reset_main: FlowBox,
position: Rc<RefCell<Position>>,
@ -191,6 +196,7 @@ impl ReSetWindow {
}
HANDLE_VOLUME_CLICK(
&self_imp.capabilities,
self_imp.listeners.clone(),
self_imp.reset_main.clone(),
self_imp.position.clone(),
@ -361,6 +367,7 @@ fn setup_callback(window: Rc<ReSetWindow>) -> Rc<ReSetWindow> {
let click_event = result.imp().on_click_event.borrow();
if let Some(event) = click_event.on_click_event {
event(
&imp.capabilities,
imp.listeners.clone(),
imp.reset_main.get(),
imp.position.clone(),

View file

@ -12,6 +12,7 @@ use gtk::{Button, CompositeTemplate, FlowBox, ListBox, SearchEntry};
use crate::components::base::error::ReSetError;
use crate::components::base::utils::{Listeners, Position};
use crate::components::utils::Capabilities;
use crate::components::wifi::wifi_box::WifiBox;
use crate::components::window::reset_window;
use crate::components::window::sidebar_entry::SidebarEntry;
@ -40,6 +41,7 @@ pub struct ReSetWindow {
pub listeners: Arc<Listeners>,
pub position: Rc<RefCell<Position>>,
pub error_popup: ReSetError,
pub capabilities: Capabilities,
}
unsafe impl Send for ReSetWindow {}

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.4"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.4"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.4"/>
@ -87,6 +87,15 @@
<property name="title">Available Devices</property>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="reset_bluetooth_saved_devices">
<property name="margin-bottom">5</property>
<property name="margin-end">5</property>
<property name="margin-start">5</property>
<property name="margin-top">10</property>
<property name="title">Saved Devices</property>
</object>
</child>
</object>
</child>
</object>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.0"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="libadwaita" version="1.4"/>
<object class="AdwComboRow" id="reset_card_entry">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<template class="resetError" parent="GtkPopover">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.4"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.0"/>
<template class="resetListBoxRow" parent="GtkListBoxRow">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gio" version="2.0"/>
<requires lib="gtk" version="4.12"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.4"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<template class="resetPopup" parent="GtkPopover">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="libadwaita" version="1.0"/>
<template class="resetSavedWifiEntry" parent="AdwActionRow">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.0"/>
<template class="resetSettingBox" parent="GtkBox">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkShortcutsWindow" id="help_overlay">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.0"/>
<template class="resetSidebarEntry" parent="GtkListBoxRow">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.3"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.3"/>

View file

@ -152,6 +152,7 @@
(10,212,"AdwActionRow","reset_bluetooth_main_tab",208,None,None,None,None,None,None),
(10,213,"GtkImage",None,212,None,None,None,None,None,None),
(10,214,"resetError","error",1,None,None,None,2,None,None),
(10,215,"AdwPreferencesGroup","reset_bluetooth_saved_devices",121,None,None,None,3,None,None),
(11,1,"AdwActionRow","resetBluetoothEntry",None,None,None,None,None,None,None),
(12,11,"GtkBox","resetAudioInput",None,None,None,None,None,None,None),
(12,12,"GtkLabel",None,11,None,None,None,None,None,None),
@ -590,6 +591,11 @@
(10,213,"GtkWidget","halign","end",None,None,None,None,None,None,None,None,None),
(10,213,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
(10,213,"GtkWidget","margin-end","5",None,None,None,None,None,None,None,None,None),
(10,215,"AdwPreferencesGroup","title","Saved Devices",None,None,None,None,None,None,None,None,None),
(10,215,"GtkWidget","margin-bottom","5",None,None,None,None,None,None,None,None,None),
(10,215,"GtkWidget","margin-end","5",None,None,None,None,None,None,None,None,None),
(10,215,"GtkWidget","margin-start","5",None,None,None,None,None,None,None,None,None),
(10,215,"GtkWidget","margin-top","10",None,None,None,None,None,None,None,None,None),
(11,1,"GtkWidget","margin-start","5",None,None,None,None,None,None,None,None,None),
(11,32,"GtkListBoxRow","child",None,None,None,None,None,39,None,None,None,None),
(11,32,"GtkWidget","margin-start","5",None,None,None,None,None,None,None,None,None),

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.6"/>
<requires lib="libadwaita" version="1.4"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.2"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="libadwaita" version="1.0"/>
<template class="resetWifiEntry" parent="AdwActionRow">

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.4"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.17.3 -->
<!-- Created with Cambalache 0.90.1 -->
<interface>
<requires lib="gtk" version="4.12"/>
<requires lib="libadwaita" version="1.2"/>