summaryrefslogtreecommitdiffstats
path: root/src/printer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/printer.rs')
-rw-r--r--src/printer.rs255
1 files changed, 0 insertions, 255 deletions
diff --git a/src/printer.rs b/src/printer.rs
deleted file mode 100644
index 5a6b0ae..0000000
--- a/src/printer.rs
+++ /dev/null
@@ -1,255 +0,0 @@
-use std::{collections::HashMap, sync::Arc, time::Duration};
-
-use futures_util::stream::StreamExt;
-use serde::{Deserialize, Serialize};
-use tokio::{
- sync::{watch::Sender, Mutex},
- task::{JoinHandle, JoinSet},
-};
-use zbus::{proxy::PropertyStream, zvariant::OwnedValue};
-
-use crate::{
- dbus::player::{PlaybackStatus, PlayerProxy},
- i3bar::Block,
- Result,
-};
-
-type StatusLock = Arc<Mutex<Status>>;
-
-const TICK_RATE: Duration = Duration::from_millis(500);
-
-const BLACK: &str = "#1d2021";
-const YELLOW: &str = "#fabd2f";
-const CYAN: &str = "#8ec07c";
-
-pub async fn printer(
- proxy: PlayerProxy<'static>,
- wtx: tokio::sync::watch::Sender<Status>,
-) -> Result<()> {
- let mut join_set: JoinSet<Result<()>> = JoinSet::new();
- let mut rotator = None;
-
- let status = Status {
- can_go_previous: proxy.can_go_previous().await.unwrap_or_default(),
- playback_status: proxy.playback_status().await.unwrap_or_default(),
- can_go_next: proxy.can_go_next().await.unwrap_or_default(),
- volume: proxy.volume().await.ok(),
- ..Default::default()
- };
-
- wtx.send_modify(|s| *s = status);
-
- process_metadata(
- wtx.clone(),
- proxy.metadata().await?,
- &mut rotator,
- &mut None,
- )
- .await;
-
- join_set.spawn(metadata(
- wtx.clone(),
- proxy.receive_metadata_changed().await,
- rotator,
- ));
-
- join_set.spawn(can_go_previous(
- wtx.clone(),
- proxy.receive_can_go_previous_changed().await,
- ));
-
- join_set.spawn(playback_state(
- wtx.clone(),
- proxy.receive_playback_status_changed().await,
- ));
-
- join_set.spawn(can_go_next(
- wtx.clone(),
- proxy.receive_can_go_next_changed().await,
- ));
-
- join_set.spawn(volume(wtx.clone(), proxy.receive_volume_changed().await));
-
- while let Some(res) = join_set.join_next().await {
- res??;
- }
-
- Ok(())
-}
-
-async fn process_metadata(
- wtx: Sender<Status>,
- metadata: HashMap<String, OwnedValue>,
- rotator: &mut Option<JoinHandle<Result<()>>>,
- old_title: &mut Option<String>,
-) {
- let title: Option<String> = metadata
- .get("xesam:title")
- .and_then(|o| o.try_to_owned().ok())
- .and_then(|o| o.try_into().ok());
-
- if *old_title == title {
- return;
- }
-
- *old_title = title.clone();
- let Some(title) = title else {
- wtx.send_modify(|s| {
- s.title = None;
- });
- return;
- };
-
- if title.len() > 10 {
- if let Some(h) = rotator.take() {
- h.abort()
- };
-
- let wtx = wtx.clone();
- *rotator = Some(tokio::spawn(async move {
- let mut interval = tokio::time::interval(TICK_RATE);
- let mut chars = title.chars().collect::<Vec<char>>();
- chars.push(' ');
- loop {
- interval.tick().await;
- wtx.send_modify(|s| s.title = Some(chars[0..10].iter().collect()));
- chars.rotate_left(1);
- }
- }));
- } else {
- wtx.send_modify(|s| s.title = Some(title));
- }
-}
-
-async fn metadata(
- wtx: Sender<Status>,
- mut stream: PropertyStream<'_, HashMap<String, OwnedValue>>,
- mut rotator: Option<JoinHandle<Result<()>>>,
-) -> Result<()> {
- let mut old_title = None;
- while let Some(signal) = stream.next().await {
- if let Ok(metadata) = signal.get().await {
- process_metadata(wtx.clone(), metadata, &mut rotator, &mut old_title).await
- };
- }
- Ok(())
-}
-
-async fn can_go_previous(wtx: Sender<Status>, mut stream: PropertyStream<'_, bool>) -> Result<()> {
- while let Some(signal) = stream.next().await {
- if let Ok(val) = signal.get().await {
- wtx.send_modify(|status| status.can_go_previous = val);
- };
- }
- Ok(())
-}
-
-async fn playback_state(
- wtx: Sender<Status>,
- mut stream: PropertyStream<'_, PlaybackStatus>,
-) -> Result<()> {
- while let Some(signal) = stream.next().await {
- if let Ok(val) = signal.get().await {
- let (color, background) = match val {
- PlaybackStatus::Playing => (Some(BLACK.into()), Some(CYAN.into())),
- PlaybackStatus::Paused => (Some(BLACK.into()), Some(YELLOW.into())),
- PlaybackStatus::Stopped => (None, None),
- };
-
- wtx.send_modify(|status| {
- status.playback_status = val;
- status.color = color;
- status.background = background;
- });
- }
- }
- Ok(())
-}
-
-async fn can_go_next(wtx: Sender<Status>, mut stream: PropertyStream<'_, bool>) -> Result<()> {
- while let Some(signal) = stream.next().await {
- if let Ok(val) = signal.get().await {
- wtx.send_modify(|status| status.can_go_next = val);
- };
- }
- Ok(())
-}
-
-async fn volume(wtx: Sender<Status>, mut stream: PropertyStream<'_, f64>) -> Result<()> {
- while let Some(signal) = stream.next().await {
- if let Ok(val) = signal.get().await {
- wtx.send_modify(|status| status.volume = Some(val));
- };
- }
- Ok(())
-}
-
-#[derive(Debug, Clone, Copy)]
-pub enum Component {
- Icon,
- Title,
- Prev,
- Play,
- Pause,
- Next,
- Volume,
- Space,
-}
-
-#[derive(Debug, Clone, Default, Serialize, Deserialize)]
-pub struct Status {
- title: Option<String>,
- can_go_previous: bool,
- playback_status: PlaybackStatus,
- can_go_next: bool,
- volume: Option<f64>,
- color: Option<String>,
- background: Option<String>,
-}
-
-impl Status {
- fn build(&mut self) -> Block {
- let mut full_text = String::new();
- full_text.push_str(" 󰝚 ");
-
- if let Some(title) = self.title.as_ref() {
- full_text.push_str(title);
- full_text.push(' ');
- }
-
- if self.can_go_previous {
- full_text.push_str("󰒮 ");
- }
-
- if self.playback_status == PlaybackStatus::Playing {
- full_text.push_str("󰏤 ");
- } else {
- full_text.push_str("󰐊 ");
- }
-
- if self.can_go_next {
- full_text.push_str("󰒭 ");
- }
-
- if let Some(volume) = self.volume.map(|v| (v * 100_f64) as u32) {
- match volume {
- v @ 66.. => full_text.push_str(&format!("󰕾 {v}% ")),
- v @ 33.. => full_text.push_str(&format!("󰖀 {v}% ")),
- v @ 0.. => full_text.push_str(&format!("󰕿 {v}% ")),
- }
- }
-
- let (color, background) = match self.playback_status {
- PlaybackStatus::Playing => (Some(BLACK.into()), Some(CYAN.into())),
- PlaybackStatus::Paused => (Some(BLACK.into()), Some(YELLOW.into())),
- PlaybackStatus::Stopped => (None, None),
- };
-
- Block {
- full_text,
- color,
- background,
- ..Default::default()
- }
- }
-}