Skip to content

Commit fdda1c5

Browse files
authored
Merge pull request electron#11647 from sethlu/accept-additional-notification-actions
feat: Accept additional notification actions
2 parents 7e2f760 + e3b70dd commit fdda1c5

4 files changed

Lines changed: 58 additions & 20 deletions

File tree

brightray/browser/mac/cocoa_notification.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#import <Foundation/Foundation.h>
99

10+
#include <map>
1011
#include <string>
1112
#include <vector>
1213

@@ -27,15 +28,17 @@ class CocoaNotification : public Notification {
2728

2829
void NotificationDisplayed();
2930
void NotificationReplied(const std::string& reply);
30-
void NotificationButtonClicked();
31+
void NotificationActivated();
32+
void NotificationActivated(NSUserNotificationAction* action);
3133

3234
NSUserNotification* notification() const { return notification_; }
3335

3436
private:
3537
void LogAction(const char* action);
3638

3739
base::scoped_nsobject<NSUserNotification> notification_;
38-
int action_index_;
40+
std::map<std::string, unsigned> additional_action_indices_;
41+
unsigned action_index_;
3942

4043
DISALLOW_COPY_AND_ASSIGN(CocoaNotification);
4144
};

brightray/browser/mac/cocoa_notification.mm

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,44 +29,59 @@
2929
void CocoaNotification::Show(const NotificationOptions& options) {
3030
notification_.reset([[NSUserNotification alloc] init]);
3131

32-
NSString* identifier = [NSString stringWithFormat:@"%s%d", "ElectronNotification", g_identifier_];
32+
NSString* identifier = [NSString stringWithFormat:@"ElectronNotification%d", g_identifier_++];
3333

3434
[notification_ setTitle:base::SysUTF16ToNSString(options.title)];
3535
[notification_ setSubtitle:base::SysUTF16ToNSString(options.subtitle)];
3636
[notification_ setInformativeText:base::SysUTF16ToNSString(options.msg)];
3737
[notification_ setIdentifier:identifier];
38-
g_identifier_++;
3938

4039
if (getenv("ELECTRON_DEBUG_NOTIFICATIONS")) {
4140
LOG(INFO) << "Notification created (" << [identifier UTF8String] << ")";
4241
}
4342

44-
if ([notification_ respondsToSelector:@selector(setContentImage:)] &&
45-
!options.icon.drawsNothing()) {
43+
if (!options.icon.drawsNothing()) {
4644
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
4745
options.icon, base::mac::GetGenericRGBColorSpace());
4846
[notification_ setContentImage:image];
4947
}
5048

5149
if (options.silent) {
5250
[notification_ setSoundName:nil];
53-
} else if (options.sound != nil) {
54-
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
55-
} else {
51+
} else if (options.sound.empty()) {
5652
[notification_ setSoundName:NSUserNotificationDefaultSoundName];
53+
} else {
54+
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
5755
}
5856

5957
[notification_ setHasActionButton:false];
6058

6159
int i = 0;
60+
action_index_ = UINT_MAX;
61+
NSMutableArray* additionalActions = [[[NSMutableArray alloc] init] autorelease];
6262
for (const auto& action : options.actions) {
6363
if (action.type == base::ASCIIToUTF16("button")) {
64-
[notification_ setHasActionButton:true];
65-
[notification_ setActionButtonTitle:base::SysUTF16ToNSString(action.text)];
66-
action_index_ = i;
64+
if (action_index_ == UINT_MAX) {
65+
// First button observed is the displayed action
66+
[notification_ setHasActionButton:true];
67+
[notification_ setActionButtonTitle:base::SysUTF16ToNSString(action.text)];
68+
action_index_ = i;
69+
} else {
70+
// All of the rest are appended to the list of additional actions
71+
NSString* actionIdentifier = [NSString stringWithFormat:@"%@Action%d", identifier, i];
72+
NSUserNotificationAction* notificationAction =
73+
[NSUserNotificationAction actionWithIdentifier:actionIdentifier
74+
title:base::SysUTF16ToNSString(action.text)];
75+
[additionalActions addObject:notificationAction];
76+
additional_action_indices_.insert(std::make_pair(base::SysNSStringToUTF8(actionIdentifier), i));
77+
}
6778
}
6879
i++;
6980
}
81+
if ([additionalActions count] > 0 &&
82+
[notification_ respondsToSelector:@selector(setAdditionalActions:)]) {
83+
[notification_ setAdditionalActions:additionalActions]; // Requires macOS 10.10
84+
}
7085

7186
if (options.has_reply) {
7287
[notification_ setResponsePlaceholder:base::SysUTF16ToNSString(options.reply_placeholder)];
@@ -101,13 +116,30 @@
101116
this->LogAction("replied to");
102117
}
103118

104-
void CocoaNotification::NotificationButtonClicked() {
119+
void CocoaNotification::NotificationActivated() {
105120
if (delegate())
106121
delegate()->NotificationAction(action_index_);
107122

108123
this->LogAction("button clicked");
109124
}
110125

126+
void CocoaNotification::NotificationActivated(NSUserNotificationAction* action) {
127+
if (delegate()) {
128+
unsigned index = action_index_;
129+
std::string identifier = base::SysNSStringToUTF8(action.identifier);
130+
for (const auto& it : additional_action_indices_) {
131+
if (it.first == identifier) {
132+
index = it.second;
133+
break;
134+
}
135+
}
136+
137+
delegate()->NotificationAction(index);
138+
}
139+
140+
this->LogAction("button clicked");
141+
}
142+
111143
void CocoaNotification::LogAction(const char* action) {
112144
if (getenv("ELECTRON_DEBUG_NOTIFICATIONS")) {
113145
NSString* identifier = [notification_ valueForKey:@"identifier"];

brightray/browser/mac/notification_center_delegate.mm

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@ - (void)userNotificationCenter:(NSUserNotificationCenter*)center
3434
}
3535

3636
if (notification) {
37-
if (notif.activationType == NSUserNotificationActivationTypeReplied) {
38-
notification->NotificationReplied([notif.response.string UTF8String]);
39-
} else if (notif.activationType == NSUserNotificationActivationTypeActionButtonClicked) {
40-
notification->NotificationButtonClicked();
41-
} else if (notif.activationType == NSUserNotificationActivationTypeContentsClicked) {
37+
// Ref: https://developer.apple.com/documentation/foundation/nsusernotificationactivationtype?language=objc
38+
if (notif.activationType == NSUserNotificationActivationTypeContentsClicked) {
4239
notification->NotificationClicked();
40+
} else if (notif.activationType == NSUserNotificationActivationTypeActionButtonClicked) {
41+
notification->NotificationActivated();
42+
} else if (notif.activationType == NSUserNotificationActivationTypeReplied) {
43+
notification->NotificationReplied([notif.response.string UTF8String]);
44+
} else if (notif.activationType == NSUserNotificationActivationTypeAdditionalActionClicked) {
45+
notification->NotificationActivated([notif additionalActivationAction]);
4346
}
4447
}
4548
}

docs/api/structures/notification-action.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77

88
| Action Type | Platform Support | Usage of `text` | Default `text` | Limitations |
99
|-------------|------------------|-----------------|----------------|-------------|
10-
| `button` | macOS | Used as the label for the button | "Show" | Maximum of one button, if multiple are provided only the last is used. This action is also incompatible with `hasReply` and will be ignored if `hasReply` is `true`. |
10+
| `button` | macOS | Used as the label for the button | "Show" (or a localized string by system default if first of such `button`, otherwise empty) | Only the first one is used. If multiple are provided, those beyond the first will be listed as additional actions (displayed when mouse active over the action button). Any such action also is incompatible with `hasReply` and will be ignored if `hasReply` is `true`. |
1111

1212
### Button support on macOS
1313

1414
In order for extra notification buttons to work on macOS your app must meet the
1515
following criteria.
1616

1717
* App is signed
18-
* App has it's `NSUserNotificationAlertStyle` set to `alert` in the `info.plist`.
18+
* App has it's `NSUserNotificationAlertStyle` set to `alert` in the `Info.plist`.
1919

2020
If either of these requirements are not met the button simply won't appear.

0 commit comments

Comments
 (0)