[implement] Implement the {progress}
placeholderr
This commit is contained in:
parent
44bb297e78
commit
0eed8c5360
4 changed files with 110 additions and 33 deletions
|
@ -1,6 +1,6 @@
|
|||
use crate::{process_template_placeholders};
|
||||
use crate::cmus::{Track};
|
||||
use crate::cmus::player_settings::{PlayerSettings};
|
||||
use crate::{CompleteStr, process_template_placeholders};
|
||||
use crate::cmus::Track;
|
||||
use crate::cmus::player_settings::PlayerSettings;
|
||||
use crate::notification::Action;
|
||||
use crate::settings::Settings;
|
||||
|
||||
|
@ -38,19 +38,46 @@ impl CmusEvent {
|
|||
_ => { return Action::None },
|
||||
};
|
||||
|
||||
let persistent = is_mutable(&body_template) || is_mutable(&summary_template);
|
||||
|
||||
Action::Show {
|
||||
body: process_template_placeholders(
|
||||
body: CompleteStr {
|
||||
template: body_template.clone(),
|
||||
str: process_template_placeholders(
|
||||
body_template,
|
||||
track,
|
||||
player_settings,
|
||||
),
|
||||
summary: process_template_placeholders(
|
||||
},
|
||||
summary: CompleteStr {
|
||||
template: summary_template.clone(),
|
||||
str: process_template_placeholders(
|
||||
summary_template,
|
||||
track,
|
||||
player_settings,
|
||||
),
|
||||
timeout: timeout * 1000 ,
|
||||
save: false,
|
||||
},
|
||||
timeout: if persistent { 0 } else { timeout * 1000 },
|
||||
save: persistent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mutable(template: &str) -> bool {
|
||||
let mut key = String::new(); // Just a buffer to build the key.
|
||||
|
||||
for c in template.chars() {
|
||||
if c == '{' {
|
||||
key = String::new();
|
||||
} else if c == '}' {
|
||||
match key.as_str() {
|
||||
"lyrics" | "progress" | "progress_bar" => return true,
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
key.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ impl TemplateProcessor for Track {
|
|||
/// Process the template with the track metadata.
|
||||
/// The template is a string with placeholders that will be replaced with the track metadata.
|
||||
/// The unknown placeholders will be skipped (don't replaced with anything, because they are maybe placeholders for player settings).
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn process(&self, template: String) -> String {
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
|
@ -107,14 +107,14 @@ impl TemplateProcessor for Track {
|
|||
Self::get_keys(template.as_str()).iter().for_each(|key| {
|
||||
#[cfg(feature = "debug")]
|
||||
debug!("Replacing the placeholder {{{key}}} with its matching value.");
|
||||
// Replace the key with their matching value if exists, if not replace with the empty string.
|
||||
let status = self.status.to_string();
|
||||
// Replace the key with their matching value if exists
|
||||
if let Some(value) = match key.as_str() {
|
||||
"status" => Some(status.as_str()),
|
||||
"title" => Some(self.get_name()),
|
||||
_ => self.metadata.get(key),
|
||||
"status" => Some(self.status.to_string()),
|
||||
"title" => Some(self.get_name().to_string()),
|
||||
"progress" => Some(format!("{:.2}/{:.2}", self.duration as f32 / 60.0, self.position as f32 / 60.0)),
|
||||
_ => self.metadata.get(key).map(|r| r.to_string()),
|
||||
} {
|
||||
processed = processed.replace(&format!("{{{key}}}"), value);
|
||||
processed = processed.replace(&format!("{{{key}}}"), value.as_str());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -112,6 +112,11 @@ pub fn search_for(
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CompleteStr {
|
||||
pub template: String,
|
||||
pub str: String
|
||||
}
|
||||
|
||||
/// The cover of a track.
|
||||
#[derive(PartialEq)]
|
||||
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
#[cfg(feature = "debug")]
|
||||
use log::{info};
|
||||
use log::info;
|
||||
use notify_rust::Notification;
|
||||
|
||||
use crate::{track_cover, TrackCover};
|
||||
use crate::{CompleteStr, track_cover, TrackCover};
|
||||
use crate::cmus::{TemplateProcessor, Track};
|
||||
use crate::cmus::events::CmusEvent;
|
||||
|
||||
use crate::cmus::player_settings::PlayerSettings;
|
||||
use crate::cmus::query::CmusQueryResponse;
|
||||
use crate::settings::Settings;
|
||||
|
||||
pub enum Action {
|
||||
Show {
|
||||
body: String,
|
||||
summary: String,
|
||||
body: CompleteStr,
|
||||
summary:CompleteStr,
|
||||
timeout: i32,
|
||||
save: bool,
|
||||
},
|
||||
|
@ -22,16 +22,33 @@ pub enum Action {
|
|||
pub struct NotificationsHandler {
|
||||
cover_set: bool,
|
||||
notification: Notification,
|
||||
handlers: Vec<notify_rust::NotificationHandle>,
|
||||
notifications: Vec<CmusNotification>,
|
||||
settings: Settings,
|
||||
}
|
||||
|
||||
struct CmusNotification {
|
||||
body_template: String,
|
||||
summary_template: String,
|
||||
visible: bool,
|
||||
handle: notify_rust::NotificationHandle
|
||||
}
|
||||
|
||||
impl CmusNotification {
|
||||
#[inline(always)]
|
||||
fn update(&mut self, track: &Track, player_settings: &PlayerSettings) {
|
||||
use crate::process_template_placeholders;
|
||||
self.handle.summary(&process_template_placeholders(self.summary_template.clone(), track, player_settings))
|
||||
.body(&process_template_placeholders(self.body_template.clone(), track, player_settings));
|
||||
self.handle.update();
|
||||
}
|
||||
}
|
||||
|
||||
impl NotificationsHandler {
|
||||
pub fn new(settings: Settings) -> Self {
|
||||
Self {
|
||||
cover_set: false,
|
||||
notification: Notification::new(),
|
||||
handlers: Vec::with_capacity(2),
|
||||
notifications: Vec::with_capacity(2),
|
||||
settings,
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +63,22 @@ impl NotificationsHandler {
|
|||
#[cfg(feature = "debug")]
|
||||
info!("event: {:?}", event);
|
||||
|
||||
if let CmusEvent::PositionChanged(track, player_settings) = &event {
|
||||
for notification in &mut self.notifications {
|
||||
if notification.visible {
|
||||
notification.update(track, player_settings);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if let CmusEvent::TrackChanged(_, _) = &event {
|
||||
for notification in &mut self.notifications {
|
||||
notification.handle.timeout = 2.into(); // Hide the notification after 2 millisecond
|
||||
notification.handle.update();
|
||||
}
|
||||
// Clean the notifications vec
|
||||
self.notifications.clear();
|
||||
}
|
||||
|
||||
match event.build_notification(&self.settings) {
|
||||
Action::Show { body, summary, timeout, save } => {
|
||||
// Setup the notification cover
|
||||
|
@ -58,12 +91,24 @@ impl NotificationsHandler {
|
|||
self.cover_set = true;
|
||||
}
|
||||
|
||||
self.notification.timeout(timeout).summary(&summary).body(&body);
|
||||
self.notification.timeout(timeout).summary(&summary.str).body(&body.str);
|
||||
|
||||
// Show the notification
|
||||
let handle = self.notification.show()?;
|
||||
let mut handle = self.notification.show()?;
|
||||
if save {
|
||||
self.handlers.push(handle);
|
||||
// Add the close handler
|
||||
/*handle.on_close(|reason| {
|
||||
|
||||
});*/
|
||||
|
||||
self.notifications.push(
|
||||
CmusNotification {
|
||||
body_template: body.template,
|
||||
summary_template: summary.template,
|
||||
visible: true,
|
||||
handle
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Action::None => {}
|
||||
|
|
Loading…
Reference in a new issue