├── .gitignore ├── examples ├── poet.jpeg ├── poetry.jpg ├── album_cover.jpg ├── button_read.png ├── album_artist.png ├── progress_logo.png ├── button_appreciation.png ├── basic.rs ├── button.rs ├── progress_bat_1.rs ├── button_2.rs ├── progress_bat_2.rs ├── advance.rs └── advance_2.rs ├── screenshots ├── basic.png ├── progress.gif ├── advance_en.png ├── advance_zh.png ├── button_basic.png └── button_image.png ├── Cargo.toml ├── Cargo.lock ├── LICENSE ├── CHANGELOG.md ├── README.md ├── README_zh.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /examples/poet.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/poet.jpeg -------------------------------------------------------------------------------- /examples/poetry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/poetry.jpg -------------------------------------------------------------------------------- /screenshots/basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/screenshots/basic.png -------------------------------------------------------------------------------- /examples/album_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/album_cover.jpg -------------------------------------------------------------------------------- /examples/button_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/button_read.png -------------------------------------------------------------------------------- /screenshots/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/screenshots/progress.gif -------------------------------------------------------------------------------- /examples/album_artist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/album_artist.png -------------------------------------------------------------------------------- /examples/progress_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/progress_logo.png -------------------------------------------------------------------------------- /screenshots/advance_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/screenshots/advance_en.png -------------------------------------------------------------------------------- /screenshots/advance_zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/screenshots/advance_zh.png -------------------------------------------------------------------------------- /screenshots/button_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/screenshots/button_basic.png -------------------------------------------------------------------------------- /screenshots/button_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/screenshots/button_image.png -------------------------------------------------------------------------------- /examples/button_appreciation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iKineticate/win-toast-notify/HEAD/examples/button_appreciation.png -------------------------------------------------------------------------------- /examples/basic.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::WinToastNotify; 2 | 3 | fn main() { 4 | WinToastNotify::new() 5 | .set_title("Title") 6 | .set_messages(vec![ 7 | "This is a simple toast message" 8 | ]) 9 | .show() 10 | .expect("Failed to show toast notification") 11 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "win-toast-notify" 3 | version = "0.1.6" 4 | edition = "2021" 5 | authors = ["iKineticate"] 6 | keywords = ["notification", "windows", "toast", "notify"] 7 | readme = "README.md" 8 | description = "Windows Toast Notifications" 9 | repository = "https://github.com/iKineticate/win-toast-notify" 10 | homepage = "https://github.com/iKineticate/win-toast-notify" 11 | documentation = "https://docs.rs/win-toast-notify" 12 | license = "MIT" 13 | exclude = ["examples", "screenshots"] 14 | 15 | [dependencies] 16 | xml = "0.8.20" 17 | 18 | [package.metadata.docs.rs] 19 | default-target = "x86_64-pc-windows-msvc" -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "win-toast-notify" 7 | version = "0.1.6" 8 | dependencies = [ 9 | "xml", 10 | ] 11 | 12 | [[package]] 13 | name = "xml" 14 | version = "0.8.20" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ede1c99c55b4b3ad0349018ef0eccbe954ce9c342334410707ee87177fcf2ab4" 17 | dependencies = [ 18 | "xml-rs", 19 | ] 20 | 21 | [[package]] 22 | name = "xml-rs" 23 | version = "0.8.20" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" 26 | -------------------------------------------------------------------------------- /examples/button.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::{WinToastNotify, Action, ActivationType}; 2 | 3 | fn main() { 4 | WinToastNotify::new() 5 | .set_actions(vec![ 6 | Action { 7 | activation_type: ActivationType::Protocol, 8 | action_content: "Url".to_string(), 9 | arguments: "https://www.google.com/".to_string(), 10 | image_url: None 11 | }, 12 | Action { 13 | activation_type: ActivationType::Protocol, 14 | action_content: "File".to_string(), 15 | arguments: r"C:\Windows\Web\Screen\img104.jpg".to_string(), 16 | image_url: None 17 | }, 18 | Action { 19 | activation_type: ActivationType::Protocol, 20 | action_content: "Folder".to_string(), 21 | arguments: r"$env:USERPROFILE\Downloads".to_string(), // PowerShell supports using environment variables 22 | image_url: None 23 | } 24 | ]) 25 | .show() 26 | .expect("Failed to show toast notification"); 27 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 iKineticate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/progress_bat_1.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::{WinToastNotify, Duration}; 2 | 3 | fn main() { 4 | let tag = "weekly-playlist"; 5 | let title = "Weekly playlist"; 6 | let mut status = String::from("Downloading..."); 7 | let mut value = 0.0; 8 | let mut value_string = String::from("0/10 songs"); 9 | 10 | WinToastNotify::new() 11 | .set_duration(Duration::Long) 12 | .set_title("Downloading your weekly playlist...") 13 | .set_progress(tag, title, &status, value, &value_string) 14 | .show() 15 | .expect("Failed to show toast notification"); 16 | 17 | for i in 1..=10 { 18 | std::thread::sleep(std::time::Duration::from_secs(1)); 19 | value = i as f32 / 10.0; 20 | if i != 10 { 21 | value_string = format!("{}/10 songs", i); 22 | WinToastNotify::progress_update(None, tag, value, &value_string).expect("Failed to update"); 23 | } else { 24 | status = String::from("Completed"); 25 | value_string = String::from("10/10 songs"); 26 | WinToastNotify::progress_complete(None, tag, &status, &value_string).expect("Failed to complete"); 27 | }; 28 | }; 29 | } -------------------------------------------------------------------------------- /examples/button_2.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::{WinToastNotify, Action, ActivationType}; 2 | 3 | fn main() { 4 | let current_dir = std::env::current_dir().expect("Failed to get current directory"); 5 | let button_read_path = current_dir.join("examples/button_read.png"); 6 | let button_appreciation_path = current_dir.join("examples/button_appreciation.png"); 7 | 8 | WinToastNotify::new() 9 | .set_title("Rust") 10 | .set_messages(vec![ 11 | "A language empowering everyone", 12 | "to build reliable and efficient software." 13 | ]) 14 | .set_actions(vec![ 15 | Action { 16 | activation_type: ActivationType::Protocol, 17 | action_content: String::new(), 18 | arguments: "https://doc.rust-lang.org/book/".to_string(), 19 | image_url: Some(button_appreciation_path.to_string_lossy().to_string()), 20 | }, 21 | Action { 22 | activation_type: ActivationType::Protocol, 23 | action_content: String::new(), 24 | arguments: r"C:\Windows\Web\Screen\img101.jpg".to_string(), 25 | image_url: Some(button_read_path.to_string_lossy().to_string()), 26 | } 27 | ]) 28 | .show() 29 | .expect("Failed to show toast notification") 30 | } -------------------------------------------------------------------------------- /examples/progress_bat_2.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::{WinToastNotify, CropCircle, Duration}; 2 | use std::env; 3 | 4 | fn main() { 5 | let current_dir = env::current_dir().expect("Failed to get current directory"); 6 | let logo_path = current_dir.join("examples/progress_logo.png"); 7 | 8 | let tag = "star-rail"; 9 | let title = "Honkai: Star Rail"; 10 | let mut status = String::from("Downloading..."); 11 | let mut value = 0.0; 12 | let mut value_string = String::from("0%"); 13 | 14 | WinToastNotify::new() 15 | .set_duration(Duration::Long) 16 | .set_title("Downloading miHoYo Game...") 17 | .set_messages(vec![ 18 | "May This Journey Lead Us Starward" 19 | ]) 20 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 21 | .set_progress(tag, title, &status, value, &value_string) 22 | .show() 23 | .expect("Failed to show toast notification"); 24 | 25 | for i in 1..=10 { 26 | std::thread::sleep(std::time::Duration::from_millis(500)); 27 | value = i as f32 / 10.0; 28 | if i != 10 { 29 | value_string = format!("{:.1}%", value * 100.0); 30 | WinToastNotify::progress_update(None, tag, value, &value_string).expect("Failed to update"); 31 | } else { 32 | status = String::from("Completed"); 33 | value_string = String::from("100%"); 34 | WinToastNotify::progress_complete(None, tag, &status, &value_string).expect("Failed to complete"); 35 | }; 36 | }; 37 | } -------------------------------------------------------------------------------- /examples/advance.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::*; 2 | use std::env; 3 | 4 | fn main() { 5 | let current_dir = env::current_dir().expect("Failed to get current directory"); 6 | let logo_path = current_dir.join("examples/album_artist.png"); 7 | let image_path = current_dir.join("examples/album_cover.jpg"); 8 | let introduce_url = "https://honkai-star-rail.fandom.com/wiki/Hope_Is_the_Thing_With_Feathers"; 9 | let music_url = "https://t.co/6urFxrI6K0"; 10 | let music_lyric = "https://x.com/honkaistarrail/status/1789149010831569254"; 11 | 12 | WinToastNotify::new() 13 | .set_open(introduce_url) // 点击通知的打开链接或文件(夹) 14 | .set_duration(Duration::Long) 15 | .set_title("Hope Is the Thing With Feathers - Robin") 16 | .set_messages(vec![ 17 | "Heads up the wheels are spinning\nAcross the plains in valleys deep", 18 | "To dawn the wheels that sing\nAn unending dream" 19 | ]) 20 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 21 | .set_image(image_path.to_str().expect("Path is an invalid unicode"), ImagePlacement::Top) 22 | .set_actions(vec![ 23 | Action { 24 | activation_type: ActivationType::Protocol, 25 | action_content: "Listen".to_string(), 26 | arguments: music_url.to_string(), 27 | image_url: None, 28 | }, 29 | Action { 30 | activation_type: ActivationType::Protocol, 31 | action_content: "Lyric".to_string(), 32 | arguments: music_lyric.to_string(), 33 | image_url: None, 34 | } 35 | ]) 36 | .set_audio(Audio::WinLoopingAlarm5, Loop::True) 37 | .show() 38 | .expect("Failed to show toast notification") 39 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.5 => 0.1.6 2 | ```rust 3 | pub struct Action<'a> { 4 | pub activation_type: ActivationType, 5 | pub action_content: &'a str, 6 | pub arguments: &'a str, 7 | pub image_url: Option<&'a str>, 8 | } 9 | 👇 10 | pub struct Action { 11 | pub activation_type: ActivationType, 12 | pub action_content: String, 13 | pub arguments: String, 14 | pub image_url: Option, 15 | } 16 | ``` 17 | 18 | ## 0.1.4 => 0.1.5 19 | ```rust 20 | // modify❗ 21 | pub struct Action { 22 | pub activation_type: ActivationType, 23 | pub action_content: &'static str, 24 | pub arguments: String, 25 | pub image_url: Option, 26 | } 27 | 👇 28 | pub struct Action<'a> { 29 | pub activation_type: ActivationType, 30 | pub action_content: &'a str, 31 | pub arguments: &'a str, 32 | pub image_url: Option<&'a str>, 33 | } 34 | 35 | pub struct Progress { 36 | pub tag: &'static str, 37 | pub title: &'static str, 38 | pub status: &'static str, 39 | pub value_string: &'static str, 40 | } 41 | 👇 42 | pub struct Progress { 43 | pub tag: &'a str, 44 | pub title: &'a str, 45 | pub status: String, 46 | pub value_string: String, 47 | } 48 | ``` 49 | ```rust 50 | // Fix errors in examples code 51 | // Fix doctest code in library 52 | ``` 53 | 54 | 55 | ## 0.1.3 => 0.1.4 56 | ```rust 57 | // modify❗ 58 | pub fn set_notf_open() 59 | 👇 60 | pub fn set_open() 61 | 62 | pub struct Action { 63 | pub activation_type: ActivationType, 64 | pub action_content: &'static str, 65 | pub arguments: &'static str, 66 | pub image_url: Option<&'static str>, 67 | } 68 | 👇 69 | pub struct Action { 70 | pub activation_type: ActivationType, 71 | pub action_content: &'static str, 72 | pub arguments: String, 73 | pub image_url: Option, 74 | } 75 | ``` 76 | 77 | ```rust 78 | // feat 79 | pub fn set_scenario() 80 | pub fn set_progress() 81 | pub fn progress_update() 82 | pub fn progress_complete() 83 | ``` -------------------------------------------------------------------------------- /examples/advance_2.rs: -------------------------------------------------------------------------------- 1 | use win_toast_notify::*; 2 | use std::env; 3 | 4 | fn main() { 5 | let current_dir = env::current_dir().expect("Failed to get current directory"); 6 | let logo_path = current_dir.join("examples/poet.jpeg"); 7 | let image_path = current_dir.join("examples/poetry.jpg"); 8 | let button_read_path = current_dir.join("examples/button_read.png"); 9 | let button_appreciation_path = current_dir.join("examples/button_appreciation.png"); 10 | let introduce_url = "https://en.wikipedia.org/wiki/Li_Qingzhao"; 11 | let read_url = "https://baike.baidu.com/item/%E4%B8%80%E5%89%AA%E6%A2%85%C2%B7%E7%BA%A2%E8%97%95%E9%A6%99%E6%AE%8B%E7%8E%89%E7%B0%9F%E7%A7%8B/593597#1"; 12 | let appreciation_url = "https://baike.baidu.com/item/%E4%B8%80%E5%89%AA%E6%A2%85%C2%B7%E7%BA%A2%E8%97%95%E9%A6%99%E6%AE%8B%E7%8E%89%E7%B0%9F%E7%A7%8B/593597#4"; 13 | 14 | WinToastNotify::new() 15 | .set_open(introduce_url) // 点击通知的打开链接或文件(夹) 16 | .set_duration(Duration::Long) 17 | .set_title("《一剪梅·红藕香残玉簟秋》 宋·李清照") 18 | .set_messages(vec![ 19 | "红藕香残玉簟秋。轻解罗裳,独上兰舟。\n云中谁寄锦书来,雁字回时,月满西楼。", 20 | "花自飘零水自流。一种相思,两处闲愁。\n此情无计可消除,才下眉头,却上心头。" 21 | ]) 22 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 23 | .set_image(image_path.to_str().expect("Path is an invalid unicode"), ImagePlacement::Top) 24 | .set_actions(vec![ 25 | Action { 26 | activation_type: ActivationType::Protocol, 27 | action_content: "阅读".to_string(), 28 | arguments: read_url.to_string(), 29 | image_url: Some(button_read_path.to_string_lossy().to_string()), 30 | }, 31 | Action { 32 | activation_type: ActivationType::Protocol, 33 | action_content: "赏析".to_string(), 34 | arguments: appreciation_url.to_string(), 35 | image_url: Some(button_appreciation_path.to_string_lossy().to_string()), 36 | } 37 | ]) 38 | .set_audio(Audio::WinLoopingAlarm5, Loop::True) 39 | .show() 40 | .expect("Failed to show toast notification") 41 | } 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

English | 简体中文

2 | 3 | # win-toast-notify 4 | win-toast-notify is a Rust library for sending Windows Toast notifications. This library is primarily inspired by the following projects: 5 | 6 | - [wpush.rs](https://github.com/saez-juan/wpush.rs) 7 | - [toast-notification-examples](https://github.com/GitHub30/toast-notification-examples) 8 | 9 | This library has been tested on Windows 11. 10 | 11 | **Important Notice: This library is currently in an unstable state.** 12 | 13 | ## Documentation 14 | For detailed usage and API reference, please refer to the [documentation](https://docs.rs/win-toast-notify). 15 | 16 | ## Changelog 17 | For recent changes and updates, see the [CHANGELOG](./CHANGELOG.md). 18 | 19 | ## Usage 20 | ```toml 21 | # Cargo.toml 22 | [dependencies] 23 | win-toast-notify = "0.1.6" 24 | ``` 25 | 26 | ## Examples 27 | 28 | ### [Basic](./examples/basic.rs) 29 | ```PowerShell 30 | cargo run --example basic 31 | ``` 32 | ```rust 33 | use win_toast_notify::WinToastNotify; 34 | 35 | fn main() { 36 | WinToastNotify::new() 37 | .set_title("Title") 38 | .set_messages(vec![ 39 | "This is a simple toast message" 40 | ]) 41 | .show() 42 | .expect("Failed to show toast notification") 43 | } 44 | ``` 45 | 46 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/basic.png) 47 | 48 | ### [Button](./examples/button.rs) 49 | ```PowerShell 50 | cargo run --example button # button_2 51 | ``` 52 | ```rust 53 | use win_toast_notify::{WinToastNotify, Action, ActivationType}; 54 | 55 | fn main() { 56 | WinToastNotify::new() 57 | .set_actions(vec![ 58 | Action { 59 | activation_type: ActivationType::Protocol, 60 | action_content: "Url".to_string(), 61 | arguments: "https://www.google.com/".to_string(), 62 | image_url: None 63 | }, 64 | Action { 65 | activation_type: ActivationType::Protocol, 66 | action_content: "File".to_string(), 67 | arguments: r"C:\Windows\Web\Screen\img104.jpg".to_string(), 68 | image_url: None 69 | }, 70 | Action { 71 | activation_type: ActivationType::Protocol, 72 | action_content: "Folder".to_string(), 73 | arguments: r"$env:USERPROFILE\Downloads".to_string(), // PowerShell supports using environment variables 74 | image_url: None 75 | } 76 | ]) 77 | .show() 78 | .expect("Failed to show toast notification"); 79 | } 80 | ``` 81 | 82 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/button_basic.png) 83 | 84 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/button_image.png) 85 | 86 | ### [Advance](./examples/advance.rs) 87 | ```PowerShell 88 | cargo run --example advance 89 | ``` 90 | ```rust 91 | use win_toast_notify::*; 92 | use std::env; 93 | 94 | fn main() { 95 | let current_dir = env::current_dir().expect("Failed to get current directory"); 96 | let logo_path = current_dir.join("examples/album_artist.png"); 97 | let image_path = current_dir.join("examples/album_cover.jpg"); 98 | let introduce_url = "https://honkai-star-rail.fandom.com/wiki/Hope_Is_the_Thing_With_Feathers"; 99 | let music_url = "https://t.co/6urFxrI6K0"; 100 | let music_lyric = "https://x.com/honkaistarrail/status/1789149010831569254"; 101 | 102 | WinToastNotify::new() 103 | .set_open(introduce_url) // 点击通知的打开链接或文件(夹) 104 | .set_duration(Duration::Long) 105 | .set_title("Hope Is the Thing With Feathers - Robin") 106 | .set_messages(vec![ 107 | "Heads up the wheels are spinning\nAcross the plains in valleys deep", 108 | "To dawn the wheels that sing\nAn unending dream" 109 | ]) 110 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 111 | .set_image(image_path.to_str().expect("Path is an invalid unicode"), ImagePlacement::Top) 112 | .set_actions(vec![ 113 | Action { 114 | activation_type: ActivationType::Protocol, 115 | action_content: "Listen".to_string(), 116 | arguments: music_url.to_string(), 117 | image_url: None, 118 | }, 119 | Action { 120 | activation_type: ActivationType::Protocol, 121 | action_content: "Lyric".to_string(), 122 | arguments: music_lyric.to_string(), 123 | image_url: None, 124 | } 125 | ]) 126 | .set_audio(Audio::WinLoopingAlarm5, Loop::True) 127 | .show() 128 | .expect("Failed to show toast notification") 129 | } 130 | ``` 131 | 132 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/advance_en.png) 133 | 134 | ### [Progress Bat](./examples/progress_bat_2.rs) 135 | ```PowerShell 136 | cargo run --example progress_bat_2 137 | ``` 138 | ```rust 139 | use win_toast_notify::{WinToastNotify, CropCircle, Duration}; 140 | use std::env; 141 | 142 | fn main() { 143 | let current_dir = env::current_dir().expect("Failed to get current directory"); 144 | let logo_path = current_dir.join("examples/progress_logo.png"); 145 | 146 | let tag = "star-rail"; 147 | let title = "Honkai: Star Rail"; 148 | let mut status = String::from("Downloading..."); 149 | let mut value = 0.0; 150 | let mut value_string = String::from("0%"); 151 | 152 | WinToastNotify::new() 153 | .set_duration(Duration::Long) 154 | .set_title("Downloading miHoYo Game...") 155 | .set_messages(vec![ 156 | "May This Journey Lead Us Starward" 157 | ]) 158 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 159 | .set_progress(tag, title, &status, value, &value_string) 160 | .show() 161 | .expect("Failed to show toast notification"); 162 | 163 | for i in 1..=10 { 164 | std::thread::sleep(std::time::Duration::from_millis(500)); 165 | value = i as f32 / 10.0; 166 | if i != 10 { 167 | value_string = format!("{:.1}%", value * 100.0); 168 | WinToastNotify::progress_update(None, tag, value, &value_string).expect("Failed to update"); 169 | } else { 170 | status = String::from("Completed"); 171 | value_string = String::from("100%"); 172 | WinToastNotify::progress_complete(None, tag, &status, &value_string).expect("Failed to complete"); 173 | }; 174 | }; 175 | } 176 | ``` 177 | 178 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/progress.gif) 179 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # win-toast-notiy 2 | 3 | **Win Toast Notify** 是一个用于发送 Windows Toast 通知的 Rust 库。该库主要参考了以下项目: 4 | 5 | - [wpush.rs](https://github.com/saez-juan/wpush.rs) 6 | - [toast-notification-examples](https://github.com/GitHub30/toast-notification-examples) 7 | 8 | 该库已经在 Windows 11 上进行了测试。 9 | 10 | **重要通知:** 该库目前处于不稳定状态。 11 | 12 | ## 文档 13 | 14 | 有关详细的使用和 API 参考,请参阅[文档](https://docs.rs/win-toast-notify)。 15 | 16 | ## 更新日志 17 | 18 | 有关最近的更改和更新,请参阅[更新日志](./CHANGELOG.md)。 19 | 20 | 21 | ## 使用 22 | ```toml 23 | #Cargo.toml 24 | [dependencies] 25 | win-toast-notify = "0.1.6" 26 | ``` 27 | 28 | ## 例子 29 | 30 | ### [文本](./examples/basic.rs) 31 | ```PowerShell 32 | cargo run --example basic 33 | ``` 34 | ```rust 35 | use win_toast_notify::WinToastNotify; 36 | 37 | fn main() { 38 | WinToastNotify::new() 39 | .set_title("Title") 40 | .set_messages(vec![ 41 | "This is a simple toast message" 42 | ]) 43 | .show() 44 | .expect("Failed to show toast notification") 45 | } 46 | ``` 47 | 48 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/basic.png) 49 | 50 | ### [按钮](./examples/button.rs) 51 | ```PowerShell 52 | cargo run --example button 53 | ``` 54 | ```rust 55 | use win_toast_notify::{WinToastNotify, Action, ActivationType}; 56 | 57 | fn main() { 58 | WinToastNotify::new() 59 | .set_actions(vec![ 60 | Action { 61 | activation_type: ActivationType::Protocol, 62 | action_content: "Url".to_string(), 63 | arguments: "https://www.google.com/".to_string(), 64 | image_url: None 65 | }, 66 | Action { 67 | activation_type: ActivationType::Protocol, 68 | action_content: "File".to_string(), 69 | arguments: r"C:\Windows\Web\Screen\img104.jpg".to_string(), 70 | image_url: None 71 | }, 72 | Action { 73 | activation_type: ActivationType::Protocol, 74 | action_content: "Folder".to_string(), 75 | arguments: r"$env:USERPROFILE\Downloads".to_string(), // PowerShell supports using environment variables 76 | image_url: None 77 | } 78 | ]) 79 | .show() 80 | .expect("Failed to show toast notification"); 81 | } 82 | ``` 83 | 84 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/button_basic.png) 85 | 86 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/button_image.png) 87 | 88 | ### [古诗](./examples/advance_2.rs) 89 | ```PowerShell 90 | cargo run --example advance_2 91 | ``` 92 | ```rust 93 | use win_toast_notify::*; 94 | use std::env; 95 | 96 | fn main() { 97 | let current_dir = env::current_dir().expect("Failed to get current directory"); 98 | let logo_path = current_dir.join("examples/poet.jpeg"); 99 | let image_path = current_dir.join("examples/poetry.jpg"); 100 | let button_read_path = current_dir.join("examples/button_read.png"); 101 | let button_appreciation_path = current_dir.join("examples/button_appreciation.png"); 102 | let introduce_url = "https://en.wikipedia.org/wiki/Li_Qingzhao"; 103 | let read_url = "https://baike.baidu.com/item/%E4%B8%80%E5%89%AA%E6%A2%85%C2%B7%E7%BA%A2%E8%97%95%E9%A6%99%E6%AE%8B%E7%8E%89%E7%B0%9F%E7%A7%8B/593597#1"; 104 | let appreciation_url = "https://baike.baidu.com/item/%E4%B8%80%E5%89%AA%E6%A2%85%C2%B7%E7%BA%A2%E8%97%95%E9%A6%99%E6%AE%8B%E7%8E%89%E7%B0%9F%E7%A7%8B/593597#4"; 105 | 106 | WinToastNotify::new() 107 | .set_open(introduce_url) // 点击通知的打开链接或文件(夹) 108 | .set_duration(Duration::Long) 109 | .set_title("《一剪梅·红藕香残玉簟秋》 宋·李清照") 110 | .set_messages(vec![ 111 | "红藕香残玉簟秋。轻解罗裳,独上兰舟。\n云中谁寄锦书来,雁字回时,月满西楼。", 112 | "花自飘零水自流。一种相思,两处闲愁。\n此情无计可消除,才下眉头,却上心头。" 113 | ]) 114 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 115 | .set_image(image_path.to_str().expect("Path is an invalid unicode"), ImagePlacement::Top) 116 | .set_actions(vec![ 117 | Action { 118 | activation_type: ActivationType::Protocol, 119 | action_content: "阅读".to_string(), 120 | arguments: read_url.to_string(), 121 | image_url: Some(button_read_path.to_string_lossy().to_string()), 122 | }, 123 | Action { 124 | activation_type: ActivationType::Protocol, 125 | action_content: "赏析".to_string(), 126 | arguments: appreciation_url.to_string(), 127 | image_url: Some(button_appreciation_path.to_string_lossy().to_string()), 128 | } 129 | ]) 130 | .set_audio(Audio::WinLoopingAlarm5, Loop::True) 131 | .show() 132 | .expect("Failed to show toast notification") 133 | } 134 | ``` 135 | 136 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/advance_zh.png) 137 | 138 | ### [进度条](./examples/progress_bat_2.rs) 139 | ```PowerShell 140 | cargo run --example progress_bat_2 141 | ``` 142 | ```rust 143 | use win_toast_notify::{WinToastNotify, CropCircle, Duration, Progress}; 144 | use std::env; 145 | 146 | fn main() { 147 | let current_dir = env::current_dir().expect("Failed to get current directory"); 148 | let logo_path = current_dir.join("examples/progress_logo.png"); 149 | 150 | let tag = "star-rail"; 151 | let title = "Honkai: Star Rail"; 152 | let mut status = String::from("Downloading..."); 153 | let mut value = 0.0; 154 | let mut value_string = String::from("0%"); 155 | 156 | WinToastNotify::new() 157 | .set_duration(Duration::Long) 158 | .set_title("Downloading miHoYo Game...") 159 | .set_messages(vec![ 160 | "May This Journey Lead Us Starward" 161 | ]) 162 | .set_logo(logo_path.to_str().expect("Path is an invalid unicode"), CropCircle::True) 163 | .set_progress(Progress {tag, title, status, value, value_string} ) 164 | .show() 165 | .expect("Failed to show toast notification"); 166 | 167 | for i in 1..=10 { 168 | std::thread::sleep(std::time::Duration::from_millis(500)); 169 | value = i as f32 / 10.0; 170 | if i != 10 { 171 | value_string = format!("{:.1}%", value * 100.0); 172 | WinToastNotify::progress_update(None, tag, value, value_string).expect("Failed to update"); 173 | } else { 174 | status = String::from("Completed"); 175 | value_string = String::from("100%"); 176 | WinToastNotify::progress_complete(None, tag, status, value_string).expect("Failed to complete"); 177 | }; 178 | }; 179 | } 180 | ``` 181 | 182 | ![image](https://raw.githubusercontent.com/iKineticate/win-toast-notify/main/screenshots/progress.gif) -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Write; 2 | use std::os::windows::process::CommandExt; 3 | use std::process::Command; 4 | use xml::escape::escape_str_attribute; 5 | 6 | pub struct WinToastNotify { 7 | pub app_id: Option, 8 | pub duration: Duration, 9 | pub scenario: Scenario, 10 | pub open: Option, 11 | pub title: Option, 12 | pub messages: Option>, 13 | pub logo: Option, 14 | pub logo_circle: CropCircle, 15 | pub image: Option, 16 | pub image_placement: ImagePlacement, 17 | pub actions: Option>, 18 | pub progress: Option, 19 | pub audio: Option