root/trunk/lilypad/Sources/LPEventNotificationsHandler.m @ 136

Revision 136, 16.7 KB (checked in by jppavao, 6 years ago)

Fixed our growl notifications to be multi-account aware. Notifications for contacts belonging to accounts which are going online/offline will no longer be displayed when the account availability changes. References #60.

Line 
1//
2//  LPEventNotificationsHandler.m
3//  Lilypad
4//
5//      Copyright (C) 2006-2007 PT.COM,  All rights reserved.
6//      Author: Joao Pavao <jppavao@criticalsoftware.com>
7//
8//      For more information on licensing, read the README file.
9//      Para mais informa›es sobre o licenciamento, leia o ficheiro README.
10//
11
12#import "LPEventNotificationsHandler.h"
13#import "LPAccount.h"
14#import "LPContact.h"
15#import "LPContactEntry.h"
16#import "LPPresenceSubscription.h"
17
18
19// Notification Names for Growl
20static NSString *LPContactAvailabilityChangedNotificationName   = @"Contact Availability Changed";
21static NSString *LPFirstChatMessageReceivedNotificationName             = @"First Chat Message Received";
22static NSString *LPChatMessageReceivedNotificationName                  = @"Chat Message Received";
23static NSString *LPSMSMessageReceivedNotificationName                   = @"SMS Message Received";
24static NSString *LPHeadlineMessageReceivedNotificationName              = @"Notification Headline Received";
25static NSString *LPOfflineMessagesReceivedNotificationName              = @"Offline Messages Received";
26static NSString *LPPresenceSubscriptionReceivedNotificationName = @"Presence Subscription Received";
27static NSString *LPFileTransferEventNotificationName                    = @"File Transfer Event";
28
29
30// Key names for the Growl click context
31static NSString *LPClickContextKindKey                  = @"Kind";
32static NSString *LPClickContextContactIDKey             = @"ContactID";
33static NSString *LPClickContextMessageURIKey    = @"MessageURI";
34
35static NSString *LPClickContextContactKindValue                                 = @"Contact";
36static NSString *LPClickContextHeadlineMessageKindValue                 = @"HeadlineMessage";
37static NSString *LPClickContextOfflineMessagesKindValue                 = @"OfflineMessages";
38static NSString *LPClickContextPresenceSubscriptionKindValue    = @"PresenceSubscription";
39static NSString *LPClickContextFileTransferKindValue                    = @"FileTransfer";
40
41@implementation LPEventNotificationsHandler
42
43+ (void)registerWithGrowl
44{
45        // This forces the LPEventNotificationsHandler to initialize and register with Growl
46        [LPEventNotificationsHandler defaultHandler];
47}
48
49+ defaultHandler
50{
51        static LPEventNotificationsHandler *defaultHandler = nil;
52
53        if (defaultHandler == nil) {
54                defaultHandler = [[LPEventNotificationsHandler alloc] init];
55                [GrowlApplicationBridge setGrowlDelegate:defaultHandler];
56        }
57        return defaultHandler;
58}
59
60
61- init
62{
63        if (self = [super init]) {
64                m_contactAvailabilityNotificationsReenableDatesByAccountUUID = [[NSMutableDictionary alloc] init];
65        }
66        return self;
67}
68
69
70- (void)dealloc
71{
72        [m_contactAvailabilityNotificationsReenableDatesByAccountUUID release];
73        [super dealloc];
74}
75
76
77- (id)delegate
78{
79        return m_delegate;
80}
81
82
83- (void)setDelegate:(id)delegate
84{
85        m_delegate = delegate;
86}
87
88
89- (id)p_clickContextForContact:(LPContact *)contact
90{
91        return [NSDictionary dictionaryWithObjectsAndKeys:
92                LPClickContextContactKindValue, LPClickContextKindKey,
93                [NSNumber numberWithInt:[contact ID]], LPClickContextContactIDKey,
94                nil];
95}
96
97- (id)p_clickContextForHeadlineMessage:(id)message
98{
99        return [NSDictionary dictionaryWithObjectsAndKeys:
100                LPClickContextHeadlineMessageKindValue, LPClickContextKindKey,
101                [[[message objectID] URIRepresentation] absoluteString], LPClickContextMessageURIKey,
102                nil];
103}
104
105- (id)p_clickContextForOfflineMessages
106{
107        return [NSDictionary dictionaryWithObjectsAndKeys:
108                LPClickContextOfflineMessagesKindValue, LPClickContextKindKey,
109                nil];
110}
111
112- (id)p_clickContextForPresenceSubscription:(id)presSub
113{
114        return [NSDictionary dictionaryWithObjectsAndKeys:
115                LPClickContextPresenceSubscriptionKindValue, LPClickContextKindKey,
116                nil];
117}
118
119- (id)p_clickContextForFileTransfer
120{
121        return [NSDictionary dictionaryWithObjectsAndKeys:
122                LPClickContextFileTransferKindValue, LPClickContextKindKey,
123                nil];
124}
125
126
127#pragma mark Public Methods to Request Posting of Notifications
128
129
130- (void)disableContactAvailabilityNotificationsForAccount:(LPAccount *)account untilDate:(NSDate *)date
131{
132        [m_contactAvailabilityNotificationsReenableDatesByAccountUUID setObject:date forKey:[account UUID]];
133}
134
135
136- (void)notifyContactAvailabilityDidChange:(LPContact *)contact
137{
138        BOOL            shouldNotify = YES;
139        NSString        *statusChangeSourceAccountUUID = [[[contact lastContactEntryToChangeStatus] account] UUID];
140        NSDate          *notificationsReenableDate = [m_contactAvailabilityNotificationsReenableDatesByAccountUUID objectForKey:statusChangeSourceAccountUUID];
141       
142        if (notificationsReenableDate != nil) {
143                NSDate *now = [NSDate date];
144               
145                if ([now compare:notificationsReenableDate] == NSOrderedAscending) {
146                        // We're still in the time interval where notifications should be disabled.
147                        shouldNotify = NO;
148                }
149                else {
150                        // Clear the "timeout" date
151                        [m_contactAvailabilityNotificationsReenableDatesByAccountUUID removeObjectForKey:statusChangeSourceAccountUUID];
152                }
153        }
154       
155       
156        if (shouldNotify) {
157                // Allow a small delay to avoid having everything happen at the same time. This also allows the avatar to be updated
158                // (if it exists) from cache before actually displaying the notification.
159                [self performSelector:@selector(p_displayContactAvailabilityDidChangeNotification:)
160                                   withObject:contact
161                                   afterDelay:0.5];
162        }
163}
164
165
166- (void)p_displayContactAvailabilityDidChangeNotification:(LPContact *)contact
167{
168        // Avoid notifying about just added (in the last n seconds) and just deleted contacts
169        if ([contact roster] != nil && [[contact creationDate] timeIntervalSinceNow] < (-10.0)) {
170                NSString *description = ( ([contact status] == LPStatusOffline) ?
171                                                                  NSLocalizedString(@"went Offline", @"contact availability change notifications") :
172                                                                  NSLocalizedString(@"is now Online", @"contact availability change notifications")  );
173                // Make "contact went offline" notifications non-clickable
174                id clickContext = ( ([contact status] == LPStatusOffline) ?
175                                                        nil :
176                                                        [self p_clickContextForContact:contact] );
177               
178                [GrowlApplicationBridge notifyWithTitle:[contact name]
179                                                                        description:description
180                                                           notificationName:LPContactAvailabilityChangedNotificationName
181                                                                           iconData:[[contact avatar] TIFFRepresentation]
182                                                                           priority:0
183                                                                           isSticky:NO
184                                                                   clickContext:clickContext];
185        }
186}
187
188
189- (void)notifyReceptionOfFirstMessage:(NSString *)message fromContact:(LPContact *)contact
190{
191        NSString *title = [NSString stringWithFormat:
192                NSLocalizedString(@"First Message from %@", @"chat messages notifications"),
193                [contact name]];
194       
195        NSNumber *contactIDNr = [NSNumber numberWithInt:[contact ID]];
196        NSString *identifier = [[contactIDNr stringValue] stringByAppendingString:message];
197        NSData *iconData = [[contact avatar] TIFFRepresentation];
198       
199        /*
200         * Shoot the two kinds of notifications coalesced under the same identifier. This way, if the user
201         * has "first message notifications" disabled in the prefs but regular "message notifications" enabled,
202         * then the first message will still be able to have a notification displayed.
203         */
204       
205        [GrowlApplicationBridge notifyWithTitle:title
206                                                                description:message
207                                                   notificationName:LPChatMessageReceivedNotificationName
208                                                                   iconData:iconData
209                                                                   priority:1
210                                                                   isSticky:NO
211                                                           clickContext:[self p_clickContextForContact:contact]
212                                                                 identifier:identifier];
213       
214        [GrowlApplicationBridge notifyWithTitle:title
215                                                                description:message
216                                                   notificationName:LPFirstChatMessageReceivedNotificationName
217                                                                   iconData:iconData
218                                                                   priority:1
219                                                                   isSticky:NO
220                                                           clickContext:[self p_clickContextForContact:contact]
221                                                                 identifier:identifier];
222}
223
224
225- (void)notifyReceptionOfMessage:(NSString *)message fromContact:(LPContact *)contact
226{
227        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Message from %@", @"chat messages notifications"),
228                [contact name]];
229       
230        [GrowlApplicationBridge notifyWithTitle:title
231                                                                description:message
232                                                   notificationName:LPChatMessageReceivedNotificationName
233                                                                   iconData:[[contact avatar] TIFFRepresentation]
234                                                                   priority:1
235                                                                   isSticky:NO
236                                                           clickContext:[self p_clickContextForContact:contact]];
237}
238
239
240- (void)notifyReceptionOfSMSMessage:(NSString *)message fromContact:(LPContact *)contact
241{
242        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"SMS Message from %@", @"chat messages notifications"),
243                [contact name]];
244       
245        [GrowlApplicationBridge notifyWithTitle:title
246                                                                description:message
247                                                   notificationName:LPSMSMessageReceivedNotificationName
248                                                                   iconData:[[contact avatar] TIFFRepresentation]
249                                                                   priority:1
250                                                                   isSticky:NO
251                                                           clickContext:[self p_clickContextForContact:contact]];
252}
253
254
255- (void)notifyReceptionOfHeadlineMessage:(id)message
256{
257        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Notification Headline", @"messages notifications")];
258       
259        [GrowlApplicationBridge notifyWithTitle:title
260                                                                description:[message valueForKey:@"subject"]
261                                                   notificationName:LPHeadlineMessageReceivedNotificationName
262                                                                   iconData:nil
263                                                                   priority:1
264                                                                   isSticky:NO
265                                                           clickContext:[self p_clickContextForHeadlineMessage:message]];
266}
267
268
269- (void)p_notifyReceptionOfOfflineMessages
270{
271        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Offline Messages", @"messages notifications")];
272        NSString *descr = [NSString stringWithFormat:NSLocalizedString(@"You have received %d messages while you were offline.", @"messages notifications"), m_nrOfOfflineMessagesForDelayedNotification];
273       
274        [GrowlApplicationBridge notifyWithTitle:title
275                                                                description:descr
276                                                   notificationName:LPOfflineMessagesReceivedNotificationName
277                                                                   iconData:nil
278                                                                   priority:1
279                                                                   isSticky:NO
280                                                           clickContext:[self p_clickContextForOfflineMessages]];
281       
282        m_nrOfOfflineMessagesForDelayedNotification = 0;
283}
284
285- (void)notifyReceptionOfOfflineMessage:(id)message
286{
287        if (m_nrOfOfflineMessagesForDelayedNotification == 0) {
288                [self performSelector:@selector(p_notifyReceptionOfOfflineMessages) withObject:nil afterDelay:3.0];
289        }
290        ++m_nrOfOfflineMessagesForDelayedNotification;
291}
292
293
294- (void)notifyReceptionOfPresenceSubscription:(LPPresenceSubscription *)presSub
295{
296        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Presence Subscription", @"messages notifications")];
297        NSString *descr = nil;
298       
299        switch ([presSub state]) {
300                case LPAuthorizationGranted:
301                        descr = [NSString stringWithFormat:
302                                NSLocalizedString(@"%@ was added to your buddy list. You can now see the online status of this contact.", @"messages notifications"),
303                                [presSub valueForKeyPath:@"contactEntry.address"]];
304                        break;
305                       
306                case LPAuthorizationRequested:
307                        descr = [NSString stringWithFormat:
308                                NSLocalizedString(@"%@ wants to add you as a buddy.", @"messages notifications"),
309                                [presSub valueForKeyPath:@"contactEntry.address"]];
310                        break;
311                       
312                case LPAuthorizationLost:
313                        descr = [NSString stringWithFormat:
314                                NSLocalizedString(@"Permission to see the online status of contact %@ was lost.", @"messages notifications"),
315                                [presSub valueForKeyPath:@"contactEntry.address"]];
316                        break;
317        }
318       
319        [GrowlApplicationBridge notifyWithTitle:title
320                                                                description:descr
321                                                   notificationName:LPPresenceSubscriptionReceivedNotificationName
322                                                                   iconData:nil
323                                                                   priority:1
324                                                                   isSticky:NO
325                                                           clickContext:[self p_clickContextForPresenceSubscription:presSub]];
326}
327
328
329- (void)notifyReceptionOfFileTransferOfferWithFileName:(NSString *)filename fromContact:(LPContact *)contact
330{
331        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"File Transfer Offer", @"file transfer notifications")];
332        NSString *description = [NSString stringWithFormat:
333                NSLocalizedString(@"%@ is offering you the file \"%@\"", @"file transfer notifications"),
334                [contact name], filename];
335       
336        [GrowlApplicationBridge notifyWithTitle:title
337                                                                description:description
338                                                   notificationName:LPFileTransferEventNotificationName
339                                                                   iconData:nil
340                                                                   priority:1
341                                                                   isSticky:NO
342                                                           clickContext:[self p_clickContextForFileTransfer]];
343}
344
345- (void)notifyAcceptanceOfFileTransferWithFileName:(NSString *)filename fromContact:(LPContact *)contact
346{
347        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"File Transfer Accepted", @"file transfer notifications")];
348        NSString *description = [NSString stringWithFormat:
349                NSLocalizedString(@"%@ accepted your file named \"%@\"", @"file transfer notifications"),
350                [contact name], filename];
351       
352        [GrowlApplicationBridge notifyWithTitle:title
353                                                                description:description
354                                                   notificationName:LPFileTransferEventNotificationName
355                                                                   iconData:nil
356                                                                   priority:1
357                                                                   isSticky:NO
358                                                           clickContext:[self p_clickContextForFileTransfer]];
359}
360
361- (void)notifyFailureOfFileTransferWithFileName:(NSString *)filename fromContact:(LPContact *)contact withErrorMessage:(NSString *)errorMsg
362{
363        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"File Transfer Failed", @"file transfer notifications")];
364        NSString *description = ( (errorMsg != nil) ?
365                                                          [NSString stringWithFormat:
366                                                                  NSLocalizedString(@"The file transfer of \"%@\" with %@ has failed with the error: %@",
367                                                                                                        @"file transfer notifications"),
368                                                                  filename, [contact name], errorMsg] :
369                                                          [NSString stringWithFormat:
370                                                                  NSLocalizedString(@"The file transfer of \"%@\" with %@ has failed", @"file transfer notifications"),
371                                                                  filename, [contact name]] );
372       
373        [GrowlApplicationBridge notifyWithTitle:title
374                                                                description:description
375                                                   notificationName:LPFileTransferEventNotificationName
376                                                                   iconData:nil
377                                                                   priority:1
378                                                                   isSticky:NO
379                                                           clickContext:[self p_clickContextForFileTransfer]];
380}
381
382- (void)notifyCompletionOfFileTransferWithFileName:(NSString *)filename withContact:(LPContact *)contact
383{
384        NSString *title = [NSString stringWithFormat:NSLocalizedString(@"File Transfer Completed", @"file transfer notifications")];
385        NSString *description = [NSString stringWithFormat:
386                NSLocalizedString(@"Transfer of the file \"%@\" with %@ has completed", @"file transfer notifications"),
387                filename, [contact name]];
388       
389        [GrowlApplicationBridge notifyWithTitle:title
390                                                                description:description
391                                                   notificationName:LPFileTransferEventNotificationName
392                                                                   iconData:nil
393                                                                   priority:1
394                                                                   isSticky:NO
395                                                           clickContext:[self p_clickContextForFileTransfer]];
396}
397
398
399#pragma mark GrowlApplicationBridge Delegate
400
401
402- (NSDictionary *)registrationDictionaryForGrowl
403{
404        return [NSDictionary dictionaryWithObjectsAndKeys:
405               
406                [NSArray arrayWithObjects:
407                        LPContactAvailabilityChangedNotificationName,
408                        LPFirstChatMessageReceivedNotificationName,
409                        LPChatMessageReceivedNotificationName,
410                        LPSMSMessageReceivedNotificationName,
411                        LPHeadlineMessageReceivedNotificationName,
412                        LPOfflineMessagesReceivedNotificationName,
413                        LPPresenceSubscriptionReceivedNotificationName,
414                        LPFileTransferEventNotificationName,
415                        nil],
416                GROWL_NOTIFICATIONS_ALL,
417               
418                [NSArray arrayWithObjects:
419                        LPContactAvailabilityChangedNotificationName,
420                        LPFirstChatMessageReceivedNotificationName,
421                        LPSMSMessageReceivedNotificationName,
422                        LPHeadlineMessageReceivedNotificationName,
423                        LPOfflineMessagesReceivedNotificationName,
424                        LPPresenceSubscriptionReceivedNotificationName,
425                        LPFileTransferEventNotificationName,
426                        nil],
427                GROWL_NOTIFICATIONS_DEFAULT,
428               
429                nil];
430}
431
432
433- (void)growlNotificationWasClicked:(id)clickContext
434{
435        NSString *kind = [clickContext objectForKey:@"Kind"];
436       
437        if ([kind isEqualToString: LPClickContextContactKindValue]) {
438                if ([m_delegate respondsToSelector:@selector(notificationsHandler:userDidClickNotificationForContactWithID:)]) {
439                        unsigned int contactID = [[clickContext objectForKey: LPClickContextContactIDKey] intValue];
440                        [m_delegate notificationsHandler:self userDidClickNotificationForContactWithID:contactID];
441                }
442        }
443        else if ([kind isEqualToString: LPClickContextHeadlineMessageKindValue]) {
444                if ([m_delegate respondsToSelector:@selector(notificationsHandler:userDidClickNotificationForHeadlineMessageWithURI:)]) {
445                        NSString *messageURI = [clickContext objectForKey: LPClickContextMessageURIKey];
446                        [m_delegate notificationsHandler:self userDidClickNotificationForHeadlineMessageWithURI:messageURI];
447                }
448        }
449        else if ([kind isEqualToString: LPClickContextOfflineMessagesKindValue]) {
450                if ([m_delegate respondsToSelector:@selector(notificationsHandlerUserDidClickNotificationForOfflineMessages:)]) {
451                        [m_delegate notificationsHandlerUserDidClickNotificationForOfflineMessages:self];
452                }
453        }
454        else if ([kind isEqualToString: LPClickContextPresenceSubscriptionKindValue]) {
455                if ([m_delegate respondsToSelector:@selector(notificationsHandlerUserDidClickNotificationForPresenceSubscriptions:)]) {
456                        [m_delegate notificationsHandlerUserDidClickNotificationForPresenceSubscriptions:self];
457                }
458        }
459        else if ([kind isEqualToString: LPClickContextFileTransferKindValue]) {
460                if ([m_delegate respondsToSelector:@selector(notificationsHandlerUserDidClickNotificationForFileTransfer:)]) {
461                        [m_delegate notificationsHandlerUserDidClickNotificationForFileTransfer:self];
462                }
463        }
464}
465
466
467@end
Note: See TracBrowser for help on using the browser.