Iimprove the articet

This commit is contained in:
Anas Elgarhy 2023-02-20 06:40:30 +02:00
parent b8af73ee0f
commit 9a5a93450a
No known key found for this signature in database
GPG key ID: 0501802A1D496528
6 changed files with 109 additions and 45 deletions

View file

@ -77,10 +77,12 @@ fn main() {
// Update the previous response. // Update the previous response.
previous_response = response; previous_response = response;
match notifications_handler.show_notification(events, &previous_response) { if !events.is_empty() {
Ok(_) => {} match notifications_handler.show_notification(events, &previous_response) {
Err(e) => { Ok(_) => {}
eprintln!("Error: {}", e); Err(e) => {
eprintln!("Error: {}", e);
}
} }
} }
} }

View file

@ -1,13 +1,13 @@
use crate::cmus::player_settings::{AAAMode, Shuffle}; use crate::cmus::player_settings::{AAAMode, PlayerSettings, Shuffle};
use crate::cmus::{Track, TrackStatus}; use crate::cmus::{Track, TrackStatus};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum CmusEvent { pub enum CmusEvent {
StatusChanged(Track), StatusChanged(Track, PlayerSettings),
TrackChanged(Track), TrackChanged(Track, PlayerSettings),
VolumeChanged { left: u8, right: u8 }, VolumeChanged(Track, PlayerSettings),
PositionChanged(u32), PositionChanged(Track, PlayerSettings),
ShuffleChanged(Shuffle), ShuffleChanged(Track, PlayerSettings),
RepeatChanged(bool), RepeatChanged(Track, PlayerSettings),
AAAMode(AAAMode), AAAMode(Track, PlayerSettings),
} }

View file

@ -12,12 +12,12 @@ use std::str::FromStr;
use thiserror::Error; use thiserror::Error;
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default, Clone)]
pub struct TrackMetadata { pub struct TrackMetadata {
tags: HashMap<String, String>, tags: HashMap<String, String>,
} }
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default, Clone)]
pub enum TrackStatus { pub enum TrackStatus {
Playing, Playing,
Paused, Paused,
@ -25,7 +25,7 @@ pub enum TrackStatus {
Stopped, Stopped,
} }
#[derive(Debug, TypedBuilder, PartialEq, Default)] #[derive(Debug, TypedBuilder, PartialEq, Default, Clone)]
pub struct Track { pub struct Track {
pub status: TrackStatus, pub status: TrackStatus,
pub path: String, pub path: String,

View file

@ -4,7 +4,7 @@ use log::{debug, info};
use std::num::ParseIntError; use std::num::ParseIntError;
use std::str::FromStr; use std::str::FromStr;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub struct PlayerSettings { pub struct PlayerSettings {
pub repeat: bool, pub repeat: bool,
pub repeat_current: bool, pub repeat_current: bool,
@ -13,7 +13,7 @@ pub struct PlayerSettings {
pub volume: Volume, pub volume: Volume,
} }
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default, Clone)]
pub enum Shuffle { pub enum Shuffle {
#[default] #[default]
Off, Off,
@ -21,13 +21,13 @@ pub enum Shuffle {
Albums, Albums,
} }
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default, Clone)]
pub struct Volume { pub struct Volume {
pub left: u8, pub left: u8,
pub right: u8, pub right: u8,
} }
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default, Clone)]
pub enum AAAMode { pub enum AAAMode {
#[default] #[default]
All, All,

View file

@ -51,7 +51,7 @@ impl CmusQueryResponse {
if self.track_row.is_empty() || self.player_settings_row.is_empty() { if self.track_row.is_empty() || self.player_settings_row.is_empty() {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
info!("Cmus response is empty, returning empty events"); info!("Cmus response is empty, returning empty events");
return Err(CmusError::NoEvents) return Ok(Vec::new())
} }
let mut events = Vec::new(); let mut events = Vec::new();
@ -59,6 +59,8 @@ impl CmusQueryResponse {
let track = self.track()?; let track = self.track()?;
let other_track = other.track()?; let other_track = other.track()?;
let other_player_settings = other.player_settings()?;
if track != other_track { if track != other_track {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!("Track changed: {:?} -> {:?}", other_track, track); debug!("Track changed: {:?} -> {:?}", other_track, track);
@ -66,7 +68,10 @@ impl CmusQueryResponse {
if track.path != other_track.path { if track.path != other_track.path {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!("Track changed: {:?} -> {:?}", other_track, track); debug!("Track changed: {:?} -> {:?}", other_track, track);
events.push(CmusEvent::TrackChanged(other_track)); events.push(CmusEvent::TrackChanged(
other_track.clone(),
other_player_settings.clone(),
));
// We don't need to check for other changes, since the track changed. // We don't need to check for other changes, since the track changed.
return Ok(events); return Ok(events);
} else if track.status != other_track.status { } else if track.status != other_track.status {
@ -75,19 +80,24 @@ impl CmusQueryResponse {
"Status changed: {:?} -> {:?}", "Status changed: {:?} -> {:?}",
other_track.status, track.status other_track.status, track.status
); );
events.push(CmusEvent::StatusChanged(track)); events.push(CmusEvent::StatusChanged(
track.clone(),
other_player_settings.clone(),
));
} else if track.position != other_track.position { } else if track.position != other_track.position {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!( debug!(
"Position changed: {:?} -> {:?}", "Position changed: {:?} -> {:?}",
other_track.position, track.position other_track.position, track.position
); );
events.push(CmusEvent::PositionChanged(other_track.position)); events.push(CmusEvent::PositionChanged(
track.clone(),
other_player_settings.clone(),
));
} }
} }
let player_settings = self.player_settings()?; let player_settings = self.player_settings()?;
let other_player_settings = other.player_settings()?;
if player_settings != other_player_settings { if player_settings != other_player_settings {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
@ -103,7 +113,10 @@ impl CmusQueryResponse {
other_player_settings.shuffle, player_settings.shuffle other_player_settings.shuffle, player_settings.shuffle
); );
events.push(CmusEvent::ShuffleChanged(player_settings.shuffle)); events.push(CmusEvent::ShuffleChanged(
other_track.clone(),
other_player_settings.clone(),
));
} }
if player_settings.repeat != other_player_settings.repeat { if player_settings.repeat != other_player_settings.repeat {
@ -113,7 +126,10 @@ impl CmusQueryResponse {
other_player_settings.repeat, player_settings.repeat other_player_settings.repeat, player_settings.repeat
); );
events.push(CmusEvent::RepeatChanged(player_settings.repeat)); events.push(CmusEvent::RepeatChanged(
other_track.clone(),
other_player_settings.clone(),
));
} }
if player_settings.aaa_mode != other_player_settings.aaa_mode { if player_settings.aaa_mode != other_player_settings.aaa_mode {
@ -123,7 +139,10 @@ impl CmusQueryResponse {
other_player_settings.aaa_mode, player_settings.aaa_mode other_player_settings.aaa_mode, player_settings.aaa_mode
); );
events.push(CmusEvent::AAAMode(player_settings.aaa_mode)); events.push(CmusEvent::AAAMode(
other_track.clone(),
other_player_settings.clone(),
));
} }
if player_settings.volume != other_player_settings.volume { if player_settings.volume != other_player_settings.volume {
@ -133,10 +152,7 @@ impl CmusQueryResponse {
other_player_settings.volume, player_settings.volume other_player_settings.volume, player_settings.volume
); );
events.push(CmusEvent::VolumeChanged { events.push(CmusEvent::VolumeChanged(other_track, other_player_settings));
left: player_settings.volume.left,
right: player_settings.volume.right,
});
} }
} }

View file

@ -1,4 +1,5 @@
use crate::cmus::events::CmusEvent; use crate::cmus::events::CmusEvent;
use crate::cmus::player_settings::PlayerSettings;
use crate::cmus::query::CmusQueryResponse; use crate::cmus::query::CmusQueryResponse;
use crate::cmus::{Track, TrackStatus}; use crate::cmus::{Track, TrackStatus};
use crate::settings::Settings; use crate::settings::Settings;
@ -7,6 +8,12 @@ use crate::{process_template_placeholders, track_cover, TrackCover};
use log::{debug, info}; use log::{debug, info};
use notify_rust::Notification; use notify_rust::Notification;
enum Action {
Show,
Update,
None,
}
pub struct NotificationsHandler { pub struct NotificationsHandler {
cover_set: bool, cover_set: bool,
notification: Notification, notification: Notification,
@ -33,26 +40,29 @@ impl NotificationsHandler {
//FIXME: Should check if the user has enabled the cover feature or use a static cover. //FIXME: Should check if the user has enabled the cover feature or use a static cover.
self.update_cover(&events[0], response); self.update_cover(&events[0], response);
let mut action = Action::None;
for event in events { for event in events {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
info!("event: {:?}", event); info!("event: {:?}", event);
match event { match event {
CmusEvent::StatusChanged(track) => { CmusEvent::StatusChanged(track, player_settings) => {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!("Status changed: {:?}", track.status); debug!("Status changed: {:?}", track.status);
self.build_status_notification(track); action = self.build_status_notification(track, player_settings);
self.notification.show()?;
} }
CmusEvent::TrackChanged(track) => { CmusEvent::TrackChanged(track, player_settings) => {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug!("Track changed: {:?}", track); debug!("Track changed: {:?}", track);
self.build_track_notification(track)? action = self.build_track_notification(track, player_settings);
} }
CmusEvent::VolumeChanged(track, player_settings)
if self.settings.show_player_notifications =>
{
action = self.build_volume_notification(track, player_settings);
}
/* /*
CmusEvent::VolumeChanged { left, right } if settings.show_player_notifications => {
build_volume_notification(left, right, settings, notification)?
}
CmusEvent::PositionChanged(position) => todo!(), CmusEvent::PositionChanged(position) => todo!(),
CmusEvent::ShuffleChanged(shuffle) if settings.show_player_notifications => { CmusEvent::ShuffleChanged(shuffle) if settings.show_player_notifications => {
build_shuffle_notification(shuffle, settings, notification)? build_shuffle_notification(shuffle, settings, notification)?
@ -66,12 +76,26 @@ impl NotificationsHandler {
*/ */
_ => {} _ => {}
} }
match action {
Action::Show => {
let _ = self.notification.show()?;
}
Action::None => {}
_ => todo!(),
};
} }
Ok(()) Ok(())
} }
#[inline(always)] #[inline(always)]
fn build_status_notification(&mut self, track: Track) { fn build_status_notification(
&mut self,
track: Track,
player_settings: PlayerSettings,
) -> Action {
// Set the summary and body of the notification. // Set the summary and body of the notification.
self.notification self.notification
.summary( .summary(
@ -83,25 +107,47 @@ impl NotificationsHandler {
.as_str(), .as_str(),
) )
.timeout(self.settings.status_notification_timeout as i32 * 1000); .timeout(self.settings.status_notification_timeout as i32 * 1000);
Action::Show
} }
#[inline(always)] #[inline(always)]
fn build_track_notification(&mut self, track: Track) -> Result<(), notify_rust::error::Error> { fn build_track_notification(
&mut self,
track: Track,
player_settings: PlayerSettings,
) -> Action {
// Set the summary and body of the notification. // Set the summary and body of the notification.
self.notification self.notification
.summary(process_template_placeholders(&self.settings.summary, &track).as_str()) .summary(process_template_placeholders(&self.settings.summary, &track).as_str())
.body(process_template_placeholders(&self.settings.body, &track).as_str()); .body(process_template_placeholders(&self.settings.body, &track).as_str());
let n = self.notification.show()?; Action::Show
}
Ok(()) #[inline(always)]
fn build_volume_notification(
&mut self,
track: Track,
player_settings: PlayerSettings,
) -> Action {
self.notification
.summary(
process_template_placeholders(&self.settings.volume_notification_summary, &track)
.as_str(),
)
.body(
process_template_placeholders(&self.settings.volume_notification_body, &track)
.as_str(),
);
Action::Show
} }
#[inline(always)] #[inline(always)]
fn update_cover(&mut self, first_event: &CmusEvent, response: &CmusQueryResponse) { fn update_cover(&mut self, first_event: &CmusEvent, response: &CmusQueryResponse) {
// If the track is changed, we need to update the cover. // If the track is changed, we need to update the cover.
match first_event { match first_event {
CmusEvent::TrackChanged(track) => { CmusEvent::TrackChanged(track, _) => {
self.set_cover(track); self.set_cover(track);
} }
_ => { _ => {
@ -133,7 +179,7 @@ impl NotificationsHandler {
self.settings.force_use_external_cover, self.settings.force_use_external_cover,
self.settings.no_use_external_cover, self.settings.no_use_external_cover,
) )
.set_notification_image(&mut self.notification); .set_notification_image(&mut self.notification);
// Flip the change flag // Flip the change flag
self.cover_set = true; self.cover_set = true;
} }