Skip to content

Commit

Permalink
initialize commit
Browse files Browse the repository at this point in the history
  • Loading branch information
buty4649 committed Dec 11, 2023
1 parent 0ac0883 commit 1a33124
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ Cargo.lock

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb


# Added by cargo

/target
17 changes: 17 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "wnotify"
version = "0.1.0"
edition = "2021"
description = "Windows CLI tool for easy, customizable toast notifications."

[dependencies]
seahorse = "2.2"

[dependencies.windows]
version = "0.52.0"
features = ["Win32_UI_Shell", "Data_Xml_Dom", "UI_Notifications"]

[profile.release]
strip = true
opt-level = "z"
lto = true
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# windows-notify
Windows CLI tool for easy, customizable toast notifications.

## Usage

```sh
$ wnotify.exe hello world
```

![sample](./docs/sample_notify.png)
Binary file added docs/sample_notify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
mod toast;

use seahorse::{ActionError, ActionResult, App, Context, Flag, FlagType};

use std::env;
use std::process::exit;

fn main() {
let args = env::args().collect::<Vec<String>>();

let app = App::new(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.usage(format!("{} <text> [<text>]", env!("CARGO_PKG_NAME")))
.flag(
Flag::new("app-id", FlagType::String)
.description("The App ID to use for the notification")
.alias("a"),
)
.action_with_result(do_action);

match app.run_with_result(args) {
Ok(_) => {}
Err(ActionError { message }) => {
eprintln!("Error: {}", message);
exit(1)
}
}
}

fn do_action(c: &Context) -> ActionResult {
if c.args.is_empty() {
return Err(ActionError {
message: "No arguments provided".to_string(),
});
}

let app_id = if let Ok(app_id) = c.string_flag("app-id") {
app_id
} else {
"wnotify".to_string()
};

let text1 = &c.args[0];
let text2 = c.args.get(1).map(|s| s.as_str());

let toast = toast::Toast::new(&app_id, text1, text2);
toast.notify();

Ok(())
}
53 changes: 53 additions & 0 deletions src/toast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use windows::{
core::HSTRING,
Data::Xml::Dom::XmlDocument,
UI::Notifications::{ToastNotification, ToastNotificationManager},
};

pub struct Toast {
app_id: String,
text1: String,
text2: Option<String>,
}

impl Toast {
pub fn new(app_id: &str, text1: &str, text2: Option<&str>) -> Toast {
Toast {
app_id: app_id.to_string(),
text1: text1.to_string(),
text2: text2.map(|s| s.to_string()),
}
}

pub fn notify(&self) {
let toast_xml = format!(
r#"<?xml version="1.0" encoding="utf-8"?>
<toast activationType="protocol" launch="{}">
<visual>
<binding template="ToastGeneric">
<text>{}</text>
</binding>
</visual>
</toast>"#,
self.app_id, self.text1
);

let xml = XmlDocument::new().unwrap();
xml.LoadXml(&HSTRING::from(toast_xml)).unwrap();

if let Some(text2) = &self.text2 {
let text = xml.CreateElement(&HSTRING::from("text")).unwrap();
text.SetInnerText(&HSTRING::from(text2)).unwrap();
xml.SelectSingleNode(&HSTRING::from("/toast/visual/binding"))
.unwrap()
.AppendChild(&text)
.unwrap();
}
let template = ToastNotification::CreateToastNotification(&xml).unwrap();

let notifier =
ToastNotificationManager::CreateToastNotifierWithId(&HSTRING::from(&self.app_id))
.unwrap();
notifier.Show(&template).unwrap();
}
}

0 comments on commit 1a33124

Please sign in to comment.