Notification Center reply

Hi,

I’ve been trying to get the Notification Center to reply back to the script, but can’t get what is written in the Developer documents. Also, what I’ve read on the internet doesn’t cover the reply back to the script. What I have already is working for sending the notification. When I test the ‘presented’ property of NSUserNotification, I don’t seem to get YES or NO. I’m thinking that I need to set the ‘delegate’. Anyway, here’s what I compiled from some of the things from the internet, my own, and especially from Shane’s posts:

script AppDelegate
	property parent : class "NSObject"
    property myNotification : missing value
	
	on applicationWillFinishLaunching_(aNotification)
		-- send a notification to indicate the application has started, then quit
        -- set theDate to current application's class "NSDate"'s |date|() -- current date
        set numSeconds to 10
        set targetDate to current application's class "NSDate"'s dateWithTimeIntervalSinceNow_(numSeconds)
        -- format string from NSDate (ShaneS)
        set myFormatter to current application's class "NSDateFormatter"'s alloc()'s init()
        myFormatter's setDateStyle_(1) -- 0 = none, 1 = short, 2 = med, 3 = long, 4 = full
        myFormatter's setTimeStyle_(2)
        set dateAsString to myFormatter's stringFromDate_(targetDate)
        -- send notification to NSUserNotificationCenter
		my sendNotification_("The Timer",dateAsString,"It's time!","Restart","Stop",targetDate,"Boing")
        say "The message was sent."
        -- how to check for delivered (presented) and recieved (NSUserNotificationActivationType)?
		quit
	end applicationWillFinishLaunching_
	
	-- Method for sending a notification
	on sendNotification_(aTitle, aSubtitle, aMessage, aActionButtonTitle, aOtherButtonTitle, aDeliveryDate, aSound)
        -- make the notification
		set myNotification to current application's NSUserNotification's alloc()'s init()
		set myNotification's title to aTitle
        set myNotification's subtitle to aSubtitle
		set myNotification's informativeText to aMessage
        set myNotification's actionButtonTitle to aActionButtonTitle
        set myNotification's otherButtonTitle to aOtherButtonTitle
        set myNotification's deliveryDate to aDeliveryDate
        set myNotification's soundName to aSound
        -- schedule the notification
		current application's NSUserNotificationCenter's defaultUserNotificationCenter's scheduleNotification_(myNotification)
	end sendNotification_
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script

What the script does is create a notification with various parameters. One thing to note is that when the user clicks on the action button, the application is rerun. If the user clicks on the ‘other’ button, the notification is removed. Mainly, my question is why don’t I read YES or NO to the ‘presented’ property for now?

Thanks,
kel

ps. getting there.

Hi,

to catch when the user clicks the action button you have to implement the

userNotificationCenter_didActivateNotification_(notificationCenter, notification) 

delegate method.

PS: Consider that notifications are only presented visibly, when the target application is not frontmost.
If you want the notifications always to be presented, implement also

userNotificationCenter_shouldPresentNotification_(notificationCenter, notification)

returning true

Hi Stefan,

I thought it should have been more complicated than it was. Now reading more on the ‘delegate’.

Thanks,
kel

Hi Stefan,

How would you know, in your application, that NSUserNotificationCenter gave a reply?

Thanks,
kel

“delegate method” means that the target class calls those methods at specific moments to inform about a progress
or an asynchronous action.

NSUserNotificationCenterDelegate Protocol provides these methods

“ userNotificationCenter:didDeliverNotification: is sent when the notification is delivered
“ userNotificationCenter:didActivateNotification: is sent when the user clicks the action button

“ userNotificationCenter:shouldPresentNotification: is sent when the user notification center has decided not to present your notification. Return YES/true to display the notification regardless. NO/false is the default

Hi Stefan,

I finally got it working! Don’t know what actually did it, but it probably was a combination of things.

Now working on the activation type.

Thanks a lot,
kel

Hi

If anybody’s interested, here’s the script I ended up with:

script AppDelegate
	property parent : class "NSObject"
    property myNotification : missing value
    property notificationCount: 0
	
	on applicationWillFinishLaunching_(aNotification)
        -- initialize
	end applicationWillFinishLaunching_
    
    on applicationShouldHandleReopen_hasVisibleWindows_(theApplication, aFlag)
        my applicationDidFinishLaunching_(missing value)
        return NO
    end applicationShouldHandleReopen_hasVisibleWindows_
    
    -- main
    on applicationDidFinishLaunching_(aNotification)
        -- set the delegate to script
        current application's NSUserNotificationCenter's defaultUserNotificationCenter's setDelegate_(me)
        -- get target date
        set numSeconds to 30
        set targetDate to current application's NSDate's dateWithTimeIntervalSinceNow_(numSeconds)
        -- format string from NSDate
        set dateAsString to my formatDate_(targetDate,1,2)
        -- make user info NSDictionary
        set notificationCount to notificationCount + 1
        set theValue to (notificationCount as string)
        set nsDict to current application's NSDictionary's dictionaryWithObjectsAndKeys_("value1", "key1", theValue, "key2", "value3", "key3", missing value)
        -- send notification to NSUserNotificationCenter
		my sendNotification_("The Timer",dateAsString,"It's time!","Restart","Stop",targetDate,"Boing",nsDict)
        say "The message was sent."
        return
	end applciationDidFinishLaunching_
    --
    
    -- Formats NSDate to string using styles
    -- 0 = none, 1 = short, 2 = med, 3 = long, 4 = full
    on formatDate_(aNSDate, aDateStyle, aTimeStyle)
        set myFormatter to current application's NSDateFormatter's alloc()'s init()
        myFormatter's setDateStyle_(aDateStyle)
        myFormatter's setTimeStyle_(aTimeStyle)
        set formattedDate to myFormatter's stringFromDate_(aNSDate)
        return formattedDate
    end formatDate_
    
	-- Method for sending a notification
	on sendNotification_(aTitle, aSubtitle, aMessage, aActionButtonTitle, aOtherButtonTitle, aDeliveryDate, aSound, aDict)
        -- make the notification
		set myNotification to current application's NSUserNotification's alloc()'s init()
		set myNotification's title to aTitle
        set myNotification's subtitle to aSubtitle
		set myNotification's informativeText to aMessage
        set myNotification's actionButtonTitle to aActionButtonTitle
        set myNotification's otherButtonTitle to aOtherButtonTitle
        set myNotification's deliveryDate to aDeliveryDate
        set myNotification's soundName to aSound
        set myNotification's userInfo to aDict
        -- schedule the notification
        current application's NSUserNotificationCenter's defaultUserNotificationCenter's scheduleNotification_(myNotification)
        return
	end sendNotification_
    
    -- delegate instance methods
    
    on userNotificationCenter_shouldPresentNotification_(aCenter, aNotification)
        return yes
    end userNotificationCenter_shouldPresentNotification_
    
    on userNotificationCenter_didDeliverNotification_(aCenter, aNotification)
        say "Notification Delivered"
        set theInfo to aNotification's userInfo
        set asRecord to theInfo as record
        set theValue to key2 of asRecord
        say (theValue as string)
        return
    end userNotificationCenter_didDeliverNotification_

    on userNotificationCenter_didActivateNotification_(aCenter, aNotification)
        say "Notification Activated"
        -- 0    none
        -- 1    contents clicked
        -- 2    action button clicked
        set userActivationType to (aNotification's activationType) as integer
        if userActivationType is 0 then
            say "no user activation"
        else if userActivationType is 1 then
            say "contents clicked"
        else if userActivationType is 2 then
            say "action button clicked"
        else
            say "I never get to say anything."
        end if
        return userActivationType
    end userNotificationCenter_didActivateNotification_
	
    --
    
    -- quit
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script

It needs to be run as an application and not from Xcode. No windows.

Edited: I found a minor bug. When I click in the text area of the last window it closed. Needs more testing.

gl,
kel

Another bug showed up. A notification was delivered just now. It must be the default delay. I wonder If that was the notification that closed when I clicked the text area.Testing is fun, but I might have to continue tomorrow. I’ll be waiting for more notifications. Think I pressed the text area many times. :slight_smile:

Edited: I can’t duplicate clicking on the last notification closing when I click in the text area of the last notification. Maybe it’s a bug in the system.

gl,
kel

Hi,

I think I accidentally swiped the notification window when I had thought that I had clicked in the text area. I’ll need to figure out what to do if the user swipes the window, which makes it open in fifteen minutes (like a fifteen minute snooze). Otherwise everything is working ok. Still need to figure out what to do about removing the delivered items from Notification Center. It depends on what you want to happen when the user clicks the action button.

Now I can complete my notification app! :smiley:

Thanks for all the help,
kel

Hi,

Here’s the final template like script I ended up with:

script AppDelegate
	property parent : class "NSObject"
    property myNotification : missing value
    property notificationCount: 0
	
	on applicationWillFinishLaunching_(aNotification)
        -- initialize
        return
	end applicationWillFinishLaunching_
    
    -- reopen handler
    on applicationShouldHandleReopen_hasVisibleWindows_(theApplication, aFlag)
        my applicationDidFinishLaunching_(missing value)
        return NO
    end applicationShouldHandleReopen_hasVisibleWindows_
    
    -- main
    on applicationDidFinishLaunching_(aNotification)
        -- set the delegate to script
        current application's NSUserNotificationCenter's defaultUserNotificationCenter's setDelegate_(me)
        -- get target date
        set numSeconds to 30
        set targetDate to current application's NSDate's dateWithTimeIntervalSinceNow_(numSeconds)
        -- format string from NSDate
        set dateAsString to my formatDate_(targetDate,1,2)
        -- make user info NSDictionary
        set notificationCount to notificationCount + 1
        set nsDict to current application's NSDictionary's dictionaryWithObjectsAndKeys_(notificationCount, "NotificationIndex", "value2", "key2", "value3", "key3", missing value)
        -- send notification to NSUserNotificationCenter
		my sendNotification_("The Notifier",dateAsString,"It's time!","Restart","Stop",targetDate,"Boing",nsDict)
        say "Notification sent."
        return
	end applciationDidFinishLaunching_
    --
    
    -- format NSDate to string using styles
    -- 0 = none, 1 = short, 2 = med, 3 = long, 4 = full
    on formatDate_(aNSDate, aDateStyle, aTimeStyle)
        set myFormatter to current application's NSDateFormatter's alloc()'s init()
        myFormatter's setDateStyle_(aDateStyle)
        myFormatter's setTimeStyle_(aTimeStyle)
        set formattedDate to myFormatter's stringFromDate_(aNSDate)
        return formattedDate
    end formatDate_
    
	-- method for sending a notification
	on sendNotification_(aTitle, aSubtitle, aMessage, aActionButtonTitle, aOtherButtonTitle, aDeliveryDate, aSound, aDict)
        -- make the notification
		set myNotification to current application's NSUserNotification's alloc()'s init()
		set myNotification's title to aTitle
        set myNotification's subtitle to aSubtitle
		set myNotification's informativeText to aMessage
        set myNotification's actionButtonTitle to aActionButtonTitle
        set myNotification's otherButtonTitle to aOtherButtonTitle
        set myNotification's deliveryDate to aDeliveryDate
        set myNotification's soundName to aSound
        set myNotification's userInfo to aDict
        -- schedule the notification
        current application's NSUserNotificationCenter's defaultUserNotificationCenter's scheduleNotification_(myNotification)
        return
	end sendNotification_
    
    -- delegate instance methods
    -- force presentation
    on userNotificationCenter_shouldPresentNotification_(aCenter, aNotification)
        return yes
    end userNotificationCenter_shouldPresentNotification_
    
    -- deliver
    on userNotificationCenter_didDeliverNotification_(aCenter, aNotification)
        say "Notification Delivered"
        return
    end userNotificationCenter_didDeliverNotification_

    -- user activation
    on userNotificationCenter_didActivateNotification_(aCenter, aNotification)
        say "Notification Activated"
        -- 0    none
        -- 1    contents clicked
        -- 2    action button clicked
        set userActivationType to (aNotification's activationType) as integer
        if userActivationType is 1 then
            say "contents clicked"
            my contentsClicked_(aNotification)
        else if userActivationType is 2 then
            say "action button clicked"
            my actionButtonClicked_(aNotification)
        else -- userActivationType is 0
            say "no user activation"
        end if
        return userActivationType
    end userNotificationCenter_didActivateNotification_
    
    --
    on contentsClicked_(aNotification)
        -- do something
        return
    end contentsClicked_
    
    -- gets user info and deletes delivered notification from Notification Center
    on actionButtonClicked_(aNotification)
        -- delete the notification and send a new one (or some other action)
        -- first get info on notification
        set theInfo to aNotification's userInfo
        set theValue to theInfo's valueForKey_("NotificationIndex")
        say (theValue as string)
        -- delete notification from notification center
        current application's NSUserNotificationCenter's defaultUserNotificationCenter's removeDeliveredNotification_(aNotification)
        -- send a new notification
        my applicationDidFinishLaunching_(missing value)
        return
    end actionButtonClicked_
    --
    
    -- quit
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script

Added deleting notification from Notification Center (if needed) and eliminated AppleScript coercion of records. I finally learned how to use Dictionaries.

gl,
kel

Hi Kel,

Thanks for this! I was just adding abridge to an ObjC class to do this but found you good ASOC example.

Everyhting works fine except the action buttons do not show up in the notifications (which I need.)

Did your buttons show up there. I am using pretty much your excat code posted above.

Thanks, Rob

Hi robdut,

You need to find your app in System Preferences > Notifications. When you choose your application. select Alerts not Banners.

gl,
kel