added menu functionality (default fuzzel)
This commit is contained in:
+12
-9
@@ -8,7 +8,7 @@ use std::process::Command;
|
||||
pub struct AudioModule;
|
||||
|
||||
impl WaybarModule for AudioModule {
|
||||
fn run(&self, _config: &Config, _state: &SharedState, args: &[&str]) -> Result<WaybarOutput> {
|
||||
fn run(&self, config: &Config, _state: &SharedState, args: &[&str]) -> Result<WaybarOutput> {
|
||||
let target_type = args.first().unwrap_or(&"sink");
|
||||
let action = args.get(1).unwrap_or(&"show");
|
||||
|
||||
@@ -23,23 +23,21 @@ impl WaybarModule for AudioModule {
|
||||
});
|
||||
}
|
||||
"show" | _ => {
|
||||
self.get_status(target_type)
|
||||
self.get_status(config, target_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AudioModule {
|
||||
fn get_status(&self, target_type: &str) -> Result<WaybarOutput> {
|
||||
fn get_status(&self, config: &Config, target_type: &str) -> Result<WaybarOutput> {
|
||||
let target = if target_type == "sink" { "@DEFAULT_AUDIO_SINK@" } else { "@DEFAULT_AUDIO_SOURCE@" };
|
||||
|
||||
// Get volume and mute status via wpctl (faster than pactl for this)
|
||||
let output = Command::new("wpctl")
|
||||
.args(["get-volume", target])
|
||||
.output()?;
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
|
||||
// Output format: "Volume: 0.50" or "Volume: 0.50 [MUTED]"
|
||||
let parts: Vec<&str> = stdout.trim().split_whitespace().collect();
|
||||
if parts.len() < 2 {
|
||||
return Err(anyhow!("Could not parse wpctl output: {}", stdout));
|
||||
@@ -59,7 +57,8 @@ impl AudioModule {
|
||||
|
||||
let (text, class) = if muted {
|
||||
let icon = if target_type == "sink" { "" } else { "" };
|
||||
(format!("{} {}", name, icon), "muted")
|
||||
let format_str = if target_type == "sink" { &config.audio.format_sink_muted } else { &config.audio.format_source_muted };
|
||||
(format_str.replace("{name}", &name).replace("{icon}", icon), "muted")
|
||||
} else {
|
||||
let icon = if target_type == "sink" {
|
||||
if display_vol <= 30 { "" }
|
||||
@@ -68,7 +67,13 @@ impl AudioModule {
|
||||
} else {
|
||||
""
|
||||
};
|
||||
(format!("{} {}% {}", name, display_vol, icon), "unmuted")
|
||||
let format_str = if target_type == "sink" { &config.audio.format_sink_unmuted } else { &config.audio.format_source_unmuted };
|
||||
let t = format_str
|
||||
.replace("{name}", &name)
|
||||
.replace("{icon}", icon)
|
||||
.replace("{volume:>3}", &format!("{:>3}", display_vol))
|
||||
.replace("{volume}", &format!("{}", display_vol));
|
||||
(t, "unmuted")
|
||||
};
|
||||
|
||||
Ok(WaybarOutput {
|
||||
@@ -80,7 +85,6 @@ impl AudioModule {
|
||||
}
|
||||
|
||||
fn get_description(&self, target_type: &str) -> Result<String> {
|
||||
// Get the default device name
|
||||
let info_output = Command::new("pactl").arg("info").output()?;
|
||||
let info_stdout = String::from_utf8_lossy(&info_output.stdout);
|
||||
let search_key = if target_type == "sink" { "Default Sink:" } else { "Default Source:" };
|
||||
@@ -91,7 +95,6 @@ impl AudioModule {
|
||||
.map(|s| s.trim())
|
||||
.ok_or_else(|| anyhow!("Default {} not found", target_type))?;
|
||||
|
||||
// Get the description of that device
|
||||
let list_cmd = if target_type == "sink" { "sinks" } else { "sources" };
|
||||
let list_output = Command::new("pactl").args(["list", list_cmd]).output()?;
|
||||
let list_stdout = String::from_utf8_lossy(&list_output.stdout);
|
||||
|
||||
+7
-9
@@ -8,7 +8,7 @@ use std::process::Command;
|
||||
pub struct BtModule;
|
||||
|
||||
impl WaybarModule for BtModule {
|
||||
fn run(&self, _config: &Config, _state: &SharedState, args: &[&str]) -> Result<WaybarOutput> {
|
||||
fn run(&self, config: &Config, _state: &SharedState, args: &[&str]) -> Result<WaybarOutput> {
|
||||
let action = args.first().unwrap_or(&"show");
|
||||
|
||||
if *action == "disconnect" {
|
||||
@@ -23,12 +23,11 @@ impl WaybarModule for BtModule {
|
||||
});
|
||||
}
|
||||
|
||||
// Check if bluetooth is powered on
|
||||
if let Ok(output) = Command::new("bluetoothctl").arg("show").output() {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
if stdout.contains("Powered: no") {
|
||||
return Ok(WaybarOutput {
|
||||
text: " Off".to_string(),
|
||||
text: config.bt.format_disabled.clone(),
|
||||
tooltip: Some("Bluetooth Disabled".to_string()),
|
||||
class: Some("disabled".to_string()),
|
||||
percentage: None,
|
||||
@@ -64,16 +63,17 @@ impl WaybarModule for BtModule {
|
||||
battery.map(|b| format!("{}%", b)).unwrap_or_else(|| "N/A".to_string())
|
||||
);
|
||||
|
||||
let text = config.bt.format_connected.replace("{alias}", &alias);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text: format!("{} ", alias),
|
||||
text,
|
||||
tooltip: Some(tooltip),
|
||||
class: Some("connected".to_string()),
|
||||
percentage: battery,
|
||||
})
|
||||
} else {
|
||||
// No device connected but Bluetooth is on
|
||||
Ok(WaybarOutput {
|
||||
text: "".to_string(),
|
||||
text: config.bt.format_disconnected.clone(),
|
||||
tooltip: Some("Bluetooth On (Disconnected)".to_string()),
|
||||
class: Some("disconnected".to_string()),
|
||||
percentage: None,
|
||||
@@ -83,7 +83,6 @@ impl WaybarModule for BtModule {
|
||||
}
|
||||
|
||||
fn find_audio_device() -> Option<String> {
|
||||
// 1. Try to check if current default sink is a bluetooth device
|
||||
if let Ok(output) = Command::new("pactl").arg("get-default-sink").output() {
|
||||
let sink = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if sink.starts_with("bluez_output.") {
|
||||
@@ -94,7 +93,6 @@ fn find_audio_device() -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback: Search bluetoothctl for connected devices with Audio Sink UUID
|
||||
if let Ok(output) = Command::new("bluetoothctl").args(["devices", "Connected"]).output() {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
for line in stdout.lines() {
|
||||
@@ -104,7 +102,7 @@ fn find_audio_device() -> Option<String> {
|
||||
let mac = parts[1];
|
||||
if let Ok(info) = Command::new("bluetoothctl").args(["info", mac]).output() {
|
||||
let info_str = String::from_utf8_lossy(&info.stdout);
|
||||
if info_str.contains("0000110b-0000-1000-8000-00805f9b34fb") { // Audio Sink UUID
|
||||
if info_str.contains("0000110b-0000-1000-8000-00805f9b34fb") {
|
||||
return Some(mac.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
+15
-21
@@ -20,56 +20,48 @@ impl WaybarModule for BudsModule {
|
||||
let next_mode = match current_mode.as_str() {
|
||||
"active" => "aware",
|
||||
"aware" => "off",
|
||||
_ => "active", // default or off goes to active
|
||||
_ => "active",
|
||||
};
|
||||
|
||||
Command::new("pbpctrl").args(["set", "anc", next_mode]).status()?;
|
||||
return Ok(WaybarOutput {
|
||||
text: String::new(),
|
||||
tooltip: None,
|
||||
class: None,
|
||||
percentage: None,
|
||||
tooltip: None, class: None, percentage: None,
|
||||
});
|
||||
}
|
||||
"connect" => {
|
||||
Command::new("bluetoothctl").args(["connect", mac]).status()?;
|
||||
return Ok(WaybarOutput {
|
||||
text: String::new(),
|
||||
tooltip: None,
|
||||
class: None,
|
||||
percentage: None,
|
||||
tooltip: None, class: None, percentage: None,
|
||||
});
|
||||
}
|
||||
"disconnect" => {
|
||||
Command::new("bluetoothctl").args(["disconnect", mac]).status()?;
|
||||
return Ok(WaybarOutput {
|
||||
text: String::new(),
|
||||
tooltip: None,
|
||||
class: None,
|
||||
percentage: None,
|
||||
tooltip: None, class: None, percentage: None,
|
||||
});
|
||||
}
|
||||
"show" | _ => {}
|
||||
}
|
||||
|
||||
// Check if connected
|
||||
let bt_info = Command::new("bluetoothctl").args(["info", mac]).output()?;
|
||||
let bt_str = String::from_utf8_lossy(&bt_info.stdout);
|
||||
|
||||
if !bt_str.contains("Connected: yes") {
|
||||
return Ok(WaybarOutput {
|
||||
text: "<span size='large'></span>".to_string(),
|
||||
text: config.buds.format_disconnected.clone(),
|
||||
tooltip: Some("Pixel Buds Pro 2 not connected".to_string()),
|
||||
class: Some("disconnected".to_string()),
|
||||
percentage: None,
|
||||
});
|
||||
}
|
||||
|
||||
// Get battery output
|
||||
let bat_cmd = Command::new("pbpctrl").args(["show", "battery"]).output();
|
||||
if bat_cmd.is_err() || !bat_cmd.as_ref().unwrap().status.success() {
|
||||
return Ok(WaybarOutput {
|
||||
text: "<span size='large'></span>".to_string(),
|
||||
text: config.buds.format_disconnected.clone(),
|
||||
tooltip: Some("Pixel Buds Pro 2 connected (No Data)".to_string()),
|
||||
class: Some("disconnected".to_string()),
|
||||
percentage: None,
|
||||
@@ -92,16 +84,13 @@ impl WaybarModule for BudsModule {
|
||||
if left_bud == "unknown" && right_bud == "unknown" {
|
||||
return Ok(WaybarOutput {
|
||||
text: "{}".to_string(),
|
||||
tooltip: None,
|
||||
class: None,
|
||||
percentage: None,
|
||||
tooltip: None, class: None, percentage: None,
|
||||
});
|
||||
}
|
||||
|
||||
let left_display = if left_bud == "unknown" { "L: ---".to_string() } else { format!("L: {}", left_bud) };
|
||||
let right_display = if right_bud == "unknown" { "R: ---".to_string() } else { format!("R: {}", right_bud) };
|
||||
let left_display = if left_bud == "unknown" { "---".to_string() } else { format!("{}%", left_bud) };
|
||||
let right_display = if right_bud == "unknown" { "---".to_string() } else { format!("{}%", right_bud) };
|
||||
|
||||
// Get ANC info
|
||||
let anc_cmd = Command::new("pbpctrl").args(["get", "anc"]).output()?;
|
||||
let current_mode = String::from_utf8_lossy(&anc_cmd.stdout).trim().to_string();
|
||||
|
||||
@@ -112,8 +101,13 @@ impl WaybarModule for BudsModule {
|
||||
_ => ("?", "anc-unknown"),
|
||||
};
|
||||
|
||||
let text = config.buds.format
|
||||
.replace("{left}", &left_display)
|
||||
.replace("{right}", &right_display)
|
||||
.replace("{anc}", anc_icon);
|
||||
|
||||
Ok(WaybarOutput {
|
||||
text: format!("{} | {} | {}", left_display, right_display, anc_icon),
|
||||
text,
|
||||
tooltip: Some("Pixel Buds Pro 2".to_string()),
|
||||
class: Some(class.to_string()),
|
||||
percentage: None,
|
||||
|
||||
+4
-8
@@ -8,19 +8,15 @@ use std::process::Command;
|
||||
pub struct GameModule;
|
||||
|
||||
impl WaybarModule for GameModule {
|
||||
fn run(&self, _config: &Config, _state: &SharedState, _args: &[&str]) -> Result<WaybarOutput> {
|
||||
fn run(&self, config: &Config, _state: &SharedState, _args: &[&str]) -> Result<WaybarOutput> {
|
||||
let output = Command::new("hyprctl")
|
||||
.args(["getoption", "animations:enabled", "-j"])
|
||||
.output();
|
||||
|
||||
let mut is_gamemode = false; // default to deactivated
|
||||
let mut is_gamemode = false;
|
||||
|
||||
if let Ok(out) = output {
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
// The JSON from hyprctl looks like {"int": 0, "float": 0.0, ...}
|
||||
// If int is 0, animations are disabled (Gamemode active)
|
||||
// If int is 1, animations are enabled (Gamemode deactivated)
|
||||
if stdout.contains("\"int\": 0") {
|
||||
is_gamemode = true;
|
||||
}
|
||||
@@ -28,14 +24,14 @@ impl WaybarModule for GameModule {
|
||||
|
||||
if is_gamemode {
|
||||
Ok(WaybarOutput {
|
||||
text: "<span size='large'></span>".to_string(),
|
||||
text: config.game.format_active.clone(),
|
||||
tooltip: Some("Gamemode activated".to_string()),
|
||||
class: Some("active".to_string()),
|
||||
percentage: None,
|
||||
})
|
||||
} else {
|
||||
Ok(WaybarOutput {
|
||||
text: "<span size='large'></span>".to_string(),
|
||||
text: config.game.format_inactive.clone(),
|
||||
tooltip: Some("Gamemode deactivated".to_string()),
|
||||
class: None,
|
||||
percentage: None,
|
||||
|
||||
Reference in New Issue
Block a user