[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::{CompleteStr, process_template_placeholders};
|
||||||
use crate::cmus::{Track};
|
use crate::cmus::Track;
|
||||||
use crate::cmus::player_settings::{PlayerSettings};
|
use crate::cmus::player_settings::PlayerSettings;
|
||||||
use crate::notification::Action;
|
use crate::notification::Action;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
|
@ -38,19 +38,46 @@ impl CmusEvent {
|
||||||
_ => { return Action::None },
|
_ => { return Action::None },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let persistent = is_mutable(&body_template) || is_mutable(&summary_template);
|
||||||
|
|
||||||
Action::Show {
|
Action::Show {
|
||||||
body: process_template_placeholders(
|
body: CompleteStr {
|
||||||
body_template,
|
template: body_template.clone(),
|
||||||
track,
|
str: process_template_placeholders(
|
||||||
player_settings,
|
body_template,
|
||||||
),
|
track,
|
||||||
summary: process_template_placeholders(
|
player_settings,
|
||||||
summary_template,
|
),
|
||||||
track,
|
},
|
||||||
player_settings,
|
summary: CompleteStr {
|
||||||
),
|
template: summary_template.clone(),
|
||||||
timeout: timeout * 1000 ,
|
str: process_template_placeholders(
|
||||||
save: false,
|
summary_template,
|
||||||
|
track,
|
||||||
|
player_settings,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
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.
|
/// Process the template with the track metadata.
|
||||||
/// The template is a string with placeholders that will be replaced 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).
|
/// 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 {
|
fn process(&self, template: String) -> String {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
{
|
{
|
||||||
|
@ -107,14 +107,14 @@ impl TemplateProcessor for Track {
|
||||||
Self::get_keys(template.as_str()).iter().for_each(|key| {
|
Self::get_keys(template.as_str()).iter().for_each(|key| {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
debug!("Replacing the placeholder {{{key}}} with its matching value.");
|
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.
|
// Replace the key with their matching value if exists
|
||||||
let status = self.status.to_string();
|
|
||||||
if let Some(value) = match key.as_str() {
|
if let Some(value) = match key.as_str() {
|
||||||
"status" => Some(status.as_str()),
|
"status" => Some(self.status.to_string()),
|
||||||
"title" => Some(self.get_name()),
|
"title" => Some(self.get_name().to_string()),
|
||||||
_ => self.metadata.get(key),
|
"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.
|
/// The cover of a track.
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
|
#[cfg_attr(any(feature = "debug", test), derive(Debug))]
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
use log::{info};
|
use log::info;
|
||||||
use notify_rust::Notification;
|
use notify_rust::Notification;
|
||||||
|
|
||||||
use crate::{track_cover, TrackCover};
|
use crate::{CompleteStr, track_cover, TrackCover};
|
||||||
use crate::cmus::{TemplateProcessor, Track};
|
use crate::cmus::{TemplateProcessor, Track};
|
||||||
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::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Show {
|
Show {
|
||||||
body: String,
|
body: CompleteStr,
|
||||||
summary: String,
|
summary:CompleteStr,
|
||||||
timeout: i32,
|
timeout: i32,
|
||||||
save: bool,
|
save: bool,
|
||||||
},
|
},
|
||||||
|
@ -22,16 +22,33 @@ pub enum Action {
|
||||||
pub struct NotificationsHandler {
|
pub struct NotificationsHandler {
|
||||||
cover_set: bool,
|
cover_set: bool,
|
||||||
notification: Notification,
|
notification: Notification,
|
||||||
handlers: Vec<notify_rust::NotificationHandle>,
|
notifications: Vec<CmusNotification>,
|
||||||
settings: Settings,
|
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 {
|
impl NotificationsHandler {
|
||||||
pub fn new(settings: Settings) -> Self {
|
pub fn new(settings: Settings) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cover_set: false,
|
cover_set: false,
|
||||||
notification: Notification::new(),
|
notification: Notification::new(),
|
||||||
handlers: Vec::with_capacity(2),
|
notifications: Vec::with_capacity(2),
|
||||||
settings,
|
settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +63,22 @@ impl NotificationsHandler {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
info!("event: {:?}", event);
|
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) {
|
match event.build_notification(&self.settings) {
|
||||||
Action::Show { body, summary, timeout, save } => {
|
Action::Show { body, summary, timeout, save } => {
|
||||||
// Setup the notification cover
|
// Setup the notification cover
|
||||||
|
@ -58,12 +91,24 @@ impl NotificationsHandler {
|
||||||
self.cover_set = true;
|
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
|
// Show the notification
|
||||||
let handle = self.notification.show()?;
|
let mut handle = self.notification.show()?;
|
||||||
if save {
|
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 => {}
|
Action::None => {}
|
||||||
|
|
Loading…
Reference in a new issue