Use tracker instead of weird clear-based system.

This commit is contained in:
Lucy 2022-03-28 10:44:00 -04:00
parent 4c562d041f
commit f5e589e724
No known key found for this signature in database
GPG key ID: EBC517FAD666BBF1
3 changed files with 56 additions and 31 deletions

1
Cargo.lock generated
View file

@ -243,6 +243,7 @@ dependencies = [
"libpulse-binding", "libpulse-binding",
"pulsectl-rs", "pulsectl-rs",
"relm4", "relm4",
"tracker",
] ]
[[package]] [[package]]

View file

@ -11,5 +11,6 @@ libcosmic-widgets = { git = "https://github.com/pop-os/libcosmic", branch = "luc
libpulse-binding = "2.26.0" libpulse-binding = "2.26.0"
pulsectl-rs = "0.3.2" pulsectl-rs = "0.3.2"
relm4 = { git = "https://github.com/AaronErhardt/relm4", branch = "new-approach", features = ["macros"] } relm4 = { git = "https://github.com/AaronErhardt/relm4", branch = "new-approach", features = ["macros"] }
tracker = "0.1.1"
[features] [features]

View file

@ -5,7 +5,10 @@ use libpulse_binding::{
volume::Volume, volume::Volume,
}; };
use pulsectl::{ use pulsectl::{
controllers::{types::DeviceInfo, AppControl, DeviceControl, SinkController, SourceController}, controllers::{
types::{ApplicationInfo, DeviceInfo},
AppControl, DeviceControl, SinkController, SourceController,
},
Handler, Handler,
}; };
use relm4::{ use relm4::{
@ -20,6 +23,7 @@ use relm4::{
view, ComponentParts, RelmContainerExt, Sender, SimpleComponent, view, ComponentParts, RelmContainerExt, Sender, SimpleComponent,
}; };
use std::rc::Rc; use std::rc::Rc;
use tracker::track;
pub enum AppInput { pub enum AppInput {
Inputs, Inputs,
@ -29,13 +33,20 @@ pub enum AppInput {
NowPlaying, NowPlaying,
} }
#[track]
pub struct App { pub struct App {
#[no_eq]
default_input: Option<DeviceInfo>, default_input: Option<DeviceInfo>,
#[no_eq]
inputs: Vec<DeviceInfo>, inputs: Vec<DeviceInfo>,
#[no_eq]
default_output: Option<DeviceInfo>, default_output: Option<DeviceInfo>,
#[no_eq]
outputs: Vec<DeviceInfo>, outputs: Vec<DeviceInfo>,
#[no_eq]
now_playing: Vec<ApplicationInfo>,
#[do_not_track]
handler: Handler, handler: Handler,
update_now_playing: bool,
} }
impl Default for App { impl Default for App {
@ -48,6 +59,7 @@ impl Default for App {
SinkController::create().expect("failed to create output controller"); SinkController::create().expect("failed to create output controller");
let default_output = output_controller.get_default_device().ok(); let default_output = output_controller.get_default_device().ok();
let outputs = output_controller.list_devices().unwrap_or_default(); let outputs = output_controller.list_devices().unwrap_or_default();
let now_playing = output_controller.list_applications().unwrap_or_default();
let handler = Handler::connect("com.system76.cosmic.applets.audio") let handler = Handler::connect("com.system76.cosmic.applets.audio")
.expect("failed to connect to pulse"); .expect("failed to connect to pulse");
relm4::spawn_local(clone!(@weak handler.mainloop as main_loop => async move { relm4::spawn_local(clone!(@weak handler.mainloop as main_loop => async move {
@ -62,8 +74,9 @@ impl Default for App {
inputs, inputs,
default_output, default_output,
outputs, outputs,
now_playing,
handler, handler,
update_now_playing: false, tracker: 0,
} }
} }
} }
@ -89,7 +102,7 @@ impl App {
} }
} }
fn update_default_input(&mut self) { fn refresh_default_input(&mut self) {
let mut input_controller = let mut input_controller =
SourceController::create().expect("failed to create input controller"); SourceController::create().expect("failed to create input controller");
self.default_input = match self.default_input.as_ref() { self.default_input = match self.default_input.as_ref() {
@ -101,7 +114,7 @@ impl App {
}; };
} }
fn update_default_output(&mut self) { fn refresh_default_output(&mut self) {
let mut output_controller = let mut output_controller =
SinkController::create().expect("failed to create output controller"); SinkController::create().expect("failed to create output controller");
self.default_output = match self.default_output.as_ref() { self.default_output = match self.default_output.as_ref() {
@ -133,15 +146,18 @@ impl App {
context.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE, |_| {}); context.subscribe(InterestMaskSet::SINK | InterestMaskSet::SOURCE, |_| {});
} }
fn update_inputs(&self, widgets: &AppWidgets) { fn refresh_input_list(&mut self) {
let mut input_controller = let mut input_controller =
SourceController::create().expect("failed to create input controller"); SourceController::create().expect("failed to create input controller");
let inputs = input_controller.list_devices().unwrap_or_default(); self.set_inputs(input_controller.list_devices().unwrap_or_default());
}
fn refresh_input_widgets(&self, widgets: &AppWidgets) {
while let Some(row) = widgets.inputs.row_at_index(0) { while let Some(row) = widgets.inputs.row_at_index(0) {
widgets.inputs.remove(&row); widgets.inputs.remove(&row);
} }
for input in inputs { for input in self.get_inputs() {
let input = Rc::new(input); let input = Rc::new(input.clone());
let name = match &input.name { let name = match &input.name {
Some(name) => name.to_owned(), Some(name) => name.to_owned(),
None => continue, // Why doesn't this have a name? Whatever, it's invalid. None => continue, // Why doesn't this have a name? Whatever, it's invalid.
@ -166,15 +182,18 @@ impl App {
} }
} }
fn update_outputs(&self, widgets: &AppWidgets) { fn refresh_output_list(&mut self) {
let mut output_controller = let mut output_controller =
SinkController::create().expect("failed to create output controller"); SinkController::create().expect("failed to create output controller");
let outputs = output_controller.list_devices().unwrap_or_default(); self.set_outputs(output_controller.list_devices().unwrap_or_default());
}
fn refresh_output_widgets(&self, widgets: &AppWidgets) {
while let Some(row) = widgets.outputs.row_at_index(0) { while let Some(row) = widgets.outputs.row_at_index(0) {
widgets.outputs.remove(&row); widgets.outputs.remove(&row);
} }
for output in outputs { for output in self.get_outputs() {
let output = Rc::new(output); let output = Rc::new(output.clone());
let name = match &output.name { let name = match &output.name {
Some(name) => name.to_owned(), Some(name) => name.to_owned(),
None => continue, // Why doesn't this have a name? Whatever, it's invalid. None => continue, // Why doesn't this have a name? Whatever, it's invalid.
@ -200,21 +219,24 @@ impl App {
} }
} }
fn update_now_playing(&self, widgets: &AppWidgets) { fn refresh_now_playing(&mut self) {
let mut output_controller = let mut output_controller =
SinkController::create().expect("failed to create output controller"); SinkController::create().expect("failed to create output controller");
let apps = output_controller.list_applications().unwrap_or_default(); self.set_now_playing(output_controller.list_applications().unwrap_or_default());
}
fn refresh_now_playing_widgets(&self, widgets: &AppWidgets) {
while let Some(row) = widgets.playing_apps.row_at_index(0) { while let Some(row) = widgets.playing_apps.row_at_index(0) {
widgets.playing_apps.remove(&row); widgets.playing_apps.remove(&row);
} }
for app in apps { for app in self.get_now_playing() {
let icon_name = app let icon_name = app
.proplist .proplist
.get_str("application.icon_name") .get_str("application.icon_name")
.unwrap_or_default(); .unwrap_or_default();
let name = app.name.unwrap_or_default(); let name = app.name.clone().unwrap_or_default();
view! { view! {
GtkBox { item = GtkBox {
set_orientation: Orientation::Horizontal, set_orientation: Orientation::Horizontal,
append: icon = &Image { append: icon = &Image {
set_icon_name: Some(&icon_name), set_icon_name: Some(&icon_name),
@ -225,6 +247,7 @@ impl App {
} }
} }
} }
widgets.playing_apps.container_add(&item);
} }
} }
} }
@ -351,37 +374,37 @@ impl SimpleComponent for App {
&mut self, &mut self,
msg: Self::Input, msg: Self::Input,
_input: &Sender<Self::Input>, _input: &Sender<Self::Input>,
_ouput: &Sender<Self::Output>, _output: &Sender<Self::Output>,
) { ) {
self.reset();
match msg { match msg {
AppInput::Outputs => { AppInput::Outputs => {
self.outputs.clear(); self.refresh_output_list();
} }
AppInput::Inputs => { AppInput::Inputs => {
self.inputs.clear(); self.refresh_input_list();
} }
AppInput::InputVolume => { AppInput::InputVolume => {
self.update_default_input(); self.refresh_default_input();
} }
AppInput::OutputVolume => { AppInput::OutputVolume => {
self.update_default_output(); self.refresh_default_output();
} }
AppInput::NowPlaying => { AppInput::NowPlaying => {
self.update_now_playing = true; self.refresh_now_playing();
} }
} }
} }
fn pre_view() { fn pre_view() {
if self.outputs.is_empty() { if model.changed(App::outputs()) {
model.update_outputs(widgets); model.refresh_output_widgets(widgets);
} }
if self.inputs.is_empty() { if model.changed(App::inputs()) {
model.update_inputs(widgets); model.refresh_input_widgets(widgets);
} }
if self.update_now_playing { if model.changed(App::now_playing()) {
model.update_now_playing(widgets); model.refresh_now_playing_widgets(widgets);
self.update_now_playing = false;
} }
} }
} }