Merge pull request #11647 from sethlu/accept-additional-notification-actions
feat: Accept additional notification actions
This commit is contained in:
commit
fdda1c55c5
4 changed files with 58 additions and 20 deletions
|
@ -7,6 +7,7 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -27,7 +28,8 @@ class CocoaNotification : public Notification {
|
|||
|
||||
void NotificationDisplayed();
|
||||
void NotificationReplied(const std::string& reply);
|
||||
void NotificationButtonClicked();
|
||||
void NotificationActivated();
|
||||
void NotificationActivated(NSUserNotificationAction* action);
|
||||
|
||||
NSUserNotification* notification() const { return notification_; }
|
||||
|
||||
|
@ -35,7 +37,8 @@ class CocoaNotification : public Notification {
|
|||
void LogAction(const char* action);
|
||||
|
||||
base::scoped_nsobject<NSUserNotification> notification_;
|
||||
int action_index_;
|
||||
std::map<std::string, unsigned> additional_action_indices_;
|
||||
unsigned action_index_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CocoaNotification);
|
||||
};
|
||||
|
|
|
@ -29,20 +29,18 @@ CocoaNotification::~CocoaNotification() {
|
|||
void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
notification_.reset([[NSUserNotification alloc] init]);
|
||||
|
||||
NSString* identifier = [NSString stringWithFormat:@"%s%d", "ElectronNotification", g_identifier_];
|
||||
NSString* identifier = [NSString stringWithFormat:@"ElectronNotification%d", g_identifier_++];
|
||||
|
||||
[notification_ setTitle:base::SysUTF16ToNSString(options.title)];
|
||||
[notification_ setSubtitle:base::SysUTF16ToNSString(options.subtitle)];
|
||||
[notification_ setInformativeText:base::SysUTF16ToNSString(options.msg)];
|
||||
[notification_ setIdentifier:identifier];
|
||||
g_identifier_++;
|
||||
|
||||
if (getenv("ELECTRON_DEBUG_NOTIFICATIONS")) {
|
||||
LOG(INFO) << "Notification created (" << [identifier UTF8String] << ")";
|
||||
}
|
||||
|
||||
if ([notification_ respondsToSelector:@selector(setContentImage:)] &&
|
||||
!options.icon.drawsNothing()) {
|
||||
if (!options.icon.drawsNothing()) {
|
||||
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
|
||||
options.icon, base::mac::GetGenericRGBColorSpace());
|
||||
[notification_ setContentImage:image];
|
||||
|
@ -50,23 +48,40 @@ void CocoaNotification::Show(const NotificationOptions& options) {
|
|||
|
||||
if (options.silent) {
|
||||
[notification_ setSoundName:nil];
|
||||
} else if (options.sound != nil) {
|
||||
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
|
||||
} else {
|
||||
} else if (options.sound.empty()) {
|
||||
[notification_ setSoundName:NSUserNotificationDefaultSoundName];
|
||||
} else {
|
||||
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
|
||||
}
|
||||
|
||||
[notification_ setHasActionButton:false];
|
||||
|
||||
int i = 0;
|
||||
action_index_ = UINT_MAX;
|
||||
NSMutableArray* additionalActions = [[[NSMutableArray alloc] init] autorelease];
|
||||
for (const auto& action : options.actions) {
|
||||
if (action.type == base::ASCIIToUTF16("button")) {
|
||||
if (action_index_ == UINT_MAX) {
|
||||
// First button observed is the displayed action
|
||||
[notification_ setHasActionButton:true];
|
||||
[notification_ setActionButtonTitle:base::SysUTF16ToNSString(action.text)];
|
||||
action_index_ = i;
|
||||
} else {
|
||||
// All of the rest are appended to the list of additional actions
|
||||
NSString* actionIdentifier = [NSString stringWithFormat:@"%@Action%d", identifier, i];
|
||||
NSUserNotificationAction* notificationAction =
|
||||
[NSUserNotificationAction actionWithIdentifier:actionIdentifier
|
||||
title:base::SysUTF16ToNSString(action.text)];
|
||||
[additionalActions addObject:notificationAction];
|
||||
additional_action_indices_.insert(std::make_pair(base::SysNSStringToUTF8(actionIdentifier), i));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if ([additionalActions count] > 0 &&
|
||||
[notification_ respondsToSelector:@selector(setAdditionalActions:)]) {
|
||||
[notification_ setAdditionalActions:additionalActions]; // Requires macOS 10.10
|
||||
}
|
||||
|
||||
if (options.has_reply) {
|
||||
[notification_ setResponsePlaceholder:base::SysUTF16ToNSString(options.reply_placeholder)];
|
||||
|
@ -101,13 +116,30 @@ void CocoaNotification::NotificationReplied(const std::string& reply) {
|
|||
this->LogAction("replied to");
|
||||
}
|
||||
|
||||
void CocoaNotification::NotificationButtonClicked() {
|
||||
void CocoaNotification::NotificationActivated() {
|
||||
if (delegate())
|
||||
delegate()->NotificationAction(action_index_);
|
||||
|
||||
this->LogAction("button clicked");
|
||||
}
|
||||
|
||||
void CocoaNotification::NotificationActivated(NSUserNotificationAction* action) {
|
||||
if (delegate()) {
|
||||
unsigned index = action_index_;
|
||||
std::string identifier = base::SysNSStringToUTF8(action.identifier);
|
||||
for (const auto& it : additional_action_indices_) {
|
||||
if (it.first == identifier) {
|
||||
index = it.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delegate()->NotificationAction(index);
|
||||
}
|
||||
|
||||
this->LogAction("button clicked");
|
||||
}
|
||||
|
||||
void CocoaNotification::LogAction(const char* action) {
|
||||
if (getenv("ELECTRON_DEBUG_NOTIFICATIONS")) {
|
||||
NSString* identifier = [notification_ valueForKey:@"identifier"];
|
||||
|
|
|
@ -34,12 +34,15 @@
|
|||
}
|
||||
|
||||
if (notification) {
|
||||
if (notif.activationType == NSUserNotificationActivationTypeReplied) {
|
||||
notification->NotificationReplied([notif.response.string UTF8String]);
|
||||
} else if (notif.activationType == NSUserNotificationActivationTypeActionButtonClicked) {
|
||||
notification->NotificationButtonClicked();
|
||||
} else if (notif.activationType == NSUserNotificationActivationTypeContentsClicked) {
|
||||
// Ref: https://developer.apple.com/documentation/foundation/nsusernotificationactivationtype?language=objc
|
||||
if (notif.activationType == NSUserNotificationActivationTypeContentsClicked) {
|
||||
notification->NotificationClicked();
|
||||
} else if (notif.activationType == NSUserNotificationActivationTypeActionButtonClicked) {
|
||||
notification->NotificationActivated();
|
||||
} else if (notif.activationType == NSUserNotificationActivationTypeReplied) {
|
||||
notification->NotificationReplied([notif.response.string UTF8String]);
|
||||
} else if (notif.activationType == NSUserNotificationActivationTypeAdditionalActionClicked) {
|
||||
notification->NotificationActivated([notif additionalActivationAction]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
| Action Type | Platform Support | Usage of `text` | Default `text` | Limitations |
|
||||
|-------------|------------------|-----------------|----------------|-------------|
|
||||
| `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`. |
|
||||
| `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`. |
|
||||
|
||||
### Button support on macOS
|
||||
|
||||
|
@ -15,6 +15,6 @@ In order for extra notification buttons to work on macOS your app must meet the
|
|||
following criteria.
|
||||
|
||||
* App is signed
|
||||
* App has it's `NSUserNotificationAlertStyle` set to `alert` in the `info.plist`.
|
||||
* App has it's `NSUserNotificationAlertStyle` set to `alert` in the `Info.plist`.
|
||||
|
||||
If either of these requirements are not met the button simply won't appear.
|
||||
|
|
Loading…
Reference in a new issue