diff --git a/Cargo.toml b/Cargo.toml index cc90b6d..8da4a6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,6 @@ zbus = "4.4.0" zvariant = "4.2.0" tokio = { version = "1.40.0", features = ["full"] } futures-util = "0.3.30" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" rson_rs = "0.2.1" \ No newline at end of file diff --git a/src/formats/json.rs b/src/formats/json.rs index c662594..839bb0f 100644 --- a/src/formats/json.rs +++ b/src/formats/json.rs @@ -3,68 +3,7 @@ use crate::notification::Notification; use serde_json::{json, Value}; // json!() macro and Value type impl Notification { - // Actions, as json - pub fn actions_json(&self) -> Value { - if self.actions().is_empty() { - json!({}) // Empty JSON object if no actions - } else { - serde_json::Value::Object( - // Wrap the map into a serde_json::Value - self.actions() - .iter() - .map(|(id, label)| { - (id.clone(), json!(label)) // Create key-value pairs: id -> label - }) - .collect::>(), // Collect into a serde_json::Map - ) - } - } - - // Default action, as json string - pub fn default_action_json(&self) -> Value { - match self.default_action() { - None => serde_json::Value::from("None"), - Some(actn) => serde_json::Value::String(actn.0), - } - } - - // Hints, as json - pub fn hints_json(&self) -> Value { - if self.hints().is_empty() { - json!({}) // Empty JSON object if no hints - } else { - serde_json::Value::Object( - self.hints() - .iter() - .map(|(key, value)| { - (key.clone(), json!(value.to_string())) // Convert hint value to string - }) - .collect::>(), // Collect into a serde_json::Map - ) - } - } - - // The notification as a json object pub fn json(&self) -> Value { - // Initialize - let mut notif_json: Value = json!({ - "app_name": &self.app_name(), - "replace_id": &self.replace_id(), - "icon": &self.icon(), - "summary": &self.summary(), - "body": &self.body(), - "hints": &self.hints_json(), - "expiration_timeout": self.expir_timeout(), - "urgency": self.urgency(), - }); - - // Conditionally add the Actions fields - if let Value::Object(ref mut map) = notif_json { - if !self.actions().is_empty() { - map.insert("actions".to_string(), self.actions_json()); - map.insert("default_action".to_string(), self.default_action_json()); - } - } - notif_json + json!(self) } } diff --git a/src/formats/rson.rs b/src/formats/rson.rs index d9420e0..ea14252 100644 --- a/src/formats/rson.rs +++ b/src/formats/rson.rs @@ -3,16 +3,6 @@ use crate::notification::Notification; use rson_rs::ser::to_string as rson_string; impl Notification { - pub fn actions_rson(&self) -> String { - if self.actions().is_empty() { - String::new() - } else { - rson_string(&self.actions()).unwrap() - } - } - pub fn hints_rson(&self) -> String { - rson_string(&self.hints()).unwrap() - } pub fn rson(&self) -> String { rson_string(&self).unwrap() } diff --git a/src/formats/serde.rs b/src/formats/serde.rs new file mode 100644 index 0000000..3a2d9ff --- /dev/null +++ b/src/formats/serde.rs @@ -0,0 +1,43 @@ +use serde::{Serialize, Serializer}; +/* +use std::collections::HashMap; +use std::hash::BuildHasher; +use zvariant::OwnedValue; */ + +pub fn serialize_actions( + actions: &[String], // Changed to a slice + serializer: S, +) -> Result +where + S: Serializer, +{ + let mut map = serde_json::Map::new(); + + // Assuming actions are in pairs: [id, label, id, label, ...] + for chunk in actions.chunks(2) { + if let [id, label] = chunk { + map.insert(id.clone(), serde_json::Value::String(label.clone())); + } + } + + map.serialize(serializer) +} +/* +pub fn serialize_hints( + hints: &HashMap, + serializer: S, +) -> Result +where + S: Serializer, + H: BuildHasher, +{ + let mut map = serde_json::Map::new(); + + for (key, value) in hints { + // Customize OwnedValue serialization as needed + map.insert(key.clone(), serde_json::Value::String(value.to_string())); + } + + map.serialize(serializer) +} +*/ diff --git a/src/main.rs b/src/main.rs index 753bf17..29bd456 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ pub mod formats { pub mod json; pub mod plain; pub mod rson; + pub mod serde; } mod notification; use notification::{to_notif, Notification}; @@ -13,7 +14,7 @@ use zbus::{message::Body, Connection, Result}; const SERVER_NAME: &str = "SNot"; // Server software name const VENDOR: &str = "candifloss.cc"; // Server software vendor -const VERSION: &str = "0.1.0"; // Server software version +const VERSION: &str = "0.1.2"; // Server software version const SPEC_VERSION: &str = "0.42"; // DBus specification version const NOTIF_INTERFACE: &str = "org.freedesktop.Notifications"; // DBus interface name @@ -32,7 +33,7 @@ fn server_properties() -> HashMap { #[tokio::main] async fn main() -> Result<()> { let args: Vec = env::args().collect(); - let op_format: &str = if args.is_empty() || args[1] == "j" { + let op_format: &str = if args.len() == 1 || args[1] == "j" { "j" // Default value, json format } else if args[1] == "p" { "p" // Plain format diff --git a/src/notification.rs b/src/notification.rs index 95d6d5f..e734e5e 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -1,3 +1,4 @@ +use crate::formats::serde::serialize_actions; use serde::Serialize; use std::collections::HashMap; use zbus::{message::Body, Result}; @@ -17,8 +18,10 @@ pub struct Notification { // Notification content/body body: String, // Action requests that can be sent back to the client - "Reply," "Mark as Read," "Play/Pause/Next," "Snooze/Dismiss," etc. + #[serde(serialize_with = "serialize_actions")] actions: Vec, // Useful extra data - notif type, urgency, notif sound, icon data, etc. + //#[serde(serialize_with = "serialize_hints")] hints: HashMap, // Seconds till this notif expires. Optional expir_timeout: i32,