cmus_notify/
notification.rs1#[cfg(feature = "debug")]
2use log::info;
3use notify_rust::Notification;
4
5use crate::{CompleteStr, track_cover, TrackCover};
6use crate::cmus::{TemplateProcessor, Track};
7use crate::cmus::events::CmusEvent;
8use crate::cmus::player_settings::PlayerSettings;
9use crate::cmus::query::CmusQueryResponse;
10use crate::settings::Settings;
11
12pub enum Action {
13 Show {
14 body: CompleteStr,
15 summary:CompleteStr,
16 timeout: i32,
17 save: bool,
18 },
19 None,
20}
21
22pub struct NotificationsHandler {
23 cover_set: bool,
24 notification: Notification,
25 notifications: Vec<CmusNotification>,
26 settings: Settings,
27}
28
29struct CmusNotification {
30 body_template: String,
31 summary_template: String,
32 visible: bool,
33 handle: notify_rust::NotificationHandle
34}
35
36impl CmusNotification {
37 #[inline(always)]
38 fn update(&mut self, track: &Track, player_settings: &PlayerSettings) {
39 use crate::process_template_placeholders;
40 self.handle.summary(&process_template_placeholders(self.summary_template.clone(), track, player_settings))
41 .body(&process_template_placeholders(self.body_template.clone(), track, player_settings));
42 self.handle.update();
43 }
44}
45
46impl NotificationsHandler {
47 pub fn new(settings: Settings) -> Self {
48 Self {
49 cover_set: false,
50 notification: Notification::new(),
51 notifications: Vec::with_capacity(2),
52 settings,
53 }
54 }
55
56 #[inline]
57 pub fn show_notification(
58 &mut self,
59 events: Vec<CmusEvent>,
60 response: &CmusQueryResponse,
61 ) -> Result<(), notify_rust::error::Error> {
62 for event in events {
63 #[cfg(feature = "debug")]
64 info!("event: {:?}", event);
65
66 if let CmusEvent::PositionChanged(track, player_settings) = &event {
67 for notification in &mut self.notifications {
68 if notification.visible {
69 notification.update(track, player_settings);
70 }
71 }
72 continue;
73 } else if let CmusEvent::TrackChanged(_, _) = &event {
74 for notification in &mut self.notifications {
75 notification.handle.timeout = 2.into(); notification.handle.update();
77 }
78 self.notifications.clear();
80 }
81
82 match event.build_notification(&self.settings) {
83 Action::Show { body, summary, timeout, save } => {
84 if self.settings.show_track_cover {
86 self.update_cover(&event, response);
87 } else if self.settings.notification_static_cover.is_some() && !self.cover_set {
88 self.setup_the_notification();
89 self.notification
90 .image_path(self.settings.notification_static_cover.as_ref().unwrap());
91 self.cover_set = true;
92 }
93
94 self.notification.timeout(timeout).summary(&summary.str).body(&body.str);
95
96 let mut handle = self.notification.show()?;
98 if save {
99 self.notifications.push(
105 CmusNotification {
106 body_template: body.template,
107 summary_template: summary.template,
108 visible: true,
109 handle
110 }
111 )
112 }
113 }
114 Action::None => {}
115 };
116 }
117
118 Ok(())
119 }
120
121 #[inline(always)]
122 fn update_cover(&mut self, event: &CmusEvent, response: &CmusQueryResponse) {
123 match event {
125 CmusEvent::TrackChanged(track, _) => {
126 self.setup_the_notification();
128 self.set_cover(track);
129 }
130 _ => {
131 if !self.cover_set {
132 if let Ok(track) = response.track() {
134 self.set_cover(&track);
135 }
136 }
137 }
138 };
139 }
140
141 #[inline]
142 fn set_cover(&mut self, track: &Track) {
143 let path = match &self.settings.cover_path_template {
144 Some(template) => track.process(template.clone()),
145 None => track.path.clone(),
146 };
147 let track_cover = track_cover(
149 path,
150 track.get_name(),
151 self.settings.depth(),
152 self.settings.force_use_external_cover,
153 self.settings.no_use_external_cover,
154 );
155
156 if track_cover != TrackCover::None {
157 track_cover.set_notification_image(&mut self.notification);
158 } else if self.settings.notification_static_cover.is_some() {
159 self.notification
160 .image_path(self.settings.notification_static_cover.as_ref().unwrap());
161 }
162
163 self.cover_set = true;
165 }
166
167 #[inline(always)]
168 fn setup_the_notification(&mut self) {
169 self.notification = Notification::new();
170 self.notification
171 .appname(self.settings.app_name().as_str())
172 .hint(notify_rust::Hint::Category("music".to_string()))
173 .hint(notify_rust::Hint::DesktopEntry("cmus.desktop".to_string()))
174 .hint(notify_rust::Hint::Resident(true));
175 }
176}