Skip to content

Commit e1166c4

Browse files
committed
Add support for hero images with Windows
1 parent 27bbbff commit e1166c4

6 files changed

Lines changed: 37 additions & 9 deletions

File tree

native/WinToastWrapper/WinToastWrapper.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,9 @@ NOTIFYAPI INT64 WNT_ShowToast(
237237
if (!descriptor || !handler)
238238
return static_cast<INT64>(WinToast::WinToastError::InvalidParameters);
239239

240-
bool hasBody = descriptor->body != nullptr && descriptor->body[0] != L'\0';
241-
bool hasImage = descriptor->imagePath != nullptr && descriptor->imagePath[0] != L'\0';
240+
bool hasBody = descriptor->body != nullptr && descriptor->body[0] != L'\0';
241+
bool hasImage = descriptor->imagePath != nullptr && descriptor->imagePath[0] != L'\0';
242+
bool hasHeroImage = descriptor->heroImagePath != nullptr && descriptor->heroImagePath[0] != L'\0';
242243

243244
WinToastTemplate tmpl(SelectTemplateType(hasImage, hasBody));
244245

@@ -249,6 +250,9 @@ NOTIFYAPI INT64 WNT_ShowToast(
249250
if (hasImage)
250251
tmpl.setImagePath(descriptor->imagePath);
251252

253+
if (hasHeroImage)
254+
tmpl.setHeroImagePath(descriptor->heroImagePath);
255+
252256
for (int i = 0; i < descriptor->buttonCount; ++i)
253257
{
254258
if (descriptor->buttonLabels && descriptor->buttonLabels[i])

native/WinToastWrapper/WinToastWrapper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ typedef enum _WNT_AudioOption {
7070
typedef struct _WNT_ToastDescriptor {
7171
const wchar_t* title; /* required */
7272
const wchar_t* body; /* nullable */
73-
const wchar_t* imagePath; /* nullable — absolute path to an image file */
73+
const wchar_t* imagePath; /* nullable — absolute path; displayed as a square thumbnail */
74+
const wchar_t* heroImagePath; /* nullable — absolute path; displayed full-width, aspect ratio preserved */
7475
const wchar_t** buttonLabels; /* nullable — array of buttonCount wchar_t* */
7576
int buttonCount;
7677
long long expirationMs; /* 0 = platform default */

src/Notify.NET/Abstractions/NotificationRequest.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@ public sealed class NotificationRequest
1616
/// <summary>Optional body text shown beneath the title.</summary>
1717
public string? Body { get; }
1818

19-
/// <summary>Absolute path to an image file to display in the notification.</summary>
19+
/// <summary>Absolute path to an image file displayed as a square thumbnail.</summary>
2020
public string? ImagePath { get; }
2121

22+
/// <summary>
23+
/// Absolute path to an image file displayed full-width above the title, preserving aspect ratio.
24+
/// Windows only — ignored on Linux and macOS.
25+
/// </summary>
26+
public string? HeroImagePath { get; }
27+
2228
/// <summary>Action buttons to display. Maximum platform limits apply (typically 5 on Windows, varies on Linux).</summary>
2329
public IReadOnlyList<NotificationButton> Buttons { get; }
2430

@@ -38,6 +44,7 @@ internal NotificationRequest(
3844
string title,
3945
string? body,
4046
string? imagePath,
47+
string? heroImagePath,
4148
IReadOnlyList<NotificationButton> buttons,
4249
INotificationHandler? handler,
4350
TimeSpan? expiration,
@@ -50,6 +57,7 @@ internal NotificationRequest(
5057
Title = title;
5158
Body = body;
5259
ImagePath = imagePath;
60+
HeroImagePath = heroImagePath;
5361
Buttons = buttons;
5462
Handler = handler;
5563
Expiration = expiration;

src/Notify.NET/Builder/NotificationBuilder.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public sealed class NotificationBuilder
2626
private string _title = string.Empty;
2727
private string? _body;
2828
private string? _imagePath;
29+
private string? _heroImagePath;
2930
private readonly List<NotificationButton> _buttons = new List<NotificationButton>();
3031
private INotificationHandler? _handler;
3132
private TimeSpan? _expiration;
@@ -58,13 +59,23 @@ public NotificationBuilder WithBody(string body)
5859
return this;
5960
}
6061

61-
/// <summary>Sets the absolute path of an image to display in the notification.</summary>
62+
/// <summary>Sets the absolute path of an image to display as a square thumbnail.</summary>
6263
public NotificationBuilder WithImage(string imagePath)
6364
{
6465
_imagePath = imagePath;
6566
return this;
6667
}
6768

69+
/// <summary>
70+
/// Sets the absolute path of an image to display full-width above the notification title,
71+
/// preserving the image's aspect ratio. Windows only — ignored on Linux and macOS.
72+
/// </summary>
73+
public NotificationBuilder WithHeroImage(string imagePath)
74+
{
75+
_heroImagePath = imagePath;
76+
return this;
77+
}
78+
6879
/// <summary>Adds an action button with an optional click callback.</summary>
6980
/// <param name="label">Text shown on the button.</param>
7081
/// <param name="callback">Called with the notification ID when the button is clicked.</param>
@@ -166,6 +177,7 @@ public NotificationRequest Build()
166177
title: _title,
167178
body: _body,
168179
imagePath: _imagePath,
180+
heroImagePath: _heroImagePath,
169181
buttons: _buttons.AsReadOnly(),
170182
handler: handler,
171183
expiration: _expiration,

src/Notify.NET/Platform/Windows/WinToastNative.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ internal struct WNT_ToastDescriptor
4545
{
4646
public IntPtr title; // wchar_t*
4747
public IntPtr body; // wchar_t* (may be IntPtr.Zero)
48-
public IntPtr imagePath; // wchar_t* (may be IntPtr.Zero)
48+
public IntPtr imagePath; // wchar_t* (may be IntPtr.Zero) — square thumbnail
49+
public IntPtr heroImagePath; // wchar_t* (may be IntPtr.Zero) — full-width, aspect ratio preserved
4950
public IntPtr buttonLabels; // wchar_t** (array of pointers, may be IntPtr.Zero)
5051
public int buttonCount;
5152
public long expirationMs; // 0 = platform default

src/Notify.NET/Platform/Windows/WindowsNotificationService.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,10 @@ private long ShowOnSta(NotificationRequest request)
214214
// Pin managed strings as unmanaged UTF-16 memory for the duration of the call.
215215
// button label pointers are pinned in the IntPtr[] and that array is pinned too.
216216

217-
using var titlePin = new PinnedString(request.Title);
218-
using var bodyPin = new PinnedString(request.Body);
219-
using var imagePin = new PinnedString(ResolveImagePath(request.ImagePath));
217+
using var titlePin = new PinnedString(request.Title);
218+
using var bodyPin = new PinnedString(request.Body);
219+
using var imagePin = new PinnedString(ResolveImagePath(request.ImagePath));
220+
using var heroImagePin = new PinnedString(ResolveImagePath(request.HeroImagePath));
220221

221222
// Build array of pinned button label pointers.
222223
var buttonPins = new PinnedString[request.Buttons.Count];
@@ -244,6 +245,7 @@ private long ShowOnSta(NotificationRequest request)
244245
title = titlePin.Pointer,
245246
body = bodyPin.Pointer,
246247
imagePath = imagePin.Pointer,
248+
heroImagePath = heroImagePin.Pointer,
247249
buttonLabels = buttonArrayPtr,
248250
buttonCount = request.Buttons.Count,
249251
expirationMs = request.Expiration.HasValue ? (long)request.Expiration.Value.TotalMilliseconds : 0L,

0 commit comments

Comments
 (0)