Skip to content

Commit 39ff5a2

Browse files
committed
enhancement(image): Add a custom guess function to image widget #1
1 parent 61726ba commit 39ff5a2

File tree

9 files changed

+128
-83
lines changed

9 files changed

+128
-83
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "win32_notif"
3-
version = "0.7.0"
3+
version = "0.7.1"
44
edition = "2021"
55
description = "Wrapper around Windows UWP XAML (WinRT) Notification api"
66
license = "MIT"

examples/lunch.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use std::{path::absolute, thread, time::Duration};
2+
3+
use win32_notif::{
4+
notification::{actions::{
5+
action::{ActivationType, AfterActivationBehavior},
6+
ActionButton,
7+
}, audio::{Audio, Src}, header::{Header, HeaderActivationType}, visual::{Image, Placement, Text}, ToastDuration}, NotificationActivatedEventHandler, NotificationBuilder, ToastsNotifier
8+
};
9+
10+
fn main() {
11+
let path = absolute("./examples/strawberry.jpg").unwrap();
12+
let path = path.to_string_lossy();
13+
14+
let notifier = ToastsNotifier::new("Microsoft.Windows.Explorer").unwrap();
15+
16+
17+
18+
let notif = NotificationBuilder::new()
19+
.audio(Audio::new(Src::Reminder, true, false))
20+
.header(Header::new("food01", "Order Food", "food", Some(HeaderActivationType::Foreground)))
21+
.visual(
22+
Image::create(20, format!("file:///{path}"))
23+
.with_placement(Placement::Hero)
24+
.without_image_query()
25+
)
26+
.visual(
27+
Text::create(1, "Would you like to order lunch today?")
28+
)
29+
.action(
30+
ActionButton::create("Yes")
31+
.set_tooltip("Yes")
32+
.set_activation_type(ActivationType::Foreground)
33+
.set_after_activation_behavior(AfterActivationBehavior::PendingUpdate)
34+
.set_id("yes")
35+
)
36+
.action(
37+
ActionButton::create("No")
38+
.set_tooltip("No")
39+
.set_activation_type(ActivationType::Foreground)
40+
.set_after_activation_behavior(AfterActivationBehavior::Default)
41+
.set_id("no")
42+
)
43+
.set_duration(ToastDuration::Long)
44+
.on_activated(NotificationActivatedEventHandler::new(|a, b| {
45+
println!("Triggered");
46+
let notification = a.unwrap();
47+
let args = b.unwrap();
48+
49+
println!("{args:?}");
50+
if let Some(x) = args.button_id {
51+
if &x == "yes" {
52+
53+
}
54+
}
55+
56+
Ok(())
57+
}))
58+
.build(0, &notifier, "01", "ahq")
59+
.expect("Unable to build notification");
60+
61+
_ = notif.show();
62+
63+
loop {
64+
thread::sleep(Duration::from_millis(200));
65+
}
66+
}

examples/prompt.rs

Lines changed: 0 additions & 68 deletions
This file was deleted.

examples/strawberry.jpg

18.3 KB
Loading

src/structs/handler/activated.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl NotificationActivatedEventHandler {
6161
mut func: T,
6262
) -> Self {
6363
let handler: TypedEventHandler<ToastNotification, IInspectable> =
64-
TypedEventHandler::new(move |a: Ref<ToastNotification>, b: Ref<IInspectable>| {
64+
TypedEventHandler::new(move |a: Ref<ToastNotification>, b: Ref<IInspectable>| {
6565
let a = a.as_ref();
6666
let a = a.and_then(|a| PartialNotification { _toast: a }.into());
6767

src/structs/notification/widgets/actions/action.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ impl Into<String> for HintButtonStyle {
183183
fn into(self) -> String {
184184
match self {
185185
Self::None => "".to_string(),
186-
Self::Success => "success".to_string(),
187-
Self::Critical => "critical".to_string(),
186+
Self::Success => "Success".to_string(),
187+
Self::Critical => "Critical".to_string(),
188188
}
189189
}
190190
}

src/structs/notification/widgets/visual/image.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,31 @@ pub struct Image {
7676

7777
impl TextOrImageElement for Image {}
7878

79+
fn guess_src(src: String) -> String {
80+
let protocols = ["https://", "http://", "file:///", "ms-appx:///", "ms-appdata:///local/"];
81+
82+
if !(protocols.iter().any(|x| src.starts_with(x))) {
83+
return format!("file:///{src}");
84+
}
85+
86+
src
87+
}
88+
7989
impl Image {
90+
/// The `src` should be the either of the following following
91+
/// - `https://url or http://url`
92+
/// - `file:///path/to/file`
93+
///
94+
/// If none of the above is provided, the `src` will be set to `file:///path/to/file`
95+
pub fn create<T: Into<String>>(id: u64, src: T) -> Self {
96+
Self::new(id, src.into(), None, false, Placement::None, ImageCrop::Default, false)
97+
}
98+
99+
/// The `src` should be the either of the following following
100+
/// - `https://url or http://url`
101+
/// - `file:///path/to/file`
102+
///
103+
/// If none of the above is provided, the `src` will be set to `file:///path/to/file`
80104
pub fn new(
81105
id: u64,
82106
src: String,
@@ -144,23 +168,23 @@ impl ToXML for Image {
144168
fn to_xml(&self) -> String {
145169
format!(
146170
r#"
147-
<image id="{id:#?}" {margin} {align} src={src:?} {alt} addImageQuery={add_image_query:#?} {placement} {crop} />
171+
<image id="{id:#?}" {margin} {align} src={src} {add_image_query} {alt} {placement} {crop} />
148172
"#,
149173
align = self.align.to_string(),
150174
margin = match self.no_margin {
151175
true => "hint-remove-margin=\"true\"".to_string(),
152176
false => "".to_string(),
153177
},
154178
id = self.id,
155-
src = &self.src,
179+
src = format!("{:?}", self.src).replace("\\\\", "\\"),
156180
alt = self
157181
.alt
158182
.clone()
159183
.map_or_else(|| string!(""), |x| format!("alt={x:#?}")),
160184
add_image_query = if self.add_image_query {
161-
"True"
185+
"addImageQuery=\"True\""
162186
} else {
163-
"False"
187+
""
164188
},
165189
placement = self.placement.to_string(),
166190
crop = self.crop.to_string()

src/structs/notifier/mod.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
1-
use windows::UI::Notifications::{
2-
NotificationData, NotificationUpdateResult, ToastNotificationManager, ToastNotifier,
3-
};
1+
use std::sync::Arc;
2+
3+
use windows::{core::HSTRING, UI::Notifications::{
4+
NotificationData, NotificationUpdateResult, ToastNotificationHistory, ToastNotificationManager, ToastNotifier
5+
}};
46

57
use crate::NotifError;
68

79
use super::NotificationDataSet;
810

911
pub struct ToastsNotifier {
1012
_inner: ToastNotifier,
13+
app_id: Arc<str>
1114
}
1215

1316
impl ToastsNotifier {
14-
pub fn new(app_id: &str) -> Result<Self, NotifError> {
15-
let _inner = ToastNotificationManager::CreateToastNotifierWithId(&app_id.into())?;
17+
pub fn new<T: Into<String>>(app_id: T) -> Result<Self, NotifError> {
18+
let string: String = app_id.into();
19+
let _inner = ToastNotificationManager::CreateToastNotifierWithId(&string.into())?;
20+
21+
Ok(Self { _inner, app_id: Arc::new(string) })
22+
}
1623

17-
Ok(Self { _inner })
24+
pub fn manager(&self) -> Result<ToastsManager, NotifError> {
25+
Ok(ToastsManager {
26+
inner: Arc::new(ToastNotificationManager::History()?),
27+
app_id: self.app_id.clone(),
28+
})
1829
}
1930

2031
pub fn update(
@@ -35,3 +46,15 @@ impl ToastsNotifier {
3546
&self._inner
3647
}
3748
}
49+
50+
#[derive(Debug, Clone)]
51+
pub struct ToastsManager {
52+
pub(crate) inner: Arc<ToastNotificationHistory>,
53+
pub app_id: Arc<SafeString>
54+
}
55+
56+
impl ToastsManager {
57+
pub fn inner(&self) -> &Arc<ToastNotificationHistory> {
58+
&self.inner
59+
}
60+
}

0 commit comments

Comments
 (0)