From c619284146aa68f44018166efd69490635d8ffb9 Mon Sep 17 00:00:00 2001 From: Fabio Lenherr / DashieTM Date: Wed, 15 Nov 2023 02:35:20 +0100 Subject: [PATCH] feat: Add default Sink and Source Switching --- src/components/input/sourceBox.rs | 6 +++- src/components/input/sourceBoxImpl.rs | 3 +- src/components/input/sourceEntry.rs | 36 +++++++++++++++++++++-- src/components/output/sinkBox.rs | 6 +++- src/components/output/sinkBoxImpl.rs | 3 +- src/components/output/sinkEntry.rs | 41 +++++++++++++++++++++++---- 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/src/components/input/sourceBox.rs b/src/components/input/sourceBox.rs index e64ab96..4fd1ff4 100644 --- a/src/components/input/sourceBox.rs +++ b/src/components/input/sourceBox.rs @@ -72,7 +72,11 @@ pub fn populate_sources(output_box: Arc) { output_box_imp.resetVolumePercentage.set_text(&percentage); output_box_imp.resetVolumeSlider.set_value(*volume as f64); for stream in sinks { - let entry = ListEntry::new(&SourceEntry::new(stream)); + let mut is_default = false; + if output_box_imp.resetDefaultSource.borrow().name == stream.name { + is_default = true; + } + let entry = ListEntry::new(&SourceEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream)); entry.set_activatable(false); output_box_imp.resetSources.append(&entry); } diff --git a/src/components/input/sourceBoxImpl.rs b/src/components/input/sourceBoxImpl.rs index 6e7ba7a..d127965 100644 --- a/src/components/input/sourceBoxImpl.rs +++ b/src/components/input/sourceBoxImpl.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex}; use crate::components::base::listEntry::ListEntry; use crate::components::input::sourceBox; use gtk::subclass::prelude::*; -use gtk::{glib, CompositeTemplate, DropDown, TemplateChild}; +use gtk::{glib, CompositeTemplate, DropDown, TemplateChild, CheckButton}; use gtk::{prelude::*, Button, Label, ProgressBar, Scale}; use ReSet_Lib::audio::audio::{OutputStream, Source}; @@ -33,6 +33,7 @@ pub struct SourceBox { pub resetOutputStreamButton: TemplateChild, #[template_child] pub resetOutputStreams: TemplateChild, + pub resetDefaultCheckButton: Arc, pub resetDefaultSource: Arc>, pub resetSourceList: Arc>>, pub resetOutputStreamList: Arc>>, diff --git a/src/components/input/sourceEntry.rs b/src/components/input/sourceEntry.rs index 7b27e2b..d7d668a 100644 --- a/src/components/input/sourceEntry.rs +++ b/src/components/input/sourceEntry.rs @@ -1,15 +1,17 @@ use std::cell::RefCell; use std::sync::Arc; +use std::thread; use std::time::Duration; use adw::glib; use adw::glib::Object; -use adw::prelude::{ButtonExt, RangeExt}; +use adw::prelude::{ButtonExt, RangeExt, CheckButtonExt}; use dbus::blocking::Connection; use dbus::Error; use glib::subclass::types::ObjectSubclassIsExt; use glib::{clone, Propagation}; use ReSet_Lib::audio::audio::Source; +use gtk::CheckButton; use super::sourceEntryImpl; @@ -20,7 +22,7 @@ glib::wrapper! { } impl SourceEntry { - pub fn new(stream: Source) -> Self { + pub fn new(is_default: bool, check_group: Arc, stream: Source) -> Self { let obj: Self = Object::builder().build(); // TODO use event callback for progress bar -> this is the "im speaking" indicator // TODO map the slider to volume @@ -30,6 +32,7 @@ impl SourceEntry { { let imp = obj.imp(); imp.resetSourceName.set_text(stream.name.clone().as_str()); + let name = Arc::new(stream.name.clone()); let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32)); let fraction = (*volume as f64 / 655.36).round(); let percentage = (fraction).to_string() + "%"; @@ -49,6 +52,18 @@ impl SourceEntry { Propagation::Proceed }), ); + imp.resetSelectedSource.set_group(Some(&*check_group)); + // check_group.set_group(Some(&*imp.resetSelectedSink)); + if is_default { + imp.resetSelectedSource.set_active(true); + } else { + imp.resetSelectedSource.set_active(false); + } + imp.resetSelectedSource.connect_toggled(move |button| { + if button.is_active() { + set_default_source(name.clone()); + } + }); imp.resetSourceMute .connect_clicked(clone!(@weak imp => move |_| { let stream = imp.stream.clone(); @@ -102,3 +117,20 @@ pub fn toggle_source_mute(index: u32, muted: bool) -> bool { } res.unwrap().0 } + +pub fn set_default_source(name: Arc) { + thread::spawn(move || { + let conn = Connection::new_session().unwrap(); + let proxy = conn.with_proxy( + "org.xetibo.ReSet", + "/org/xetibo/ReSet", + Duration::from_millis(1000), + ); + let res: Result<(bool,), Error> = + proxy.method_call("org.xetibo.ReSet", "SetDefaultSink", (name.as_str(),)); + if res.is_err() { + return; + } + // handle change + }); +} diff --git a/src/components/output/sinkBox.rs b/src/components/output/sinkBox.rs index 8df1c28..e47e2f7 100644 --- a/src/components/output/sinkBox.rs +++ b/src/components/output/sinkBox.rs @@ -73,7 +73,11 @@ pub fn populate_sinks(output_box: Arc) { output_box_imp.resetVolumeSlider.set_value(*volume as f64); for stream in sinks { // TODO create sink handler -> currently only allows input streams - let entry = ListEntry::new(&SinkEntry::new(stream)); + let mut is_default = false; + if output_box_imp.resetDefaultSink.borrow().name == stream.name { + is_default = true; + } + let entry = ListEntry::new(&SinkEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream)); entry.set_activatable(false); output_box_imp.resetSinks.append(&entry); } diff --git a/src/components/output/sinkBoxImpl.rs b/src/components/output/sinkBoxImpl.rs index f8c79ca..3b6eac7 100644 --- a/src/components/output/sinkBoxImpl.rs +++ b/src/components/output/sinkBoxImpl.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex}; use crate::components::base::listEntry::ListEntry; use crate::components::output::inputStreamEntry::InputStreamEntry; use gtk::subclass::prelude::*; -use gtk::{glib, Box, Button, CompositeTemplate, DropDown, Label, TemplateChild}; +use gtk::{glib, Box, Button, CompositeTemplate, DropDown, Label, TemplateChild, CheckButton}; use gtk::{prelude::*, ProgressBar, Scale}; use ReSet_Lib::audio::audio::{InputStream, Sink}; @@ -33,6 +33,7 @@ pub struct SinkBox { pub resetInputStreamButton: TemplateChild, #[template_child] pub resetInputStreams: TemplateChild, + pub resetDefaultCheckButton: Arc, pub resetDefaultSink: Arc>, pub resetSinkList: Arc>>, pub resetInputStreamList: Arc>>, diff --git a/src/components/output/sinkEntry.rs b/src/components/output/sinkEntry.rs index b323319..4563c8f 100644 --- a/src/components/output/sinkEntry.rs +++ b/src/components/output/sinkEntry.rs @@ -1,14 +1,15 @@ -use std::cell::RefCell; use std::sync::Arc; +use std::thread; use std::time::Duration; use adw::glib; use adw::glib::Object; -use adw::prelude::{ButtonExt, RangeExt}; +use adw::prelude::{ButtonExt, CheckButtonExt, RangeExt}; use dbus::blocking::Connection; use dbus::Error; use glib::subclass::types::ObjectSubclassIsExt; use glib::{clone, Propagation}; +use gtk::CheckButton; use ReSet_Lib::audio::audio::Sink; use super::sinkEntryImpl; @@ -20,16 +21,14 @@ glib::wrapper! { } impl SinkEntry { - pub fn new(stream: Sink) -> Self { + pub fn new(is_default: bool, check_group: Arc, stream: Sink) -> Self { let obj: Self = Object::builder().build(); // TODO use event callback for progress bar -> this is the "im speaking" indicator - // TODO map the slider to volume - // TODO properly use volume fraction - // TODO map mute to callback // TODO map dropdown { let imp = obj.imp(); imp.resetSinkName.set_text(stream.name.clone().as_str()); + let name = Arc::new(stream.name.clone()); let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32)); let fraction = (*volume as f64 / 655.36).round(); let percentage = (fraction).to_string() + "%"; @@ -49,6 +48,18 @@ impl SinkEntry { Propagation::Proceed }), ); + imp.resetSelectedSink.set_group(Some(&*check_group)); + // check_group.set_group(Some(&*imp.resetSelectedSink)); + if is_default { + imp.resetSelectedSink.set_active(true); + } else { + imp.resetSelectedSink.set_active(false); + } + imp.resetSelectedSink.connect_toggled(move |button| { + if button.is_active() { + set_default_sink(name.clone()); + } + }); imp.resetSinkMute .connect_clicked(clone!(@weak imp => move |_| { let stream = imp.stream.clone(); @@ -102,3 +113,21 @@ pub fn toggle_sink_mute(index: u32, muted: bool) -> bool { } res.unwrap().0 } + +pub fn set_default_sink(name: Arc) { + thread::spawn(move || { + dbg!(name.clone()); + let conn = Connection::new_session().unwrap(); + let proxy = conn.with_proxy( + "org.xetibo.ReSet", + "/org/xetibo/ReSet", + Duration::from_millis(1000), + ); + let res: Result<(bool,), Error> = + proxy.method_call("org.xetibo.ReSet", "SetDefaultSink", (name.as_str(),)); + if res.is_err() { + return; + } + // handle change + }); +}