NSUserNotification - How open the app when clicked - objective-c

I'm using NSUserNotification to display notifications. This is working fine. The problem is that when you click on a notification:
The apps notifications are not removed from the notification center.
The app (when minimized) does not open.
Anyone familiar with the NSUserNotification who can offer some pointers?
notice.m
#import "Notice.h"
#implementation Notice
- (void) notify:(NSDictionary *)message {
NSLog(#"Notification - Show it");
NSUserNotification *notification = [[NSUserNotification alloc] init];
[notification setTitle:[message valueForKey:#"title"]];
[notification setInformativeText:[message valueForKey:#"content"]];
[notification setDeliveryDate:[NSDate dateWithTimeInterval:0 sinceDate:[NSDate date]]];
[notification setSoundName:NSUserNotificationDefaultSoundName];
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center scheduleNotification:notification];
}
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSLog(#"Notification - Clicked");
notification=nil;
[center removeDeliveredNotification: notification];
}
#pragma mark WebScripting Protocol
+ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector
{
if (selector == #selector(notify:))
return NO;
return YES;
}
+ (NSString*) webScriptNameForSelector:(SEL)selector
{
id result = nil;
if (selector == #selector(notify:)) {
result = #"notify";
}
return result;
}
// right now exclude all properties (eg keys)
+ (BOOL) isKeyExcludedFromWebScript:(const char*)name
{
return YES;
}
#end
Thank you

Just implement the NSUserNotificationCenterDelegate and define this method:
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
Example:
This is what I did in a "notifier" application.
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSRunAlertPanel([notification title], [notification informativeText], #"Ok", nil, nil);
}
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification
{
notifications=nil;
[tableView reloadData];
[center removeDeliveredNotification: notification];
}
When the notification is activated (click by the user) I just inform the user with a panel (I could use a hud window).In this case I immediately remove the delivered notification, but this is not what happens usually.The notification could stay there some time and be removed after 1/2 hours (it depends on the application that you are developing).

Related

NSUserNotification close calls didActivateNotification

Since MacOS 10.13 everytime I click the close button on a NSUserNotification it calls:
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
How can I prevent this or handle the close vs the action button
To create the notification I do:
NSUserNotification *notification = [[NSUserNotification alloc] init];
...
[notification setHasActionButton:false];
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:(id)self];
and NSUserNotificationAlertStyle in the .plist is set to "alert"
but now basically the close button reacts the same way the actionButton does??
NSUserNotification has property from which you can manage notification identifier or hasActionButton value, so you can handle the close vs the action button with if else in the same delegate method
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification{
}
This is works for me..
you can remove notification in didActivateNotification: method
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSLog(#"Notification - Clicked");
[center removeDeliveredNotification: notification];
notification=nil;
}
where center is...
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center scheduleNotification:notification];

NSNotification not being called when UIButton triggered

I don't understand why a NSNotification I'm trying to send is not being called when I pulse a UIButton. I'm trying to send an object from a ViewController to other ViewController with Notifications.
My code:
In Viewcontroller.m :
- In Init method:
[self.goPanelRightButton addTarget:self action:#selector(btnMovePanelRight:) forControlEvents:UIControlEventTouchUpInside];
- (IBAction)btnMovePanelRight:(id)sender
{
UIButton *button = sender;
switch (button.tag) {
case 0: {
[self movePanelToOriginalPosition];
break;
}
case 1: {
[self sendModel];
NSLog(#"Entered case 1");
[self movePanelRight];
break;
}
default:
break;
}
}
-(void)sendModel{
[[NSNotificationCenter defaultCenter] postNotificationName:kModelNotification
object:self
userInfo:#{GALLERY_KEY:self.model}];
In ObserverViewController:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:#selector(getModelMain:)
name:kModelNotification
object:nil];
}
}
-(void)getModelMain:(NSNotification *) notification{
NSDictionary *dict = [notification userInfo];
self.model=[dict objectForKey:GALLERY_KEY];
}
Thanks ;)
I resolved with Key Value Coding. Passing the object before I change to the next view:
SEL selector = NSSelectorFromString(#"setModel:");
if ([self.leftPanelViewController respondsToSelector:selector]) {
[self.leftPanelViewController setValue:self.model forKey:#"model"];
}

Why is controlTextDidEndEditing being called when I send setEditable?

//1:
-(void) TextFieldEdit:(CDTextField *)textField{
[textField setEditable:YES];
}
//2:
- (void)controlTextDidEndEditing:(NSNotification *)aNotification{
NSTextField* textField = (NSTextField *)[aNotification object];
[textField setEditable:NO];
}
I hope setEditable at time 1, and close it at time 2.
But I found when I sent setEditable Xcode immediately called the controlTextDidEndEditing:.
Why?
EDIT: The first method is invoked via the following sub-classed method:
-(void)mouseDown:(NSEvent *)event {
if ([event type]==1)
{
NSInteger key=[event modifierFlags];
if ( key & NSCommandKeyMask)
{[self.delegate CDTextFieldEdit:self]; }
else
if (event.clickCount >1)
{[self.delegate CDTextFieldClicked:self]; return;}
}
[super mouseDown:event];
}

didActivateNotification is not responding to NSUserNotification

I'm working to get osx native notifications working. I'm able to create a notification but not get the didActivateNotification working. I want didActivateNotification to allow me to focus the window and remove the notification from the notification center.
Here is my code: notice.m
#import "Notice.h"
#implementation Notice
- (void) notify:(NSDictionary *)message {
NSLog(#"Notification - Show it");
NSUserNotification *notification = [[NSUserNotification alloc] init];
[notification setTitle:[message valueForKey:#"title"]];
[notification setInformativeText:[message valueForKey:#"content"]];
[notification setDeliveryDate:[NSDate dateWithTimeInterval:0 sinceDate:[NSDate date]]];
[notification setSoundName:NSUserNotificationDefaultSoundName];
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
[center scheduleNotification:notification];
}
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
NSLog(#"Notification - Clicked");
notification=nil;
[center removeDeliveredNotification: notification];
}
This is firing properly:
NSLog(#"Notification - Show it");
But this is not:
NSLog(#"Notification - Clicked");
Any suggestions? Thanks
You probably have to set the delegate for NSUserNotificationCenter:
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
center.delegate = self;
You should also make sure your Notice class implements the NSUserNotificationCenterDelegate protocol.

Play video in Mac OS X 10.7

What is the simplest way to play a video programmatically with Objective-C in Mac OS X 10.7 (Lion)? And if I want to support OS X 10.6 (Snow Leopard) too?
I noticed that iOS AV Foundation was introduced to OS X 10.7. Unfortunately the documentation seems to be written for iOS and I found it confusing.
Here's a NSView subclass that plays a video given a URL, using AV Foundation (thus Mac OS X 10.7 upwards only). Based on the AVSimplePlayer sample code.
Header:
#interface RMVideoView : NSView
#property (nonatomic, readonly, strong) AVPlayer* player;
#property (nonatomic, readonly, strong) AVPlayerLayer* playerLayer;
#property (nonatomic, retain) NSURL* videoURL;
- (void) play;
#end
Implementation:
static void *RMVideoViewPlayerLayerReadyForDisplay = &RMVideoViewPlayerLayerReadyForDisplay;
static void *RMVideoViewPlayerItemStatusContext = &RMVideoViewPlayerItemStatusContext;
#interface RMVideoView()
- (void)onError:(NSError*)error;
- (void)onReadyToPlay;
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys;
#end
#implementation RMVideoView
#synthesize player = _player;
#synthesize playerLayer = _playerLayer;
#synthesize videoURL = _videoURL;
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.wantsLayer = YES;
_player = [[AVPlayer alloc] init];
[self addObserver:self forKeyPath:#"player.currentItem.status" options:NSKeyValueObservingOptionNew context:RMVideoViewPlayerItemStatusContext];
}
return self;
}
- (void) dealloc {
[self.player pause];
[self removeObserver:self forKeyPath:#"player.currentItem.status"];
[self removeObserver:self forKeyPath:#"playerLayer.readyForDisplay"];
[_player release];
[_playerLayer release];
[_videoURL release];
[super dealloc];
}
- (void) setVideoURL:(NSURL *)videoURL {
_videoURL = videoURL;
[self.player pause];
[self.playerLayer removeFromSuperlayer];
AVURLAsset *asset = [AVAsset assetWithURL:self.videoURL];
NSArray *assetKeysToLoadAndTest = [NSArray arrayWithObjects:#"playable", #"hasProtectedContent", #"tracks", #"duration", nil];
[asset loadValuesAsynchronouslyForKeys:assetKeysToLoadAndTest completionHandler:^(void) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self setUpPlaybackOfAsset:asset withKeys:assetKeysToLoadAndTest];
});
}];
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == RMVideoViewPlayerItemStatusContext) {
AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
switch (status) {
case AVPlayerItemStatusUnknown:
break;
case AVPlayerItemStatusReadyToPlay:
[self onReadyToPlay];
break;
case AVPlayerItemStatusFailed:
[self onError:nil];
break;
}
} else if (context == RMVideoViewPlayerLayerReadyForDisplay) {
if ([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) {
self.playerLayer.hidden = NO;
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - Private
- (void)onError:(NSError*)error {
// Notify delegate
}
- (void)onReadyToPlay {
// Notify delegate
}
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys {
for (NSString *key in keys) {
NSError *error = nil;
if ([asset statusOfValueForKey:key error:&error] == AVKeyValueStatusFailed) {
[self onError:error];
return;
}
}
if (!asset.isPlayable || asset.hasProtectedContent) {
[self onError:nil];
return;
}
if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0) { // Asset has video tracks
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.frame = self.layer.bounds;
self.playerLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.playerLayer.hidden = YES;
[self.layer addSublayer:self.playerLayer];
[self addObserver:self forKeyPath:#"playerLayer.readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:RMVideoViewPlayerLayerReadyForDisplay];
}
// Create a new AVPlayerItem and make it our player's current item.
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[self.player replaceCurrentItemWithPlayerItem:playerItem];
}
#pragma mark - Public
- (void) play {
[self.player play];
}
#end
"Simplest" depends on exactly what you're trying to do. If you want more control (e.g., rendering the movie as an OpenGL texture) or less (e.g., a completely independent window that you can just pop up and ignore), there might be different answers.
But for most use cases, if you want 10.6+ support, the simplest way to show a movie is QTKit. See the article "Using QTKit for Media Playback" in the Xcode documentation for a good starting point.